diff options
author | Julien HENRY <julien.henry@sonarsource.com> | 2015-02-19 21:56:36 +0100 |
---|---|---|
committer | Julien HENRY <julien.henry@sonarsource.com> | 2015-02-19 21:58:03 +0100 |
commit | eac465bea9f5bf89a7beb8036e4d8eea4723f421 (patch) | |
tree | 630ed3ca988523e0a8ab2102eeb53affbdcde297 /plugins | |
parent | a5627abf8dce968a864a2b57b910ad4bc1e8c9d5 (diff) | |
download | sonarqube-eac465bea9f5bf89a7beb8036e4d8eea4723f421.tar.gz sonarqube-eac465bea9f5bf89a7beb8036e4d8eea4723f421.zip |
SONAR-6202 Compute overall coverage on all files
Diffstat (limited to 'plugins')
3 files changed, 199 insertions, 1 deletions
diff --git a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/CorePlugin.java b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/CorePlugin.java index cc03c972881..602948249a4 100644 --- a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/CorePlugin.java +++ b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/CorePlugin.java @@ -47,8 +47,9 @@ import org.sonar.plugins.core.sensors.ItBranchCoverageDecorator; import org.sonar.plugins.core.sensors.ItCoverageDecorator; import org.sonar.plugins.core.sensors.ItLineCoverageDecorator; import org.sonar.plugins.core.sensors.LineCoverageDecorator; -import org.sonar.plugins.core.sensors.MissingCoverageDecorator; import org.sonar.plugins.core.sensors.ManualMeasureDecorator; +import org.sonar.plugins.core.sensors.MissingCoverageDecorator; +import org.sonar.plugins.core.sensors.MissingOverallCoverageDecorator; import org.sonar.plugins.core.sensors.OverallBranchCoverageDecorator; import org.sonar.plugins.core.sensors.OverallCoverageDecorator; import org.sonar.plugins.core.sensors.OverallLineCoverageDecorator; @@ -337,6 +338,7 @@ public final class CorePlugin extends SonarPlugin { FilesDecorator.class, ManualMeasureDecorator.class, MissingCoverageDecorator.class, + MissingOverallCoverageDecorator.class, // time machine TendencyDecorator.class, diff --git a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/sensors/MissingOverallCoverageDecorator.java b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/sensors/MissingOverallCoverageDecorator.java new file mode 100644 index 00000000000..bdae925a865 --- /dev/null +++ b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/sensors/MissingOverallCoverageDecorator.java @@ -0,0 +1,82 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2014 SonarSource + * mailto:contact AT sonarsource DOT com + * + * SonarQube 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. + * + * SonarQube 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 this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +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.batch.DependsUpon; +import org.sonar.api.measures.CoreMetrics; +import org.sonar.api.measures.CoverageMeasuresBuilder; +import org.sonar.api.measures.Measure; +import org.sonar.api.measures.MeasureUtils; +import org.sonar.api.measures.Metric; +import org.sonar.api.resources.Project; +import org.sonar.api.resources.Qualifiers; +import org.sonar.api.resources.Resource; + +import java.util.List; + +/** + * Compute overall coverage when it was not already saved by language plugin. + */ +public final class MissingOverallCoverageDecorator implements Decorator { + + @DependsUpon + public Metric dependsUpon() { + return CoreMetrics.LINES_TO_COVER; + } + + @DependedUpon + public List<Metric> provides() { + return CoverageMeasuresBuilder.CoverageType.OVERALL.all(); + } + + @Override + public boolean shouldExecuteOnProject(Project project) { + return true; + } + + @Override + public void decorate(Resource resource, DecoratorContext context) { + if (Qualifiers.isFile(resource) && !MeasureUtils.hasValue(context.getMeasure(CoreMetrics.OVERALL_LINES_TO_COVER))) { + copyMeasure(context, CoreMetrics.LINES_TO_COVER, CoreMetrics.OVERALL_LINES_TO_COVER); + copyMeasure(context, CoreMetrics.UNCOVERED_LINES, CoreMetrics.OVERALL_UNCOVERED_LINES); + copyMeasure(context, CoreMetrics.COVERAGE_LINE_HITS_DATA, CoreMetrics.OVERALL_COVERAGE_LINE_HITS_DATA); + copyMeasure(context, CoreMetrics.CONDITIONS_TO_COVER, CoreMetrics.OVERALL_CONDITIONS_TO_COVER); + copyMeasure(context, CoreMetrics.UNCOVERED_CONDITIONS, CoreMetrics.OVERALL_UNCOVERED_CONDITIONS); + copyMeasure(context, CoreMetrics.CONDITIONS_BY_LINE, CoreMetrics.OVERALL_CONDITIONS_BY_LINE); + copyMeasure(context, CoreMetrics.COVERED_CONDITIONS_BY_LINE, CoreMetrics.OVERALL_COVERED_CONDITIONS_BY_LINE); + } + } + + private void copyMeasure(DecoratorContext context, Metric<?> from, Metric<?> to) { + Measure sourceMeasure = context.getMeasure(from); + if (sourceMeasure != null) { + Double value = sourceMeasure.getValue(); + if (value != null) { + context.saveMeasure(to, value); + } else if (sourceMeasure.hasData()) { + context.saveMeasure(new Measure(to, sourceMeasure.getData())); + } + } + + } +} diff --git a/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/sensors/MissingOverallCoverageDecoratorTest.java b/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/sensors/MissingOverallCoverageDecoratorTest.java new file mode 100644 index 00000000000..c94eb3bce52 --- /dev/null +++ b/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/sensors/MissingOverallCoverageDecoratorTest.java @@ -0,0 +1,114 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2014 SonarSource + * mailto:contact AT sonarsource DOT com + * + * SonarQube 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. + * + * SonarQube 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 this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.plugins.core.sensors; + +import org.junit.Before; +import org.junit.Test; +import org.sonar.api.batch.DecoratorContext; +import org.sonar.api.measures.CoreMetrics; +import org.sonar.api.measures.Measure; +import org.sonar.api.resources.Directory; +import org.sonar.api.resources.File; +import org.sonar.api.resources.Java; +import org.sonar.api.resources.Project; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Matchers.anyDouble; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; +import static org.mockito.Mockito.when; + +public class MissingOverallCoverageDecoratorTest { + + private MissingOverallCoverageDecorator decorator; + + @Before + public void prepare() { + decorator = new MissingOverallCoverageDecorator(); + } + + @Test + public void increaseCoverage() { + assertThat(decorator.provides()).isNotEmpty(); + assertThat(decorator.dependsUpon()).isEqualTo(CoreMetrics.LINES_TO_COVER); + assertThat(decorator.shouldExecuteOnProject(new Project("foo"))).isTrue(); + } + + @Test + public void testExecuteOnlyOnMainFile() { + DecoratorContext context = mock(DecoratorContext.class); + decorator.decorate(File.create("test/FooTest.java", Java.INSTANCE, true), context); + decorator.decorate(Directory.create("src"), context); + decorator.decorate(new Project("foo"), context); + verifyNoMoreInteractions(context); + } + + @Test + public void dontDoAnythingIfOverallCoverageAlreadyDefined() { + DecoratorContext context = mock(DecoratorContext.class); + File file = File.create("src/Foo.java"); + + when(context.getMeasure(CoreMetrics.OVERALL_LINES_TO_COVER)).thenReturn(new Measure<>(CoreMetrics.OVERALL_LINES_TO_COVER, 0.0)); + + decorator.decorate(file, context); + + verify(context, never()).saveMeasure(eq(CoreMetrics.OVERALL_LINES_TO_COVER), anyDouble()); + } + + @Test + public void testCopyUnitTestMeasures() { + DecoratorContext context = mock(DecoratorContext.class); + File file = File.create("src/Foo.java"); + + when(context.getMeasure(CoreMetrics.LINES_TO_COVER)).thenReturn(new Measure<>(CoreMetrics.LINES_TO_COVER, 10.0)); + when(context.getMeasure(CoreMetrics.UNCOVERED_LINES)).thenReturn(new Measure<>(CoreMetrics.UNCOVERED_LINES, 5.0)); + when(context.getMeasure(CoreMetrics.COVERAGE_LINE_HITS_DATA)).thenReturn(new Measure<>(CoreMetrics.COVERAGE_LINE_HITS_DATA, "1=1;2=2;")); + when(context.getMeasure(CoreMetrics.CONDITIONS_TO_COVER)).thenReturn(new Measure<>(CoreMetrics.CONDITIONS_TO_COVER, 2.0)); + when(context.getMeasure(CoreMetrics.UNCOVERED_CONDITIONS)).thenReturn(new Measure<>(CoreMetrics.UNCOVERED_CONDITIONS, 1.0)); + when(context.getMeasure(CoreMetrics.CONDITIONS_BY_LINE)).thenReturn(new Measure<>(CoreMetrics.CONDITIONS_BY_LINE, "1=4")); + when(context.getMeasure(CoreMetrics.COVERED_CONDITIONS_BY_LINE)).thenReturn(new Measure<>(CoreMetrics.COVERED_CONDITIONS_BY_LINE, "1=2")); + + decorator.decorate(file, context); + + verify(context).saveMeasure(CoreMetrics.OVERALL_LINES_TO_COVER, 10.0); + verify(context).saveMeasure(CoreMetrics.OVERALL_UNCOVERED_LINES, 5.0); + verify(context).saveMeasure(new Measure(CoreMetrics.OVERALL_COVERAGE_LINE_HITS_DATA, "1=1;2=2;")); + verify(context).saveMeasure(CoreMetrics.OVERALL_CONDITIONS_TO_COVER, 2.0); + verify(context).saveMeasure(CoreMetrics.OVERALL_UNCOVERED_CONDITIONS, 1.0); + verify(context).saveMeasure(new Measure(CoreMetrics.OVERALL_CONDITIONS_BY_LINE, "1=4")); + verify(context).saveMeasure(new Measure(CoreMetrics.OVERALL_COVERED_CONDITIONS_BY_LINE, "1=2")); + } + + @Test + public void dontFailOnBrokenValues() { + DecoratorContext context = mock(DecoratorContext.class); + File file = File.create("src/Foo.java"); + + when(context.getMeasure(CoreMetrics.LINES_TO_COVER)).thenReturn(new Measure<>(CoreMetrics.LINES_TO_COVER, 10.0)); + when(context.getMeasure(CoreMetrics.COVERAGE_LINE_HITS_DATA)).thenReturn(new Measure<>(CoreMetrics.COVERAGE_LINE_HITS_DATA)); + + decorator.decorate(file, context); + + verify(context).saveMeasure(CoreMetrics.OVERALL_LINES_TO_COVER, 10.0); + } +} |