]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-2804 Merged coverage
authorDavid Gageot <david@gageot.net>
Tue, 2 Oct 2012 15:02:31 +0000 (17:02 +0200)
committerDavid Gageot <david@gageot.net>
Tue, 2 Oct 2012 19:50:12 +0000 (21:50 +0200)
13 files changed:
plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/CorePlugin.java
plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/sensors/AllTestsBranchCoverageDecorator.java [new file with mode: 0644]
plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/sensors/AllTestsCoverageDecorator.java [new file with mode: 0644]
plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/sensors/AllTestsLineCoverageDecorator.java [new file with mode: 0644]
plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/widgets/AllTestsCoverageWidget.java [new file with mode: 0644]
plugins/sonar-core-plugin/src/main/resources/org/sonar/l10n/core.properties
plugins/sonar-core-plugin/src/main/resources/org/sonar/plugins/core/widgets/merged_coverage.html.erb [new file with mode: 0644]
plugins/sonar-jacoco-plugin/src/main/java/org/sonar/plugins/jacoco/JaCoCoAllTestsSensor.java [new file with mode: 0644]
plugins/sonar-jacoco-plugin/src/main/java/org/sonar/plugins/jacoco/JaCoCoPlugin.java
sonar-plugin-api/src/main/java/org/sonar/api/measures/CoreMetrics.java
sonar-server/src/main/webapp/WEB-INF/app/controllers/resource_controller.rb
sonar-server/src/main/webapp/WEB-INF/app/views/resource/_header_coverage.html.erb
sonar-server/src/main/webapp/WEB-INF/app/views/resource/_options.html.erb

index 11899dfbb6be24ac89d9784e0d4c96372ffba7d4..7dacd86b642280d46a1c1787addf42f41b74e8cc 100644 (file)
@@ -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 (file)
index 0000000..7949cc9
--- /dev/null
@@ -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 (file)
index 0000000..f83d329
--- /dev/null
@@ -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 (file)
index 0000000..6fb9a97
--- /dev/null
@@ -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 (file)
index 0000000..8828ded
--- /dev/null
@@ -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
index ebba87384b4c1ba0302a2dc7760834f9d92e4f92..563a2c217a04627b3dc6480bb86342e8d4d0e7bb 100644 (file)
@@ -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 (file)
index 0000000..8fae498
--- /dev/null
@@ -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 (file)
index 0000000..57e4cb8
--- /dev/null
@@ -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();
+  }
+}
index 8fd1e6c5cbd32206eba3821e08637b77698e4f86..9a6a2016982f1c54010963d1339c918d4e2dbdd0 100644 (file)
@@ -39,6 +39,7 @@ public class JaCoCoPlugin extends SonarPlugin {
         // Unit tests
         JaCoCoSensor.class,
         // Integration tests
-        JaCoCoItSensor.class);
+        JaCoCoItSensor.class,
+        JaCoCoAllTestsSensor.class);
   }
 }
index 9ac19fe6034bbafdefb9cae85bf4f11ac3f51af9..a03ab232ef8db060de84283038a58a2bb1b53d28 100644 (file)
@@ -40,6 +40,7 @@ public final class CoreMetrics {
   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";
@@ -957,6 +958,291 @@ public final class CoreMetrics {
       .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
index a9e54122f813f508987360284a26dc28462a844a..69f3fe56700231574bf1c1c6757da1e61a70bb4f 100644 (file)
@@ -177,11 +177,15 @@ class ResourceController < ApplicationController
     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")
@@ -212,24 +216,30 @@ class ResourceController < ApplicationController
       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
index c3b9e18b93586d468429767c6b0470d24c1c38b3..140c68084547b6c3896d09a8a8bf4dc2fd845fc1 100644 (file)
@@ -84,7 +84,7 @@
       </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 %>
 
index c0754df974bb124f2b8a53aaca2a7b0002081eed..07e4d531b24e16bfaf6415d5c8807b7cfd3c23f4 100644 (file)
                     <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