diff options
17 files changed, 724 insertions, 222 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 82e3a1c8723..00ea4547077 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 @@ -268,6 +268,9 @@ public class CorePlugin extends SonarPlugin { extensions.add(LineCoverageDecorator.class); extensions.add(CoverageDecorator.class); extensions.add(BranchCoverageDecorator.class); + extensions.add(ItLineCoverageDecorator.class); + extensions.add(ItCoverageDecorator.class); + extensions.add(ItBranchCoverageDecorator.class); extensions.add(ApplyProjectRolesDecorator.class); extensions.add(ExcludedResourceFilter.class); extensions.add(CommentDensityDecorator.class); @@ -286,6 +289,7 @@ public class CorePlugin extends SonarPlugin { extensions.add(NewViolationsDecorator.class); extensions.add(TimeMachineConfigurationPersister.class); extensions.add(NewCoverageFileAnalyzer.class); + extensions.add(NewItCoverageFileAnalyzer.class); extensions.add(NewCoverageAggregator.class); return extensions; diff --git a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/sensors/ItBranchCoverageDecorator.java b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/sensors/ItBranchCoverageDecorator.java new file mode 100644 index 00000000000..90a624305d7 --- /dev/null +++ b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/sensors/ItBranchCoverageDecorator.java @@ -0,0 +1,72 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2008-2011 SonarSource + * mailto:contact AT sonarsource DOT com + * + * Sonar is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * Sonar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with Sonar; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.plugins.core.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 ItBranchCoverageDecorator extends AbstractCoverageDecorator { + + @DependsUpon + public List<Metric> dependsUponMetrics() { + return Arrays.asList(CoreMetrics.IT_UNCOVERED_CONDITIONS, CoreMetrics.IT_CONDITIONS_TO_COVER, + CoreMetrics.NEW_IT_UNCOVERED_CONDITIONS, CoreMetrics.NEW_IT_CONDITIONS_TO_COVER); + } + + @Override + protected Metric getGeneratedMetric() { + return CoreMetrics.IT_BRANCH_COVERAGE; + } + + @Override + protected Long countElements(DecoratorContext context) { + return MeasureUtils.getValueAsLong(context.getMeasure(CoreMetrics.IT_CONDITIONS_TO_COVER), 0L); + } + + @Override + protected long countCoveredElements(DecoratorContext context) { + long uncoveredConditions = MeasureUtils.getValueAsLong(context.getMeasure(CoreMetrics.IT_UNCOVERED_CONDITIONS), 0L); + long conditions = MeasureUtils.getValueAsLong(context.getMeasure(CoreMetrics.IT_CONDITIONS_TO_COVER), 0L); + return conditions - uncoveredConditions; + } + + @Override + protected Metric getGeneratedMetricForNewCode() { + return CoreMetrics.NEW_IT_BRANCH_COVERAGE; + } + + @Override + protected Long countElementsForNewCode(DecoratorContext context, int periodIndex) { + return MeasureUtils.getVariationAsLong(context.getMeasure(CoreMetrics.NEW_IT_CONDITIONS_TO_COVER), periodIndex); + } + + @Override + protected long countCoveredElementsForNewCode(DecoratorContext context, int periodIndex) { + long uncoveredConditions = MeasureUtils.getVariationAsLong(context.getMeasure(CoreMetrics.NEW_IT_UNCOVERED_CONDITIONS), periodIndex, 0L); + long conditions = MeasureUtils.getVariationAsLong(context.getMeasure(CoreMetrics.NEW_IT_CONDITIONS_TO_COVER), periodIndex, 0L); + return conditions - uncoveredConditions; + } +} diff --git a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/sensors/ItCoverageDecorator.java b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/sensors/ItCoverageDecorator.java new file mode 100644 index 00000000000..ce538aa1f1f --- /dev/null +++ b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/sensors/ItCoverageDecorator.java @@ -0,0 +1,85 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2008-2011 SonarSource + * mailto:contact AT sonarsource DOT com + * + * Sonar is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * Sonar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with Sonar; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.plugins.core.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 ItCoverageDecorator extends AbstractCoverageDecorator { + + @DependsUpon + public Collection<Metric> usedMetrics() { + return Arrays.asList(CoreMetrics.IT_LINES_TO_COVER, CoreMetrics.IT_UNCOVERED_LINES, CoreMetrics.NEW_IT_LINES_TO_COVER, + CoreMetrics.NEW_IT_UNCOVERED_LINES, CoreMetrics.IT_CONDITIONS_TO_COVER, CoreMetrics.IT_UNCOVERED_CONDITIONS, + CoreMetrics.NEW_IT_CONDITIONS_TO_COVER, CoreMetrics.NEW_IT_UNCOVERED_CONDITIONS); + } + + @Override + protected Metric getGeneratedMetric() { + return CoreMetrics.IT_COVERAGE; + } + + @Override + protected Long countElements(DecoratorContext context) { + long lines = MeasureUtils.getValueAsLong(context.getMeasure(CoreMetrics.IT_LINES_TO_COVER), 0L); + long conditions = MeasureUtils.getValueAsLong(context.getMeasure(CoreMetrics.IT_CONDITIONS_TO_COVER), 0L); + return lines + conditions; + } + + @Override + protected long countCoveredElements(DecoratorContext context) { + long uncoveredLines = MeasureUtils.getValueAsLong(context.getMeasure(CoreMetrics.IT_UNCOVERED_LINES), 0L); + long lines = MeasureUtils.getValueAsLong(context.getMeasure(CoreMetrics.IT_LINES_TO_COVER), 0L); + long uncoveredConditions = MeasureUtils.getValueAsLong(context.getMeasure(CoreMetrics.IT_UNCOVERED_CONDITIONS), 0L); + long conditions = MeasureUtils.getValueAsLong(context.getMeasure(CoreMetrics.IT_CONDITIONS_TO_COVER), 0L); + return lines + conditions - uncoveredConditions - uncoveredLines; + } + + + @Override + protected Metric getGeneratedMetricForNewCode() { + return CoreMetrics.NEW_IT_COVERAGE; + } + + @Override + protected Long countElementsForNewCode(DecoratorContext context, int periodIndex) { + Long newLinesToCover = MeasureUtils.getVariationAsLong(context.getMeasure(CoreMetrics.NEW_IT_LINES_TO_COVER), periodIndex); + if (newLinesToCover != null) { + long newConditionsToCover = MeasureUtils.getVariationAsLong(context.getMeasure(CoreMetrics.NEW_IT_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_IT_LINES_TO_COVER), periodIndex, 0L); + long newUncoveredLines = MeasureUtils.getVariationAsLong(context.getMeasure(CoreMetrics.NEW_IT_UNCOVERED_LINES), periodIndex, 0L); + long newUncoveredConditions = MeasureUtils.getVariationAsLong(context.getMeasure(CoreMetrics.NEW_IT_UNCOVERED_CONDITIONS), periodIndex, 0L); + long newConditions = MeasureUtils.getVariationAsLong(context.getMeasure(CoreMetrics.NEW_IT_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/ItLineCoverageDecorator.java b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/sensors/ItLineCoverageDecorator.java new file mode 100644 index 00000000000..53c46fd4119 --- /dev/null +++ b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/sensors/ItLineCoverageDecorator.java @@ -0,0 +1,73 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2008-2011 SonarSource + * mailto:contact AT sonarsource DOT com + * + * Sonar is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * Sonar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with Sonar; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.plugins.core.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 ItLineCoverageDecorator extends AbstractCoverageDecorator { + + @DependsUpon + public List<Metric> dependsUponMetrics() { + return Arrays.asList(CoreMetrics.IT_UNCOVERED_LINES, CoreMetrics.IT_LINES_TO_COVER, CoreMetrics.NEW_IT_UNCOVERED_LINES, + CoreMetrics.NEW_IT_LINES_TO_COVER); + } + + @Override + protected Metric getGeneratedMetric() { + return CoreMetrics.IT_LINE_COVERAGE; + } + + @Override + protected Long countElements(DecoratorContext context) { + return MeasureUtils.getValueAsLong(context.getMeasure(CoreMetrics.IT_LINES_TO_COVER), 0L); + } + + @Override + protected long countCoveredElements(DecoratorContext context) { + long uncoveredLines = MeasureUtils.getValueAsLong(context.getMeasure(CoreMetrics.IT_UNCOVERED_LINES), 0L); + long lines = MeasureUtils.getValueAsLong(context.getMeasure(CoreMetrics.IT_LINES_TO_COVER), 0L); + return lines - uncoveredLines; + } + + + @Override + protected Metric getGeneratedMetricForNewCode() { + return CoreMetrics.NEW_IT_LINE_COVERAGE; + } + + @Override + protected Long countElementsForNewCode(DecoratorContext context, int periodIndex) { + return MeasureUtils.getVariationAsLong(context.getMeasure(CoreMetrics.NEW_IT_LINES_TO_COVER), periodIndex); + } + + @Override + protected long countCoveredElementsForNewCode(DecoratorContext context, int periodIndex) { + long uncoveredLines = MeasureUtils.getVariationAsLong(context.getMeasure(CoreMetrics.NEW_IT_UNCOVERED_LINES), periodIndex, 0L); + long lines = MeasureUtils.getVariationAsLong(context.getMeasure(CoreMetrics.NEW_IT_LINES_TO_COVER), periodIndex, 0L); + return lines - uncoveredLines; + } +} diff --git a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/AbstractNewCoverageFileAnalyzer.java b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/AbstractNewCoverageFileAnalyzer.java new file mode 100644 index 00000000000..f5740ffebf1 --- /dev/null +++ b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/AbstractNewCoverageFileAnalyzer.java @@ -0,0 +1,216 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2008-2011 SonarSource + * mailto:contact AT sonarsource DOT com + * + * Sonar is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * Sonar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with Sonar; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.plugins.core.timemachine; + +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; +import org.apache.commons.lang.ObjectUtils; +import org.sonar.api.batch.*; +import org.sonar.api.measures.CoreMetrics; +import org.sonar.api.measures.Measure; +import org.sonar.api.measures.Metric; +import org.sonar.api.resources.Project; +import org.sonar.api.resources.Qualifiers; +import org.sonar.api.resources.Resource; +import org.sonar.api.resources.Scopes; +import org.sonar.api.utils.KeyValueFormat; +import org.sonar.batch.components.PastSnapshot; +import org.sonar.batch.components.TimeMachineConfiguration; +import org.sonar.core.NotDryRun; + +import java.util.Arrays; +import java.util.Date; +import java.util.List; +import java.util.Map; + +/** + * @since 2.7 + */ +@NotDryRun +@DependedUpon(DecoratorBarriers.END_OF_TIME_MACHINE) +public abstract class AbstractNewCoverageFileAnalyzer implements Decorator { + + private List<PeriodStruct> structs; + + public AbstractNewCoverageFileAnalyzer(TimeMachineConfiguration timeMachineConfiguration) { + structs = Lists.newArrayList(); + for (PastSnapshot pastSnapshot : timeMachineConfiguration.getProjectPastSnapshots()) { + structs.add(new PeriodStruct(pastSnapshot)); + } + } + + AbstractNewCoverageFileAnalyzer(List<PeriodStruct> structs) { + this.structs = structs; + } + + public abstract Metric getCoverageLineHitsDataMetric(); + + public abstract Metric getConditionsByLineMetric(); + + public abstract Metric getCoveredConditionsByLineMetric(); + + public abstract Metric getNewLinesToCoverMetric(); + + public abstract Metric getNewUncoveredLinesMetric(); + + public abstract Metric getNewConditionsToCoverMetric(); + + public abstract Metric getNewUncoveredConditionsMetric(); + + public boolean shouldExecuteOnProject(Project project) { + return project.isLatestAnalysis() && !structs.isEmpty(); + } + + private boolean shouldDecorate(Resource resource) { + return Scopes.isFile(resource) && !Qualifiers.UNIT_TEST_FILE.equals(resource.getQualifier()); + } + + @DependsUpon + public List<Metric> dependsOnMetrics() { + + return Arrays.asList(CoreMetrics.SCM_LAST_COMMIT_DATETIMES_BY_LINE, + getCoverageLineHitsDataMetric(), getConditionsByLineMetric(), getCoveredConditionsByLineMetric()); + } + + @DependedUpon + public List<Metric> generatesNewCoverageMetrics() { + return Arrays.asList(getNewLinesToCoverMetric(), getNewUncoveredLinesMetric(), getNewConditionsToCoverMetric(), getNewUncoveredConditionsMetric()); + } + + public void decorate(Resource resource, DecoratorContext context) { + if (shouldDecorate(resource)) { + doDecorate(context); + } + } + + void doDecorate(DecoratorContext context) { + if (parse(context)) { + compute(context); + } + } + + private boolean parse(DecoratorContext context) { + Measure lastCommits = context.getMeasure(CoreMetrics.SCM_LAST_COMMIT_DATETIMES_BY_LINE); + Measure hitsByLineMeasure = context.getMeasure(getCoverageLineHitsDataMetric()); + + if (lastCommits != null && lastCommits.hasData() && hitsByLineMeasure != null && hitsByLineMeasure.hasData()) { + Map<Integer, Date> datesByLine = KeyValueFormat.parseIntDateTime(lastCommits.getData()); + Map<Integer, Integer> hitsByLine = parseCountByLine(hitsByLineMeasure); + Map<Integer, Integer> conditionsByLine = parseCountByLine(context.getMeasure(getConditionsByLineMetric())); + Map<Integer, Integer> coveredConditionsByLine = parseCountByLine(context.getMeasure(getCoveredConditionsByLineMetric())); + + reset(); + + for (Map.Entry<Integer, Integer> entry : hitsByLine.entrySet()) { + int lineId = entry.getKey(); + int hits = entry.getValue(); + int conditions = (Integer) ObjectUtils.defaultIfNull(conditionsByLine.get(lineId), 0); + int coveredConditions = (Integer) ObjectUtils.defaultIfNull(coveredConditionsByLine.get(lineId), 0); + Date date = datesByLine.get(lineId); + for (PeriodStruct struct : structs) { + struct.analyze(date, hits, conditions, coveredConditions); + } + } + + return true; + } + return false; + } + + private void reset() { + for (PeriodStruct struct : structs) { + struct.reset(); + } + } + + private void compute(DecoratorContext context) { + Measure newLines = new Measure(getNewLinesToCoverMetric()); + Measure newUncoveredLines = new Measure(getNewUncoveredLinesMetric()); + Measure newConditions = new Measure(getNewConditionsToCoverMetric()); + Measure newUncoveredConditions = new Measure(getNewUncoveredConditionsMetric()); + + for (PeriodStruct struct : structs) { + newLines.setVariation(struct.index, (double) struct.newLines); + newUncoveredLines.setVariation(struct.index, (double) (struct.newLines - struct.newCoveredLines)); + newConditions.setVariation(struct.index, (double) struct.newConditions); + newUncoveredConditions.setVariation(struct.index, (double) struct.newConditions - struct.newCoveredConditions); + } + + context.saveMeasure(newLines); + context.saveMeasure(newUncoveredLines); + context.saveMeasure(newConditions); + context.saveMeasure(newUncoveredConditions); + } + + private Map<Integer, Integer> parseCountByLine(Measure measure) { + if (measure != null && measure.hasData()) { + return KeyValueFormat.parseIntInt(measure.getData()); + } + return Maps.newHashMap(); + } + + public static final class PeriodStruct { + int index; + Date date; + int newLines = 0, newCoveredLines = 0, newConditions = 0, newCoveredConditions = 0; + + PeriodStruct(PastSnapshot pastSnapshot) { + this.index = pastSnapshot.getIndex(); + this.date = pastSnapshot.getTargetDate(); + } + + PeriodStruct(int index, Date date) { + this.index = index; + this.date = date; + } + + void reset() { + newLines = 0; + newCoveredLines = 0; + newConditions = 0; + newCoveredConditions = 0; + } + + void analyze(Date lineDate, int hits, int conditions, int coveredConditions) { + if (lineDate == null) { + // TODO warning + + } else if (date == null || lineDate.after(date)) { + // TODO test if string comparison is faster or not + addLine(hits > 0); + addConditions(conditions, coveredConditions); + } + } + + void addLine(boolean covered) { + newLines += 1; + if (covered) { + newCoveredLines += 1; + } + } + + void addConditions(int count, int countCovered) { + newConditions += count; + if (count > 0) { + newCoveredConditions += countCovered; + } + } + } +} diff --git a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/NewCoverageAggregator.java b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/NewCoverageAggregator.java index 15d0e7a1f68..c4ffc776450 100644 --- a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/NewCoverageAggregator.java +++ b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/NewCoverageAggregator.java @@ -44,8 +44,9 @@ public final class NewCoverageAggregator implements Decorator { @DependedUpon public List<Metric> generatesNewCoverageMetrics() { - return Arrays.asList(CoreMetrics.NEW_LINES_TO_COVER, CoreMetrics.NEW_UNCOVERED_LINES, - CoreMetrics.NEW_CONDITIONS_TO_COVER, CoreMetrics.NEW_UNCOVERED_CONDITIONS); + return Arrays.asList( + CoreMetrics.NEW_LINES_TO_COVER, CoreMetrics.NEW_UNCOVERED_LINES, CoreMetrics.NEW_CONDITIONS_TO_COVER, CoreMetrics.NEW_UNCOVERED_CONDITIONS, + CoreMetrics.NEW_IT_LINES_TO_COVER, CoreMetrics.NEW_IT_UNCOVERED_LINES, CoreMetrics.NEW_IT_CONDITIONS_TO_COVER, CoreMetrics.NEW_IT_UNCOVERED_CONDITIONS); } public void decorate(Resource resource, DecoratorContext context) { @@ -55,6 +56,10 @@ public final class NewCoverageAggregator implements Decorator { aggregate(context, CoreMetrics.NEW_UNCOVERED_LINES, maxPeriods); aggregate(context, CoreMetrics.NEW_CONDITIONS_TO_COVER, maxPeriods); aggregate(context, CoreMetrics.NEW_UNCOVERED_CONDITIONS, maxPeriods); + aggregate(context, CoreMetrics.NEW_IT_LINES_TO_COVER, maxPeriods); + aggregate(context, CoreMetrics.NEW_IT_UNCOVERED_LINES, maxPeriods); + aggregate(context, CoreMetrics.NEW_IT_CONDITIONS_TO_COVER, maxPeriods); + aggregate(context, CoreMetrics.NEW_IT_UNCOVERED_CONDITIONS, maxPeriods); } } diff --git a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/NewCoverageFileAnalyzer.java b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/NewCoverageFileAnalyzer.java index d44ffd056e1..59929b27d88 100644 --- a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/NewCoverageFileAnalyzer.java +++ b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/NewCoverageFileAnalyzer.java @@ -19,184 +19,54 @@ */ package org.sonar.plugins.core.timemachine; -import com.google.common.collect.Lists; -import com.google.common.collect.Maps; -import org.apache.commons.lang.ObjectUtils; -import org.sonar.api.batch.*; import org.sonar.api.measures.CoreMetrics; -import org.sonar.api.measures.Measure; import org.sonar.api.measures.Metric; -import org.sonar.api.resources.Project; -import org.sonar.api.resources.Qualifiers; -import org.sonar.api.resources.Resource; -import org.sonar.api.resources.Scopes; -import org.sonar.api.utils.KeyValueFormat; -import org.sonar.batch.components.PastSnapshot; import org.sonar.batch.components.TimeMachineConfiguration; -import org.sonar.core.NotDryRun; -import java.util.Arrays; -import java.util.Date; import java.util.List; -import java.util.Map; -/** - * @since 2.7 - */ -@NotDryRun -@DependedUpon(DecoratorBarriers.END_OF_TIME_MACHINE) -public final class NewCoverageFileAnalyzer implements Decorator { - - private List<PeriodStruct> structs; +public class NewCoverageFileAnalyzer extends AbstractNewCoverageFileAnalyzer { public NewCoverageFileAnalyzer(TimeMachineConfiguration timeMachineConfiguration) { - structs = Lists.newArrayList(); - for (PastSnapshot pastSnapshot : timeMachineConfiguration.getProjectPastSnapshots()) { - structs.add(new PeriodStruct(pastSnapshot)); - } + super(timeMachineConfiguration); } NewCoverageFileAnalyzer(List<PeriodStruct> structs) { - this.structs = structs; - } - - public boolean shouldExecuteOnProject(Project project) { - return project.isLatestAnalysis() && !structs.isEmpty(); - } - - private boolean shouldDecorate(Resource resource) { - return Scopes.isFile(resource) && !Qualifiers.UNIT_TEST_FILE.equals(resource.getQualifier()); + super(structs); } - @DependsUpon - public List<Metric> dependsOnMetrics() { - return Arrays.asList(CoreMetrics.SCM_LAST_COMMIT_DATETIMES_BY_LINE, CoreMetrics.COVERAGE_LINE_HITS_DATA, - CoreMetrics.CONDITIONS_BY_LINE, CoreMetrics.COVERED_CONDITIONS_BY_LINE); + @Override + public Metric getCoverageLineHitsDataMetric() { + return CoreMetrics.COVERAGE_LINE_HITS_DATA; } - @DependedUpon - public List<Metric> generatesNewCoverageMetrics() { - return Arrays.asList(CoreMetrics.NEW_LINES_TO_COVER, CoreMetrics.NEW_UNCOVERED_LINES, - CoreMetrics.NEW_CONDITIONS_TO_COVER, CoreMetrics.NEW_UNCOVERED_CONDITIONS); + @Override + public Metric getConditionsByLineMetric() { + return CoreMetrics.CONDITIONS_BY_LINE; } - public void decorate(Resource resource, DecoratorContext context) { - if (shouldDecorate(resource)) { - doDecorate(context); - } + @Override + public Metric getCoveredConditionsByLineMetric() { + return CoreMetrics.COVERED_CONDITIONS_BY_LINE; } - void doDecorate(DecoratorContext context) { - if (parse(context)) { - compute(context); - } + @Override + public Metric getNewLinesToCoverMetric() { + return CoreMetrics.NEW_LINES_TO_COVER; } - private boolean parse(DecoratorContext context) { - Measure lastCommits = context.getMeasure(CoreMetrics.SCM_LAST_COMMIT_DATETIMES_BY_LINE); - Measure hitsByLineMeasure = context.getMeasure(CoreMetrics.COVERAGE_LINE_HITS_DATA); - - if (lastCommits != null && lastCommits.hasData() && hitsByLineMeasure != null && hitsByLineMeasure.hasData()) { - Map<Integer, Date> datesByLine = KeyValueFormat.parseIntDateTime(lastCommits.getData()); - Map<Integer, Integer> hitsByLine = parseCountByLine(hitsByLineMeasure); - Map<Integer, Integer> conditionsByLine = parseCountByLine(context.getMeasure(CoreMetrics.CONDITIONS_BY_LINE)); - Map<Integer, Integer> coveredConditionsByLine = parseCountByLine(context.getMeasure(CoreMetrics.COVERED_CONDITIONS_BY_LINE)); - - reset(); - - for (Map.Entry<Integer, Integer> entry : hitsByLine.entrySet()) { - int lineId = entry.getKey(); - int hits = entry.getValue(); - int conditions = (Integer)ObjectUtils.defaultIfNull(conditionsByLine.get(lineId), 0); - int coveredConditions = (Integer)ObjectUtils.defaultIfNull(coveredConditionsByLine.get(lineId), 0); - Date date = datesByLine.get(lineId); - for (PeriodStruct struct : structs) { - struct.analyze(date, hits, conditions, coveredConditions); - } - } - - return true; - } - return false; + @Override + public Metric getNewUncoveredLinesMetric() { + return CoreMetrics.NEW_UNCOVERED_LINES; } - private void reset() { - for (PeriodStruct struct : structs) { - struct.reset(); - } + @Override + public Metric getNewConditionsToCoverMetric() { + return CoreMetrics.NEW_CONDITIONS_TO_COVER; } - private void compute(DecoratorContext context) { - Measure newLines = new Measure(CoreMetrics.NEW_LINES_TO_COVER); - Measure newUncoveredLines = new Measure(CoreMetrics.NEW_UNCOVERED_LINES); - Measure newConditions = new Measure(CoreMetrics.NEW_CONDITIONS_TO_COVER); - Measure newUncoveredConditions = new Measure(CoreMetrics.NEW_UNCOVERED_CONDITIONS); - - for (PeriodStruct struct : structs) { - newLines.setVariation(struct.index, (double)struct.newLines); - newUncoveredLines.setVariation(struct.index, (double) (struct.newLines - struct.newCoveredLines)); - newConditions.setVariation(struct.index, (double)struct.newConditions); - newUncoveredConditions.setVariation(struct.index, (double)struct.newConditions-struct.newCoveredConditions); - } - - context.saveMeasure(newLines); - context.saveMeasure(newUncoveredLines); - context.saveMeasure(newConditions); - context.saveMeasure(newUncoveredConditions); - } - - private Map<Integer, Integer> parseCountByLine(Measure measure) { - if (measure != null && measure.hasData()) { - return KeyValueFormat.parseIntInt(measure.getData()); - } - return Maps.newHashMap(); - } - - public static final class PeriodStruct { - int index; - Date date; - int newLines = 0, newCoveredLines = 0, newConditions = 0, newCoveredConditions = 0; - - PeriodStruct(PastSnapshot pastSnapshot) { - this.index = pastSnapshot.getIndex(); - this.date = pastSnapshot.getTargetDate(); - } - - PeriodStruct(int index, Date date) { - this.index = index; - this.date = date; - } - - void reset() { - newLines = 0; - newCoveredLines = 0; - newConditions = 0; - newCoveredConditions = 0; - } - - void analyze(Date lineDate, int hits, int conditions, int coveredConditions) { - if (lineDate == null) { - // TODO warning - - } else if (date == null || lineDate.after(date)) { - // TODO test if string comparison is faster or not - addLine(hits > 0); - addConditions(conditions, coveredConditions); - } - } - - void addLine(boolean covered) { - newLines += 1; - if (covered) { - newCoveredLines += 1; - } - } - - void addConditions(int count, int countCovered) { - newConditions += count; - if (count > 0) { - newCoveredConditions += countCovered; - } - } + @Override + public Metric getNewUncoveredConditionsMetric() { + return CoreMetrics.NEW_UNCOVERED_CONDITIONS; } } diff --git a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/NewItCoverageFileAnalyzer.java b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/NewItCoverageFileAnalyzer.java new file mode 100644 index 00000000000..d3492f73935 --- /dev/null +++ b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/NewItCoverageFileAnalyzer.java @@ -0,0 +1,66 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2008-2011 SonarSource + * mailto:contact AT sonarsource DOT com + * + * Sonar is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * Sonar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with Sonar; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.plugins.core.timemachine; + +import org.sonar.api.measures.CoreMetrics; +import org.sonar.api.measures.Metric; +import org.sonar.batch.components.TimeMachineConfiguration; + +public class NewItCoverageFileAnalyzer extends AbstractNewCoverageFileAnalyzer { + + public NewItCoverageFileAnalyzer(TimeMachineConfiguration timeMachineConfiguration) { + super(timeMachineConfiguration); + } + + @Override + public Metric getCoverageLineHitsDataMetric() { + return CoreMetrics.IT_COVERAGE_LINE_HITS_DATA; + } + + @Override + public Metric getConditionsByLineMetric() { + return CoreMetrics.IT_CONDITIONS_BY_LINE; + } + + @Override + public Metric getCoveredConditionsByLineMetric() { + return CoreMetrics.IT_COVERED_CONDITIONS_BY_LINE; + } + + @Override + public Metric getNewLinesToCoverMetric() { + return CoreMetrics.NEW_IT_LINES_TO_COVER; + } + + @Override + public Metric getNewUncoveredLinesMetric() { + return CoreMetrics.NEW_IT_UNCOVERED_LINES; + } + + @Override + public Metric getNewConditionsToCoverMetric() { + return CoreMetrics.NEW_IT_CONDITIONS_TO_COVER; + } + + @Override + public Metric getNewUncoveredConditionsMetric() { + return CoreMetrics.NEW_IT_UNCOVERED_CONDITIONS; + } +} diff --git a/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/timemachine/NewCoverageFileAnalyzerTest.java b/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/timemachine/NewCoverageFileAnalyzerTest.java index 3eb6a0f27ed..85d1eb5b6c2 100644 --- a/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/timemachine/NewCoverageFileAnalyzerTest.java +++ b/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/timemachine/NewCoverageFileAnalyzerTest.java @@ -44,7 +44,7 @@ public class NewCoverageFileAnalyzerTest { when(context.getMeasure(CoreMetrics.COVERAGE_LINE_HITS_DATA)) .thenReturn(new Measure(CoreMetrics.COVERAGE_LINE_HITS_DATA, "1=10")); - NewCoverageFileAnalyzer decorator = newDecorator(); + AbstractNewCoverageFileAnalyzer decorator = newDecorator(); decorator.doDecorate(context); verify(context, never()).saveMeasure((Measure) anyObject()); } @@ -55,7 +55,7 @@ public class NewCoverageFileAnalyzerTest { when(context.getMeasure(CoreMetrics.SCM_LAST_COMMIT_DATETIMES_BY_LINE)) .thenReturn(new Measure(CoreMetrics.SCM_LAST_COMMIT_DATETIMES_BY_LINE, "10=2008-05-18T00:00:00+0000")); - NewCoverageFileAnalyzer decorator = newDecorator(); + AbstractNewCoverageFileAnalyzer decorator = newDecorator(); decorator.doDecorate(context); verify(context, never()).saveMeasure((Measure) anyObject()); @@ -69,7 +69,7 @@ public class NewCoverageFileAnalyzerTest { when(context.getMeasure(CoreMetrics.SCM_LAST_COMMIT_DATETIMES_BY_LINE)).thenReturn( new Measure(CoreMetrics.SCM_LAST_COMMIT_DATETIMES_BY_LINE, "10=2007-01-15T00:00:00+0000;11=2011-01-01T00:00:00+0000")); - NewCoverageFileAnalyzer decorator = newDecorator(); + AbstractNewCoverageFileAnalyzer decorator = newDecorator(); decorator.doDecorate(context); // line 11 has been updated after date1 (2009-12-25). This line is covered. @@ -101,7 +101,7 @@ public class NewCoverageFileAnalyzerTest { when(context.getMeasure(CoreMetrics.SCM_LAST_COMMIT_DATETIMES_BY_LINE)).thenReturn( new Measure(CoreMetrics.SCM_LAST_COMMIT_DATETIMES_BY_LINE, "10=2007-01-15T00:00:00+0000;11=2011-01-01T00:00:00+0000")); - NewCoverageFileAnalyzer decorator = newDecorator(); + AbstractNewCoverageFileAnalyzer decorator = newDecorator(); decorator.doDecorate(context); // line 11 has been updated after date1 (2009-12-25). This line has 1 covered condition amongst 4 @@ -133,7 +133,7 @@ public class NewCoverageFileAnalyzerTest { when(context.getMeasure(CoreMetrics.SCM_LAST_COMMIT_DATETIMES_BY_LINE)).thenReturn( new Measure(CoreMetrics.SCM_LAST_COMMIT_DATETIMES_BY_LINE, "10=2007-01-15T00:00:00+0000;11=2011-01-01T00:00:00+0000")); - NewCoverageFileAnalyzer decorator = newDecorator(); + AbstractNewCoverageFileAnalyzer decorator = newDecorator(); decorator.doDecorate(context); // line 11 has been updated after date1 (2009-12-25) but it has no conditions @@ -169,10 +169,10 @@ public class NewCoverageFileAnalyzerTest { } } - private NewCoverageFileAnalyzer newDecorator() throws ParseException { - List<NewCoverageFileAnalyzer.PeriodStruct> structs = Arrays.asList( - new NewCoverageFileAnalyzer.PeriodStruct(1, newDate("2009-12-25")), - new NewCoverageFileAnalyzer.PeriodStruct(3, newDate("2011-02-18"))); + private AbstractNewCoverageFileAnalyzer newDecorator() throws ParseException { + List<AbstractNewCoverageFileAnalyzer.PeriodStruct> structs = Arrays.asList( + new AbstractNewCoverageFileAnalyzer.PeriodStruct(1, newDate("2009-12-25")), + new AbstractNewCoverageFileAnalyzer.PeriodStruct(3, newDate("2011-02-18"))); return new NewCoverageFileAnalyzer(structs); } 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 18be4847537..aee588e9d47 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 @@ -102,9 +102,6 @@ public class JaCoCoPlugin extends SonarPlugin { // Integration tests JaCoCoItSensor.class, - ItCoverageWidget.class, - ItCoverageDecorator.class, - ItLineCoverageDecorator.class, - ItBranchCoverageDecorator.class); + ItCoverageWidget.class); } } diff --git a/plugins/sonar-l10n-en-plugin/src/main/resources/org/sonar/l10n/core.properties b/plugins/sonar-l10n-en-plugin/src/main/resources/org/sonar/l10n/core.properties index 283b3cd524b..0a60f2e9a89 100644 --- a/plugins/sonar-l10n-en-plugin/src/main/resources/org/sonar/l10n/core.properties +++ b/plugins/sonar-l10n-en-plugin/src/main/resources/org/sonar/l10n/core.properties @@ -593,11 +593,11 @@ violations_drilldown.no_violations=No violations #------------------------------------------------------------------------------ # -# DUPLICATION TAB +# DUPLICATION VIEWER # #------------------------------------------------------------------------------ -duplications.no_duplicated_block=No duplicated block. +duplications.no_duplicated_block=No duplicated blocks. duplications.blocks=Blocks duplications.number_of_lines=Nb Lines duplications.from_line=From line @@ -609,11 +609,12 @@ duplications.collapse=Collapse #------------------------------------------------------------------------------ # -# COVERAGE TAB +# COVERAGE VIEWER # #------------------------------------------------------------------------------ -coverage_tab.unit_tests=Unit Tests -coverage_tab.integration_tests=Integration Tests +coverage_viewer.on_new_code=On new code +coverage_viewer.unit_tests=Unit Tests +coverage_viewer.integration_tests=Integration Tests #------------------------------------------------------------------------------ # @@ -1119,35 +1120,35 @@ metric.covered_conditions_by_line.description=Covered branches by line # #-------------------------------------------------------------------------------------------------------------------- -metric.it_coverage.name=Coverage -metric.it_coverage.description=Coverage by unit tests +metric.it_coverage.name=IT Coverage +metric.it_coverage.description=Coverage by Integration Tests -metric.it_lines_to_cover.name=Lines to cover -metric.it_lines_to_cover.description=Lines to cover +metric.it_lines_to_cover.name=Lines to cover by IT +metric.it_lines_to_cover.description=Lines to cover by Integration Tests -metric.it_uncovered_lines.name=Uncovered lines -metric.it_uncovered_lines.description=Uncovered lines +metric.it_uncovered_lines.name=Uncovered lines by IT +metric.it_uncovered_lines.description=Uncovered lines by Integration Tests -metric.it_line_coverage.name=Line coverage -metric.it_line_coverage.description=Line coverage +metric.it_line_coverage.name=Line coverage by IT +metric.it_line_coverage.description=Line coverage by Integration Tests -metric.it_coverage_line_hits_data.name=Coverage hits by line -metric.it_coverage_line_hits_data.description=Coverage hits by line +metric.it_coverage_line_hits_data.name=IT Coverage hits by line +metric.it_coverage_line_hits_data.description=Coverage hits by line by Integration Tests -metric.it_conditions_to_cover.name=Branches to cover -metric.it_conditions_to_cover.description=Branches to cover +metric.it_conditions_to_cover.name=Branches to cover by IT +metric.it_conditions_to_cover.description=Branches to cover by Integration Tests -metric.it_uncovered_conditions.name=Uncovered branches -metric.it_uncovered_conditions.description=Uncovered branches +metric.it_uncovered_conditions.name=Uncovered branches by IT +metric.it_uncovered_conditions.description=Uncovered branches by Integration Tests -metric.it_branch_coverage.name=Branch coverage -metric.it_branch_coverage.description=Branch coverage +metric.it_branch_coverage.name=Branch coverage by IT +metric.it_branch_coverage.description=Branch coverage by Integration Tests -metric.it_conditions_by_line.name=Branches by line -metric.it_conditions_by_line.description=Branches by line +metric.it_conditions_by_line.name=IT Branches by line +metric.it_conditions_by_line.description=IT Branches by line -metric.it_covered_conditions_by_line.name=Covered branches by line -metric.it_covered_conditions_by_line.description=Covered branches by line +metric.it_covered_conditions_by_line.name=IT Covered branches by line +metric.it_covered_conditions_by_line.description=IT Covered branches by line #-------------------------------------------------------------------------------------------------------------------- # diff --git a/sonar-core/src/main/java/org/sonar/jpa/session/CustomHibernateConnectionProvider.java b/sonar-core/src/main/java/org/sonar/jpa/session/CustomHibernateConnectionProvider.java index e391d3ad130..5f8490a3858 100644 --- a/sonar-core/src/main/java/org/sonar/jpa/session/CustomHibernateConnectionProvider.java +++ b/sonar-core/src/main/java/org/sonar/jpa/session/CustomHibernateConnectionProvider.java @@ -27,7 +27,7 @@ import java.util.Properties; public class CustomHibernateConnectionProvider extends InjectedDataSourceConnectionProvider { static DataSource datasource; - + @Override public void configure(Properties props) { setDataSource(datasource); diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/measures/CoreMetrics.java b/sonar-plugin-api/src/main/java/org/sonar/api/measures/CoreMetrics.java index 555d753440a..c498bc00ca9 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/measures/CoreMetrics.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/measures/CoreMetrics.java @@ -618,9 +618,20 @@ public final class CoreMetrics { .setBestValue(100.0) .create(); +public static final String NEW_IT_COVERAGE_KEY = "new_it_coverage"; + public static final Metric NEW_IT_COVERAGE = new Metric.Builder(NEW_IT_COVERAGE_KEY, "New IT coverage", Metric.ValueType.PERCENT) + .setDescription("Integration Tests Coverage of new/changed code") + .setDirection(Metric.DIRECTION_BETTER) + .setQualitative(true) + .setDomain(DOMAIN_INTEGRATION_TESTS) + .setWorstValue(0.0) + .setBestValue(100.0) + .create(); + + public static final String IT_LINES_TO_COVER_KEY = "it_lines_to_cover"; public static final Metric IT_LINES_TO_COVER = new Metric.Builder(IT_LINES_TO_COVER_KEY, "IT Lines to cover", Metric.ValueType.INT) - .setDescription("IT lines to cover") + .setDescription("Lines to cover by Integration Tests") .setDirection(Metric.DIRECTION_BETTER) .setDomain(DOMAIN_INTEGRATION_TESTS) .setQualitative(false) @@ -628,6 +639,16 @@ public final class CoreMetrics { .setHidden(true) .create(); +public static final String NEW_IT_LINES_TO_COVER_KEY = "new_it_lines_to_cover"; + public static final Metric NEW_IT_LINES_TO_COVER = new Metric.Builder(NEW_IT_LINES_TO_COVER_KEY, "New lines to cover by IT", Metric.ValueType.INT) + .setDescription("New lines to cover by Integration Tests") + .setDirection(Metric.DIRECTION_WORST) + .setQualitative(false) + .setDomain(DOMAIN_INTEGRATION_TESTS) + .setFormula(new SumChildValuesFormula(false)) + .create(); + + public static final String IT_UNCOVERED_LINES_KEY = "it_uncovered_lines"; public static final Metric IT_UNCOVERED_LINES = new Metric.Builder(IT_UNCOVERED_LINES_KEY, "IT Uncovered lines", Metric.ValueType.INT) .setDescription("IT uncovered lines") @@ -637,6 +658,15 @@ public final class CoreMetrics { .setFormula(new SumChildValuesFormula(false)) .create(); + public static final String NEW_IT_UNCOVERED_LINES_KEY = "new_it_uncovered_lines"; + public static final Metric NEW_IT_UNCOVERED_LINES = new Metric.Builder(NEW_IT_UNCOVERED_LINES_KEY, "New uncovered lines by IT", Metric.ValueType.INT) + .setDescription("New uncovered lines by Integration Tests") + .setDirection(Metric.DIRECTION_WORST) + .setDomain(DOMAIN_INTEGRATION_TESTS) + .setFormula(new SumChildValuesFormula(false)) + .setBestValue(0.0) + .create(); + public static final String IT_LINE_COVERAGE_KEY = "it_line_coverage"; public static final Metric IT_LINE_COVERAGE = new Metric.Builder(IT_LINE_COVERAGE_KEY, "IT Line coverage", Metric.ValueType.PERCENT) .setDescription("IT line coverage") @@ -645,6 +675,16 @@ public final class CoreMetrics { .setDomain(DOMAIN_INTEGRATION_TESTS) .create(); + public static final String NEW_IT_LINE_COVERAGE_KEY = "new_it_line_coverage"; + public static final Metric NEW_IT_LINE_COVERAGE = new Metric.Builder(NEW_IT_LINE_COVERAGE_KEY, "New line coverage by IT", Metric.ValueType.PERCENT) + .setDescription("Line Coverage by Integration Tests of added/changed code") + .setDirection(Metric.DIRECTION_BETTER) + .setQualitative(true) + .setWorstValue(0.0) + .setBestValue(100.0) + .setDomain(DOMAIN_INTEGRATION_TESTS) + .create(); + public static final String IT_COVERAGE_LINE_HITS_DATA_KEY = "it_coverage_line_hits_data"; public static final Metric IT_COVERAGE_LINE_HITS_DATA = new Metric.Builder(IT_COVERAGE_LINE_HITS_DATA_KEY, "IT Coverage hits data", Metric.ValueType.DATA) .setDescription("IT Code coverage line hits data") @@ -663,6 +703,13 @@ public final class CoreMetrics { .setHidden(true) .create(); + public static final String NEW_IT_CONDITIONS_TO_COVER_KEY = "new_it_conditions_to_cover"; + public static final Metric NEW_IT_CONDITIONS_TO_COVER = new Metric.Builder(NEW_IT_CONDITIONS_TO_COVER_KEY, "New conditions to cover by IT", Metric.ValueType.INT) + .setDescription("New conditions to cover by Integration Tests") + .setDomain(DOMAIN_INTEGRATION_TESTS) + .setFormula(new SumChildValuesFormula(false)) + .create(); + public static final String IT_UNCOVERED_CONDITIONS_KEY = "it_uncovered_conditions"; public static final Metric IT_UNCOVERED_CONDITIONS = new Metric.Builder(IT_UNCOVERED_CONDITIONS_KEY, "IT Uncovered branches", Metric.ValueType.INT) .setDescription("IT Uncovered conditions") @@ -671,6 +718,15 @@ public final class CoreMetrics { .setFormula(new SumChildValuesFormula(false)) .create(); + public static final String NEW_IT_UNCOVERED_CONDITIONS_KEY = "new_it_uncovered_conditions"; + public static final Metric NEW_IT_UNCOVERED_CONDITIONS = new Metric.Builder(NEW_IT_UNCOVERED_CONDITIONS_KEY, "New uncovered conditions by IT", Metric.ValueType.INT) + .setDescription("New uncovered conditions by Integration Tests") + .setDirection(Metric.DIRECTION_WORST) + .setDomain(DOMAIN_INTEGRATION_TESTS) + .setFormula(new SumChildValuesFormula(false)) + .setBestValue(0.0) + .create(); + public static final String IT_BRANCH_COVERAGE_KEY = "it_branch_coverage"; public static final Metric IT_BRANCH_COVERAGE = new Metric.Builder(IT_BRANCH_COVERAGE_KEY, "IT Branch coverage", Metric.ValueType.PERCENT) .setDescription("IT Branch coverage") @@ -681,6 +737,16 @@ public final class CoreMetrics { .setBestValue(100.0) .create(); + public static final String NEW_IT_BRANCH_COVERAGE_KEY = "new_it_branch_coverage"; + public static final Metric NEW_IT_BRANCH_COVERAGE = new Metric.Builder(NEW_IT_BRANCH_COVERAGE_KEY, "New branch coverage by IT", Metric.ValueType.PERCENT) + .setDescription("Branch coverage by Integration Tests of new/changed code") + .setDirection(Metric.DIRECTION_BETTER) + .setQualitative(true) + .setDomain(DOMAIN_INTEGRATION_TESTS) + .setWorstValue(0.0) + .setBestValue(100.0) + .create(); + public static final String IT_CONDITIONS_BY_LINE_KEY = "it_conditions_by_line"; public static final Metric IT_CONDITIONS_BY_LINE = new Metric.Builder(IT_CONDITIONS_BY_LINE_KEY, "IT Branches by line", Metric.ValueType.DATA) diff --git a/sonar-server/src/main/webapp/WEB-INF/app/controllers/resource_controller.rb b/sonar-server/src/main/webapp/WEB-INF/app/controllers/resource_controller.rb index 2b753e44d7a..d977d296130 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/controllers/resource_controller.rb +++ b/sonar-server/src/main/webapp/WEB-INF/app/controllers/resource_controller.rb @@ -167,21 +167,25 @@ class ResourceController < ApplicationController @filtered = true 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) + '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) @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 + elsif ('uncovered_lines'==@coverage_filter || 'new_uncovered_lines'==@coverage_filter || + 'it_uncovered_lines'==@coverage_filter || 'new_it_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 || + 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 + 'it_conditions_to_cover'==@coverage_filter || 'it_branch_coverage'==@coverage_filter || + 'new_it_conditions_to_cover' == @coverage_filter || 'new_it_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 + elsif ('uncovered_conditions' == @coverage_filter || 'new_uncovered_conditions' == @coverage_filter || + 'it_uncovered_conditions'==@coverage_filter || 'new_it_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 diff --git a/sonar-server/src/main/webapp/WEB-INF/app/helpers/application_helper.rb b/sonar-server/src/main/webapp/WEB-INF/app/helpers/application_helper.rb index 1745af879e9..de128aa09bb 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/helpers/application_helper.rb +++ b/sonar-server/src/main/webapp/WEB-INF/app/helpers/application_helper.rb @@ -542,9 +542,8 @@ module ApplicationHelper end html="<span class='#{css_class}'>#{formatted_val}</span>" end - else - html = options[:default].to_s end + html = options[:default].to_s if html.nil? && options[:default] html end end diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/resource/_header_coverage.html.erb b/sonar-server/src/main/webapp/WEB-INF/app/views/resource/_header_coverage.html.erb index abcf4e4c397..c3b9e18b935 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/views/resource/_header_coverage.html.erb +++ b/sonar-server/src/main/webapp/WEB-INF/app/views/resource/_header_coverage.html.erb @@ -1,15 +1,15 @@ <div id="coverage_header" class="tab_header"> - <% if @period && measure('new_coverage') %> - <p>On new code:</p> + <% if @period && (measure('new_coverage') || measure('new_it_coverage')) %> + <p><%= message('coverage_viewer.on_new_code') -%> :</p> <table> <tr> - <td class="big" rowspan="2"><%= format_variation('new_coverage', :period => @period, :style => 'none') -%></td> + <td class="big" rowspan="2"><%= format_variation('new_coverage', :period => @period, :default => '-', :style => 'none') -%></td> <td class="sep"> </td> <% if m=measure('new_line_coverage') %> <td class="name"><%= Metric.name_for('line_coverage') -%>:</td> - <td class="value"><%= format_variation(m, :period => @period, :style => 'none') -%></td> + <td class="value"><%= format_variation(m, :period => @period, :default => '-', :style => 'none') -%></td> <% else %> <td colspan="2"></td> <% end %> @@ -17,7 +17,7 @@ <td class="sep"> </td> <% if m=measure('new_branch_coverage') %> <td class="name"><%= Metric.name_for('branch_coverage') -%>:</td> - <td class="value"><%= format_variation(m, :period => @period, :style => 'none') -%></td> + <td class="value"><%= format_variation(m, :period => @period, :default => '-', :style => 'none') -%></td> <% else %> <td colspan="2"></td> <% end %> @@ -39,13 +39,54 @@ <td colspan="2"></td> <% end %> </tr> + <% if measure('new_it_coverage') %> + <tr> + <td colspan="7"><br/><%= message('coverage_viewer.integration_tests') -%></td> + </tr> + <tr> + <td class="big" rowspan="2"><%= format_variation('new_it_coverage', :period => @period, :default => '-', :style => 'none') -%></td> + + <td class="sep"> </td> + + <% if m=measure('new_it_line_coverage') %> + <td class="name"><%= Metric.name_for('it_line_coverage') -%>:</td> + <td class="value"><%= format_variation(m, :period => @period, :default => '-', :style => 'none') -%></td> + <% else %> + <td colspan="2"></td> + <% end %> + + <td class="sep"> </td> + <% if m=measure('new_it_branch_coverage') %> + <td class="name"><%= Metric.name_for('it_branch_coverage') -%>:</td> + <td class="value"><%= format_variation(m, :period => @period, :default => '-', :style => 'none') -%></td> + <% else %> + <td colspan="2"></td> + <% end %> + </tr> + <tr> + <td class="sep"> </td> + <% if m=measure('new_it_uncovered_lines') %> + <td class="name"><%= Metric.name_for('it_uncovered_lines') -%>:</td> + <td class="value"><%= format_variation(m, :period => @period, :style => 'none') -%>/<%= format_variation('new_it_lines_to_cover', :period => @period, :style => 'none') -%></td> + <% else %> + <td colspan="2"></td> + <% end %> + + <td class="sep"> </td> + <% if m=measure('new_it_uncovered_conditions') %> + <td class="name"><%= Metric.name_for('it_uncovered_conditions') -%>: </td> + <td class="value"><%= format_variation(m, :period => @period, :style => 'none') -%>/<%= format_variation('new_it_conditions_to_cover', :period => @period, :style => 'none') -%></td> + <% else %> + <td colspan="2"></td> + <% end %> + </tr> + <% end %> </table> <% else %> <table> <% if @display_it_coverage %> <tr> - <td colspan="8"><%= message('coverage_tab.unit_tests') -%></td> - <td colspan="7"><%= message('coverage_tab.integration_tests') -%></td> + <td colspan="7"><%= message('coverage_viewer.unit_tests') -%></td> </tr> <% end %> <tr> @@ -54,32 +95,35 @@ <%= render :partial => 'measure', :locals => {:measure => measure('line_coverage'), :title => Metric.name_for('line_coverage')} -%> <td class="sep"> </td> <%= render :partial => 'measure', :locals => {:measure => measure('branch_coverage'), :title => Metric.name_for('branch_coverage')} -%> + </tr> + <tr> <td class="sep"> </td> + <%= render :partial => 'measure', :locals => {:measure => measure('uncovered_lines'), :title => Metric.name_for('uncovered_lines'), :ratio => measure('lines_to_cover')} -%> + <td class="sep"> </td> + <%= render :partial => 'measure', :locals => {:measure => measure('uncovered_conditions'), :title => Metric.name_for('uncovered_conditions'), :ratio => measure('conditions_to_cover')} -%> + </tr> - <% if @display_it_coverage %> + <% 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')} -%> - <% end %> </tr> <tr> <td class="sep"> </td> - <%= render :partial => 'measure', :locals => {:measure => measure('uncovered_lines'), :title => Metric.name_for('uncovered_lines'), :ratio => measure('lines_to_cover')} -%> - <td class="sep"> </td> - <%= render :partial => 'measure', :locals => {:measure => measure('uncovered_conditions'), :title => Metric.name_for('uncovered_conditions'), :ratio => measure('conditions_to_cover')} -%> - <td class="sep"> </td> - <% if @display_it_coverage %> - <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')} -%> - <% end %> </tr> + <% end %> </table> <% end %> - + <%= render :partial => 'options' -%> </div> diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/resource/_options.html.erb b/sonar-server/src/main/webapp/WEB-INF/app/views/resource/_options.html.erb index d625f26280d..221c1b3680f 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/views/resource/_options.html.erb +++ b/sonar-server/src/main/webapp/WEB-INF/app/views/resource/_options.html.erb @@ -67,14 +67,14 @@ <% if @display_coverage %> <td class="<%= 'first' if first -%>"> <select id="coverage_filter" name="coverage_filter" onchange="applyOptions()"> - <optgroup label="<%= h message('coverage_tab.unit_tests') -%>"> + <optgroup label="<%= h message('coverage_viewer.unit_tests') -%>"> <option value="lines_to_cover" <%= 'selected' if @coverage_filter=='lines_to_cover' -%>><%= Metric.name_for('lines_to_cover') -%></option> <option value="uncovered_lines" <%= 'selected' if @coverage_filter=='uncovered_lines' -%>><%= Metric.name_for('uncovered_lines') -%></option> <option value="conditions_to_cover" <%= 'selected' if @coverage_filter=='conditions_to_cover' -%>><%= Metric.name_for('conditions_to_cover') -%></option> <option value="uncovered_conditions" <%= 'selected' if @coverage_filter=='uncovered_conditions' -%>><%= Metric.name_for('uncovered_conditions') -%></option> </optgroup> <% if @display_it_coverage %> - <optgroup label="<%= h message('coverage_tab.integration_tests') -%>"> + <optgroup label="<%= h message('coverage_viewer.integration_tests') -%>"> <option value="it_lines_to_cover" <%= 'selected' if @coverage_filter=='it_lines_to_cover' -%>><%= Metric.name_for('it_lines_to_cover') -%></option> <option value="it_uncovered_lines" <%= 'selected' if @coverage_filter=='it_uncovered_lines' -%>><%= Metric.name_for('it_uncovered_lines') -%></option> <option value="it_conditions_to_cover" <%= 'selected' if @coverage_filter=='it_conditions_to_cover' -%>><%= Metric.name_for('it_conditions_to_cover') -%></option> |