]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-7952 New metric « Duplicated blocks on new code » 1141/head
authorTeryk Bellahsene <teryk.bellahsene@sonarsource.com>
Thu, 11 Aug 2016 07:41:55 +0000 (09:41 +0200)
committerTeryk Bellahsene <teryk.bellahsene@sonarsource.com>
Fri, 12 Aug 2016 13:56:36 +0000 (15:56 +0200)
server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/step/NewDuplicationMeasuresStep.java
server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/step/ReportNewDuplicationMeasuresStepTest.java
server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/step/ViewsNewDuplicationMeasuresStepTest.java [deleted file]
sonar-core/src/main/resources/org/sonar/l10n/core.properties
sonar-plugin-api/src/main/java/org/sonar/api/measures/CoreMetrics.java

index c0de8c85b5fdd6018a677efbd7a0c2e31d01237e..7af5d96b5b330ad65a6869f4b5c366f39bb76c4a 100644 (file)
 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};
     }
   }
 }
index 9fe70a560cf7d7ff694a918896a9ae592f8d4542..d9e38d3d18733d7b8ce142452829e2f9f4377c3e 100644 (file)
 
 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 (file)
index d14f427..0000000
+++ /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);
-  }
-
-}
index 03e7873b2a57b0f85254128f143e36acb7ca3138..24c54a1633ef97d7b3c485199e28f791995e7c4f 100644 (file)
@@ -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
index 11240f588e4061cc0e103ed61336d4eb487b72b6..a576efb753021aa5b7ca8b1b221baca397783f0a 100644 (file)
@@ -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";
 
   /**