diff options
author | David Gageot <david@gageot.net> | 2012-10-02 17:02:31 +0200 |
---|---|---|
committer | David Gageot <david@gageot.net> | 2012-10-02 21:50:12 +0200 |
commit | a0408f68ce3b7eaee7b20cbeb2712201411a7bb2 (patch) | |
tree | 21edc0996feb6b2702e03afe106400501a02ad74 /plugins | |
parent | cc24a2bbd3aa86dd9c91564c5ce071e095fde61b (diff) | |
download | sonarqube-a0408f68ce3b7eaee7b20cbeb2712201411a7bb2.tar.gz sonarqube-a0408f68ce3b7eaee7b20cbeb2712201411a7bb2.zip |
SONAR-2804 Merged coverage
Diffstat (limited to 'plugins')
9 files changed, 524 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 11899dfbb6b..7dacd86b642 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 @@ -48,6 +48,9 @@ import org.sonar.plugins.core.filters.ProjectFilter; import org.sonar.plugins.core.filters.TreeMapFilter; import org.sonar.plugins.core.security.ApplyProjectRolesDecorator; import org.sonar.plugins.core.security.DefaultResourcePermissions; +import org.sonar.plugins.core.sensors.AllTestsBranchCoverageDecorator; +import org.sonar.plugins.core.sensors.AllTestsCoverageDecorator; +import org.sonar.plugins.core.sensors.AllTestsLineCoverageDecorator; import org.sonar.plugins.core.sensors.BranchCoverageDecorator; import org.sonar.plugins.core.sensors.CheckAlertThresholds; import org.sonar.plugins.core.sensors.CommentDensityDecorator; @@ -86,6 +89,7 @@ import org.sonar.plugins.core.timemachine.ViolationPersisterDecorator; import org.sonar.plugins.core.timemachine.ViolationTrackingDecorator; import org.sonar.plugins.core.web.Lcom4Viewer; import org.sonar.plugins.core.widgets.AlertsWidget; +import org.sonar.plugins.core.widgets.AllTestsCoverageWidget; import org.sonar.plugins.core.widgets.CommentsDuplicationsWidget; import org.sonar.plugins.core.widgets.ComplexityWidget; import org.sonar.plugins.core.widgets.CoverageWidget; @@ -341,6 +345,7 @@ public final class CorePlugin extends SonarPlugin { AlertsWidget.class, CoverageWidget.class, ItCoverageWidget.class, + AllTestsCoverageWidget.class, CommentsDuplicationsWidget.class, DescriptionWidget.class, ComplexityWidget.class, @@ -398,6 +403,9 @@ public final class CorePlugin extends SonarPlugin { ItLineCoverageDecorator.class, ItCoverageDecorator.class, ItBranchCoverageDecorator.class, + AllTestsLineCoverageDecorator.class, + AllTestsCoverageDecorator.class, + AllTestsBranchCoverageDecorator.class, DefaultResourcePermissions.class, ApplyProjectRolesDecorator.class, ExcludedResourceFilter.class, diff --git a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/sensors/AllTestsBranchCoverageDecorator.java b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/sensors/AllTestsBranchCoverageDecorator.java new file mode 100644 index 00000000000..7949cc91e89 --- /dev/null +++ b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/sensors/AllTestsBranchCoverageDecorator.java @@ -0,0 +1,72 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2008-2012 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.sensors; + +import org.sonar.api.batch.DecoratorContext; +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.List; + +public final class AllTestsBranchCoverageDecorator extends AbstractCoverageDecorator { + + @DependsUpon + public List<Metric> dependsUponMetrics() { + return Arrays.asList(CoreMetrics.MERGED_UNCOVERED_CONDITIONS, CoreMetrics.MERGED_CONDITIONS_TO_COVER, + CoreMetrics.NEW_MERGED_UNCOVERED_CONDITIONS, CoreMetrics.NEW_MERGED_CONDITIONS_TO_COVER); + } + + @Override + protected Metric getGeneratedMetric() { + return CoreMetrics.MERGED_BRANCH_COVERAGE; + } + + @Override + protected Long countElements(DecoratorContext context) { + return MeasureUtils.getValueAsLong(context.getMeasure(CoreMetrics.MERGED_CONDITIONS_TO_COVER), 0L); + } + + @Override + protected long countCoveredElements(DecoratorContext context) { + long uncoveredConditions = MeasureUtils.getValueAsLong(context.getMeasure(CoreMetrics.MERGED_UNCOVERED_CONDITIONS), 0L); + long conditions = MeasureUtils.getValueAsLong(context.getMeasure(CoreMetrics.MERGED_CONDITIONS_TO_COVER), 0L); + return conditions - uncoveredConditions; + } + + @Override + protected Metric getGeneratedMetricForNewCode() { + return CoreMetrics.NEW_MERGED_BRANCH_COVERAGE; + } + + @Override + protected Long countElementsForNewCode(DecoratorContext context, int periodIndex) { + return MeasureUtils.getVariationAsLong(context.getMeasure(CoreMetrics.NEW_MERGED_CONDITIONS_TO_COVER), periodIndex); + } + + @Override + protected long countCoveredElementsForNewCode(DecoratorContext context, int periodIndex) { + long uncoveredConditions = MeasureUtils.getVariationAsLong(context.getMeasure(CoreMetrics.NEW_MERGED_UNCOVERED_CONDITIONS), periodIndex, 0L); + long conditions = MeasureUtils.getVariationAsLong(context.getMeasure(CoreMetrics.NEW_MERGED_CONDITIONS_TO_COVER), periodIndex, 0L); + return conditions - uncoveredConditions; + } +} diff --git a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/sensors/AllTestsCoverageDecorator.java b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/sensors/AllTestsCoverageDecorator.java new file mode 100644 index 00000000000..f83d3291140 --- /dev/null +++ b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/sensors/AllTestsCoverageDecorator.java @@ -0,0 +1,85 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2008-2012 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.sensors; + +import org.sonar.api.batch.DecoratorContext; +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; + +public final class AllTestsCoverageDecorator extends AbstractCoverageDecorator { + + @DependsUpon + public Collection<Metric> usedMetrics() { + return Arrays.asList(CoreMetrics.MERGED_LINES_TO_COVER, CoreMetrics.MERGED_UNCOVERED_LINES, CoreMetrics.NEW_MERGED_LINES_TO_COVER, + CoreMetrics.NEW_MERGED_UNCOVERED_LINES, CoreMetrics.MERGED_CONDITIONS_TO_COVER, CoreMetrics.MERGED_UNCOVERED_CONDITIONS, + CoreMetrics.NEW_MERGED_CONDITIONS_TO_COVER, CoreMetrics.NEW_MERGED_UNCOVERED_CONDITIONS); + } + + @Override + protected Metric getGeneratedMetric() { + return CoreMetrics.MERGED_COVERAGE; + } + + @Override + protected Long countElements(DecoratorContext context) { + long lines = MeasureUtils.getValueAsLong(context.getMeasure(CoreMetrics.MERGED_LINES_TO_COVER), 0L); + long conditions = MeasureUtils.getValueAsLong(context.getMeasure(CoreMetrics.MERGED_CONDITIONS_TO_COVER), 0L); + return lines + conditions; + } + + @Override + protected long countCoveredElements(DecoratorContext context) { + long uncoveredLines = MeasureUtils.getValueAsLong(context.getMeasure(CoreMetrics.MERGED_UNCOVERED_LINES), 0L); + long lines = MeasureUtils.getValueAsLong(context.getMeasure(CoreMetrics.MERGED_LINES_TO_COVER), 0L); + long uncoveredConditions = MeasureUtils.getValueAsLong(context.getMeasure(CoreMetrics.MERGED_UNCOVERED_CONDITIONS), 0L); + long conditions = MeasureUtils.getValueAsLong(context.getMeasure(CoreMetrics.MERGED_CONDITIONS_TO_COVER), 0L); + return lines + conditions - uncoveredConditions - uncoveredLines; + } + + + @Override + protected Metric getGeneratedMetricForNewCode() { + return CoreMetrics.NEW_MERGED_COVERAGE; + } + + @Override + protected Long countElementsForNewCode(DecoratorContext context, int periodIndex) { + Long newLinesToCover = MeasureUtils.getVariationAsLong(context.getMeasure(CoreMetrics.NEW_MERGED_LINES_TO_COVER), periodIndex); + if (newLinesToCover != null) { + long newConditionsToCover = MeasureUtils.getVariationAsLong(context.getMeasure(CoreMetrics.NEW_MERGED_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_MERGED_LINES_TO_COVER), periodIndex, 0L); + long newUncoveredLines = MeasureUtils.getVariationAsLong(context.getMeasure(CoreMetrics.NEW_MERGED_UNCOVERED_LINES), periodIndex, 0L); + long newUncoveredConditions = MeasureUtils.getVariationAsLong(context.getMeasure(CoreMetrics.NEW_MERGED_UNCOVERED_CONDITIONS), periodIndex, 0L); + long newConditions = MeasureUtils.getVariationAsLong(context.getMeasure(CoreMetrics.NEW_MERGED_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/AllTestsLineCoverageDecorator.java b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/sensors/AllTestsLineCoverageDecorator.java new file mode 100644 index 00000000000..6fb9a973994 --- /dev/null +++ b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/sensors/AllTestsLineCoverageDecorator.java @@ -0,0 +1,73 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2008-2012 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.sensors; + +import org.sonar.api.batch.DecoratorContext; +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.List; + +public final class AllTestsLineCoverageDecorator extends AbstractCoverageDecorator { + + @DependsUpon + public List<Metric> dependsUponMetrics() { + return Arrays.asList(CoreMetrics.MERGED_UNCOVERED_LINES, CoreMetrics.MERGED_LINES_TO_COVER, CoreMetrics.NEW_MERGED_UNCOVERED_LINES, + CoreMetrics.NEW_MERGED_LINES_TO_COVER); + } + + @Override + protected Metric getGeneratedMetric() { + return CoreMetrics.MERGED_LINE_COVERAGE; + } + + @Override + protected Long countElements(DecoratorContext context) { + return MeasureUtils.getValueAsLong(context.getMeasure(CoreMetrics.MERGED_LINES_TO_COVER), 0L); + } + + @Override + protected long countCoveredElements(DecoratorContext context) { + long uncoveredLines = MeasureUtils.getValueAsLong(context.getMeasure(CoreMetrics.MERGED_UNCOVERED_LINES), 0L); + long lines = MeasureUtils.getValueAsLong(context.getMeasure(CoreMetrics.MERGED_LINES_TO_COVER), 0L); + return lines - uncoveredLines; + } + + + @Override + protected Metric getGeneratedMetricForNewCode() { + return CoreMetrics.NEW_MERGED_LINE_COVERAGE; + } + + @Override + protected Long countElementsForNewCode(DecoratorContext context, int periodIndex) { + return MeasureUtils.getVariationAsLong(context.getMeasure(CoreMetrics.NEW_MERGED_LINES_TO_COVER), periodIndex); + } + + @Override + protected long countCoveredElementsForNewCode(DecoratorContext context, int periodIndex) { + long uncoveredLines = MeasureUtils.getVariationAsLong(context.getMeasure(CoreMetrics.NEW_MERGED_UNCOVERED_LINES), periodIndex, 0L); + long lines = MeasureUtils.getVariationAsLong(context.getMeasure(CoreMetrics.NEW_MERGED_LINES_TO_COVER), periodIndex, 0L); + return lines - uncoveredLines; + } +} diff --git a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/widgets/AllTestsCoverageWidget.java b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/widgets/AllTestsCoverageWidget.java new file mode 100644 index 00000000000..8828ded647a --- /dev/null +++ b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/widgets/AllTestsCoverageWidget.java @@ -0,0 +1,43 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2008-2012 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.widgets; + +import org.sonar.api.web.AbstractRubyTemplate; +import org.sonar.api.web.RubyRailsWidget; +import org.sonar.api.web.UserRole; +import org.sonar.api.web.WidgetCategory; + +@WidgetCategory({ "Tests" }) +@UserRole(UserRole.USER) +public class AllTestsCoverageWidget extends AbstractRubyTemplate implements RubyRailsWidget { + + public String getId() { + return "merged-coverage"; + } + + public String getTitle() { + return "All Tests Coverage"; + } + + @Override + protected String getTemplatePath() { + return "/org/sonar/plugins/core/widgets/merged_coverage.html.erb"; + } +}
\ No newline at end of file diff --git a/plugins/sonar-core-plugin/src/main/resources/org/sonar/l10n/core.properties b/plugins/sonar-core-plugin/src/main/resources/org/sonar/l10n/core.properties index ebba87384b4..563a2c217a0 100644 --- a/plugins/sonar-core-plugin/src/main/resources/org/sonar/l10n/core.properties +++ b/plugins/sonar-core-plugin/src/main/resources/org/sonar/l10n/core.properties @@ -730,6 +730,14 @@ widget.it-coverage.lines_to_cover.suffix=\ lines to cover widget.it-coverage.on_new_code=On new code widget.it-coverage.no_new_lines_to_cover=No new lines to cover +# id of this widget does not use underscore in order to be backward-compatible with previous version of JaCoCo plugin +widget.merged-coverage.name=All tests coverage +widget.merged-coverage.description=Reports on code coverage by all tests +widget.merged-coverage.line_coverage.suffix=\ line coverage +widget.merged-coverage.branch_coverage.suffix=\ branch coverage +widget.merged-coverage.lines_to_cover.suffix=\ lines to cover +widget.merged-coverage.on_new_code=On new code +widget.merged-coverage.no_new_lines_to_cover=No new lines to cover widget.comments_duplications.name=Comments & Duplications widget.comments_duplications.description=Reports on copy/paste and documentation @@ -963,6 +971,7 @@ duplications.collapse=Collapse coverage_viewer.on_new_code=On new code coverage_viewer.unit_tests=Unit Tests coverage_viewer.integration_tests=Integration Tests +coverage_viewer.all_tests=All Tests #------------------------------------------------------------------------------ diff --git a/plugins/sonar-core-plugin/src/main/resources/org/sonar/plugins/core/widgets/merged_coverage.html.erb b/plugins/sonar-core-plugin/src/main/resources/org/sonar/plugins/core/widgets/merged_coverage.html.erb new file mode 100644 index 00000000000..8fae498e7ff --- /dev/null +++ b/plugins/sonar-core-plugin/src/main/resources/org/sonar/plugins/core/widgets/merged_coverage.html.erb @@ -0,0 +1,76 @@ +<% + coverage_measure=measure('merged_coverage') + if coverage_measure +%> +<table width="100%"> + <tr> + <td nowrap valign="top"> + <div class="dashbox"> + <p class="title"><%= message('widget.merged-coverage.name') -%></p> + <p> + <span class="big"><%= format_measure(coverage_measure, :suffix => '', :url => url_for_drilldown('merged_coverage'), :default => '-') %></span> + <%= dashboard_configuration.selected_period? ? format_variation(coverage_measure) : trend_icon(coverage_measure) -%> + </p> + <% it_line_coverage=measure('merged_line_coverage') + if it_line_coverage %> + <p> + <%= format_measure(it_line_coverage, :suffix => message('widget.merged-coverage.line_coverage.suffix'), :url => url_for_drilldown('merged_uncovered_lines', :highlight => 'merged_line_coverage')) %> + <%= dashboard_configuration.selected_period? ? format_variation(it_line_coverage) : trend_icon(it_line_coverage) -%> + </p> + <% end %> + <% it_branch_coverage=measure('merged_branch_coverage') + if it_branch_coverage %> + <p> + <%= format_measure(it_branch_coverage, :suffix => message('widget.merged-coverage.branch_coverage.suffix'), :url => url_for_drilldown('merged_uncovered_conditions', :highlight => 'merged_branch_coverage')) %> + <%= dashboard_configuration.selected_period? ? format_variation(it_branch_coverage) : trend_icon(it_branch_coverage) -%> + </p> + <% end %> + </div> + </td> + <td nowrap valign="top"> + <div class="dashbox"> + <% + if dashboard_configuration.selected_period? + new_lines_to_cover_measure=measure('new_merged_lines_to_cover') + if new_lines_to_cover_measure + new_lines=new_lines_to_cover_measure.variation(dashboard_configuration.period_index) + if new_lines + new_coverage=measure('new_merged_coverage') + new_line_coverage=measure('new_merged_line_coverage') + new_branch_coverage=measure('new_merged_branch_coverage') + %> + <h3><%= message('widget.merged-coverage.on_new_code') -%>: </h3> + <% if new_lines.to_i==0 %> + <p><%= message('widget.merged-coverage.no_new_lines_to_cover') -%></p> + <% else %> + <% if new_coverage %> + <p> + <span class="big"> + <a href="<%= url_for_drilldown('new_merged_coverage', :period => dashboard_configuration.period_index) -%>"><%= format_variation(new_coverage, :style => 'none', :default => '-') -%></a> + </span> + </p> + <% end %> + <p> + <a href="<%= url_for_drilldown('new_merged_lines_to_cover', :period => dashboard_configuration.period_index) -%>"><%= format_variation(new_lines_to_cover_measure, :style => 'none', :default => '-') -%><%= message('widget.merged-coverage.lines_to_cover.suffix') -%></a> + </p> + <% if new_line_coverage %> + <p> + <a href="<%= url_for_drilldown('new_merged_uncovered_lines', :highlight => 'new_merged_line_coverage', :period => dashboard_configuration.period_index) -%>"><%= format_variation(new_line_coverage, :style => 'none', :default => '-') -%><%= message('widget.merged-coverage.line_coverage.suffix') -%></a> + </p> + <% end %> + <% if new_branch_coverage %> + <p> + <a href="<%= url_for_drilldown('new_merged_uncovered_conditions', :highlight => 'new_merged_branch_coverage', :period => dashboard_configuration.period_index) -%>"><%= format_variation(new_branch_coverage, :style => 'none', :default => '-') -%><%= message('widget.merged-coverage.branch_coverage.suffix') -%></a> + </p> + <% + end + end + end + end + end + %> + </div> + </td> +</tr> +</table> +<% end %> diff --git a/plugins/sonar-jacoco-plugin/src/main/java/org/sonar/plugins/jacoco/JaCoCoAllTestsSensor.java b/plugins/sonar-jacoco-plugin/src/main/java/org/sonar/plugins/jacoco/JaCoCoAllTestsSensor.java new file mode 100644 index 00000000000..57e4cb84dfa --- /dev/null +++ b/plugins/sonar-jacoco-plugin/src/main/java/org/sonar/plugins/jacoco/JaCoCoAllTestsSensor.java @@ -0,0 +1,156 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2008-2012 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.jacoco; + +import com.google.common.io.Closeables; +import org.apache.commons.lang.StringUtils; +import org.jacoco.core.data.ExecutionDataReader; +import org.jacoco.core.data.ExecutionDataStore; +import org.jacoco.core.data.ExecutionDataWriter; +import org.jacoco.core.data.SessionInfoStore; +import org.sonar.api.batch.Sensor; +import org.sonar.api.batch.SensorContext; +import org.sonar.api.measures.CoreMetrics; +import org.sonar.api.measures.Measure; +import org.sonar.api.resources.JavaFile; +import org.sonar.api.resources.Project; +import org.sonar.api.resources.ProjectFileSystem; +import org.sonar.api.utils.SonarException; + +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.Collection; + +public class JaCoCoAllTestsSensor implements Sensor { + private static final String MERGED_EXEC = "target/merged.exec"; + + private final JacocoConfiguration configuration; + private final ProjectFileSystem projectFileSystem; + + public JaCoCoAllTestsSensor(JacocoConfiguration configuration, ProjectFileSystem projectFileSystem) { + this.configuration = configuration; + this.projectFileSystem = projectFileSystem; + } + + public boolean shouldExecuteOnProject(Project project) { + return StringUtils.isNotBlank(configuration.getItReportPath()) + && project.getAnalysisType().isDynamic(true); + } + + public void analyse(Project project, SensorContext context) { + mergeReports(); + new AllTestsAnalyzer().analyse(project, context); + } + + private void mergeReports() { + String reportUTs = configuration.getReportPath(); + String reportITs = configuration.getItReportPath(); + String reportAllTests = MERGED_EXEC; + + File baseDir = projectFileSystem.getBasedir(); + File destFile = new File(baseDir, reportAllTests); + + final SessionInfoStore infoStore = new SessionInfoStore(); + final ExecutionDataStore dataStore = new ExecutionDataStore(); + + loadSourceFiles(infoStore, dataStore, new File(baseDir, reportUTs), new File(baseDir, reportITs)); + + BufferedOutputStream outputStream = null; + try { + outputStream = new BufferedOutputStream(new FileOutputStream(destFile)); + ExecutionDataWriter dataWriter = new ExecutionDataWriter(outputStream); + + infoStore.accept(dataWriter); + dataStore.accept(dataWriter); + } catch (IOException e) { + throw new SonarException(String.format("Unable to write merged file %s", destFile.getAbsolutePath()), e); + } finally { + Closeables.closeQuietly(outputStream); + } + } + + private void loadSourceFiles(SessionInfoStore infoStore, ExecutionDataStore dataStore, File... files) { + for (File file : files) { + InputStream resourceStream = null; + try { + resourceStream = new BufferedInputStream(new FileInputStream(file)); + ExecutionDataReader reader = new ExecutionDataReader(resourceStream); + reader.setSessionInfoVisitor(infoStore); + reader.setExecutionDataVisitor(dataStore); + reader.read(); + } catch (final IOException e) { + throw new SonarException(String.format("Unable to read %s", file.getAbsolutePath()), e); + } finally { + Closeables.closeQuietly(resourceStream); + } + } + } + + class AllTestsAnalyzer extends AbstractAnalyzer { + @Override + protected String getReportPath(Project project) { + return MERGED_EXEC; + } + + @Override + protected String getExcludes(Project project) { + return configuration.getExcludes(); + } + + @Override + protected void saveMeasures(SensorContext context, JavaFile resource, Collection<Measure> measures) { + for (Measure measure : measures) { + Measure mergedMeasure = convertForIT(measure); + if (mergedMeasure != null) { + context.saveMeasure(resource, mergedMeasure); + } + } + } + + private Measure convertForIT(Measure measure) { + if (CoreMetrics.LINES_TO_COVER.equals(measure.getMetric())) { + return new Measure(CoreMetrics.MERGED_LINES_TO_COVER, measure.getValue()); + } else if (CoreMetrics.UNCOVERED_LINES.equals(measure.getMetric())) { + return new Measure(CoreMetrics.MERGED_UNCOVERED_LINES, measure.getValue()); + } else if (CoreMetrics.COVERAGE_LINE_HITS_DATA.equals(measure.getMetric())) { + return new Measure(CoreMetrics.MERGED_COVERAGE_LINE_HITS_DATA, measure.getData()); + } else if (CoreMetrics.CONDITIONS_TO_COVER.equals(measure.getMetric())) { + return new Measure(CoreMetrics.MERGED_CONDITIONS_TO_COVER, measure.getValue()); + } else if (CoreMetrics.UNCOVERED_CONDITIONS.equals(measure.getMetric())) { + return new Measure(CoreMetrics.MERGED_UNCOVERED_CONDITIONS, measure.getValue()); + } else if (CoreMetrics.COVERED_CONDITIONS_BY_LINE.equals(measure.getMetric())) { + return new Measure(CoreMetrics.MERGED_COVERED_CONDITIONS_BY_LINE, measure.getData()); + } else if (CoreMetrics.CONDITIONS_BY_LINE.equals(measure.getMetric())) { + return new Measure(CoreMetrics.MERGED_CONDITIONS_BY_LINE, measure.getData()); + } + return null; + } + } + + @Override + public String toString() { + return getClass().getSimpleName(); + } +} diff --git a/plugins/sonar-jacoco-plugin/src/main/java/org/sonar/plugins/jacoco/JaCoCoPlugin.java b/plugins/sonar-jacoco-plugin/src/main/java/org/sonar/plugins/jacoco/JaCoCoPlugin.java index 8fd1e6c5cbd..9a6a2016982 100644 --- a/plugins/sonar-jacoco-plugin/src/main/java/org/sonar/plugins/jacoco/JaCoCoPlugin.java +++ b/plugins/sonar-jacoco-plugin/src/main/java/org/sonar/plugins/jacoco/JaCoCoPlugin.java @@ -39,6 +39,7 @@ public class JaCoCoPlugin extends SonarPlugin { // Unit tests JaCoCoSensor.class, // Integration tests - JaCoCoItSensor.class); + JaCoCoItSensor.class, + JaCoCoAllTestsSensor.class); } } |