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;
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;
AlertsWidget.class,
CoverageWidget.class,
ItCoverageWidget.class,
+ AllTestsCoverageWidget.class,
CommentsDuplicationsWidget.class,
DescriptionWidget.class,
ComplexityWidget.class,
ItLineCoverageDecorator.class,
ItCoverageDecorator.class,
ItBranchCoverageDecorator.class,
+ AllTestsLineCoverageDecorator.class,
+ AllTestsCoverageDecorator.class,
+ AllTestsBranchCoverageDecorator.class,
DefaultResourcePermissions.class,
ApplyProjectRolesDecorator.class,
ExcludedResourceFilter.class,
--- /dev/null
+/*
+ * 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;
+ }
+}
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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;
+ }
+}
--- /dev/null
+/*
+ * 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
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
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
#------------------------------------------------------------------------------
--- /dev/null
+<%
+ 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 %>
--- /dev/null
+/*
+ * 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();
+ }
+}
// Unit tests
JaCoCoSensor.class,
// Integration tests
- JaCoCoItSensor.class);
+ JaCoCoItSensor.class,
+ JaCoCoAllTestsSensor.class);
}
}
public static final String DOMAIN_SIZE = "Size";
public static final String DOMAIN_TESTS = "Tests";
public static final String DOMAIN_INTEGRATION_TESTS = "Integration Tests";
+ public static final String DOMAIN_MERGED_TESTS = "Merged Tests";
public static final String DOMAIN_COMPLEXITY = "Complexity";
public static final String DOMAIN_DOCUMENTATION = "Documentation";
public static final String DOMAIN_RULES = "Rules";
.setDeleteHistoricalData(true)
.create();
+ // --------------------------------------------------------------------------------------------------------------------
+ //
+ // MERGED TESTS
+ //
+ // --------------------------------------------------------------------------------------------------------------------
+
+ /**
+ * @since 3.3
+ */
+ public static final String MERGED_COVERAGE_KEY = "merged_coverage";
+
+ /**
+ * @since 3.3
+ */
+ public static final Metric MERGED_COVERAGE = new Metric.Builder(MERGED_COVERAGE_KEY, "All Tests Coverage", Metric.ValueType.PERCENT)
+ .setDescription("Coverage by All Tests")
+ .setDirection(Metric.DIRECTION_BETTER)
+ .setQualitative(true)
+ .setDomain(DOMAIN_MERGED_TESTS)
+ .setWorstValue(0.0)
+ .setBestValue(100.0)
+ .create();
+
+ /**
+ * @since 3.3
+ */
+ public static final String NEW_MERGED_COVERAGE_KEY = "new_merged_coverage";
+
+ /**
+ * @since 3.3
+ */
+ public static final Metric NEW_MERGED_COVERAGE = new Metric.Builder(NEW_MERGED_COVERAGE_KEY, "New Coverage by All Tests", Metric.ValueType.PERCENT)
+ .setDescription("All Tests Coverage of new/changed code")
+ .setDirection(Metric.DIRECTION_BETTER)
+ .setQualitative(true)
+ .setDomain(DOMAIN_MERGED_TESTS)
+ .setWorstValue(0.0)
+ .setBestValue(100.0)
+ .setDeleteHistoricalData(true)
+ .create();
+
+ /**
+ * @since 3.3
+ */
+ public static final String MERGED_LINES_TO_COVER_KEY = "merged_lines_to_cover";
+
+ /**
+ * @since 3.3
+ */
+ public static final Metric MERGED_LINES_TO_COVER = new Metric.Builder(MERGED_LINES_TO_COVER_KEY, "All Tests Lines to Cover", Metric.ValueType.INT)
+ .setDescription("Lines to cover by All Tests")
+ .setDirection(Metric.DIRECTION_BETTER)
+ .setDomain(DOMAIN_MERGED_TESTS)
+ .setQualitative(false)
+ .setFormula(new SumChildValuesFormula(false))
+ .setHidden(true)
+ .setDeleteHistoricalData(true)
+ .create();
+
+ /**
+ * @since 3.3
+ */
+ public static final String NEW_MERGED_LINES_TO_COVER_KEY = "new_merged_lines_to_cover";
+
+ /**
+ * @since 3.3
+ */
+ public static final Metric NEW_MERGED_LINES_TO_COVER = new Metric.Builder(NEW_MERGED_LINES_TO_COVER_KEY, "New Lines to Cover by All Tests", Metric.ValueType.INT)
+ .setDescription("New lines to cover by All Tests")
+ .setDirection(Metric.DIRECTION_WORST)
+ .setQualitative(false)
+ .setDomain(DOMAIN_MERGED_TESTS)
+ .setFormula(new SumChildValuesFormula(false))
+ .setDeleteHistoricalData(true)
+ .create();
+
+ /**
+ * @since 3.3
+ */
+ public static final String MERGED_UNCOVERED_LINES_KEY = "merged_uncovered_lines";
+
+ /**
+ * @since 3.3
+ */
+ public static final Metric MERGED_UNCOVERED_LINES = new Metric.Builder(MERGED_UNCOVERED_LINES_KEY, "All Tests Uncovered Lines", Metric.ValueType.INT)
+ .setDescription("All Tests uncovered lines")
+ .setDirection(Metric.DIRECTION_WORST)
+ .setQualitative(false)
+ .setDomain(DOMAIN_MERGED_TESTS)
+ .setFormula(new SumChildValuesFormula(false))
+ .create();
+
+ /**
+ * @since 3.3
+ */
+ public static final String NEW_MERGED_UNCOVERED_LINES_KEY = "new_merged_uncovered_lines";
+
+ /**
+ * @since 3.3
+ */
+ public static final Metric NEW_MERGED_UNCOVERED_LINES = new Metric.Builder(NEW_MERGED_UNCOVERED_LINES_KEY, "New Uncovered Lines by All Tests", Metric.ValueType.INT)
+ .setDescription("New uncovered lines by All Tests")
+ .setDirection(Metric.DIRECTION_WORST)
+ .setDomain(DOMAIN_MERGED_TESTS)
+ .setFormula(new SumChildValuesFormula(false))
+ .setBestValue(0.0)
+ .setDeleteHistoricalData(true)
+ .create();
+
+ /**
+ * @since 3.3
+ */
+ public static final String MERGED_LINE_COVERAGE_KEY = "merged_line_coverage";
+
+ /**
+ * @since 3.3
+ */
+ public static final Metric MERGED_LINE_COVERAGE = new Metric.Builder(MERGED_LINE_COVERAGE_KEY, "All Tests Line coverage", Metric.ValueType.PERCENT)
+ .setDescription("All Tests line coverage")
+ .setDirection(Metric.DIRECTION_BETTER)
+ .setQualitative(true)
+ .setDomain(DOMAIN_MERGED_TESTS)
+ .create();
+
+ /**
+ * @since 3.3
+ */
+ public static final String NEW_MERGED_LINE_COVERAGE_KEY = "new_merged_line_coverage";
+
+ /**
+ * @since 3.3
+ */
+ public static final Metric NEW_MERGED_LINE_COVERAGE = new Metric.Builder(NEW_MERGED_LINE_COVERAGE_KEY, "New Line Coverage by All Tests", Metric.ValueType.PERCENT)
+ .setDescription("Line Coverage by All Tests of added/changed code")
+ .setDirection(Metric.DIRECTION_BETTER)
+ .setQualitative(true)
+ .setWorstValue(0.0)
+ .setBestValue(100.0)
+ .setDomain(DOMAIN_MERGED_TESTS)
+ .setDeleteHistoricalData(true)
+ .create();
+
+ /**
+ * @since 3.3
+ */
+ public static final String MERGED_COVERAGE_LINE_HITS_DATA_KEY = "merged_coverage_line_hits_data";
+
+ /**
+ * @since 3.3
+ */
+ public static final Metric MERGED_COVERAGE_LINE_HITS_DATA = new Metric.Builder(MERGED_COVERAGE_LINE_HITS_DATA_KEY, "All Tests Coverage Hits Data", Metric.ValueType.DATA)
+ .setDescription("All Tests Code coverage line hits data")
+ .setDirection(Metric.DIRECTION_NONE)
+ .setQualitative(false)
+ .setDomain(DOMAIN_MERGED_TESTS)
+ .setDeleteHistoricalData(true)
+ .create();
+
+ /**
+ * @since 3.3
+ */
+ public static final String MERGED_CONDITIONS_TO_COVER_KEY = "merged_conditions_to_cover";
+
+ /**
+ * @since 3.3
+ */
+ public static final Metric MERGED_CONDITIONS_TO_COVER = new Metric.Builder(MERGED_CONDITIONS_TO_COVER_KEY, "All Tests Branches to Cover", Metric.ValueType.INT)
+ .setDescription("All Tests Conditions to cover")
+ .setDirection(Metric.DIRECTION_BETTER)
+ .setQualitative(false)
+ .setDomain(DOMAIN_MERGED_TESTS)
+ .setFormula(new SumChildValuesFormula(false))
+ .setHidden(true)
+ .setDeleteHistoricalData(true)
+ .create();
+
+ /**
+ * @since 3.3
+ */
+ public static final String NEW_MERGED_CONDITIONS_TO_COVER_KEY = "new_merged_conditions_to_cover";
+
+ /**
+ * @since 3.3
+ */
+ public static final Metric NEW_MERGED_CONDITIONS_TO_COVER = new Metric.Builder(NEW_MERGED_CONDITIONS_TO_COVER_KEY, "New Conditions to Cover by All Tests", Metric.ValueType.INT)
+ .setDescription("New conditions to cover by All Tests")
+ .setDomain(DOMAIN_MERGED_TESTS)
+ .setFormula(new SumChildValuesFormula(false))
+ .setDeleteHistoricalData(true)
+ .create();
+
+ /**
+ * @since 3.3
+ */
+ public static final String MERGED_UNCOVERED_CONDITIONS_KEY = "merged_uncovered_conditions";
+
+ /**
+ * @since 3.3
+ */
+ public static final Metric MERGED_UNCOVERED_CONDITIONS = new Metric.Builder(MERGED_UNCOVERED_CONDITIONS_KEY, "All Tests Uncovered Branches", Metric.ValueType.INT)
+ .setDescription("All Tests Uncovered conditions")
+ .setDirection(Metric.DIRECTION_WORST)
+ .setDomain(DOMAIN_MERGED_TESTS)
+ .setFormula(new SumChildValuesFormula(false))
+ .create();
+
+ /**
+ * @since 3.3
+ */
+ public static final String NEW_MERGED_UNCOVERED_CONDITIONS_KEY = "new_merged_uncovered_conditions";
+
+ /**
+ * @since 3.3
+ */
+ public static final Metric NEW_MERGED_UNCOVERED_CONDITIONS = new Metric.Builder(NEW_MERGED_UNCOVERED_CONDITIONS_KEY, "New Uncovered Conditions by All Tests", Metric.ValueType.INT)
+ .setDescription("New uncovered conditions by All Tests")
+ .setDirection(Metric.DIRECTION_WORST)
+ .setDomain(DOMAIN_MERGED_TESTS)
+ .setFormula(new SumChildValuesFormula(false))
+ .setBestValue(0.0)
+ .setDeleteHistoricalData(true)
+ .create();
+
+ /**
+ * @since 3.3
+ */
+ public static final String MERGED_BRANCH_COVERAGE_KEY = "merged_branch_coverage";
+
+ /**
+ * @since 3.3
+ */
+ public static final Metric MERGED_BRANCH_COVERAGE = new Metric.Builder(MERGED_BRANCH_COVERAGE_KEY, "All Tests Branch Coverage", Metric.ValueType.PERCENT)
+ .setDescription("All Tests Branch coverage")
+ .setDirection(Metric.DIRECTION_BETTER)
+ .setQualitative(true)
+ .setDomain(DOMAIN_MERGED_TESTS)
+ .setWorstValue(0.0)
+ .setBestValue(100.0)
+ .create();
+
+ /**
+ * @since 3.3
+ */
+ public static final String NEW_MERGED_BRANCH_COVERAGE_KEY = "new_merged_branch_coverage";
+
+ /**
+ * @since 3.3
+ */
+ public static final Metric NEW_MERGED_BRANCH_COVERAGE = new Metric.Builder(NEW_MERGED_BRANCH_COVERAGE_KEY, "New Branch Coverage by All Tests", Metric.ValueType.PERCENT)
+ .setDescription("Branch coverage by All Tests of new/changed code")
+ .setDirection(Metric.DIRECTION_BETTER)
+ .setQualitative(true)
+ .setDomain(DOMAIN_MERGED_TESTS)
+ .setWorstValue(0.0)
+ .setBestValue(100.0)
+ .setDeleteHistoricalData(true)
+ .create();
+
+ /**
+ * @since 3.3
+ */
+ public static final String MERGED_CONDITIONS_BY_LINE_KEY = "merged_conditions_by_line";
+
+ /**
+ * @since 3.3
+ */
+ public static final Metric MERGED_CONDITIONS_BY_LINE = new Metric.Builder(MERGED_CONDITIONS_BY_LINE_KEY, "All Tests Branches by Line", Metric.ValueType.DATA)
+ .setDomain(DOMAIN_MERGED_TESTS)
+ .setDeleteHistoricalData(true)
+ .create();
+
+ /**
+ * @since 3.3
+ */
+ public static final String MERGED_COVERED_CONDITIONS_BY_LINE_KEY = "merged_covered_conditions_by_line";
+
+ /**
+ * @since 3.3
+ */
+ public static final Metric MERGED_COVERED_CONDITIONS_BY_LINE = new Metric.Builder(MERGED_COVERED_CONDITIONS_BY_LINE_KEY, "All Tests Covered Branches by Line", Metric.ValueType.DATA)
+ .setDomain(DOMAIN_MERGED_TESTS)
+ .setDeleteHistoricalData(true)
+ .create();
+
+
// --------------------------------------------------------------------------------------------------------------------
//
// DUPLICATIONS
load_sources()
@display_coverage = true
@display_it_coverage = (!@snapshot.measure('it_coverage').nil?)
+ @display_all_tests_coverage = (!@snapshot.measure('merged_coverage').nil?)
@expandable = (@lines!=nil)
if @lines
metric = Metric.by_key(params[:coverage_filter]||params[:metric])
@coverage_filter = (metric ? metric.key : 'coverage')
- it_prefix = (@coverage_filter.start_with?('it_') ? 'it_' : '')
+
+ it_prefix = ''
+ it_prefix = 'it_' if @coverage_filter.start_with?('it_')
+ it_prefix = 'merged_' if @coverage_filter.start_with?('merged_')
@hits_by_line = load_distribution("#{it_prefix}coverage_line_hits_data")
@conditions_by_line = load_distribution("#{it_prefix}conditions_by_line")
if ('lines_to_cover'==@coverage_filter || 'coverage'==@coverage_filter || 'line_coverage'==@coverage_filter ||
'new_lines_to_cover'==@coverage_filter || 'new_coverage'==@coverage_filter || 'new_line_coverage'==@coverage_filter ||
'it_lines_to_cover'==@coverage_filter || 'it_coverage'==@coverage_filter || 'it_line_coverage'==@coverage_filter ||
- 'new_it_lines_to_cover'==@coverage_filter || 'new_it_coverage'==@coverage_filter || 'new_it_line_coverage'==@coverage_filter)
+ 'new_it_lines_to_cover'==@coverage_filter || 'new_it_coverage'==@coverage_filter || 'new_it_line_coverage'==@coverage_filter
+ 'merged_lines_to_cover'==@coverage_filter || 'merged_coverage'==@coverage_filter || 'merged_line_coverage'==@coverage_filter ||
+ 'new_merged_lines_to_cover'==@coverage_filter || 'new_merged_coverage'==@coverage_filter || 'new_merged_line_coverage'==@coverage_filter)
@coverage_filter = "#{it_prefix}lines_to_cover"
filter_lines { |line| line.hits && line.after(to) }
elsif ('uncovered_lines'==@coverage_filter || 'new_uncovered_lines'==@coverage_filter ||
- 'it_uncovered_lines'==@coverage_filter || 'new_it_uncovered_lines'==@coverage_filter)
+ 'it_uncovered_lines'==@coverage_filter || 'new_it_uncovered_lines'==@coverage_filter
+ 'merged_uncovered_lines'==@coverage_filter || 'new_merged_uncovered_lines'==@coverage_filter)
@coverage_filter = "#{it_prefix}uncovered_lines"
filter_lines { |line| line.hits && line.hits==0 && line.after(to) }
elsif ('conditions_to_cover'==@coverage_filter || 'branch_coverage'==@coverage_filter ||
'new_conditions_to_cover'==@coverage_filter || 'new_branch_coverage'==@coverage_filter ||
'it_conditions_to_cover'==@coverage_filter || 'it_branch_coverage'==@coverage_filter ||
- 'new_it_conditions_to_cover' == @coverage_filter || 'new_it_branch_coverage'==@coverage_filter)
+ 'new_it_conditions_to_cover' == @coverage_filter || 'new_it_branch_coverage'==@coverage_filter
+ 'merged_conditions_to_cover'==@coverage_filter || 'merged_branch_coverage'==@coverage_filter ||
+ 'new_merged_conditions_to_cover' == @coverage_filter || 'new_merged_branch_coverage'==@coverage_filter)
@coverage_filter="#{it_prefix}conditions_to_cover"
filter_lines { |line| line.conditions && line.conditions>0 && line.after(to) }
elsif ('uncovered_conditions' == @coverage_filter || 'new_uncovered_conditions' == @coverage_filter ||
- 'it_uncovered_conditions'==@coverage_filter || 'new_it_uncovered_conditions' == @coverage_filter)
+ 'it_uncovered_conditions'==@coverage_filter || 'new_it_uncovered_conditions' == @coverage_filter
+ 'merged_uncovered_conditions'==@coverage_filter || 'new_merged_uncovered_conditions' == @coverage_filter)
@coverage_filter="#{it_prefix}uncovered_conditions"
filter_lines { |line| line.conditions && line.covered_conditions && line.covered_conditions<line.conditions && line.after(to) }
end
</table>
<% else %>
<table>
- <% if @display_it_coverage %>
+ <% if @display_it_coverage || @display_all_tests_coverage %>
<tr>
<td colspan="7"><%= message('coverage_viewer.unit_tests') -%></td>
</tr>
<%= render :partial => 'measure', :locals => {:measure => measure('uncovered_conditions'), :title => Metric.name_for('uncovered_conditions'), :ratio => measure('conditions_to_cover')} -%>
</tr>
- <% if @display_it_coverage %>
- <tr>
- <td colspan="7"><br/><%= message('coverage_viewer.integration_tests') -%></td>
- </tr>
- <tr>
- <td class="big" rowspan="2"><%= format_measure('it_coverage', :default => '-') -%></td>
- <td class="sep"> </td>
- <%= render :partial => 'measure', :locals => {:measure => measure('it_line_coverage'), :title => Metric.name_for('it_line_coverage')} -%>
- <td class="sep"> </td>
- <%= render :partial => 'measure', :locals => {:measure => measure('it_branch_coverage'), :title => Metric.name_for('it_branch_coverage')} -%>
- </tr>
- <tr>
- <td class="sep"> </td>
- <%= render :partial => 'measure', :locals => {:measure => measure('it_uncovered_lines'), :title => Metric.name_for('it_uncovered_lines'), :ratio => measure('it_lines_to_cover')} -%>
- <td class="sep"> </td>
- <%= render :partial => 'measure', :locals => {:measure => measure('it_uncovered_conditions'), :title => Metric.name_for('it_uncovered_conditions'), :ratio => measure('it_conditions_to_cover')} -%>
- </tr>
- <% end %>
+ <% if @display_it_coverage %>
+ <tr>
+ <td colspan="7"><br/><%= message('coverage_viewer.integration_tests') -%></td>
+ </tr>
+ <tr>
+ <td class="big" rowspan="2"><%= format_measure('it_coverage', :default => '-') -%></td>
+ <td class="sep"></td>
+ <%= render :partial => 'measure', :locals => {:measure => measure('it_line_coverage'), :title => Metric.name_for('it_line_coverage')} -%>
+ <td class="sep"></td>
+ <%= render :partial => 'measure', :locals => {:measure => measure('it_branch_coverage'), :title => Metric.name_for('it_branch_coverage')} -%>
+ </tr>
+ <tr>
+ <td class="sep"></td>
+ <%= render :partial => 'measure', :locals => {:measure => measure('it_uncovered_lines'), :title => Metric.name_for('it_uncovered_lines'), :ratio => measure('it_lines_to_cover')} -%>
+ <td class="sep"></td>
+ <%= render :partial => 'measure', :locals => {:measure => measure('it_uncovered_conditions'), :title => Metric.name_for('it_uncovered_conditions'), :ratio => measure('it_conditions_to_cover')} -%>
+ </tr>
+ <% end %>
+
+ <% if @display_all_tests_coverage %>
+ <tr>
+ <td colspan="7"><br/><%= message('coverage_viewer.all_tests') -%></td>
+ </tr>
+ <tr>
+ <td class="big" rowspan="2"><%= format_measure('merged_coverage', :default => '-') -%></td>
+ <td class="sep"> </td>
+ <%= render :partial => 'measure', :locals => {:measure => measure('merged_line_coverage'), :title => Metric.name_for('merged_line_coverage')} -%>
+ <td class="sep"> </td>
+ <%= render :partial => 'measure', :locals => {:measure => measure('merged_branch_coverage'), :title => Metric.name_for('merged_branch_coverage')} -%>
+ </tr>
+ <tr>
+ <td class="sep"> </td>
+ <%= render :partial => 'measure', :locals => {:measure => measure('merged_uncovered_lines'), :title => Metric.name_for('merged_uncovered_lines'), :ratio => measure('merged_lines_to_cover')} -%>
+ <td class="sep"> </td>
+ <%= render :partial => 'measure', :locals => {:measure => measure('merged_uncovered_conditions'), :title => Metric.name_for('merged_uncovered_conditions'), :ratio => measure('merged_conditions_to_cover')} -%>
+ </tr>
+ <% end %>
</table>
<% end %>
<option value="it_uncovered_conditions" <%= 'selected' if @coverage_filter=='it_uncovered_conditions' -%>><%= Metric.name_for('it_uncovered_conditions') -%></option>
</optgroup>
<% end %>
+ <% if @display_all_tests_coverage %>
+ <optgroup label="<%= h message('coverage_viewer.all_tests') -%>">
+ <option value="merged_lines_to_cover" <%= 'selected' if @coverage_filter=='merged_lines_to_cover' -%>><%= Metric.name_for('merged_lines_to_cover') -%></option>
+ <option value="merged_uncovered_lines" <%= 'selected' if @coverage_filter=='merged_uncovered_lines' -%>><%= Metric.name_for('merged_uncovered_lines') -%></option>
+ <option value="merged_conditions_to_cover" <%= 'selected' if @coverage_filter=='merged_conditions_to_cover' -%>><%= Metric.name_for('merged_conditions_to_cover') -%></option>
+ <option value="merged_uncovered_conditions" <%= 'selected' if @coverage_filter=='merged_uncovered_conditions' -%>><%= Metric.name_for('merged_uncovered_conditions') -%></option>
+ </optgroup>
+ <% end %>
</select>
</td>
<% first=false