diff options
author | Sébastien Lesaint <sebastien.lesaint@sonarsource.com> | 2015-11-09 16:33:42 +0100 |
---|---|---|
committer | Sébastien Lesaint <sebastien.lesaint@sonarsource.com> | 2015-11-10 16:35:57 +0100 |
commit | a03c1567fa122666bb21f126742ebe4064cb3138 (patch) | |
tree | e896934711be271aabfce6d41653dad4d77f6580 /server | |
parent | ab2df01969a95f5b46407fcd6dcceccf86686efc (diff) | |
download | sonarqube-a03c1567fa122666bb21f126742ebe4064cb3138.tar.gz sonarqube-a03c1567fa122666bb21f126742ebe4064cb3138.zip |
SONAR-6991 compute all duplicate_* measure in CE
duplicated_files, duplicated_blocks and duplicated_lines are now ignored when present in analysis report
Diffstat (limited to 'server')
4 files changed, 337 insertions, 206 deletions
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/step/DuplicationMeasuresStep.java b/server/sonar-server/src/main/java/org/sonar/server/computation/step/DuplicationMeasuresStep.java index b9e12564d26..2d60d64a37b 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/step/DuplicationMeasuresStep.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/step/DuplicationMeasuresStep.java @@ -22,21 +22,29 @@ package org.sonar.server.computation.step; import com.google.common.base.Optional; import com.google.common.collect.ImmutableList; +import java.util.HashSet; +import java.util.Set; +import javax.annotation.CheckForNull; +import javax.annotation.Nullable; import org.sonar.api.measures.CoreMetrics; -import org.sonar.server.computation.component.CrawlerDepthLimit; +import org.sonar.server.computation.component.Component; import org.sonar.server.computation.component.PathAwareCrawler; import org.sonar.server.computation.component.TreeRootHolder; +import org.sonar.server.computation.duplication.Duplication; +import org.sonar.server.computation.duplication.DuplicationRepository; +import org.sonar.server.computation.duplication.InnerDuplicate; +import org.sonar.server.computation.duplication.TextBlock; import org.sonar.server.computation.formula.Counter; import org.sonar.server.computation.formula.CounterInitializationContext; import org.sonar.server.computation.formula.CreateMeasureContext; import org.sonar.server.computation.formula.Formula; import org.sonar.server.computation.formula.FormulaExecutorComponentVisitor; -import org.sonar.server.computation.formula.counter.IntSumCounter; import org.sonar.server.computation.measure.Measure; import org.sonar.server.computation.measure.MeasureRepository; import org.sonar.server.computation.metric.Metric; import org.sonar.server.computation.metric.MetricRepository; +import static com.google.common.collect.FluentIterable.from; import static java.util.Objects.requireNonNull; import static org.sonar.api.measures.CoreMetrics.COMMENT_LINES_KEY; import static org.sonar.api.measures.CoreMetrics.DUPLICATED_BLOCKS_KEY; @@ -59,63 +67,149 @@ public class DuplicationMeasuresStep implements ComputationStep { private final MetricRepository metricRepository; private final MeasureRepository measureRepository; - public DuplicationMeasuresStep(TreeRootHolder treeRootHolder, MetricRepository metricRepository, MeasureRepository measureRepository) { + public DuplicationMeasuresStep(TreeRootHolder treeRootHolder, MetricRepository metricRepository, MeasureRepository measureRepository, + @Nullable DuplicationRepository duplicationRepository) { this.treeRootHolder = treeRootHolder; this.metricRepository = metricRepository; this.measureRepository = measureRepository; - this.formulas = ImmutableList.<Formula>of( - new SumDuplicationFormula(DUPLICATED_BLOCKS_KEY), - new SumDuplicationFormula(DUPLICATED_FILES_KEY), - new DuplicationFormula()); + this.formulas = ImmutableList.<Formula>of(new DuplicationFormula(metricRepository, measureRepository, duplicationRepository)); + } + + /** + * Constructor used by Pico in Views where no DuplicationRepository is available. + */ + public DuplicationMeasuresStep(TreeRootHolder treeRootHolder, MetricRepository metricRepository, MeasureRepository measureRepository) { + this(treeRootHolder, metricRepository, measureRepository, null); + } + + @Override + public String getDescription() { + return "Compute duplication measures"; } @Override public void execute() { new PathAwareCrawler<>( FormulaExecutorComponentVisitor.newBuilder(metricRepository, measureRepository).buildFor(formulas)) - .visit(treeRootHolder.getRoot()); + .visit(treeRootHolder.getRoot()); } - private class DuplicationFormula implements Formula<SumDuplicationCounter> { + private static class DuplicationCounter implements Counter<DuplicationCounter> { + @CheckForNull + private final DuplicationRepository duplicationRepository; + private int fileCount = 0; + private int blockCount = 0; + private int lineCount = 0; + + private DuplicationCounter(@Nullable DuplicationRepository duplicationRepository) { + this.duplicationRepository = duplicationRepository; + } + + @Override + public void aggregate(DuplicationCounter counter) { + this.fileCount += counter.fileCount; + this.blockCount += counter.blockCount; + this.lineCount += counter.lineCount; + } + + @Override + public void initialize(CounterInitializationContext context) { + Component leaf = context.getLeaf(); + if (leaf.getType() == Component.Type.FILE) { + initializeForFile(leaf); + } else if (leaf.getType() == Component.Type.PROJECT_VIEW) { + initializeForProjectView(context); + } + } + + private void initializeForFile(Component file) { + Set<Duplication> duplications = requireNonNull(this.duplicationRepository, "DuplicationRepository missing") + .getDuplications(file); + if (duplications.isEmpty()) { + return; + } + + // use a set to count lines only once + Set<Integer> duplicatedLineNumbers = new HashSet<>(); + long blocks = 0; + for (Duplication duplication : duplications) { + blocks++; + addLines(duplication.getOriginal(), duplicatedLineNumbers); + for (InnerDuplicate innerDuplicate : from(duplication.getDuplicates()).filter(InnerDuplicate.class)) { + blocks++; + addLines(innerDuplicate.getTextBlock(), duplicatedLineNumbers); + } + } + + this.fileCount += 1; + this.blockCount += blocks; + this.lineCount += duplicatedLineNumbers.size(); + } + + private static void addLines(TextBlock textBlock, Set<Integer> duplicatedLineNumbers) { + for (int i = textBlock.getStart(); i <= textBlock.getEnd(); i++) { + duplicatedLineNumbers.add(i); + } + } + + private void initializeForProjectView(CounterInitializationContext context) { + fileCount += getMeasure(context, DUPLICATED_FILES_KEY); + blockCount += getMeasure(context, DUPLICATED_BLOCKS_KEY); + lineCount += getMeasure(context, DUPLICATED_LINES_KEY); + } + + private static int getMeasure(CounterInitializationContext context, String metricKey) { + Optional<Measure> files = context.getMeasure(metricKey); + if (files.isPresent()) { + return files.get().getIntValue(); + } + return 0; + } + } + private static final class DuplicationFormula implements Formula<DuplicationCounter> { + private final MeasureRepository measureRepository; + @CheckForNull + private final DuplicationRepository duplicationRepository; private final Metric nclocMetric; private final Metric linesMetric; private final Metric commentLinesMetric; - public DuplicationFormula() { + private DuplicationFormula(MetricRepository metricRepository, MeasureRepository measureRepository, @Nullable DuplicationRepository duplicationRepository) { + this.measureRepository = measureRepository; + this.duplicationRepository = duplicationRepository; this.nclocMetric = metricRepository.getByKey(NCLOC_KEY); this.linesMetric = metricRepository.getByKey(LINES_KEY); this.commentLinesMetric = metricRepository.getByKey(COMMENT_LINES_KEY); } @Override - public SumDuplicationCounter createNewCounter() { - return new SumDuplicationCounter(DUPLICATED_LINES_KEY); + public DuplicationCounter createNewCounter() { + return new DuplicationCounter(duplicationRepository); } @Override - public Optional<Measure> createMeasure(SumDuplicationCounter counter, CreateMeasureContext context) { - return createDuplicatedLinesMeasure(counter, context) - .or(createDuplicatedLinesDensityMeasure(counter, context)); - } - - private Optional<Measure> createDuplicatedLinesMeasure(SumDuplicationCounter counter, CreateMeasureContext context) { - int duplicatedLines = counter.value; - if (context.getMetric().getKey().equals(DUPLICATED_LINES_KEY) - && CrawlerDepthLimit.LEAVES.isDeeperThan(context.getComponent().getType())) { - return Optional.of(Measure.newMeasureBuilder().create(duplicatedLines)); + public Optional<Measure> createMeasure(DuplicationCounter counter, CreateMeasureContext context) { + switch (context.getMetric().getKey()) { + case DUPLICATED_FILES_KEY: + return Optional.of(Measure.newMeasureBuilder().create(counter.fileCount)); + case DUPLICATED_LINES_KEY: + return Optional.of(Measure.newMeasureBuilder().create(counter.lineCount)); + case DUPLICATED_LINES_DENSITY_KEY: + return createDuplicatedLinesDensityMeasure(counter, context); + case DUPLICATED_BLOCKS_KEY: + return Optional.of(Measure.newMeasureBuilder().create(counter.blockCount)); + default: + throw new IllegalArgumentException("Unsupported metric " + context.getMetric()); } - return Optional.absent(); } - private Optional<Measure> createDuplicatedLinesDensityMeasure(SumDuplicationCounter counter, CreateMeasureContext context) { - int duplicatedLines = counter.value; - if (context.getMetric().getKey().equals(DUPLICATED_LINES_DENSITY_KEY)) { - Optional<Integer> nbLines = getNbLinesFromLocOrNcloc(context); - if (nbLines.isPresent() && nbLines.get() > 0) { - double density = Math.min(100d, 100d * duplicatedLines / nbLines.get()); - return Optional.of(Measure.newMeasureBuilder().create(density)); - } + private Optional<Measure> createDuplicatedLinesDensityMeasure(DuplicationCounter counter, CreateMeasureContext context) { + int duplicatedLines = counter.lineCount; + Optional<Integer> nbLines = getNbLinesFromLocOrNcloc(context); + if (nbLines.isPresent() && nbLines.get() > 0) { + double density = Math.min(100d, 100d * duplicatedLines / nbLines.get()); + return Optional.of(Measure.newMeasureBuilder().create(density)); } return Optional.absent(); } @@ -136,67 +230,7 @@ public class DuplicationMeasuresStep implements ComputationStep { @Override public String[] getOutputMetricKeys() { - return new String[] {DUPLICATED_LINES_KEY, DUPLICATED_LINES_DENSITY_KEY}; - } - } - - private class SumDuplicationFormula implements Formula<SumDuplicationCounter> { - - private final String metricKey; - - public SumDuplicationFormula(String metricKey) { - this.metricKey = requireNonNull(metricKey, "Metric key cannot be null"); - } - - @Override - public SumDuplicationCounter createNewCounter() { - return new SumDuplicationCounter(metricKey); - } - - @Override - public Optional<Measure> createMeasure(SumDuplicationCounter counter, CreateMeasureContext context) { - int value = counter.value; - if (CrawlerDepthLimit.LEAVES.isDeeperThan(context.getComponent().getType())) { - return Optional.of(Measure.newMeasureBuilder().create(value)); - } - return Optional.absent(); - } - - @Override - public String[] getOutputMetricKeys() { - return new String[] {metricKey}; + return new String[] {DUPLICATED_FILES_KEY, DUPLICATED_LINES_KEY, DUPLICATED_LINES_DENSITY_KEY, DUPLICATED_BLOCKS_KEY}; } } - - /** - * This counter is almost the same as {@link IntSumCounter}, expect that it will aggregate a value of 0 when there's no measure on file level - */ - private class SumDuplicationCounter implements Counter<SumDuplicationCounter> { - - private final String metricKey; - - private int value = 0; - - public SumDuplicationCounter(String metricKey) { - this.metricKey = metricKey; - } - - @Override - public void aggregate(SumDuplicationCounter counter) { - value += counter.value; - } - - @Override - public void initialize(CounterInitializationContext context) { - Optional<Measure> measureOptional = context.getMeasure(metricKey); - if (measureOptional.isPresent()) { - value += measureOptional.get().getIntValue(); - } - } - } - - @Override - public String getDescription() { - return "Compute duplication measures"; - } } diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/step/ReportComputationSteps.java b/server/sonar-server/src/main/java/org/sonar/server/computation/step/ReportComputationSteps.java index 067fd2f44cc..3750a67e129 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/step/ReportComputationSteps.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/step/ReportComputationSteps.java @@ -58,6 +58,7 @@ public class ReportComputationSteps implements ComputationSteps { CoverageMeasuresStep.class, CommentMeasuresStep.class, CustomMeasuresCopyStep.class, + LoadDuplicationsFromReportStep.class, DuplicationMeasuresStep.class, LanguageDistributionMeasuresStep.class, UnitTestMeasuresStep.class, @@ -85,7 +86,6 @@ public class ReportComputationSteps implements ComputationSteps { PersistIssuesStep.class, PersistProjectLinksStep.class, PersistEventsStep.class, - LoadDuplicationsFromReportStep.class, PersistDuplicationsStep.class, PersistFileSourcesStep.class, PersistTestsStep.class, diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/step/ReportDuplicationMeasuresStepTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/step/ReportDuplicationMeasuresStepTest.java index d54c75ed33e..05f4ca5ffeb 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/computation/step/ReportDuplicationMeasuresStepTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/step/ReportDuplicationMeasuresStepTest.java @@ -23,9 +23,12 @@ package org.sonar.server.computation.step; import org.junit.Rule; import org.junit.Test; import org.sonar.server.computation.batch.TreeRootHolderRule; +import org.sonar.server.computation.duplication.DuplicationRepositoryRule; +import org.sonar.server.computation.duplication.TextBlock; import org.sonar.server.computation.measure.MeasureRepositoryRule; import org.sonar.server.computation.metric.MetricRepositoryRule; +import static com.google.common.base.Preconditions.checkArgument; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.guava.api.Assertions.assertThat; import static org.sonar.api.measures.CoreMetrics.COMMENT_LINES; @@ -53,10 +56,14 @@ public class ReportDuplicationMeasuresStepTest { private static final int ROOT_REF = 1; private static final int MODULE_REF = 12; - private static final int SUB_MODULE_REF = 123; + 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 FILE_1_REF = 12341; private static final int FILE_2_REF = 12342; + private static final int FILE_3_REF = 1261; + private static final int FILE_4_REF = 1262; + private static final String SOME_FILE_KEY = "some file key"; @Rule public TreeRootHolderRule treeRootHolder = new TreeRootHolderRule() @@ -65,13 +72,19 @@ public class ReportDuplicationMeasuresStepTest { .addChildren( builder(MODULE, MODULE_REF) .addChildren( - builder(MODULE, SUB_MODULE_REF) + builder(MODULE, SUB_MODULE_1_REF) .addChildren( builder(DIRECTORY, DIRECTORY_REF) .addChildren( builder(FILE, FILE_1_REF).build(), builder(FILE, FILE_2_REF).build()) .build()) + .build(), + builder(MODULE, SUB_MODULE_2_REF) + .addChildren( + builder(FILE, FILE_3_REF).build(), + builder(FILE, FILE_4_REF).build() + ) .build()) .build()) .build()); @@ -86,144 +99,191 @@ public class ReportDuplicationMeasuresStepTest { .add(DUPLICATED_LINES_DENSITY); @Rule public MeasureRepositoryRule measureRepository = MeasureRepositoryRule.create(treeRootHolder, metricRepository); + @Rule + public DuplicationRepositoryRule duplicationRepository = DuplicationRepositoryRule.create(treeRootHolder); + + ComputationStep underTest = new DuplicationMeasuresStep(treeRootHolder, metricRepository, measureRepository, duplicationRepository); + + @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)); + duplicationRepository.addDuplication(FILE_1_REF, original, new TextBlock(3, 3)); + duplicationRepository.addDuplication(FILE_1_REF, original, new TextBlock(2, 3)); + + underTest.execute(); + + assertRawMeasureValue(FILE_1_REF, DUPLICATED_BLOCKS_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(3, 3)); + duplicationRepository.addDuplication(FILE_1_REF, new TextBlock(2, 2), new TextBlock(3, 3)); - ComputationStep underTest = new DuplicationMeasuresStep(treeRootHolder, metricRepository, measureRepository); + underTest.execute(); + + assertRawMeasureValue(FILE_1_REF, DUPLICATED_BLOCKS_KEY, 4); + } @Test - public void aggregate_duplicated_blocks() { - addRawMeasure(FILE_1_REF, DUPLICATED_BLOCKS_KEY, 10); - addRawMeasure(FILE_2_REF, DUPLICATED_BLOCKS_KEY, 40); + 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)); underTest.execute(); - assertNoRawMeasure(FILE_1_REF, DUPLICATED_BLOCKS_KEY); - assertNoRawMeasure(FILE_2_REF, DUPLICATED_BLOCKS_KEY); + assertRawMeasureValue(FILE_1_REF, DUPLICATED_BLOCKS_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)); + + underTest.execute(); + + assertRawMeasureValue(FILE_1_REF, DUPLICATED_BLOCKS_KEY, 1); + } + + @Test + public void compute_and_aggregate_duplicated_blocks_from_single_duplication() { + addDuplicatedBlock(FILE_1_REF, 10); + addDuplicatedBlock(FILE_2_REF, 40); + addDuplicatedBlock(FILE_4_REF, 5); + + underTest.execute(); + + assertRawMeasureValue(FILE_1_REF, DUPLICATED_BLOCKS_KEY, 10); + assertRawMeasureValue(FILE_2_REF, DUPLICATED_BLOCKS_KEY, 40); + assertRawMeasureValue(FILE_3_REF, DUPLICATED_BLOCKS_KEY, 0); + assertRawMeasureValue(FILE_4_REF, DUPLICATED_BLOCKS_KEY, 5); assertRawMeasureValue(DIRECTORY_REF, DUPLICATED_BLOCKS_KEY, 50); - assertRawMeasureValue(SUB_MODULE_REF, DUPLICATED_BLOCKS_KEY, 50); - assertRawMeasureValue(MODULE_REF, DUPLICATED_BLOCKS_KEY, 50); - assertRawMeasureValue(ROOT_REF, DUPLICATED_BLOCKS_KEY, 50); + assertRawMeasureValue(SUB_MODULE_1_REF, DUPLICATED_BLOCKS_KEY, 50); + assertRawMeasureValue(SUB_MODULE_2_REF, DUPLICATED_BLOCKS_KEY, 5); + assertRawMeasureValue(MODULE_REF, DUPLICATED_BLOCKS_KEY, 55); + assertRawMeasureValue(ROOT_REF, DUPLICATED_BLOCKS_KEY, 55); } @Test - public void aggregate_zero_duplicated_blocks() { - addRawMeasure(FILE_1_REF, DUPLICATED_BLOCKS_KEY, 0); - addRawMeasure(FILE_2_REF, DUPLICATED_BLOCKS_KEY, 0); + public void compute_and_aggregate_duplicated_blocks_to_zero_when_no_duplication() { + underTest.execute(); + + assertComputedAndAggregatedToZeroInt(DUPLICATED_BLOCKS_KEY); + } + + @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)); underTest.execute(); - assertNoRawMeasure(FILE_1_REF, DUPLICATED_BLOCKS_KEY); - assertNoRawMeasure(FILE_2_REF, DUPLICATED_BLOCKS_KEY); - assertRawMeasureValue(DIRECTORY_REF, DUPLICATED_BLOCKS_KEY, 0); - assertRawMeasureValue(SUB_MODULE_REF, DUPLICATED_BLOCKS_KEY, 0); - assertRawMeasureValue(MODULE_REF, DUPLICATED_BLOCKS_KEY, 0); - assertRawMeasureValue(ROOT_REF, DUPLICATED_BLOCKS_KEY, 0); + assertRawMeasureValue(FILE_1_REF, DUPLICATED_LINES_KEY, 2); } @Test - public void aggregate_zero_duplicated_blocks_when_no_data() { + public void compute_duplicated_lines_counts_lines_from_original_and_ignores_InProjectDuplicate() { + TextBlock original = new TextBlock(1, 1); + duplicationRepository.addDuplication(FILE_1_REF, original, FILE_2_REF, new TextBlock(2, 2)); + underTest.execute(); - assertNoRawMeasure(FILE_1_REF, DUPLICATED_BLOCKS_KEY); - assertNoRawMeasure(FILE_2_REF, DUPLICATED_BLOCKS_KEY); - assertRawMeasureValue(DIRECTORY_REF, DUPLICATED_BLOCKS_KEY, 0); - assertRawMeasureValue(SUB_MODULE_REF, DUPLICATED_BLOCKS_KEY, 0); - assertRawMeasureValue(MODULE_REF, DUPLICATED_BLOCKS_KEY, 0); - assertRawMeasureValue(ROOT_REF, DUPLICATED_BLOCKS_KEY, 0); + assertRawMeasureValue(FILE_1_REF, DUPLICATED_LINES_KEY, 1); } @Test - public void aggregate_duplicated_files() { - addRawMeasure(FILE_1_REF, DUPLICATED_FILES_KEY, 10); - addRawMeasure(FILE_2_REF, DUPLICATED_FILES_KEY, 40); + public void compute_duplicated_lines_counts_lines_from_original_and_ignores_CrossProjectDuplicate() { + TextBlock original = new TextBlock(1, 1); + duplicationRepository.addDuplication(FILE_1_REF, original, SOME_FILE_KEY, new TextBlock(2, 2)); underTest.execute(); - assertNoRawMeasure(FILE_1_REF, DUPLICATED_FILES_KEY); - assertNoRawMeasure(FILE_2_REF, DUPLICATED_FILES_KEY); - assertRawMeasureValue(DIRECTORY_REF, DUPLICATED_FILES_KEY, 50); - assertRawMeasureValue(SUB_MODULE_REF, DUPLICATED_FILES_KEY, 50); - assertRawMeasureValue(MODULE_REF, DUPLICATED_FILES_KEY, 50); - assertRawMeasureValue(ROOT_REF, DUPLICATED_FILES_KEY, 50); + assertRawMeasureValue(FILE_1_REF, DUPLICATED_LINES_KEY, 1); } @Test - public void aggregate_zero_duplicated_files() { - addRawMeasure(FILE_1_REF, DUPLICATED_FILES_KEY, 0); - addRawMeasure(FILE_2_REF, DUPLICATED_FILES_KEY, 0); + public void compute_duplicated_lines_counts_lines_from_original_and_InnerDuplicate() { + TextBlock original = new TextBlock(1, 5); + duplicationRepository.addDuplication(FILE_1_REF, original, new TextBlock(10, 11)); underTest.execute(); - assertNoRawMeasure(FILE_1_REF, DUPLICATED_FILES_KEY); - assertNoRawMeasure(FILE_2_REF, DUPLICATED_FILES_KEY); - assertRawMeasureValue(DIRECTORY_REF, DUPLICATED_FILES_KEY, 0); - assertRawMeasureValue(SUB_MODULE_REF, DUPLICATED_FILES_KEY, 0); - assertRawMeasureValue(MODULE_REF, DUPLICATED_FILES_KEY, 0); - assertRawMeasureValue(ROOT_REF, DUPLICATED_FILES_KEY, 0); + assertRawMeasureValue(FILE_1_REF, DUPLICATED_LINES_KEY, 7); } @Test - public void aggregate_zero_duplicated_files_when_no_data() { + public void compute_duplicated_lines_counts_lines_from_original_and_InnerDuplicate_only_once() { + TextBlock original = new TextBlock(1, 12); + duplicationRepository.addDuplication(FILE_1_REF, original, new TextBlock(10, 11)); + duplicationRepository.addDuplication(FILE_1_REF, original, new TextBlock(11, 15)); + duplicationRepository.addDuplication(FILE_1_REF, new TextBlock(2, 2), new TextBlock(96, 96)); + underTest.execute(); - assertNoRawMeasure(FILE_1_REF, DUPLICATED_FILES_KEY); - assertNoRawMeasure(FILE_2_REF, DUPLICATED_FILES_KEY); - assertRawMeasureValue(DIRECTORY_REF, DUPLICATED_FILES_KEY, 0); - assertRawMeasureValue(SUB_MODULE_REF, DUPLICATED_FILES_KEY, 0); - assertRawMeasureValue(MODULE_REF, DUPLICATED_FILES_KEY, 0); - assertRawMeasureValue(ROOT_REF, DUPLICATED_FILES_KEY, 0); + assertRawMeasureValue(FILE_1_REF, DUPLICATED_LINES_KEY, 16); } @Test - public void aggregate_duplicated_lines() { - addRawMeasure(FILE_1_REF, DUPLICATED_LINES_KEY, 10); - addRawMeasure(FILE_2_REF, DUPLICATED_LINES_KEY, 40); + public void compute_and_aggregate_duplicated_files() { + addDuplicatedBlock(FILE_1_REF, 2); + addDuplicatedBlock(FILE_3_REF, 10); + addDuplicatedBlock(FILE_4_REF, 50); underTest.execute(); - assertNoRawMeasure(FILE_1_REF, DUPLICATED_LINES_KEY); - assertNoRawMeasure(FILE_2_REF, DUPLICATED_LINES_KEY); - assertRawMeasureValue(DIRECTORY_REF, DUPLICATED_LINES_KEY, 50); - assertRawMeasureValue(SUB_MODULE_REF, DUPLICATED_LINES_KEY, 50); - assertRawMeasureValue(MODULE_REF, DUPLICATED_LINES_KEY, 50); - assertRawMeasureValue(ROOT_REF, DUPLICATED_LINES_KEY, 50); + assertRawMeasureValue(FILE_1_REF, DUPLICATED_FILES_KEY, 1); + assertRawMeasureValue(FILE_2_REF, DUPLICATED_FILES_KEY, 0); + assertRawMeasureValue(FILE_3_REF, DUPLICATED_FILES_KEY, 1); + assertRawMeasureValue(FILE_4_REF, DUPLICATED_FILES_KEY, 1); + assertRawMeasureValue(DIRECTORY_REF, DUPLICATED_FILES_KEY, 1); + assertRawMeasureValue(SUB_MODULE_1_REF, DUPLICATED_FILES_KEY, 1); + assertRawMeasureValue(SUB_MODULE_2_REF, DUPLICATED_FILES_KEY, 2); + assertRawMeasureValue(MODULE_REF, DUPLICATED_FILES_KEY, 3); + assertRawMeasureValue(ROOT_REF, DUPLICATED_FILES_KEY, 3); } @Test - public void aggregate_zero_duplicated_line() { - addRawMeasure(FILE_1_REF, DUPLICATED_LINES_KEY, 0); - addRawMeasure(FILE_2_REF, DUPLICATED_LINES_KEY, 0); + public void compute_and_aggregate_zero_duplicated_files_when_no_duplication_data() { + underTest.execute(); + + assertComputedAndAggregatedToZeroInt(DUPLICATED_FILES_KEY); + } + + @Test + public void compute_and_aggregate_duplicated_lines() { + addDuplicatedBlock(FILE_1_REF, 10); + addDuplicatedBlock(FILE_2_REF, 9); + addDuplicatedBlock(FILE_4_REF, 7); underTest.execute(); - assertNoRawMeasure(FILE_1_REF, DUPLICATED_LINES_KEY); - assertNoRawMeasure(FILE_2_REF, DUPLICATED_LINES_KEY); - assertRawMeasureValue(DIRECTORY_REF, DUPLICATED_LINES_KEY, 0); - assertRawMeasureValue(SUB_MODULE_REF, DUPLICATED_LINES_KEY, 0); - assertRawMeasureValue(MODULE_REF, DUPLICATED_LINES_KEY, 0); - assertRawMeasureValue(ROOT_REF, DUPLICATED_LINES_KEY, 0); + assertRawMeasureValue(FILE_1_REF, DUPLICATED_LINES_KEY, 10); + assertRawMeasureValue(FILE_2_REF, DUPLICATED_LINES_KEY, 9); + assertRawMeasureValue(FILE_3_REF, DUPLICATED_LINES_KEY, 0); + assertRawMeasureValue(FILE_4_REF, DUPLICATED_LINES_KEY, 7); + assertRawMeasureValue(DIRECTORY_REF, DUPLICATED_LINES_KEY, 19); + assertRawMeasureValue(SUB_MODULE_1_REF, DUPLICATED_LINES_KEY, 19); + assertRawMeasureValue(SUB_MODULE_2_REF, DUPLICATED_LINES_KEY, 7); + assertRawMeasureValue(MODULE_REF, DUPLICATED_LINES_KEY, 26); + assertRawMeasureValue(ROOT_REF, DUPLICATED_LINES_KEY, 26); } @Test - public void aggregate_zero_duplicated_line_when_no_data() { + public void compute_and_aggregate_zero_duplicated_line_when_no_duplication() { underTest.execute(); - assertNoRawMeasure(FILE_1_REF, DUPLICATED_LINES_KEY); - assertNoRawMeasure(FILE_2_REF, DUPLICATED_LINES_KEY); - assertRawMeasureValue(DIRECTORY_REF, DUPLICATED_LINES_KEY, 0); - assertRawMeasureValue(SUB_MODULE_REF, DUPLICATED_LINES_KEY, 0); - assertRawMeasureValue(MODULE_REF, DUPLICATED_LINES_KEY, 0); - assertRawMeasureValue(ROOT_REF, DUPLICATED_LINES_KEY, 0); + String metricKey = DUPLICATED_LINES_KEY; + assertComputedAndAggregatedToZeroInt(metricKey); } @Test public void compute_and_aggregate_duplicated_lines_density_using_lines() throws Exception { - addRawMeasure(FILE_1_REF, DUPLICATED_LINES_KEY, 2); - addRawMeasure(FILE_2_REF, DUPLICATED_LINES_KEY, 3); + addDuplicatedBlock(FILE_1_REF, 2); + addDuplicatedBlock(FILE_2_REF, 3); addRawMeasure(FILE_1_REF, LINES_KEY, 10); addRawMeasure(FILE_2_REF, LINES_KEY, 40); addRawMeasure(DIRECTORY_REF, LINES_KEY, 50); - addRawMeasure(SUB_MODULE_REF, LINES_KEY, 50); + addRawMeasure(SUB_MODULE_1_REF, LINES_KEY, 50); addRawMeasure(MODULE_REF, LINES_KEY, 50); addRawMeasure(ROOT_REF, LINES_KEY, 50); @@ -231,28 +291,31 @@ public class ReportDuplicationMeasuresStepTest { assertRawMeasureValue(FILE_1_REF, DUPLICATED_LINES_DENSITY_KEY, 20d); assertRawMeasureValue(FILE_2_REF, DUPLICATED_LINES_DENSITY_KEY, 7.5d); + assertNoRawMeasure(FILE_3_REF, DUPLICATED_LINES_DENSITY_KEY); + assertNoRawMeasure(FILE_4_REF, DUPLICATED_LINES_DENSITY_KEY); assertRawMeasureValue(DIRECTORY_REF, DUPLICATED_LINES_DENSITY_KEY, 10d); - assertRawMeasureValue(SUB_MODULE_REF, DUPLICATED_LINES_DENSITY_KEY, 10d); + assertRawMeasureValue(SUB_MODULE_1_REF, DUPLICATED_LINES_DENSITY_KEY, 10d); + assertNoRawMeasure(SUB_MODULE_2_REF, DUPLICATED_LINES_DENSITY_KEY); assertRawMeasureValue(MODULE_REF, DUPLICATED_LINES_DENSITY_KEY, 10d); assertRawMeasureValue(ROOT_REF, DUPLICATED_LINES_DENSITY_KEY, 10d); } @Test public void compute_and_aggregate_duplicated_lines_density_using_nclocs_and_comment_lines() throws Exception { - addRawMeasure(FILE_1_REF, DUPLICATED_LINES_KEY, 2); - addRawMeasure(FILE_2_REF, DUPLICATED_LINES_KEY, 3); + addDuplicatedBlock(FILE_1_REF, 2); + addDuplicatedBlock(FILE_2_REF, 3); addRawMeasure(FILE_1_REF, COMMENT_LINES_KEY, 2); addRawMeasure(FILE_2_REF, COMMENT_LINES_KEY, 10); addRawMeasure(DIRECTORY_REF, COMMENT_LINES_KEY, 12); - addRawMeasure(SUB_MODULE_REF, COMMENT_LINES_KEY, 12); + addRawMeasure(SUB_MODULE_1_REF, COMMENT_LINES_KEY, 12); addRawMeasure(MODULE_REF, COMMENT_LINES_KEY, 12); addRawMeasure(ROOT_REF, COMMENT_LINES_KEY, 12); addRawMeasure(FILE_1_REF, NCLOC_KEY, 8); addRawMeasure(FILE_2_REF, NCLOC_KEY, 30); addRawMeasure(DIRECTORY_REF, NCLOC_KEY, 38); - addRawMeasure(SUB_MODULE_REF, NCLOC_KEY, 38); + addRawMeasure(SUB_MODULE_1_REF, NCLOC_KEY, 38); addRawMeasure(MODULE_REF, NCLOC_KEY, 38); addRawMeasure(ROOT_REF, NCLOC_KEY, 38); @@ -260,21 +323,24 @@ public class ReportDuplicationMeasuresStepTest { assertRawMeasureValue(FILE_1_REF, DUPLICATED_LINES_DENSITY_KEY, 20d); assertRawMeasureValue(FILE_2_REF, DUPLICATED_LINES_DENSITY_KEY, 7.5d); + assertNoRawMeasure(FILE_3_REF, DUPLICATED_LINES_DENSITY_KEY); + assertNoRawMeasure(FILE_4_REF, DUPLICATED_LINES_DENSITY_KEY); assertRawMeasureValue(DIRECTORY_REF, DUPLICATED_LINES_DENSITY_KEY, 10d); - assertRawMeasureValue(SUB_MODULE_REF, DUPLICATED_LINES_DENSITY_KEY, 10d); + assertRawMeasureValue(SUB_MODULE_1_REF, DUPLICATED_LINES_DENSITY_KEY, 10d); + assertNoRawMeasure(SUB_MODULE_2_REF, DUPLICATED_LINES_DENSITY_KEY); assertRawMeasureValue(MODULE_REF, DUPLICATED_LINES_DENSITY_KEY, 10d); assertRawMeasureValue(ROOT_REF, DUPLICATED_LINES_DENSITY_KEY, 10d); } @Test public void compute_duplicated_lines_density_using_only_nclocs() throws Exception { - addRawMeasure(FILE_1_REF, DUPLICATED_LINES_KEY, 2); - addRawMeasure(FILE_2_REF, DUPLICATED_LINES_KEY, 3); + addDuplicatedBlock(FILE_1_REF, 2); + addDuplicatedBlock(FILE_2_REF, 3); addRawMeasure(FILE_1_REF, NCLOC_KEY, 10); addRawMeasure(FILE_2_REF, NCLOC_KEY, 40); addRawMeasure(DIRECTORY_REF, NCLOC_KEY, 50); - addRawMeasure(SUB_MODULE_REF, NCLOC_KEY, 50); + addRawMeasure(SUB_MODULE_1_REF, NCLOC_KEY, 50); addRawMeasure(MODULE_REF, NCLOC_KEY, 50); addRawMeasure(ROOT_REF, NCLOC_KEY, 50); @@ -282,28 +348,28 @@ public class ReportDuplicationMeasuresStepTest { assertRawMeasureValue(FILE_1_REF, DUPLICATED_LINES_DENSITY_KEY, 20d); assertRawMeasureValue(FILE_2_REF, DUPLICATED_LINES_DENSITY_KEY, 7.5d); + assertNoRawMeasure(FILE_3_REF, DUPLICATED_LINES_DENSITY_KEY); + assertNoRawMeasure(FILE_4_REF, DUPLICATED_LINES_DENSITY_KEY); assertRawMeasureValue(DIRECTORY_REF, DUPLICATED_LINES_DENSITY_KEY, 10d); - assertRawMeasureValue(SUB_MODULE_REF, DUPLICATED_LINES_DENSITY_KEY, 10d); + assertRawMeasureValue(SUB_MODULE_1_REF, DUPLICATED_LINES_DENSITY_KEY, 10d); + assertNoRawMeasure(SUB_MODULE_2_REF, DUPLICATED_LINES_DENSITY_KEY); assertRawMeasureValue(MODULE_REF, DUPLICATED_LINES_DENSITY_KEY, 10d); assertRawMeasureValue(ROOT_REF, DUPLICATED_LINES_DENSITY_KEY, 10d); } @Test - public void compute_zero_percent_duplicated_lines_density_when_duplicated_lines_are_zero() throws Exception { - addRawMeasure(FILE_1_REF, DUPLICATED_LINES_KEY, 0); - addRawMeasure(FILE_2_REF, DUPLICATED_LINES_KEY, 0); - + public void compute_zero_percent_duplicated_lines_density_when_there_is_no_duplication() throws Exception { addRawMeasure(FILE_1_REF, COMMENT_LINES_KEY, 2); addRawMeasure(FILE_2_REF, COMMENT_LINES_KEY, 10); addRawMeasure(DIRECTORY_REF, COMMENT_LINES_KEY, 12); - addRawMeasure(SUB_MODULE_REF, COMMENT_LINES_KEY, 12); + addRawMeasure(SUB_MODULE_1_REF, COMMENT_LINES_KEY, 12); addRawMeasure(MODULE_REF, COMMENT_LINES_KEY, 12); addRawMeasure(ROOT_REF, COMMENT_LINES_KEY, 12); addRawMeasure(FILE_1_REF, NCLOC_KEY, 8); addRawMeasure(FILE_2_REF, NCLOC_KEY, 30); addRawMeasure(DIRECTORY_REF, NCLOC_KEY, 38); - addRawMeasure(SUB_MODULE_REF, NCLOC_KEY, 38); + addRawMeasure(SUB_MODULE_1_REF, NCLOC_KEY, 38); addRawMeasure(MODULE_REF, NCLOC_KEY, 38); addRawMeasure(ROOT_REF, NCLOC_KEY, 38); @@ -311,8 +377,11 @@ public class ReportDuplicationMeasuresStepTest { assertRawMeasureValue(FILE_1_REF, DUPLICATED_LINES_DENSITY_KEY, 0d); assertRawMeasureValue(FILE_2_REF, DUPLICATED_LINES_DENSITY_KEY, 0d); + assertNoRawMeasure(FILE_3_REF, DUPLICATED_LINES_DENSITY_KEY); + assertNoRawMeasure(FILE_4_REF, DUPLICATED_LINES_DENSITY_KEY); assertRawMeasureValue(DIRECTORY_REF, DUPLICATED_LINES_DENSITY_KEY, 0d); - assertRawMeasureValue(SUB_MODULE_REF, DUPLICATED_LINES_DENSITY_KEY, 0d); + assertRawMeasureValue(SUB_MODULE_1_REF, DUPLICATED_LINES_DENSITY_KEY, 0d); + assertNoRawMeasure(SUB_MODULE_2_REF, DUPLICATED_LINES_DENSITY_KEY); assertRawMeasureValue(MODULE_REF, DUPLICATED_LINES_DENSITY_KEY, 0d); assertRawMeasureValue(ROOT_REF, DUPLICATED_LINES_DENSITY_KEY, 0d); } @@ -322,7 +391,7 @@ public class ReportDuplicationMeasuresStepTest { addRawMeasure(FILE_1_REF, LINES_KEY, 0); addRawMeasure(FILE_2_REF, LINES_KEY, 0); addRawMeasure(DIRECTORY_REF, LINES_KEY, 0); - addRawMeasure(SUB_MODULE_REF, LINES_KEY, 0); + addRawMeasure(SUB_MODULE_1_REF, LINES_KEY, 0); addRawMeasure(MODULE_REF, LINES_KEY, 0); addRawMeasure(ROOT_REF, LINES_KEY, 0); @@ -336,14 +405,14 @@ public class ReportDuplicationMeasuresStepTest { addRawMeasure(FILE_1_REF, COMMENT_LINES_KEY, 0); addRawMeasure(FILE_2_REF, COMMENT_LINES_KEY, 0); addRawMeasure(DIRECTORY_REF, COMMENT_LINES_KEY, 0); - addRawMeasure(SUB_MODULE_REF, COMMENT_LINES_KEY, 0); + addRawMeasure(SUB_MODULE_1_REF, COMMENT_LINES_KEY, 0); addRawMeasure(MODULE_REF, COMMENT_LINES_KEY, 0); addRawMeasure(ROOT_REF, COMMENT_LINES_KEY, 0); addRawMeasure(FILE_1_REF, NCLOC_KEY, 0); addRawMeasure(FILE_2_REF, NCLOC_KEY, 0); addRawMeasure(DIRECTORY_REF, NCLOC_KEY, 0); - addRawMeasure(SUB_MODULE_REF, NCLOC_KEY, 0); + addRawMeasure(SUB_MODULE_1_REF, NCLOC_KEY, 0); addRawMeasure(MODULE_REF, NCLOC_KEY, 0); addRawMeasure(ROOT_REF, NCLOC_KEY, 0); @@ -354,13 +423,13 @@ public class ReportDuplicationMeasuresStepTest { @Test public void compute_100_percent_duplicated_lines_density() throws Exception { - addRawMeasure(FILE_1_REF, DUPLICATED_LINES_KEY, 2); - addRawMeasure(FILE_2_REF, DUPLICATED_LINES_KEY, 3); + addDuplicatedBlock(FILE_1_REF, 2); + addDuplicatedBlock(FILE_2_REF, 3); addRawMeasure(FILE_1_REF, LINES_KEY, 2); addRawMeasure(FILE_2_REF, LINES_KEY, 3); addRawMeasure(DIRECTORY_REF, LINES_KEY, 5); - addRawMeasure(SUB_MODULE_REF, LINES_KEY, 5); + addRawMeasure(SUB_MODULE_1_REF, LINES_KEY, 5); addRawMeasure(MODULE_REF, LINES_KEY, 5); addRawMeasure(ROOT_REF, LINES_KEY, 5); @@ -368,12 +437,28 @@ public class ReportDuplicationMeasuresStepTest { assertRawMeasureValue(FILE_1_REF, DUPLICATED_LINES_DENSITY_KEY, 100d); assertRawMeasureValue(FILE_2_REF, DUPLICATED_LINES_DENSITY_KEY, 100d); + assertNoRawMeasure(FILE_3_REF, DUPLICATED_LINES_DENSITY_KEY); + assertNoRawMeasure(FILE_4_REF, DUPLICATED_LINES_DENSITY_KEY); assertRawMeasureValue(DIRECTORY_REF, DUPLICATED_LINES_DENSITY_KEY, 100d); - assertRawMeasureValue(SUB_MODULE_REF, DUPLICATED_LINES_DENSITY_KEY, 100d); + assertRawMeasureValue(SUB_MODULE_1_REF, DUPLICATED_LINES_DENSITY_KEY, 100d); + assertNoRawMeasure(SUB_MODULE_2_REF, DUPLICATED_LINES_DENSITY_KEY); assertRawMeasureValue(MODULE_REF, DUPLICATED_LINES_DENSITY_KEY, 100d); assertRawMeasureValue(ROOT_REF, DUPLICATED_LINES_DENSITY_KEY, 100d); } + /** + * Adds duplication blocks of a single line (each line is specific to its block). + * + * This is a very simple use case, convenient for unit tests but more realistic and complex use cases must be tested separately. + */ + private void addDuplicatedBlock(int fileRef, int blockCount) { + checkArgument(blockCount > 1, "BlockCount can not be less than 2"); + TextBlock original = new TextBlock(1, 1); + for (int i = 10; i < blockCount + 9; i++) { + duplicationRepository.addDuplication(fileRef, original, new TextBlock(i, i)); + } + } + private void addRawMeasure(int componentRef, String metricKey, int value) { measureRepository.addRawMeasure(componentRef, metricKey, newMeasureBuilder().create(value)); } @@ -382,7 +467,7 @@ public class ReportDuplicationMeasuresStepTest { assertThat(measureRepository.getAddedRawMeasures(FILE_1_REF).get(metricKey)).isEmpty(); assertThat(measureRepository.getAddedRawMeasures(FILE_2_REF).get(metricKey)).isEmpty(); assertThat(measureRepository.getAddedRawMeasures(DIRECTORY_REF).get(metricKey)).isEmpty(); - assertThat(measureRepository.getAddedRawMeasures(SUB_MODULE_REF).get(metricKey)).isEmpty(); + assertThat(measureRepository.getAddedRawMeasures(SUB_MODULE_1_REF).get(metricKey)).isEmpty(); assertThat(measureRepository.getAddedRawMeasures(MODULE_REF).get(metricKey)).isEmpty(); assertThat(measureRepository.getAddedRawMeasures(ROOT_REF).get(metricKey)).isEmpty(); } @@ -399,4 +484,16 @@ public class ReportDuplicationMeasuresStepTest { assertThat(measureRepository.getAddedRawMeasure(componentRef, metricKey).get().getDoubleValue()).isEqualTo(value); } + 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/step/ViewsDuplicationMeasuresStepTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/step/ViewsDuplicationMeasuresStepTest.java index 64dd85ba8f3..e0d626ef3da 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/computation/step/ViewsDuplicationMeasuresStepTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/step/ViewsDuplicationMeasuresStepTest.java @@ -60,15 +60,15 @@ public class ViewsDuplicationMeasuresStepTest { public TreeRootHolderRule treeRootHolder = new TreeRootHolderRule() .setRoot(builder(VIEW, ROOT_REF) .addChildren( - builder(SUBVIEW, SUBVIEW_REF) + builder(SUBVIEW, SUBVIEW_REF) + .addChildren( + builder(SUBVIEW, SUB_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()) + 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 MetricRepositoryRule metricRepository = new MetricRepositoryRule() |