aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--org.jacoco.core.test/src/org/jacoco/core/analysis/CoverageBuilderTest.java2
-rw-r--r--org.jacoco.core.test/src/org/jacoco/core/analysis/CoverageNodeImplTest.java9
-rw-r--r--org.jacoco.core.test/src/org/jacoco/core/internal/analysis/ClassCoverageImplTest.java1
-rw-r--r--org.jacoco.core.test/src/org/jacoco/core/internal/analysis/MethodCoverageImplTest.java86
-rw-r--r--org.jacoco.core.test/src/org/jacoco/core/test/validation/CyclomaticComplexityTest.java275
-rw-r--r--org.jacoco.core/src/org/jacoco/core/analysis/CoverageNodeImpl.java17
-rw-r--r--org.jacoco.core/src/org/jacoco/core/analysis/ICoverageNode.java10
-rw-r--r--org.jacoco.core/src/org/jacoco/core/internal/analysis/MethodAnalyzer.java1
-rw-r--r--org.jacoco.core/src/org/jacoco/core/internal/analysis/MethodCoverageImpl.java20
-rw-r--r--org.jacoco.doc/docroot/doc/changes.html5
-rw-r--r--org.jacoco.report.test/src/org/jacoco/report/ReportStructureTestDriver.java1
-rw-r--r--org.jacoco.report.test/src/org/jacoco/report/csv/CSVFormatterTest.java8
-rw-r--r--org.jacoco.report.test/src/org/jacoco/report/csv/CSVGroupHandlerTest.java4
13 files changed, 415 insertions, 24 deletions
diff --git a/org.jacoco.core.test/src/org/jacoco/core/analysis/CoverageBuilderTest.java b/org.jacoco.core.test/src/org/jacoco/core/analysis/CoverageBuilderTest.java
index d7741ade..ec242c75 100644
--- a/org.jacoco.core.test/src/org/jacoco/core/analysis/CoverageBuilderTest.java
+++ b/org.jacoco.core.test/src/org/jacoco/core/analysis/CoverageBuilderTest.java
@@ -49,6 +49,7 @@ public class CoverageBuilderTest {
method.increment(CounterImpl.COUNTER_1_0, CounterImpl.COUNTER_0_0, 6);
method.increment(CounterImpl.COUNTER_1_0, CounterImpl.COUNTER_0_0, 7);
method.increment(CounterImpl.COUNTER_1_0, CounterImpl.COUNTER_0_0, 8);
+ method.incrementMethodCounter();
addClass(123L, "Sample", null, method);
final Collection<IClassCoverage> classes = coverageBuilder.getClasses();
@@ -80,6 +81,7 @@ public class CoverageBuilderTest {
method.increment(CounterImpl.COUNTER_0_1, CounterImpl.COUNTER_0_0, 6);
method.increment(CounterImpl.COUNTER_0_1, CounterImpl.COUNTER_0_0, 7);
method.increment(CounterImpl.COUNTER_0_1, CounterImpl.COUNTER_0_0, 8);
+ method.incrementMethodCounter();
addClass(123L, "Sample", null, method);
final Collection<IClassCoverage> classes = coverageBuilder.getClasses();
diff --git a/org.jacoco.core.test/src/org/jacoco/core/analysis/CoverageNodeImplTest.java b/org.jacoco.core.test/src/org/jacoco/core/analysis/CoverageNodeImplTest.java
index 7a8a0641..f2f7ec9f 100644
--- a/org.jacoco.core.test/src/org/jacoco/core/analysis/CoverageNodeImplTest.java
+++ b/org.jacoco.core.test/src/org/jacoco/core/analysis/CoverageNodeImplTest.java
@@ -13,6 +13,7 @@ package org.jacoco.core.analysis;
import static org.jacoco.core.analysis.ICoverageNode.CounterEntity.BRANCH;
import static org.jacoco.core.analysis.ICoverageNode.CounterEntity.CLASS;
+import static org.jacoco.core.analysis.ICoverageNode.CounterEntity.COMPLEXITY;
import static org.jacoco.core.analysis.ICoverageNode.CounterEntity.INSTRUCTION;
import static org.jacoco.core.analysis.ICoverageNode.CounterEntity.LINE;
import static org.jacoco.core.analysis.ICoverageNode.CounterEntity.METHOD;
@@ -42,6 +43,7 @@ public class CoverageNodeImplTest {
assertEquals(CounterImpl.COUNTER_0_0, node.getBranchCounter());
assertEquals(CounterImpl.COUNTER_0_0, node.getInstructionCounter());
assertEquals(CounterImpl.COUNTER_0_0, node.getLineCounter());
+ assertEquals(CounterImpl.COUNTER_0_0, node.getComplexityCounter());
assertEquals(CounterImpl.COUNTER_0_0, node.getMethodCounter());
assertEquals(CounterImpl.COUNTER_0_0, node.getClassCounter());
}
@@ -55,6 +57,7 @@ public class CoverageNodeImplTest {
instructionCounter = CounterImpl.getInstance(1, 41);
branchCounter = CounterImpl.getInstance(10, 15);
lineCounter = CounterImpl.getInstance(5, 3);
+ complexityCounter = CounterImpl.getInstance(4, 2);
methodCounter = CounterImpl.getInstance(1, 21);
classCounter = CounterImpl.getInstance(1, 11);
}
@@ -68,6 +71,10 @@ public class CoverageNodeImplTest {
assertEquals(CounterImpl.getInstance(10, 15), parent.getBranchCounter());
assertEquals(CounterImpl.getInstance(5, 3), parent.getCounter(LINE));
assertEquals(CounterImpl.getInstance(5, 3), parent.getLineCounter());
+ assertEquals(CounterImpl.getInstance(4, 2),
+ parent.getCounter(COMPLEXITY));
+ assertEquals(CounterImpl.getInstance(4, 2),
+ parent.getComplexityCounter());
assertEquals(CounterImpl.getInstance(1, 21), parent.getCounter(METHOD));
assertEquals(CounterImpl.getInstance(1, 21), parent.getMethodCounter());
assertEquals(CounterImpl.getInstance(1, 11), parent.getCounter(CLASS));
@@ -101,6 +108,7 @@ public class CoverageNodeImplTest {
branchCounter = CounterImpl.getInstance(3, 3);
instructionCounter = CounterImpl.getInstance(4, 4);
lineCounter = CounterImpl.getInstance(5, 5);
+ complexityCounter = CounterImpl.getInstance(6, 6);
}
};
ICoverageNode copy = node.getPlainCopy();
@@ -112,6 +120,7 @@ public class CoverageNodeImplTest {
assertEquals(CounterImpl.getInstance(4, 4),
copy.getInstructionCounter());
assertEquals(CounterImpl.getInstance(5, 5), copy.getLineCounter());
+ assertEquals(CounterImpl.getInstance(6, 6), copy.getComplexityCounter());
}
@Test
diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/ClassCoverageImplTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/ClassCoverageImplTest.java
index 2821070f..90fb0886 100644
--- a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/ClassCoverageImplTest.java
+++ b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/ClassCoverageImplTest.java
@@ -87,6 +87,7 @@ public class ClassCoverageImplTest {
m.increment(
covered ? CounterImpl.COUNTER_0_1 : CounterImpl.COUNTER_1_0,
CounterImpl.COUNTER_0_0, ISourceNode.UNKNOWN_LINE);
+ m.incrementMethodCounter();
return m;
}
diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/MethodCoverageImplTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/MethodCoverageImplTest.java
index 2d2af18a..bebd3420 100644
--- a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/MethodCoverageImplTest.java
+++ b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/MethodCoverageImplTest.java
@@ -38,30 +38,94 @@ public class MethodCoverageImplTest {
public void testEmptyMethod() {
ICoverageNode node = new MethodCoverageImpl("sample", "()V", null);
- assertEquals(CounterImpl.getInstance(0, 0), node.getLineCounter());
- assertEquals(CounterImpl.getInstance(0, 0),
- node.getInstructionCounter());
- assertEquals(CounterImpl.getInstance(0, 0), node.getBranchCounter());
- assertEquals(CounterImpl.getInstance(1, 0), node.getMethodCounter());
- assertEquals(CounterImpl.getInstance(0, 0), node.getClassCounter());
+ assertEquals(CounterImpl.COUNTER_0_0, node.getInstructionCounter());
+ assertEquals(CounterImpl.COUNTER_0_0, node.getBranchCounter());
+ assertEquals(CounterImpl.COUNTER_0_0, node.getLineCounter());
+ assertEquals(CounterImpl.COUNTER_0_0, node.getComplexityCounter());
+ assertEquals(CounterImpl.COUNTER_0_0, node.getMethodCounter());
+ assertEquals(CounterImpl.COUNTER_0_0, node.getClassCounter());
}
@Test
- public void testIncrementMissed() {
+ public void testIncrementMissedInstructions() {
MethodCoverageImpl node = new MethodCoverageImpl("sample", "()V", null);
node.increment(CounterImpl.getInstance(25, 0), CounterImpl.COUNTER_0_0,
3);
-
- assertEquals(CounterImpl.getInstance(1, 0), node.getMethodCounter());
+ node.incrementMethodCounter();
+ assertEquals(CounterImpl.COUNTER_1_0, node.getMethodCounter());
+ assertEquals(CounterImpl.COUNTER_1_0, node.getComplexityCounter());
}
@Test
- public void testIncrementCovered() {
+ public void testIncrementCoveredInstructions() {
MethodCoverageImpl node = new MethodCoverageImpl("sample", "()V", null);
node.increment(CounterImpl.getInstance(12, 13),
CounterImpl.COUNTER_0_0, 3);
+ node.incrementMethodCounter();
+ assertEquals(CounterImpl.COUNTER_0_1, node.getMethodCounter());
+ assertEquals(CounterImpl.COUNTER_0_1, node.getComplexityCounter());
+ }
+
+ @Test
+ public void testIncrementComplexity1() {
+ MethodCoverageImpl node = new MethodCoverageImpl("sample", "()V", null);
+ node.increment(CounterImpl.COUNTER_0_0, CounterImpl.COUNTER_0_0, 3);
+ assertEquals(CounterImpl.COUNTER_0_0, node.getComplexityCounter());
+ }
+
+ @Test
+ public void testIncrementComplexity2() {
+ MethodCoverageImpl node = new MethodCoverageImpl("sample", "()V", null);
+ node.increment(CounterImpl.COUNTER_0_0, CounterImpl.getInstance(2, 0),
+ 3);
+ assertEquals(CounterImpl.getInstance(1, 0), node.getComplexityCounter());
+ }
+
+ @Test
+ public void testIncrementComplexity3() {
+ MethodCoverageImpl node = new MethodCoverageImpl("sample", "()V", null);
+ node.increment(CounterImpl.COUNTER_0_0, CounterImpl.getInstance(1, 1),
+ 3);
+ assertEquals(CounterImpl.getInstance(1, 0), node.getComplexityCounter());
+ }
+
+ @Test
+ public void testIncrementComplexity4() {
+ MethodCoverageImpl node = new MethodCoverageImpl("sample", "()V", null);
+ node.increment(CounterImpl.COUNTER_0_0, CounterImpl.getInstance(0, 2),
+ 3);
+ assertEquals(CounterImpl.getInstance(0, 1), node.getComplexityCounter());
+ }
+
+ @Test
+ public void testIncrementComplexity5() {
+ MethodCoverageImpl node = new MethodCoverageImpl("sample", "()V", null);
+ node.increment(CounterImpl.COUNTER_0_0, CounterImpl.getInstance(3, 0),
+ 3);
+ assertEquals(CounterImpl.getInstance(2, 0), node.getComplexityCounter());
+ }
- assertEquals(CounterImpl.getInstance(0, 1), node.getMethodCounter());
+ @Test
+ public void testIncrementComplexity6() {
+ MethodCoverageImpl node = new MethodCoverageImpl("sample", "()V", null);
+ node.increment(CounterImpl.COUNTER_0_0, CounterImpl.getInstance(2, 1),
+ 3);
+ assertEquals(CounterImpl.getInstance(2, 0), node.getComplexityCounter());
}
+ @Test
+ public void testIncrementComplexity7() {
+ MethodCoverageImpl node = new MethodCoverageImpl("sample", "()V", null);
+ node.increment(CounterImpl.COUNTER_0_0, CounterImpl.getInstance(1, 2),
+ 3);
+ assertEquals(CounterImpl.getInstance(1, 1), node.getComplexityCounter());
+ }
+
+ @Test
+ public void testIncrementComplexity8() {
+ MethodCoverageImpl node = new MethodCoverageImpl("sample", "()V", null);
+ node.increment(CounterImpl.COUNTER_0_0, CounterImpl.getInstance(0, 3),
+ 3);
+ assertEquals(CounterImpl.getInstance(0, 2), node.getComplexityCounter());
+ }
}
diff --git a/org.jacoco.core.test/src/org/jacoco/core/test/validation/CyclomaticComplexityTest.java b/org.jacoco.core.test/src/org/jacoco/core/test/validation/CyclomaticComplexityTest.java
new file mode 100644
index 00000000..088c089f
--- /dev/null
+++ b/org.jacoco.core.test/src/org/jacoco/core/test/validation/CyclomaticComplexityTest.java
@@ -0,0 +1,275 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2011 Mountainminds GmbH & Co. KG and Contributors
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Marc R. Hoffmann - initial API and implementation
+ *
+ *******************************************************************************/
+package org.jacoco.core.test.validation;
+
+import static org.jacoco.core.test.validation.targets.Stubs.nop;
+import static org.junit.Assert.assertEquals;
+
+import java.util.Collection;
+
+import org.jacoco.core.analysis.Analyzer;
+import org.jacoco.core.analysis.CoverageBuilder;
+import org.jacoco.core.analysis.IClassCoverage;
+import org.jacoco.core.analysis.ICounter;
+import org.jacoco.core.analysis.IMethodCoverage;
+import org.jacoco.core.data.ExecutionDataStore;
+import org.jacoco.core.instr.Instrumenter;
+import org.jacoco.core.internal.analysis.CounterImpl;
+import org.jacoco.core.runtime.IRuntime;
+import org.jacoco.core.runtime.SystemPropertiesRuntime;
+import org.jacoco.core.test.TargetLoader;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.objectweb.asm.ClassReader;
+
+/**
+ * Various tests for cyclomatic complexity of methods.
+ */
+public class CyclomaticComplexityTest {
+
+ public interface Target {
+ public void test(int arg);
+ }
+
+ private IRuntime runtime;
+ private ClassReader reader;
+ private Target target;
+
+ @Before
+ public void setup() throws Exception {
+ runtime = new SystemPropertiesRuntime();
+ runtime.startup();
+ }
+
+ @After
+ public void teardown() {
+ runtime.shutdown();
+ }
+
+ public static class Simple implements Target {
+ public void test(int arg) {
+ nop();
+ nop();
+ nop();
+ }
+ }
+
+ @Test
+ public void testSimple1() throws Exception {
+ instrument(Simple.class);
+ final ICounter complexity = analyze();
+ assertEquals(CounterImpl.getInstance(1, 0), complexity);
+ }
+
+ @Test
+ public void testSimple2() throws Exception {
+ instrument(Simple.class);
+ target.test(0);
+ final ICounter complexity = analyze();
+ assertEquals(CounterImpl.getInstance(0, 1), complexity);
+ }
+
+ public static class If implements Target {
+ public void test(int arg) {
+ if (arg == 0) {
+ nop();
+ }
+ }
+ }
+
+ @Test
+ public void testIf1() throws Exception {
+ instrument(If.class);
+ final ICounter complexity = analyze();
+ assertEquals(CounterImpl.getInstance(2, 0), complexity);
+ }
+
+ @Test
+ public void testIf2() throws Exception {
+ instrument(If.class);
+ target.test(0);
+ final ICounter complexity = analyze();
+ assertEquals(CounterImpl.getInstance(1, 1), complexity);
+ }
+
+ @Test
+ public void testIf3() throws Exception {
+ instrument(If.class);
+ target.test(0);
+ target.test(1);
+ final ICounter complexity = analyze();
+ assertEquals(CounterImpl.getInstance(0, 2), complexity);
+ }
+
+ public static class TwoIf implements Target {
+ public void test(int arg) {
+ if (arg < 0) {
+ nop();
+ }
+ if (arg > 0) {
+ nop();
+ }
+ }
+ }
+
+ @Test
+ public void testTwoIf1() throws Exception {
+ instrument(TwoIf.class);
+ final ICounter complexity = analyze();
+ assertEquals(CounterImpl.getInstance(3, 0), complexity);
+ }
+
+ @Test
+ public void testTwoIf2() throws Exception {
+ instrument(TwoIf.class);
+ target.test(-1);
+ final ICounter complexity = analyze();
+ assertEquals(CounterImpl.getInstance(2, 1), complexity);
+ }
+
+ @Test
+ public void testTwoIf3() throws Exception {
+ instrument(TwoIf.class);
+ target.test(-1);
+ target.test(0);
+ final ICounter complexity = analyze();
+ assertEquals(CounterImpl.getInstance(1, 2), complexity);
+ }
+
+ @Test
+ public void testTwoIf4() throws Exception {
+ instrument(TwoIf.class);
+ target.test(-1);
+ target.test(+1);
+ final ICounter complexity = analyze();
+ assertEquals(CounterImpl.getInstance(0, 3), complexity);
+ }
+
+ public static class NestedIf implements Target {
+ public void test(int arg) {
+ if (arg >= 0) {
+ if (arg == 0) {
+ nop();
+ }
+ nop();
+ }
+ }
+ }
+
+ @Test
+ public void testNestedIf1() throws Exception {
+ instrument(NestedIf.class);
+ final ICounter complexity = analyze();
+ assertEquals(CounterImpl.getInstance(3, 0), complexity);
+ }
+
+ @Test
+ public void testNestedIf2() throws Exception {
+ instrument(NestedIf.class);
+ target.test(-1);
+ final ICounter complexity = analyze();
+ assertEquals(CounterImpl.getInstance(2, 1), complexity);
+ }
+
+ @Test
+ public void testNestedIf3() throws Exception {
+ instrument(NestedIf.class);
+ target.test(-1);
+ target.test(0);
+ final ICounter complexity = analyze();
+ assertEquals(CounterImpl.getInstance(1, 2), complexity);
+ }
+
+ @Test
+ public void testNestedIf4() throws Exception {
+ instrument(NestedIf.class);
+ target.test(-1);
+ target.test(0);
+ target.test(+1);
+ final ICounter complexity = analyze();
+ assertEquals(CounterImpl.getInstance(0, 3), complexity);
+ }
+
+ public static class Switch implements Target {
+ public void test(int arg) {
+ switch (arg) {
+ case 1:
+ nop();
+ break;
+ case 2:
+ nop();
+ break;
+ }
+ }
+ }
+
+ @Test
+ public void testSwitch1() throws Exception {
+ instrument(Switch.class);
+ final ICounter complexity = analyze();
+ assertEquals(CounterImpl.getInstance(3, 0), complexity);
+ }
+
+ @Test
+ public void testSwitch2() throws Exception {
+ instrument(Switch.class);
+ target.test(0);
+ final ICounter complexity = analyze();
+ assertEquals(CounterImpl.getInstance(2, 1), complexity);
+ }
+
+ @Test
+ public void testSwitch3() throws Exception {
+ instrument(Switch.class);
+ target.test(0);
+ target.test(1);
+ final ICounter complexity = analyze();
+ assertEquals(CounterImpl.getInstance(1, 2), complexity);
+ }
+
+ @Test
+ public void testSwitch4() throws Exception {
+ instrument(Switch.class);
+ target.test(0);
+ target.test(1);
+ target.test(2);
+ final ICounter complexity = analyze();
+ assertEquals(CounterImpl.getInstance(0, 3), complexity);
+ }
+
+ private void instrument(final Class<? extends Target> clazz)
+ throws Exception {
+ reader = new ClassReader(TargetLoader.getClassData(clazz));
+ final byte[] bytes = new Instrumenter(runtime).instrument(reader);
+ final TargetLoader loader = new TargetLoader(clazz, bytes);
+ target = (Target) loader.getTargetClass().newInstance();
+ }
+
+ private ICounter analyze() {
+ final CoverageBuilder builder = new CoverageBuilder();
+ final ExecutionDataStore store = new ExecutionDataStore();
+ runtime.collect(store, null, false);
+ final Analyzer analyzer = new Analyzer(store, builder);
+ analyzer.analyzeClass(reader);
+ final Collection<IClassCoverage> classes = builder.getClasses();
+ assertEquals(1, classes.size(), 0.0);
+ final IClassCoverage classCoverage = classes.iterator().next();
+ for (final IMethodCoverage m : classCoverage.getMethods()) {
+ if (m.getName().equals("test")) {
+ return m.getComplexityCounter();
+ }
+ }
+ throw new AssertionError("No test() method.");
+ }
+
+}
diff --git a/org.jacoco.core/src/org/jacoco/core/analysis/CoverageNodeImpl.java b/org.jacoco.core/src/org/jacoco/core/analysis/CoverageNodeImpl.java
index eae6124e..7abc8723 100644
--- a/org.jacoco.core/src/org/jacoco/core/analysis/CoverageNodeImpl.java
+++ b/org.jacoco.core/src/org/jacoco/core/analysis/CoverageNodeImpl.java
@@ -33,6 +33,9 @@ public class CoverageNodeImpl implements ICoverageNode {
/** Counter for lines, if this element does not have lines. */
protected CounterImpl lineCounter;
+ /** Counter for complexity. */
+ protected CounterImpl complexityCounter;
+
/** Counter for methods. */
protected CounterImpl methodCounter;
@@ -52,6 +55,7 @@ public class CoverageNodeImpl implements ICoverageNode {
this.name = name;
this.branchCounter = CounterImpl.COUNTER_0_0;
this.instructionCounter = CounterImpl.COUNTER_0_0;
+ this.complexityCounter = CounterImpl.COUNTER_0_0;
this.methodCounter = CounterImpl.COUNTER_0_0;
this.classCounter = CounterImpl.COUNTER_0_0;
this.lineCounter = CounterImpl.COUNTER_0_0;
@@ -67,9 +71,11 @@ public class CoverageNodeImpl implements ICoverageNode {
instructionCounter = instructionCounter.increment(child
.getInstructionCounter());
branchCounter = branchCounter.increment(child.getBranchCounter());
+ lineCounter = lineCounter.increment(child.getLineCounter());
+ complexityCounter = complexityCounter.increment(child
+ .getComplexityCounter());
methodCounter = methodCounter.increment(child.getMethodCounter());
classCounter = classCounter.increment(child.getClassCounter());
- lineCounter = lineCounter.increment(child.getLineCounter());
}
/**
@@ -107,6 +113,10 @@ public class CoverageNodeImpl implements ICoverageNode {
return lineCounter;
}
+ public ICounter getComplexityCounter() {
+ return complexityCounter;
+ }
+
public ICounter getMethodCounter() {
return methodCounter;
}
@@ -123,6 +133,8 @@ public class CoverageNodeImpl implements ICoverageNode {
return getBranchCounter();
case LINE:
return getLineCounter();
+ case COMPLEXITY:
+ return getComplexityCounter();
case METHOD:
return getMethodCounter();
case CLASS:
@@ -135,9 +147,10 @@ public class CoverageNodeImpl implements ICoverageNode {
final CoverageNodeImpl copy = new CoverageNodeImpl(elementType, name);
copy.instructionCounter = CounterImpl.getInstance(instructionCounter);
copy.branchCounter = CounterImpl.getInstance(branchCounter);
+ copy.lineCounter = CounterImpl.getInstance(lineCounter);
+ copy.complexityCounter = CounterImpl.getInstance(complexityCounter);
copy.methodCounter = CounterImpl.getInstance(methodCounter);
copy.classCounter = CounterImpl.getInstance(classCounter);
- copy.lineCounter = CounterImpl.getInstance(lineCounter);
return copy;
}
diff --git a/org.jacoco.core/src/org/jacoco/core/analysis/ICoverageNode.java b/org.jacoco.core/src/org/jacoco/core/analysis/ICoverageNode.java
index 45f97789..bf9d1d2d 100644
--- a/org.jacoco.core/src/org/jacoco/core/analysis/ICoverageNode.java
+++ b/org.jacoco.core/src/org/jacoco/core/analysis/ICoverageNode.java
@@ -56,6 +56,9 @@ public interface ICoverageNode {
/** Counter for source lines */
LINE,
+ /** Counter for cyclomatic complexity */
+ COMPLEXITY,
+
/** Counter for methods */
METHOD,
@@ -99,6 +102,13 @@ public interface ICoverageNode {
public ICounter getLineCounter();
/**
+ * Returns the counter for cyclomatic complexity.
+ *
+ * @return counter for complexity
+ */
+ public ICounter getComplexityCounter();
+
+ /**
* Returns the counter for methods.
*
* @return counter for methods
diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/MethodAnalyzer.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/MethodAnalyzer.java
index fd1af6fc..515fc8e0 100644
--- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/MethodAnalyzer.java
+++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/MethodAnalyzer.java
@@ -257,6 +257,7 @@ public class MethodAnalyzer implements IMethodProbesVisitor {
- covered, covered) : CounterImpl.COUNTER_0_0;
coverage.increment(instructions, branches, i.getLine());
}
+ coverage.incrementMethodCounter();
}
// === nothing to do here ===
diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/MethodCoverageImpl.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/MethodCoverageImpl.java
index acbc9ebc..67c5053f 100644
--- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/MethodCoverageImpl.java
+++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/MethodCoverageImpl.java
@@ -39,19 +39,31 @@ public class MethodCoverageImpl extends SourceNodeImpl implements
super(ElementType.METHOD, name);
this.desc = desc;
this.signature = signature;
- this.methodCounter = CounterImpl.COUNTER_1_0;
}
@Override
public void increment(final ICounter instructions, final ICounter branches,
final int line) {
super.increment(instructions, branches, line);
- if (instructions.getCoveredCount() > 0
- && this.methodCounter.getCoveredCount() == 0) {
- this.methodCounter = CounterImpl.COUNTER_0_1;
+ // Additionally increment complexity counter:
+ if (branches.getTotalCount() > 1) {
+ final int c = Math.max(0, branches.getCoveredCount() - 1);
+ final int m = Math.max(0, branches.getTotalCount() - c - 1);
+ this.complexityCounter = this.complexityCounter.increment(m, c);
}
}
+ /**
+ * This method must be called exactly once after all instructions and
+ * branches have been incremented for this method coverage node.
+ */
+ public void incrementMethodCounter() {
+ final ICounter base = this.instructionCounter.getCoveredCount() == 0 ? CounterImpl.COUNTER_1_0
+ : CounterImpl.COUNTER_0_1;
+ this.methodCounter = this.methodCounter.increment(base);
+ this.complexityCounter = this.complexityCounter.increment(base);
+ }
+
// === IMethodCoverage implementation ===
public String getDesc() {
diff --git a/org.jacoco.doc/docroot/doc/changes.html b/org.jacoco.doc/docroot/doc/changes.html
index aa8f8354..9d189d43 100644
--- a/org.jacoco.doc/docroot/doc/changes.html
+++ b/org.jacoco.doc/docroot/doc/changes.html
@@ -22,6 +22,7 @@
<h3>New Features</h3>
<ul>
+ <li>JaCoCo core calculates cyclomatic complexity (Trac #129).</li>
<li>For HTML reports the tab width can be specified on the
<code>sourcefiles</code> attribute of the <code>report</code> Ant task
(Track #152).</li>
@@ -29,8 +30,10 @@
<h3>API Changes</h3>
<ul>
+ <li><code>ICoverageNode</code> API has been extended for cyclomatic
+ complexity (Trac #129).</li>
<li>New method <code>getTabWidth()</code> in callback interface
- <code>ISourceFileLocator.getTabWidth()</code> (Trac #152).</li>
+ <code>ISourceFileLocator</code> (Trac #152).</li>
</ul>
<h2>Release 0.5.1 (2011/03/21)</h2>
diff --git a/org.jacoco.report.test/src/org/jacoco/report/ReportStructureTestDriver.java b/org.jacoco.report.test/src/org/jacoco/report/ReportStructureTestDriver.java
index 7369eec8..e3cff089 100644
--- a/org.jacoco.report.test/src/org/jacoco/report/ReportStructureTestDriver.java
+++ b/org.jacoco.report.test/src/org/jacoco/report/ReportStructureTestDriver.java
@@ -68,6 +68,7 @@ public class ReportStructureTestDriver {
{
instructionCounter = CounterImpl.getInstance(2, 22);
branchCounter = CounterImpl.getInstance(3, 33);
+ methodCounter = CounterImpl.COUNTER_0_1;
}
};
diff --git a/org.jacoco.report.test/src/org/jacoco/report/csv/CSVFormatterTest.java b/org.jacoco.report.test/src/org/jacoco/report/csv/CSVFormatterTest.java
index d280ddae..212df80a 100644
--- a/org.jacoco.report.test/src/org/jacoco/report/csv/CSVFormatterTest.java
+++ b/org.jacoco.report.test/src/org/jacoco/report/csv/CSVFormatterTest.java
@@ -67,7 +67,7 @@ public class CSVFormatterTest {
final List<String> lines = getLines();
assertEquals(HEADER, lines.get(0));
assertEquals(
- "group/bundle,org.jacoco.example,FooClass,2,22,3,33,0,0,1,0",
+ "group/bundle,org.jacoco.example,FooClass,2,22,3,33,0,0,0,1",
lines.get(1));
}
@@ -82,10 +82,10 @@ public class CSVFormatterTest {
final List<String> lines = getLines();
assertEquals(HEADER, lines.get(0));
assertEquals(
- "group/bundle,org.jacoco.example,FooClass,2,22,3,33,0,0,1,0",
+ "group/bundle,org.jacoco.example,FooClass,2,22,3,33,0,0,0,1",
lines.get(1));
assertEquals(
- "group/bundle,org.jacoco.example,FooClass,2,22,3,33,0,0,1,0",
+ "group/bundle,org.jacoco.example,FooClass,2,22,3,33,0,0,0,1",
lines.get(2));
}
@@ -94,7 +94,7 @@ public class CSVFormatterTest {
driver.sendBundle(visitor);
final List<String> lines = getLines();
assertEquals(HEADER, lines.get(0));
- assertEquals("bundle,org.jacoco.example,FooClass,2,22,3,33,0,0,1,0",
+ assertEquals("bundle,org.jacoco.example,FooClass,2,22,3,33,0,0,0,1",
lines.get(1));
}
diff --git a/org.jacoco.report.test/src/org/jacoco/report/csv/CSVGroupHandlerTest.java b/org.jacoco.report.test/src/org/jacoco/report/csv/CSVGroupHandlerTest.java
index 74c01cdc..28378301 100644
--- a/org.jacoco.report.test/src/org/jacoco/report/csv/CSVGroupHandlerTest.java
+++ b/org.jacoco.report.test/src/org/jacoco/report/csv/CSVGroupHandlerTest.java
@@ -48,7 +48,7 @@ public class CSVGroupHandlerTest {
driver.sendBundle(handler);
final BufferedReader reader = getResultReader();
reader.readLine();
- assertEquals("bundle,org.jacoco.example,FooClass,2,22,3,33,0,0,1,0",
+ assertEquals("bundle,org.jacoco.example,FooClass,2,22,3,33,0,0,0,1",
reader.readLine());
}
@@ -58,7 +58,7 @@ public class CSVGroupHandlerTest {
final BufferedReader reader = getResultReader();
reader.readLine();
assertEquals(
- "group/bundle,org.jacoco.example,FooClass,2,22,3,33,0,0,1,0",
+ "group/bundle,org.jacoco.example,FooClass,2,22,3,33,0,0,0,1",
reader.readLine());
}