diff options
author | simonbrandhof <simon.brandhof@gmail.com> | 2011-02-28 18:05:03 +0100 |
---|---|---|
committer | simonbrandhof <simon.brandhof@gmail.com> | 2011-02-28 18:05:03 +0100 |
commit | 1ec6704480f79ab80b0c43c2a663d810df93f1b7 (patch) | |
tree | 90d4e15ae9dba55d6b0451cd2d0e58efc74b39d5 /plugins | |
parent | 8c1d9bf46953dfde3ab5b4ade5a80e4dcaa9d10d (diff) | |
download | sonarqube-1ec6704480f79ab80b0c43c2a663d810df93f1b7.tar.gz sonarqube-1ec6704480f79ab80b0c43c2a663d810df93f1b7.zip |
SONAR-2218 compute coverage on new/changed code
Diffstat (limited to 'plugins')
7 files changed, 242 insertions, 51 deletions
diff --git a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/sensors/AbstractCoverageDecorator.java b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/sensors/AbstractCoverageDecorator.java index b548de52143..d5a6e95c047 100644 --- a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/sensors/AbstractCoverageDecorator.java +++ b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/sensors/AbstractCoverageDecorator.java @@ -22,11 +22,15 @@ package org.sonar.plugins.core.sensors; import org.sonar.api.batch.Decorator; import org.sonar.api.batch.DecoratorContext; import org.sonar.api.batch.DependedUpon; +import org.sonar.api.measures.Measure; import org.sonar.api.measures.Metric; import org.sonar.api.resources.Project; import org.sonar.api.resources.Resource; import org.sonar.api.resources.ResourceUtils; +import java.util.Arrays; +import java.util.Collection; + public abstract class AbstractCoverageDecorator implements Decorator { public boolean shouldExecuteOnProject(Project project) { @@ -34,36 +38,60 @@ public abstract class AbstractCoverageDecorator implements Decorator { } @DependedUpon - public Metric generatesCoverage() { - return getTargetMetric(); + public Collection<Metric> generatedMetrics() { + return Arrays.asList(getGeneratedMetric(), getGeneratedMetricForNewCode()); } public void decorate(final Resource resource, final DecoratorContext context) { if (shouldDecorate(resource, context)) { - saveLineCoverage(context); + computeMeasure(context); + computeMeasureForNewCode(context); } } protected boolean shouldDecorate(final Resource resource, final DecoratorContext context) { - return context.getMeasure(getTargetMetric()) == null && !ResourceUtils.isUnitTestClass(resource); + return context.getMeasure(getGeneratedMetric()) == null && !ResourceUtils.isUnitTestClass(resource); + } + + private void computeMeasure(DecoratorContext context) { + Long elements = countElements(context); + if (elements != null && elements > 0L) { + Long coveredElements = countCoveredElements(context); + context.saveMeasure(getGeneratedMetric(), calculateCoverage(coveredElements, elements)); + } } - private void saveLineCoverage(DecoratorContext context) { - Double elements = countElements(context); - Double coveredElements = countCoveredElements(context); + private void computeMeasureForNewCode(DecoratorContext context) { + Measure measure = new Measure(getGeneratedMetricForNewCode()); + boolean hasValue = false; + /* TODO remove this magic number */ + for (int periodIndex = 1; periodIndex <= 5; periodIndex++) { + Long elements = countElementsForNewCode(context, periodIndex); - if (elements != null && elements > 0.0 && coveredElements != null) { - context.saveMeasure(getTargetMetric(), calculateCoverage(coveredElements, elements)); + if (elements != null && elements > 0L) { + long coveredElements = countCoveredElementsForNewCode(context, periodIndex); + measure.setVariation(periodIndex, calculateCoverage(coveredElements, elements)); + hasValue = true; + } + } + if (hasValue) { + context.saveMeasure(measure); } } - private double calculateCoverage(final Double coveredLines, final Double lines) { + private double calculateCoverage(final long coveredLines, final long lines) { return (100.0 * coveredLines) / lines; } - protected abstract Metric getTargetMetric(); + protected abstract Metric getGeneratedMetric(); + + protected abstract Long countElements(DecoratorContext context); + + protected abstract long countCoveredElements(DecoratorContext context); + + protected abstract Metric getGeneratedMetricForNewCode(); - protected abstract Double countCoveredElements(DecoratorContext context); + protected abstract Long countElementsForNewCode(DecoratorContext context, int periodIndex); - protected abstract Double countElements(DecoratorContext context); + protected abstract long countCoveredElementsForNewCode(DecoratorContext context, int periodIndex); } diff --git a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/sensors/BranchCoverageDecorator.java b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/sensors/BranchCoverageDecorator.java index ce4c61bd11a..d9f3cc76ef0 100644 --- a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/sensors/BranchCoverageDecorator.java +++ b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/sensors/BranchCoverageDecorator.java @@ -28,27 +28,45 @@ import org.sonar.api.measures.Metric; import java.util.Arrays; import java.util.List; -public class BranchCoverageDecorator extends AbstractCoverageDecorator { +public final class BranchCoverageDecorator extends AbstractCoverageDecorator { + + @DependsUpon + public List<Metric> dependsUponMetrics() { + return Arrays.asList(CoreMetrics.UNCOVERED_CONDITIONS, CoreMetrics.CONDITIONS_TO_COVER, + CoreMetrics.NEW_UNCOVERED_CONDITIONS, CoreMetrics.NEW_CONDITIONS_TO_COVER); + } @Override - protected Metric getTargetMetric() { + protected Metric getGeneratedMetric() { return CoreMetrics.BRANCH_COVERAGE; } - @DependsUpon - public List<Metric> dependsUponMetrics() { - return Arrays.asList(CoreMetrics.UNCOVERED_CONDITIONS, CoreMetrics.CONDITIONS_TO_COVER); + @Override + protected Long countElements(DecoratorContext context) { + return MeasureUtils.getValueAsLong(context.getMeasure(CoreMetrics.CONDITIONS_TO_COVER), 0L); } @Override - protected Double countCoveredElements(DecoratorContext context) { - double uncoveredConditions = MeasureUtils.getValue(context.getMeasure(CoreMetrics.UNCOVERED_CONDITIONS), 0.0); - double conditions = MeasureUtils.getValue(context.getMeasure(CoreMetrics.CONDITIONS_TO_COVER), 0.0); + protected long countCoveredElements(DecoratorContext context) { + long uncoveredConditions = MeasureUtils.getValueAsLong(context.getMeasure(CoreMetrics.UNCOVERED_CONDITIONS), 0L); + long conditions = MeasureUtils.getValueAsLong(context.getMeasure(CoreMetrics.CONDITIONS_TO_COVER), 0L); return conditions - uncoveredConditions; } @Override - protected Double countElements(DecoratorContext context) { - return MeasureUtils.getValue(context.getMeasure(CoreMetrics.CONDITIONS_TO_COVER), 0.0); + protected Metric getGeneratedMetricForNewCode() { + return CoreMetrics.NEW_BRANCH_COVERAGE; + } + + @Override + protected Long countElementsForNewCode(DecoratorContext context, int periodIndex) { + return MeasureUtils.getVariationAsLong(context.getMeasure(CoreMetrics.NEW_CONDITIONS_TO_COVER), periodIndex); + } + + @Override + protected long countCoveredElementsForNewCode(DecoratorContext context, int periodIndex) { + long uncoveredConditions = MeasureUtils.getVariationAsLong(context.getMeasure(CoreMetrics.NEW_UNCOVERED_CONDITIONS), periodIndex, 0L); + long conditions = MeasureUtils.getVariationAsLong(context.getMeasure(CoreMetrics.NEW_CONDITIONS_TO_COVER), periodIndex, 0L); + return conditions - uncoveredConditions; } } diff --git a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/sensors/CoverageDecorator.java b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/sensors/CoverageDecorator.java index 4342742a87e..0944f8dabcd 100644 --- a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/sensors/CoverageDecorator.java +++ b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/sensors/CoverageDecorator.java @@ -20,39 +20,69 @@ package org.sonar.plugins.core.sensors; import org.sonar.api.batch.DecoratorContext; +import org.sonar.api.batch.DependedUpon; import org.sonar.api.batch.DependsUpon; import org.sonar.api.measures.CoreMetrics; import org.sonar.api.measures.MeasureUtils; import org.sonar.api.measures.Metric; import java.util.Arrays; +import java.util.Collection; import java.util.List; -public class CoverageDecorator extends AbstractCoverageDecorator { +public final class CoverageDecorator extends AbstractCoverageDecorator { + + @DependsUpon + public Collection<Metric> usedMetrics() { + return Arrays.asList(CoreMetrics.LINES_TO_COVER, CoreMetrics.UNCOVERED_LINES, CoreMetrics.NEW_LINES_TO_COVER, + CoreMetrics.NEW_UNCOVERED_LINES, CoreMetrics.CONDITIONS_TO_COVER, CoreMetrics.UNCOVERED_CONDITIONS, + CoreMetrics.NEW_CONDITIONS_TO_COVER, CoreMetrics.NEW_UNCOVERED_CONDITIONS); + } @Override - protected Metric getTargetMetric() { + protected Metric getGeneratedMetric() { return CoreMetrics.COVERAGE; } - @DependsUpon - public List<Metric> dependsUponMetrics() { - return Arrays.asList(CoreMetrics.LINES_TO_COVER, CoreMetrics.UNCOVERED_LINES, CoreMetrics.CONDITIONS_TO_COVER, CoreMetrics.UNCOVERED_CONDITIONS); + @Override + protected Long countElements(DecoratorContext context) { + long lines = MeasureUtils.getValueAsLong(context.getMeasure(CoreMetrics.LINES_TO_COVER), 0L); + long conditions = MeasureUtils.getValueAsLong(context.getMeasure(CoreMetrics.CONDITIONS_TO_COVER), 0L); + return lines + conditions; } @Override - protected Double countCoveredElements(DecoratorContext context) { - double uncoveredLines = MeasureUtils.getValue(context.getMeasure(CoreMetrics.UNCOVERED_LINES), 0.0); - double lines = MeasureUtils.getValue(context.getMeasure(CoreMetrics.LINES_TO_COVER), 0.0); - double uncoveredConditions = MeasureUtils.getValue(context.getMeasure(CoreMetrics.UNCOVERED_CONDITIONS), 0.0); - double conditions = MeasureUtils.getValue(context.getMeasure(CoreMetrics.CONDITIONS_TO_COVER), 0.0); + protected long countCoveredElements(DecoratorContext context) { + long uncoveredLines = MeasureUtils.getValueAsLong(context.getMeasure(CoreMetrics.UNCOVERED_LINES), 0L); + long lines = MeasureUtils.getValueAsLong(context.getMeasure(CoreMetrics.LINES_TO_COVER), 0L); + long uncoveredConditions = MeasureUtils.getValueAsLong(context.getMeasure(CoreMetrics.UNCOVERED_CONDITIONS), 0L); + long conditions = MeasureUtils.getValueAsLong(context.getMeasure(CoreMetrics.CONDITIONS_TO_COVER), 0L); return lines + conditions - uncoveredConditions - uncoveredLines; } + + @Override - protected Double countElements(DecoratorContext context) { - double lines = MeasureUtils.getValue(context.getMeasure(CoreMetrics.LINES_TO_COVER), 0.0); - double conditions = MeasureUtils.getValue(context.getMeasure(CoreMetrics.CONDITIONS_TO_COVER), 0.0); - return lines + conditions; + protected Metric getGeneratedMetricForNewCode() { + return CoreMetrics.NEW_COVERAGE; + } + + @Override + protected Long countElementsForNewCode(DecoratorContext context, int periodIndex) { + Long newLinesToCover = MeasureUtils.getVariationAsLong(context.getMeasure(CoreMetrics.NEW_LINES_TO_COVER), periodIndex); + if (newLinesToCover!=null) { + long newConditionsToCover = MeasureUtils.getVariationAsLong(context.getMeasure(CoreMetrics.NEW_CONDITIONS_TO_COVER), periodIndex, 0L); + return newLinesToCover + newConditionsToCover; + } + return null; + } + + @Override + protected long countCoveredElementsForNewCode(DecoratorContext context, int periodIndex) { + long newLines = MeasureUtils.getVariationAsLong(context.getMeasure(CoreMetrics.NEW_LINES_TO_COVER), periodIndex, 0L); + long newUncoveredLines = MeasureUtils.getVariationAsLong(context.getMeasure(CoreMetrics.NEW_UNCOVERED_LINES), periodIndex, 0L); + long newUncoveredConditions = MeasureUtils.getVariationAsLong(context.getMeasure(CoreMetrics.NEW_UNCOVERED_CONDITIONS), periodIndex, 0L); + long newConditions = MeasureUtils.getVariationAsLong(context.getMeasure(CoreMetrics.NEW_CONDITIONS_TO_COVER), periodIndex, 0L); + return newLines + newConditions - newUncoveredConditions - newUncoveredLines; } }
\ No newline at end of file diff --git a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/sensors/LineCoverageDecorator.java b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/sensors/LineCoverageDecorator.java index 5d8ed7bd57a..d702f6b3c12 100644 --- a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/sensors/LineCoverageDecorator.java +++ b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/sensors/LineCoverageDecorator.java @@ -28,27 +28,46 @@ import org.sonar.api.measures.Metric; import java.util.Arrays; import java.util.List; -public class LineCoverageDecorator extends AbstractCoverageDecorator { +public final class LineCoverageDecorator extends AbstractCoverageDecorator { + + @DependsUpon + public List<Metric> dependsUponMetrics() { + return Arrays.asList(CoreMetrics.UNCOVERED_LINES, CoreMetrics.LINES_TO_COVER, CoreMetrics.NEW_UNCOVERED_LINES, + CoreMetrics.NEW_LINES_TO_COVER); + } @Override - protected Metric getTargetMetric() { + protected Metric getGeneratedMetric() { return CoreMetrics.LINE_COVERAGE; } - @DependsUpon - public List<Metric> dependsUponMetrics() { - return Arrays.asList(CoreMetrics.UNCOVERED_LINES, CoreMetrics.LINES_TO_COVER); + @Override + protected Long countElements(DecoratorContext context) { + return MeasureUtils.getValueAsLong(context.getMeasure(CoreMetrics.LINES_TO_COVER), 0L); } @Override - protected Double countCoveredElements(DecoratorContext context) { - double uncoveredLines = MeasureUtils.getValue(context.getMeasure(CoreMetrics.UNCOVERED_LINES), 0.0); - double lines = MeasureUtils.getValue(context.getMeasure(CoreMetrics.LINES_TO_COVER), 0.0); + protected long countCoveredElements(DecoratorContext context) { + long uncoveredLines = MeasureUtils.getValueAsLong(context.getMeasure(CoreMetrics.UNCOVERED_LINES), 0L); + long lines = MeasureUtils.getValueAsLong(context.getMeasure(CoreMetrics.LINES_TO_COVER), 0L); return lines - uncoveredLines; } + @Override - protected Double countElements(DecoratorContext context) { - return MeasureUtils.getValue(context.getMeasure(CoreMetrics.LINES_TO_COVER), 0.0); + protected Metric getGeneratedMetricForNewCode() { + return CoreMetrics.NEW_LINE_COVERAGE; + } + + @Override + protected Long countElementsForNewCode(DecoratorContext context, int periodIndex) { + return MeasureUtils.getVariationAsLong(context.getMeasure(CoreMetrics.NEW_LINES_TO_COVER), periodIndex); + } + + @Override + protected long countCoveredElementsForNewCode(DecoratorContext context, int periodIndex) { + long uncoveredLines = MeasureUtils.getVariationAsLong(context.getMeasure(CoreMetrics.NEW_UNCOVERED_LINES), periodIndex, 0L); + long lines = MeasureUtils.getVariationAsLong(context.getMeasure(CoreMetrics.NEW_LINES_TO_COVER), periodIndex, 0L); + return lines - uncoveredLines; } } diff --git a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/NewCoverageAggregator.java b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/NewCoverageAggregator.java index f4d56097161..0104f20faa5 100644 --- a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/NewCoverageAggregator.java +++ b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/NewCoverageAggregator.java @@ -56,7 +56,7 @@ public final class NewCoverageAggregator implements Decorator { } } - private void aggregate(DecoratorContext context, Metric metric, int maxPeriods) { + void aggregate(DecoratorContext context, Metric metric, int maxPeriods) { int[] variations = {0,0,0,0,0}; boolean[] hasValues = {false,false,false,false,false}; for (Measure child : context.getChildrenMeasures(metric)) { @@ -80,7 +80,7 @@ public final class NewCoverageAggregator implements Decorator { } } - private boolean shouldDecorate(Resource resource) { + boolean shouldDecorate(Resource resource) { return Scopes.isHigherThan(resource, Scopes.FILE); } } diff --git a/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/sensors/BranchCoverageDecoratorTest.java b/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/sensors/BranchCoverageDecoratorTest.java index e98980ba776..2c529e87a96 100644 --- a/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/sensors/BranchCoverageDecoratorTest.java +++ b/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/sensors/BranchCoverageDecoratorTest.java @@ -31,7 +31,7 @@ import org.sonar.api.resources.Project; public class BranchCoverageDecoratorTest { @Test - public void noBranchCoverageIfMissingConditions() { + public void shouldNotSaveBranchCoverageIfMissingConditions() { Project resource = mock(Project.class); when(resource.getScope()).thenReturn(Project.SCOPE_SET); when(resource.getQualifier()).thenReturn(Project.QUALIFIER_SUBVIEW); @@ -43,7 +43,7 @@ public class BranchCoverageDecoratorTest { } @Test - public void branchCoverage() { + public void shouldSaveBranchCoverage() { Project resource = mock(Project.class); when(resource.getScope()).thenReturn(Project.SCOPE_SET); when(resource.getQualifier()).thenReturn(Project.QUALIFIER_PROJECT); diff --git a/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/timemachine/NewCoverageAggregatorTest.java b/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/timemachine/NewCoverageAggregatorTest.java new file mode 100644 index 00000000000..e5d7ea44a5c --- /dev/null +++ b/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/timemachine/NewCoverageAggregatorTest.java @@ -0,0 +1,96 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2008-2011 SonarSource + * mailto:contact AT sonarsource DOT com + * + * Sonar is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * Sonar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with Sonar; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.plugins.core.timemachine; + +import org.hamcrest.BaseMatcher; +import org.hamcrest.Description; +import org.junit.Test; +import org.mockito.Matchers; +import org.sonar.api.batch.DecoratorContext; +import org.sonar.api.measures.CoreMetrics; +import org.sonar.api.measures.Measure; + +import java.util.Arrays; +import java.util.Collections; + +import static org.mockito.Mockito.*; + +public class NewCoverageAggregatorTest { + + @Test + public void shouldNotSaveDataWhenNoMeasures() { + NewCoverageAggregator aggregator = new NewCoverageAggregator(); + DecoratorContext context = mock(DecoratorContext.class); + when(context.getChildrenMeasures(CoreMetrics.NEW_LINES_TO_COVER)).thenReturn(Collections.<Measure>emptyList()); + + aggregator.aggregate(context, CoreMetrics.NEW_LINES_TO_COVER, 3); + + verify(context, never()).saveMeasure(Matchers.<Measure>anyObject()); + } + + @Test + public void shouldNotsetZeroWhenNoValueOnPeriod() { + NewCoverageAggregator aggregator = new NewCoverageAggregator(); + DecoratorContext context = mock(DecoratorContext.class); + when(context.getChildrenMeasures(CoreMetrics.NEW_LINES_TO_COVER)).thenReturn(Arrays.asList(newMeasure(null, 3.0, 2.0), newMeasure(null, 13.0, null))); + + aggregator.aggregate(context, CoreMetrics.NEW_LINES_TO_COVER, 3); + + verify(context).saveMeasure(argThat(new BaseMatcher<Measure>() { + public boolean matches(Object o) { + Measure m = (Measure)o; + return m.getVariation1()==null; + } + + public void describeTo(Description description) { + + } + })); + } + + + @Test + public void shouldSumValues() { + NewCoverageAggregator aggregator = new NewCoverageAggregator(); + DecoratorContext context = mock(DecoratorContext.class); + when(context.getChildrenMeasures(CoreMetrics.NEW_LINES_TO_COVER)).thenReturn(Arrays.asList(newMeasure(null, 3.0, 2.0), newMeasure(null, 13.0, null))); + + aggregator.aggregate(context, CoreMetrics.NEW_LINES_TO_COVER, 3); + + verify(context).saveMeasure(argThat(new BaseMatcher<Measure>() { + public boolean matches(Object o) { + Measure m = (Measure)o; + return m.getVariation2()==16.0 && m.getVariation3()==2.0; + } + + public void describeTo(Description description) { + + } + })); + } + + + private Measure newMeasure(Double variation1, Double variation2, Double variation3) { + return new Measure(CoreMetrics.NEW_LINES_TO_COVER) + .setVariation1(variation1) + .setVariation2(variation2) + .setVariation3(variation3); + } +} |