diff options
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());
}
|