diff options
5 files changed, 206 insertions, 282 deletions
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/step/NewDuplicationMeasuresStep.java b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/step/NewDuplicationMeasuresStep.java index c0de8c85b5f..7af5d96b5b3 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/step/NewDuplicationMeasuresStep.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/step/NewDuplicationMeasuresStep.java @@ -21,17 +21,20 @@ package org.sonar.server.computation.task.projectanalysis.step; import com.google.common.base.Optional; +import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Iterables; import com.google.common.collect.LinkedHashMultimap; +import com.google.common.collect.Multiset; import com.google.common.collect.SetMultimap; +import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.function.Function; +import java.util.stream.Collectors; import java.util.stream.IntStream; -import javax.annotation.CheckForNull; -import javax.annotation.Nullable; import org.sonar.server.computation.task.projectanalysis.component.Component; import org.sonar.server.computation.task.projectanalysis.component.PathAwareCrawler; import org.sonar.server.computation.task.projectanalysis.component.TreeRootHolder; @@ -44,7 +47,6 @@ import org.sonar.server.computation.task.projectanalysis.formula.CounterInitiali import org.sonar.server.computation.task.projectanalysis.formula.CreateMeasureContext; import org.sonar.server.computation.task.projectanalysis.formula.Formula; import org.sonar.server.computation.task.projectanalysis.formula.FormulaExecutorComponentVisitor; -import org.sonar.server.computation.task.projectanalysis.formula.VariationSumFormula; import org.sonar.server.computation.task.projectanalysis.formula.counter.IntVariationValue; import org.sonar.server.computation.task.projectanalysis.measure.Measure; import org.sonar.server.computation.task.projectanalysis.measure.MeasureRepository; @@ -56,38 +58,28 @@ import org.sonar.server.computation.task.projectanalysis.scm.ScmInfo; import org.sonar.server.computation.task.projectanalysis.scm.ScmInfoRepository; import org.sonar.server.computation.task.step.ComputationStep; -import static java.util.Objects.requireNonNull; import static java.util.stream.Collectors.toMap; +import static org.sonar.api.measures.CoreMetrics.NEW_BLOCKS_DUPLICATED_KEY; import static org.sonar.api.measures.CoreMetrics.NEW_LINES_DUPLICATED_KEY; -import static org.sonar.server.computation.task.projectanalysis.period.PeriodPredicates.viewsRestrictedPeriods; /** * Computes new duplication measures on files and then aggregates them on higher components. - * */ public class NewDuplicationMeasuresStep implements ComputationStep { - private final ImmutableList<Formula> formulas; - private final TreeRootHolder treeRootHolder; private final PeriodsHolder periodsHolder; private final MetricRepository metricRepository; private final MeasureRepository measureRepository; + private final NewDuplicationFormula duplicationFormula; public NewDuplicationMeasuresStep(TreeRootHolder treeRootHolder, PeriodsHolder periodsHolder, MetricRepository metricRepository, MeasureRepository measureRepository, - ScmInfoRepository scmInfoRepository, @Nullable DuplicationRepository duplicationRepository) { + ScmInfoRepository scmInfoRepository, DuplicationRepository duplicationRepository) { this.treeRootHolder = treeRootHolder; this.periodsHolder = periodsHolder; this.metricRepository = metricRepository; this.measureRepository = measureRepository; - this.formulas = ImmutableList.of(NewDuplicationFormula.from(scmInfoRepository, duplicationRepository)); - } - - /** - * Constructor used by Pico in Governance where no DuplicationRepository is available. - */ - public NewDuplicationMeasuresStep(TreeRootHolder treeRootHolder, PeriodsHolder periodsHolder, MetricRepository metricRepository, MeasureRepository measureRepository) { - this(treeRootHolder, periodsHolder, metricRepository, measureRepository, null, null); + this.duplicationFormula = new NewDuplicationFormula(scmInfoRepository, duplicationRepository); } @Override @@ -100,17 +92,17 @@ public class NewDuplicationMeasuresStep implements ComputationStep { new PathAwareCrawler<>( FormulaExecutorComponentVisitor.newBuilder(metricRepository, measureRepository) .withVariationSupport(periodsHolder) - .buildFor(formulas)) - .visit(treeRootHolder.getRoot()); + .buildFor(ImmutableList.of(duplicationFormula))) + .visit(treeRootHolder.getRoot()); } private static class NewDuplicationCounter implements Counter<NewDuplicationCounter> { - @CheckForNull private final DuplicationRepository duplicationRepository; private final ScmInfoRepository scmInfoRepository; private final IntVariationValue.Array newLines = IntVariationValue.newArray(); + private final IntVariationValue.Array newBlocks = IntVariationValue.newArray(); - private NewDuplicationCounter(@Nullable DuplicationRepository duplicationRepository, ScmInfoRepository scmInfoRepository) { + private NewDuplicationCounter(DuplicationRepository duplicationRepository, ScmInfoRepository scmInfoRepository) { this.duplicationRepository = duplicationRepository; this.scmInfoRepository = scmInfoRepository; } @@ -118,53 +110,75 @@ public class NewDuplicationMeasuresStep implements ComputationStep { @Override public void aggregate(NewDuplicationCounter counter) { this.newLines.incrementAll(counter.newLines); + this.newBlocks.incrementAll(counter.newBlocks); } @Override public void initialize(CounterInitializationContext context) { Component leaf = context.getLeaf(); - Iterable<Duplication> duplications = requireNonNull(this.duplicationRepository, "DuplicationRepository missing").getDuplications(leaf); + if (leaf.getType() != Component.Type.FILE) { + context.getPeriods().forEach(period -> { + newLines.increment(period, 0); + newBlocks.increment(period, 0); + }); + return; + } + Iterable<Duplication> duplications = duplicationRepository.getDuplications(leaf); Optional<ScmInfo> scmInfo = scmInfoRepository.getScmInfo(leaf); if (!scmInfo.isPresent()) { return; } - NewLinesDuplicatedAccumulator newLinesDuplicatedAccumulator = new NewLinesDuplicatedAccumulator(scmInfo.get(), context.getPeriods()); + DuplicationCounters duplicationCounters = new DuplicationCounters(scmInfo.get(), context.getPeriods()); for (Duplication duplication : duplications) { - newLinesDuplicatedAccumulator.addBlock(duplication.getOriginal()); + duplicationCounters.addBlock(duplication.getOriginal()); duplication.getDuplicates().stream() .filter(InnerDuplicate.class::isInstance) .map(duplicate -> (InnerDuplicate) duplicate) - .forEach(duplicate -> newLinesDuplicatedAccumulator.addBlock(duplicate.getTextBlock())); + .forEach(duplicate -> duplicationCounters.addBlock(duplicate.getTextBlock())); } - Map<Period, Integer> newLinesDuplicatedByPeriod = newLinesDuplicatedAccumulator.getNewLinesDuplicated(); - context.getPeriods().forEach(period -> newLines.increment(period, newLinesDuplicatedByPeriod.getOrDefault(period, 0))); + Map<Period, Integer> newLinesDuplicatedByPeriod = duplicationCounters.getNewLinesDuplicated(); + context.getPeriods().forEach(period -> { + newLines.increment(period, newLinesDuplicatedByPeriod.getOrDefault(period, 0)); + newBlocks.increment(period, duplicationCounters.getNewBlocksDuplicated().getOrDefault(period, 0)); + }); } } - private static class NewLinesDuplicatedAccumulator { + private static class DuplicationCounters { private final ScmInfo scmInfo; private final List<Period> periods; - private final SetMultimap<Period, Integer> counts; + private final SetMultimap<Period, Integer> lineCounts; + private final Multiset<Period> blockCounts; - private NewLinesDuplicatedAccumulator(ScmInfo scmInfo, List<Period> periods) { + private DuplicationCounters(ScmInfo scmInfo, List<Period> periods) { this.scmInfo = scmInfo; this.periods = periods; - this.counts = LinkedHashMultimap.create(periods.size(), Iterables.size(scmInfo.getAllChangesets())); + this.lineCounts = LinkedHashMultimap.create(periods.size(), Iterables.size(scmInfo.getAllChangesets())); + this.blockCounts = HashMultiset.create(); } void addBlock(TextBlock textBlock) { + Set<Period> periodWithNewCode = new HashSet<>(); IntStream.rangeClosed(textBlock.getStart(), textBlock.getEnd()) .forEach(line -> periods.stream() .filter(period -> isLineInPeriod(line, period)) - .forEach(period -> counts.put(period, line))); + .forEach(period -> { + lineCounts.put(period, line); + periodWithNewCode.add(period); + })); + blockCounts.addAll(periodWithNewCode); } Map<Period, Integer> getNewLinesDuplicated() { - return ImmutableMap.copyOf(counts.keySet().stream().collect(toMap(Function.identity(), period -> counts.get(period).size()))); + return ImmutableMap.copyOf(lineCounts.keySet().stream().collect(toMap(Function.identity(), period -> lineCounts.get(period).size()))); + } + + Map<Period, Integer> getNewBlocksDuplicated() { + return blockCounts.entrySet().stream().collect(Collectors.toMap(Multiset.Entry::getElement, Multiset.Entry::getCount)); } private boolean isLineInPeriod(int lineNumber, Period period) { @@ -173,22 +187,14 @@ public class NewDuplicationMeasuresStep implements ComputationStep { } private static final class NewDuplicationFormula implements Formula<NewDuplicationCounter> { - private static final Formula VIEW_FORMULA = new VariationSumFormula(NEW_LINES_DUPLICATED_KEY, viewsRestrictedPeriods(), 0.0d); - private final DuplicationRepository duplicationRepository; private final ScmInfoRepository scmInfoRepository; - private NewDuplicationFormula(ScmInfoRepository scmInfoRepository, @Nullable DuplicationRepository duplicationRepository) { + private NewDuplicationFormula(ScmInfoRepository scmInfoRepository, DuplicationRepository duplicationRepository) { this.duplicationRepository = duplicationRepository; this.scmInfoRepository = scmInfoRepository; } - public static Formula<?> from(@Nullable ScmInfoRepository scmInfoRepository, @Nullable DuplicationRepository duplicationRepository) { - return scmInfoRepository == null - ? VIEW_FORMULA - : new NewDuplicationFormula(scmInfoRepository, duplicationRepository); - } - @Override public NewDuplicationCounter createNewCounter() { return new NewDuplicationCounter(duplicationRepository, scmInfoRepository); @@ -197,19 +203,25 @@ public class NewDuplicationMeasuresStep implements ComputationStep { @Override public Optional<Measure> createMeasure(NewDuplicationCounter counter, CreateMeasureContext context) { String metricKey = context.getMetric().getKey(); - if (NEW_LINES_DUPLICATED_KEY.equals(metricKey)) { - Optional<MeasureVariations> variations = counter.newLines.toMeasureVariations(); - return variations.isPresent() - ? Optional.of(Measure.newMeasureBuilder().setVariations(variations.get()).createNoValue()) - : Optional.absent(); + switch (metricKey) { + case NEW_LINES_DUPLICATED_KEY: + Optional<MeasureVariations> newLinesDuplicated = counter.newLines.toMeasureVariations(); + return newLinesDuplicated.isPresent() + ? Optional.of(Measure.newMeasureBuilder().setVariations(newLinesDuplicated.get()).createNoValue()) + : Optional.absent(); + case NEW_BLOCKS_DUPLICATED_KEY: + Optional<MeasureVariations> newBlocksDuplicated = counter.newBlocks.toMeasureVariations(); + return newBlocksDuplicated.isPresent() + ? Optional.of(Measure.newMeasureBuilder().setVariations(newBlocksDuplicated.get()).createNoValue()) + : Optional.absent(); + default: + throw new IllegalArgumentException("Unsupported metric " + context.getMetric()); } - - throw new IllegalArgumentException("Unsupported metric " + context.getMetric()); } @Override public String[] getOutputMetricKeys() { - return new String[] {NEW_LINES_DUPLICATED_KEY}; + return new String[]{NEW_LINES_DUPLICATED_KEY, NEW_BLOCKS_DUPLICATED_KEY}; } } } diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/step/ReportNewDuplicationMeasuresStepTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/step/ReportNewDuplicationMeasuresStepTest.java index 9fe70a560cf..d9e38d3d187 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/step/ReportNewDuplicationMeasuresStepTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/step/ReportNewDuplicationMeasuresStepTest.java @@ -20,14 +20,12 @@ package org.sonar.server.computation.task.projectanalysis.step; -import javax.annotation.Nullable; -import org.junit.Before; +import java.util.Arrays; import org.junit.Rule; import org.junit.Test; import org.sonar.server.computation.task.projectanalysis.component.TreeRootHolderRule; import org.sonar.server.computation.task.projectanalysis.duplication.DuplicationRepositoryRule; import org.sonar.server.computation.task.projectanalysis.duplication.TextBlock; -import org.sonar.server.computation.task.projectanalysis.measure.Measure; import org.sonar.server.computation.task.projectanalysis.measure.MeasureRepositoryRule; import org.sonar.server.computation.task.projectanalysis.measure.MeasureVariations; import org.sonar.server.computation.task.projectanalysis.metric.MetricRepositoryRule; @@ -38,6 +36,8 @@ import org.sonar.server.computation.task.projectanalysis.scm.ScmInfoRepositoryRu import static com.google.common.base.Preconditions.checkArgument; import static org.assertj.core.api.Assertions.assertThat; +import static org.sonar.api.measures.CoreMetrics.NEW_BLOCKS_DUPLICATED; +import static org.sonar.api.measures.CoreMetrics.NEW_BLOCKS_DUPLICATED_KEY; import static org.sonar.api.measures.CoreMetrics.NEW_LINES_DUPLICATED; import static org.sonar.api.measures.CoreMetrics.NEW_LINES_DUPLICATED_KEY; import static org.sonar.api.utils.DateUtils.parseDate; @@ -46,10 +46,6 @@ import static org.sonar.server.computation.task.projectanalysis.component.Compon import static org.sonar.server.computation.task.projectanalysis.component.Component.Type.MODULE; import static org.sonar.server.computation.task.projectanalysis.component.Component.Type.PROJECT; import static org.sonar.server.computation.task.projectanalysis.component.ReportComponent.builder; -import static org.sonar.server.computation.task.projectanalysis.measure.Measure.newMeasureBuilder; -import static org.sonar.server.computation.task.projectanalysis.measure.MeasureRepoEntry.entryOf; -import static org.sonar.server.computation.task.projectanalysis.measure.MeasureRepoEntry.toEntries; -import static org.sonar.server.computation.task.projectanalysis.measure.MeasureVariations.newMeasureVariationsBuilder; public class ReportNewDuplicationMeasuresStepTest { private static final int ROOT_REF = 1; @@ -57,6 +53,7 @@ public class ReportNewDuplicationMeasuresStepTest { private static final int SUB_MODULE_1_REF = 123; private static final int SUB_MODULE_2_REF = 126; private static final int DIRECTORY_REF = 1234; + private static final int DIRECTORY_2_REF = 1235; private static final int FILE_1_REF = 12341; private static final int FILE_2_REF = 12342; private static final int FILE_3_REF = 1261; @@ -76,7 +73,8 @@ public class ReportNewDuplicationMeasuresStepTest { .addChildren( builder(FILE, FILE_1_REF).build(), builder(FILE, FILE_2_REF).build()) - .build()) + .build(), + builder(DIRECTORY, DIRECTORY_2_REF).build()) .build(), builder(MODULE, SUB_MODULE_2_REF) .addChildren( @@ -86,36 +84,31 @@ public class ReportNewDuplicationMeasuresStepTest { .build()) .build()); @Rule - public PeriodsHolderRule periodsHolder = new PeriodsHolderRule(); + public PeriodsHolderRule periodsHolder = new PeriodsHolderRule().setPeriods( + new Period(2, "mode_p_1", null, parseDate("2009-12-25").getTime(), "u1"), + new Period(5, "mode_p_5", null, parseDate("2011-02-18").getTime(), "u2")); @Rule public ScmInfoRepositoryRule scmInfoRepository = new ScmInfoRepositoryRule(); @Rule public MetricRepositoryRule metricRepository = new MetricRepositoryRule() - .add(NEW_LINES_DUPLICATED); + .add(NEW_LINES_DUPLICATED) + .add(NEW_BLOCKS_DUPLICATED); @Rule public MeasureRepositoryRule measureRepository = MeasureRepositoryRule.create(treeRootHolder, metricRepository); @Rule public DuplicationRepositoryRule duplicationRepository = DuplicationRepositoryRule.create(treeRootHolder); - @Before - public void setUp() { - periodsHolder.setPeriods( - new Period(2, "mode_p_1", null, parseDate("2009-12-25").getTime(), "u1"), - new Period(5, "mode_p_5", null, parseDate("2011-02-18").getTime(), "u2")); - } - NewDuplicationMeasuresStep underTest = new NewDuplicationMeasuresStep(treeRootHolder, periodsHolder, metricRepository, measureRepository, scmInfoRepository, duplicationRepository); @Test public void compute_duplicated_lines_counts_lines_from_original_and_InnerDuplicate_of_a_single_line() { - TextBlock original = new TextBlock(1, 1); - duplicationRepository.addDuplication(FILE_1_REF, original, new TextBlock(2, 2)); + duplicationRepository.addDuplication(FILE_1_REF, new TextBlock(1, 1), new TextBlock(2, 2)); setChangesets(FILE_1_REF); underTest.execute(); - assertRawMeasureValue(FILE_1_REF, 2d); + assertRawMeasureValue(FILE_1_REF, NEW_LINES_DUPLICATED_KEY, 2d); } @Test @@ -126,7 +119,7 @@ public class ReportNewDuplicationMeasuresStepTest { underTest.execute(); - assertRawMeasureValue(FILE_1_REF, 1d); + assertRawMeasureValue(FILE_1_REF, NEW_LINES_DUPLICATED_KEY, 1d); } @Test @@ -137,7 +130,7 @@ public class ReportNewDuplicationMeasuresStepTest { underTest.execute(); - assertRawMeasureValue(FILE_1_REF, 1d); + assertRawMeasureValue(FILE_1_REF, NEW_LINES_DUPLICATED_KEY, 1d); } @Test @@ -148,7 +141,7 @@ public class ReportNewDuplicationMeasuresStepTest { underTest.execute(); - assertRawMeasureValue(FILE_1_REF, 6d); + assertRawMeasureValue(FILE_1_REF, NEW_LINES_DUPLICATED_KEY, 6d); } @Test @@ -160,7 +153,7 @@ public class ReportNewDuplicationMeasuresStepTest { underTest.execute(); - assertRawMeasureValue(FILE_1_REF, 11d); + assertRawMeasureValue(FILE_1_REF, NEW_LINES_DUPLICATED_KEY, 11d); } @Test @@ -173,7 +166,7 @@ public class ReportNewDuplicationMeasuresStepTest { underTest.execute(); - assertRawMeasureValue(FILE_1_REF, 2d, 1d); + assertRawMeasureValue(FILE_1_REF, NEW_LINES_DUPLICATED_KEY, 2d, 1d); } @Test @@ -188,15 +181,16 @@ public class ReportNewDuplicationMeasuresStepTest { underTest.execute(); - assertRawMeasureValue(FILE_1_REF, 2d); - assertRawMeasureValue(FILE_2_REF, 0d); - assertRawMeasureValue(FILE_3_REF, 9d); - assertRawMeasureValue(FILE_4_REF, 11d); - assertRawMeasureValue(DIRECTORY_REF, 2d); - assertRawMeasureValue(SUB_MODULE_1_REF, 2d); - assertRawMeasureValue(SUB_MODULE_2_REF, 20d); - assertRawMeasureValue(MODULE_REF, 22d); - assertRawMeasureValue(ROOT_REF, 22d); + assertRawMeasureValue(FILE_1_REF, NEW_LINES_DUPLICATED_KEY, 2d); + assertRawMeasureValue(FILE_2_REF, NEW_LINES_DUPLICATED_KEY, 0d); + assertRawMeasureValue(FILE_3_REF, NEW_LINES_DUPLICATED_KEY, 9d); + assertRawMeasureValue(FILE_4_REF, NEW_LINES_DUPLICATED_KEY, 11d); + assertRawMeasureValue(DIRECTORY_REF, NEW_LINES_DUPLICATED_KEY, 2d); + assertRawMeasureValue(DIRECTORY_2_REF, NEW_LINES_DUPLICATED_KEY, 0d); + assertRawMeasureValue(SUB_MODULE_1_REF, NEW_LINES_DUPLICATED_KEY, 2d); + assertRawMeasureValue(SUB_MODULE_2_REF, NEW_LINES_DUPLICATED_KEY, 20d); + assertRawMeasureValue(MODULE_REF, NEW_LINES_DUPLICATED_KEY, 22d); + assertRawMeasureValue(ROOT_REF, NEW_LINES_DUPLICATED_KEY, 22d); } @Test @@ -208,7 +202,78 @@ public class ReportNewDuplicationMeasuresStepTest { underTest.execute(); - assertComputedAndAggregatedToZeroInt(); + assertComputedAndAggregatedToZeroInt(NEW_LINES_DUPLICATED_KEY); + } + + @Test + public void compute_duplicated_blocks_one_for_original_one_for_each_InnerDuplicate() { + TextBlock original = new TextBlock(1, 1); + duplicationRepository.addDuplication(FILE_1_REF, original, new TextBlock(2, 2), new TextBlock(4, 4), new TextBlock(3, 4)); + setChangesets(FILE_1_REF); + + underTest.execute(); + + assertRawMeasureValue(FILE_1_REF, NEW_BLOCKS_DUPLICATED_KEY, 4); + } + + @Test + public void compute_duplicated_blocks_does_not_count_blocks_only_once_it_assumes_consistency_from_duplication_data() { + duplicationRepository.addDuplication(FILE_1_REF, new TextBlock(1, 1), new TextBlock(4, 4)); + duplicationRepository.addDuplication(FILE_1_REF, new TextBlock(2, 2), new TextBlock(4, 4)); + setChangesets(FILE_1_REF); + + underTest.execute(); + + assertRawMeasureValue(FILE_1_REF, NEW_BLOCKS_DUPLICATED_KEY, 4); + } + + @Test + public void compute_duplicated_blocks_one_for_original_and_ignores_InProjectDuplicate() { + duplicationRepository.addDuplication(FILE_1_REF, new TextBlock(1, 1), FILE_2_REF, new TextBlock(2, 2)); + setChangesets(FILE_1_REF); + + underTest.execute(); + + assertRawMeasureValue(FILE_1_REF, NEW_BLOCKS_DUPLICATED_KEY, 1); + } + + @Test + public void compute_duplicated_blocks_one_for_original_and_ignores_CrossProjectDuplicate() { + duplicationRepository.addDuplication(FILE_1_REF, new TextBlock(1, 1), SOME_FILE_KEY, new TextBlock(2, 2)); + setChangesets(FILE_1_REF); + + underTest.execute(); + + assertRawMeasureValue(FILE_1_REF, NEW_BLOCKS_DUPLICATED_KEY, 1); + } + + @Test + public void compute_and_aggregate_duplicated_blocks_from_single_duplication() { + addDuplicatedBlock(FILE_1_REF, 11); + addDuplicatedBlock(FILE_2_REF, 2); + addDuplicatedBlock(FILE_4_REF, 7); + setChangesets(FILE_1_REF, FILE_2_REF, FILE_3_REF, FILE_4_REF); + + underTest.execute(); + + assertRawMeasureValue(FILE_1_REF, NEW_BLOCKS_DUPLICATED_KEY, 10); + assertRawMeasureValue(FILE_2_REF, NEW_BLOCKS_DUPLICATED_KEY, 2); + assertRawMeasureValue(FILE_3_REF, NEW_BLOCKS_DUPLICATED_KEY, 0); + assertRawMeasureValue(FILE_4_REF, NEW_BLOCKS_DUPLICATED_KEY, 6); + assertRawMeasureValue(DIRECTORY_REF, NEW_BLOCKS_DUPLICATED_KEY, 12); + assertRawMeasureValue(SUB_MODULE_1_REF, NEW_BLOCKS_DUPLICATED_KEY, 12); + assertRawMeasureValue(SUB_MODULE_2_REF, NEW_BLOCKS_DUPLICATED_KEY, 6); + assertRawMeasureValue(MODULE_REF, NEW_BLOCKS_DUPLICATED_KEY, 18); + assertRawMeasureValue(ROOT_REF, NEW_BLOCKS_DUPLICATED_KEY, 18); + } + + @Test + public void compute_and_aggregate_duplicated_blocks_to_zero_when_no_duplication() { + setChangesets(FILE_1_REF, FILE_2_REF, FILE_3_REF, FILE_4_REF); + + underTest.execute(); + + assertComputedAndAggregatedToZeroInt(NEW_BLOCKS_DUPLICATED_KEY); } /** @@ -226,55 +291,43 @@ public class ReportNewDuplicationMeasuresStepTest { duplicationRepository.addDuplication(fileRef, original, duplicates); } - private void setChangesets(int componentRef) { - scmInfoRepository.setScmInfo(componentRef, - Changeset.newChangesetBuilder().setDate(parseDate("2011-01-01").getTime()).setRevision("rev-1").build(), - Changeset.newChangesetBuilder().setDate(parseDate("2011-01-01").getTime()).setRevision("rev-1").build(), - // line 3 is older, part of no period - Changeset.newChangesetBuilder().setDate(parseDate("2007-01-15").getTime()).setRevision("rev-2").build(), - Changeset.newChangesetBuilder().setDate(parseDate("2011-01-01").getTime()).setRevision("rev-1").build(), - Changeset.newChangesetBuilder().setDate(parseDate("2011-01-01").getTime()).setRevision("rev-1").build(), - Changeset.newChangesetBuilder().setDate(parseDate("2011-01-01").getTime()).setRevision("rev-1").build(), - Changeset.newChangesetBuilder().setDate(parseDate("2011-01-01").getTime()).setRevision("rev-1").build(), - Changeset.newChangesetBuilder().setDate(parseDate("2011-01-01").getTime()).setRevision("rev-1").build(), - Changeset.newChangesetBuilder().setDate(parseDate("2011-01-01").getTime()).setRevision("rev-1").build(), - Changeset.newChangesetBuilder().setDate(parseDate("2011-01-01").getTime()).setRevision("rev-1").build(), - Changeset.newChangesetBuilder().setDate(parseDate("2011-01-01").getTime()).setRevision("rev-1").build(), - Changeset.newChangesetBuilder().setDate(parseDate("2011-01-01").getTime()).setRevision("rev-1").build()); - } - - private void assertRawMeasureValue(int componentRef, double period2Value) { - assertRawMeasureValue(componentRef, period2Value, 0d); + private void setChangesets(int... componentRefs) { + Arrays.stream(componentRefs) + .forEach(componentRef -> scmInfoRepository.setScmInfo(componentRef, + Changeset.newChangesetBuilder().setDate(parseDate("2011-01-01").getTime()).setRevision("rev-1").build(), + Changeset.newChangesetBuilder().setDate(parseDate("2011-01-01").getTime()).setRevision("rev-1").build(), + // line 3 is older, part of no period + Changeset.newChangesetBuilder().setDate(parseDate("2007-01-15").getTime()).setRevision("rev-2").build(), + Changeset.newChangesetBuilder().setDate(parseDate("2011-01-01").getTime()).setRevision("rev-1").build(), + Changeset.newChangesetBuilder().setDate(parseDate("2011-01-01").getTime()).setRevision("rev-1").build(), + Changeset.newChangesetBuilder().setDate(parseDate("2011-01-01").getTime()).setRevision("rev-1").build(), + Changeset.newChangesetBuilder().setDate(parseDate("2011-01-01").getTime()).setRevision("rev-1").build(), + Changeset.newChangesetBuilder().setDate(parseDate("2011-01-01").getTime()).setRevision("rev-1").build(), + Changeset.newChangesetBuilder().setDate(parseDate("2011-01-01").getTime()).setRevision("rev-1").build(), + Changeset.newChangesetBuilder().setDate(parseDate("2011-01-01").getTime()).setRevision("rev-1").build(), + Changeset.newChangesetBuilder().setDate(parseDate("2011-01-01").getTime()).setRevision("rev-1").build(), + Changeset.newChangesetBuilder().setDate(parseDate("2011-01-01").getTime()).setRevision("rev-1").build())); } - private void assertRawMeasureValue(int componentRef, double period2Value, double period5Value) { - assertThat(toEntries(measureRepository.getAddedRawMeasures(componentRef))).containsOnlyOnce( - entryOf(NEW_LINES_DUPLICATED_KEY, createMeasure(period2Value, period5Value))); + private void assertRawMeasureValue(int componentRef, String metricKey, double period2Value) { + assertRawMeasureValue(componentRef, metricKey, period2Value, 0d); } - private void assertComputedAndAggregatedToZeroInt() { - assertRawMeasureValue(FILE_1_REF, 0); - assertRawMeasureValue(FILE_2_REF, 0); - assertRawMeasureValue(FILE_3_REF, 0); - assertRawMeasureValue(FILE_4_REF, 0); - assertRawMeasureValue(DIRECTORY_REF, 0); - assertRawMeasureValue(SUB_MODULE_1_REF, 0); - assertRawMeasureValue(SUB_MODULE_2_REF, 0); - assertRawMeasureValue(MODULE_REF, 0); - assertRawMeasureValue(ROOT_REF, 0); + private void assertRawMeasureValue(int componentRef, String metricKey, double period2Value, double period5Value) { + MeasureVariations variations = measureRepository.getAddedRawMeasure(componentRef, metricKey).get().getVariations(); + assertThat(variations.getVariation2()).isEqualTo(period2Value); + assertThat(variations.getVariation5()).isEqualTo(period5Value); } - private static Measure createMeasure(@Nullable Double variationPeriod2, @Nullable Double variationPeriod5) { - MeasureVariations.Builder variationBuilder = newMeasureVariationsBuilder(); - if (variationPeriod2 != null) { - variationBuilder.setVariation(new Period(2, "", null, 1L, "u2"), variationPeriod2); - } - if (variationPeriod5 != null) { - variationBuilder.setVariation(new Period(5, "", null, 1L, "u2"), variationPeriod5); - } - return newMeasureBuilder() - .setVariations(variationBuilder.build()) - .createNoValue(); + private void assertComputedAndAggregatedToZeroInt(String metricKey) { + assertRawMeasureValue(FILE_1_REF, metricKey, 0); + assertRawMeasureValue(FILE_2_REF, metricKey, 0); + assertRawMeasureValue(FILE_3_REF, metricKey, 0); + assertRawMeasureValue(FILE_4_REF, metricKey, 0); + assertRawMeasureValue(DIRECTORY_REF, metricKey, 0); + assertRawMeasureValue(SUB_MODULE_1_REF, metricKey, 0); + assertRawMeasureValue(SUB_MODULE_2_REF, metricKey, 0); + assertRawMeasureValue(MODULE_REF, metricKey, 0); + assertRawMeasureValue(ROOT_REF, metricKey, 0); } - } diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/step/ViewsNewDuplicationMeasuresStepTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/step/ViewsNewDuplicationMeasuresStepTest.java deleted file mode 100644 index d14f427ff25..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/step/ViewsNewDuplicationMeasuresStepTest.java +++ /dev/null @@ -1,153 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2016 SonarSource SA - * mailto:contact AT sonarsource DOT com - * - * This program 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. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -package org.sonar.server.computation.task.projectanalysis.step; - -import javax.annotation.Nullable; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.sonar.server.computation.task.projectanalysis.component.TreeRootHolderRule; -import org.sonar.server.computation.task.projectanalysis.measure.Measure; -import org.sonar.server.computation.task.projectanalysis.measure.MeasureRepositoryRule; -import org.sonar.server.computation.task.projectanalysis.measure.MeasureVariations; -import org.sonar.server.computation.task.projectanalysis.metric.MetricRepositoryRule; -import org.sonar.server.computation.task.projectanalysis.period.Period; -import org.sonar.server.computation.task.projectanalysis.period.PeriodsHolderRule; -import org.sonar.server.computation.task.step.ComputationStep; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.guava.api.Assertions.assertThat; -import static org.sonar.api.measures.CoreMetrics.NEW_LINES_DUPLICATED; -import static org.sonar.api.measures.CoreMetrics.NEW_LINES_DUPLICATED_KEY; -import static org.sonar.api.utils.DateUtils.parseDate; -import static org.sonar.server.computation.task.projectanalysis.component.Component.Type.PROJECT_VIEW; -import static org.sonar.server.computation.task.projectanalysis.component.Component.Type.SUBVIEW; -import static org.sonar.server.computation.task.projectanalysis.component.Component.Type.VIEW; -import static org.sonar.server.computation.task.projectanalysis.component.ViewsComponent.builder; -import static org.sonar.server.computation.task.projectanalysis.measure.Measure.newMeasureBuilder; -import static org.sonar.server.computation.task.projectanalysis.measure.MeasureVariations.newMeasureVariationsBuilder; - -public class ViewsNewDuplicationMeasuresStepTest { - - private static final int ROOT_REF = 1; - private static final int SUBVIEW_REF = 12; - private static final int SUB_SUBVIEW_REF = 123; - private static final int PROJECT_VIEW_1_REF = 1231; - private static final int PROJECT_VIEW_2_REF = 1232; - private static final int PROJECT_VIEW_3_REF = 13; - - @Rule - public TreeRootHolderRule treeRootHolder = new TreeRootHolderRule() - .setRoot(builder(VIEW, ROOT_REF) - .addChildren( - builder(SUBVIEW, SUBVIEW_REF) - .addChildren( - builder(SUBVIEW, SUB_SUBVIEW_REF) - .addChildren( - builder(PROJECT_VIEW, PROJECT_VIEW_1_REF).build(), - builder(PROJECT_VIEW, PROJECT_VIEW_2_REF).build()) - .build()) - .build(), - builder(PROJECT_VIEW, PROJECT_VIEW_3_REF).build()) - .build()); - @Rule - public PeriodsHolderRule periodsHolder = new PeriodsHolderRule(); - @Rule - public MetricRepositoryRule metricRepository = new MetricRepositoryRule() - .add(NEW_LINES_DUPLICATED); - @Rule - public MeasureRepositoryRule measureRepository = MeasureRepositoryRule.create(treeRootHolder, metricRepository); - - ComputationStep underTest = new NewDuplicationMeasuresStep(treeRootHolder, periodsHolder, metricRepository, measureRepository); - - @Before - public void setUp() { - periodsHolder.setPeriods( - new Period(2, "mode_p_1", null, parseDate("2009-12-25").getTime(), "u1"), - new Period(5, "mode_p_5", null, parseDate("2011-02-18").getTime(), "u2")); - } - - @Test - public void aggregate_duplicated_lines() { - addRawMeasure(PROJECT_VIEW_1_REF, NEW_LINES_DUPLICATED_KEY, 10); - addRawMeasure(PROJECT_VIEW_2_REF, NEW_LINES_DUPLICATED_KEY, 40); - addRawMeasure(PROJECT_VIEW_3_REF, NEW_LINES_DUPLICATED_KEY, 50); - - underTest.execute(); - - assertNoNewRawMeasuresOnProjectViews(); - assertRawMeasureValue(SUB_SUBVIEW_REF, NEW_LINES_DUPLICATED_KEY, 50); - assertRawMeasureValue(SUBVIEW_REF, NEW_LINES_DUPLICATED_KEY, 50); - assertRawMeasureValue(ROOT_REF, NEW_LINES_DUPLICATED_KEY, 100); - } - - @Test - public void aggregate_zero_duplicated_line() { - addRawMeasure(PROJECT_VIEW_1_REF, NEW_LINES_DUPLICATED_KEY, 0); - addRawMeasure(PROJECT_VIEW_2_REF, NEW_LINES_DUPLICATED_KEY, 0); - // no raw measure for PROJECT_VIEW_3_REF - - underTest.execute(); - - assertNoNewRawMeasuresOnProjectViews(); - assertRawMeasureValue(SUB_SUBVIEW_REF, NEW_LINES_DUPLICATED_KEY, 0); - assertRawMeasureValue(SUBVIEW_REF, NEW_LINES_DUPLICATED_KEY, 0); - assertRawMeasureValue(ROOT_REF, NEW_LINES_DUPLICATED_KEY, 0); - } - - @Test - public void aggregate_zero_duplicated_line_when_no_data() { - underTest.execute(); - - assertNoNewRawMeasuresOnProjectViews(); - assertRawMeasureValue(SUB_SUBVIEW_REF, NEW_LINES_DUPLICATED_KEY, 0); - assertRawMeasureValue(SUBVIEW_REF, NEW_LINES_DUPLICATED_KEY, 0); - assertRawMeasureValue(ROOT_REF, NEW_LINES_DUPLICATED_KEY, 0); - } - - private void addRawMeasure(int componentRef, String metricKey, double value) { - measureRepository.addRawMeasure(componentRef, metricKey, createMeasure(value, value)); - } - - private static Measure createMeasure(@Nullable Double variationPeriod2, @Nullable Double variationPeriod5) { - MeasureVariations.Builder variationBuilder = newMeasureVariationsBuilder(); - if (variationPeriod2 != null) { - variationBuilder.setVariation(new Period(2, "", null, 1L, "U2"), variationPeriod2); - } - if (variationPeriod5 != null) { - variationBuilder.setVariation(new Period(5, "", null, 1L, "U2"), variationPeriod5); - } - return newMeasureBuilder() - .setVariations(variationBuilder.build()) - .createNoValue(); - } - - private void assertNoNewRawMeasuresOnProjectViews() { - assertThat(measureRepository.getAddedRawMeasures(PROJECT_VIEW_1_REF)).isEmpty(); - assertThat(measureRepository.getAddedRawMeasures(PROJECT_VIEW_2_REF)).isEmpty(); - assertThat(measureRepository.getAddedRawMeasures(PROJECT_VIEW_3_REF)).isEmpty(); - } - - private void assertRawMeasureValue(int componentRef, String metricKey, int value) { - assertThat(measureRepository.getAddedRawMeasure(componentRef, metricKey).get().getVariations().getVariation2()).isEqualTo(value); - } - -} diff --git a/sonar-core/src/main/resources/org/sonar/l10n/core.properties b/sonar-core/src/main/resources/org/sonar/l10n/core.properties index 03e7873b2a5..24c54a1633e 100644 --- a/sonar-core/src/main/resources/org/sonar/l10n/core.properties +++ b/sonar-core/src/main/resources/org/sonar/l10n/core.properties @@ -2472,6 +2472,8 @@ metric.new_coverage.description=Coverage of new/changed code metric.new_coverage.name=Coverage on New Code metric.new_critical_violations.description=New Critical issues metric.new_critical_violations.name=New Critical Issues +metric.new_duplicated_blocks.name=Duplicated Blocks on New Code +metric.new_duplicated_blocks.description=Duplicated blocks on new code metric.new_duplicated_lines.name=New Duplicated Lines metric.new_duplicated_lines.description=New duplicated lines metric.new_info_violations.description=New Info issues 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 11240f588e4..a576efb7530 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 @@ -1334,6 +1334,16 @@ public final class CoreMetrics { .setOptimizedBestValue(true) .create(); + public static final String NEW_BLOCKS_DUPLICATED_KEY = "new_duplicated_blocks"; + public static final Metric<Integer> NEW_BLOCKS_DUPLICATED = new Metric.Builder(NEW_BLOCKS_DUPLICATED_KEY, "Duplicated Blocks on New Code", Metric.ValueType.INT) + .setDescription("Duplicated blocks on new code") + .setDirection(Metric.DIRECTION_WORST) + .setQualitative(true) + .setDomain(DOMAIN_DUPLICATIONS) + .setBestValue(0.0) + .setDeleteHistoricalData(true) + .create(); + public static final String DUPLICATED_FILES_KEY = "duplicated_files"; /** |