Bladeren bron

SONAR-7952 New metric « Duplicated blocks on new code »

tags/6.1-RC1
Teryk Bellahsene 7 jaren geleden
bovenliggende
commit
d7db41d8ed

+ 62
- 50
server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/step/NewDuplicationMeasuresStep.java Bestand weergeven

@@ -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};
}
}
}

+ 132
- 79
server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/step/ReportNewDuplicationMeasuresStepTest.java Bestand weergeven

@@ -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);
}

}

+ 0
- 153
server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/step/ViewsNewDuplicationMeasuresStepTest.java Bestand weergeven

@@ -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);
}

}

+ 2
- 0
sonar-core/src/main/resources/org/sonar/l10n/core.properties Bestand weergeven

@@ -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

+ 10
- 0
sonar-plugin-api/src/main/java/org/sonar/api/measures/CoreMetrics.java Bestand weergeven

@@ -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";

/**

Laden…
Annuleren
Opslaan