@@ -37,7 +37,6 @@ import org.sonar.ce.task.projectanalysis.measure.Measure; | |||
import org.sonar.ce.task.projectanalysis.measure.MeasureRepository; | |||
import org.sonar.ce.task.projectanalysis.metric.MetricRepository; | |||
import static com.google.common.collect.FluentIterable.from; | |||
import static com.google.common.collect.Iterables.isEmpty; | |||
import static java.util.Objects.requireNonNull; | |||
import static org.sonar.api.measures.CoreMetrics.DUPLICATED_BLOCKS_KEY; | |||
@@ -88,10 +87,6 @@ public class DuplicationMeasures { | |||
protected int dupLineCount = 0; | |||
protected int lineCount = 0; | |||
protected DuplicationCounter() { | |||
this(null); | |||
} | |||
private DuplicationCounter(@Nullable DuplicationRepository duplicationRepository) { | |||
this.duplicationRepository = duplicationRepository; | |||
} | |||
@@ -107,7 +102,7 @@ public class DuplicationMeasures { | |||
@Override | |||
public void initialize(CounterInitializationContext context) { | |||
Component leaf = context.getLeaf(); | |||
if (leaf.getType() == Component.Type.FILE) { | |||
if (leaf.getType() == Component.Type.FILE && !leaf.getFileAttributes().isUnitTest()) { | |||
initializeForFile(leaf); | |||
} else if (leaf.getType() == Component.Type.PROJECT_VIEW) { | |||
initializeForProjectView(context); | |||
@@ -129,7 +124,12 @@ public class DuplicationMeasures { | |||
for (Duplication duplication : duplications) { | |||
blocks++; | |||
addLines(duplication.getOriginal(), duplicatedLineNumbers); | |||
for (InnerDuplicate innerDuplicate : from(duplication.getDuplicates()).filter(InnerDuplicate.class)) { | |||
InnerDuplicate[] innerDuplicates = duplication.getDuplicates().stream() | |||
.filter(x -> x instanceof InnerDuplicate) | |||
.map(d -> (InnerDuplicate) d) | |||
.toArray(InnerDuplicate[]::new); | |||
for (InnerDuplicate innerDuplicate : innerDuplicates) { | |||
blocks++; | |||
addLines(innerDuplicate.getTextBlock(), duplicatedLineNumbers); | |||
} |
@@ -19,6 +19,7 @@ | |||
*/ | |||
package org.sonar.ce.task.projectanalysis.duplication; | |||
import org.junit.Before; | |||
import org.junit.Rule; | |||
import org.junit.Test; | |||
import org.sonar.ce.task.projectanalysis.component.FileAttributes; | |||
@@ -51,10 +52,13 @@ public class DuplicationMeasuresTest { | |||
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 int FILE_5_REF = 1263; | |||
private static final FileAttributes FILE_1_ATTRS = mock(FileAttributes.class); | |||
private static final FileAttributes FILE_2_ATTRS = mock(FileAttributes.class); | |||
private static final FileAttributes FILE_3_ATTRS = mock(FileAttributes.class); | |||
private static final FileAttributes FILE_4_ATTRS = mock(FileAttributes.class); | |||
private static final FileAttributes FILE_5_ATTRS = mock(FileAttributes.class); | |||
private static final String SOME_FILE_KEY = "some file key"; | |||
@@ -69,7 +73,8 @@ public class DuplicationMeasuresTest { | |||
builder(FILE, FILE_2_REF).setFileAttributes(FILE_2_ATTRS).build()) | |||
.build(), | |||
builder(FILE, FILE_3_REF).setFileAttributes(FILE_3_ATTRS).build(), | |||
builder(FILE, FILE_4_REF).setFileAttributes(FILE_4_ATTRS).build()) | |||
builder(FILE, FILE_4_REF).setFileAttributes(FILE_4_ATTRS).build(), | |||
builder(FILE, FILE_5_REF).setFileAttributes(FILE_5_ATTRS).build()) | |||
.build()); | |||
@Rule | |||
public MetricRepositoryRule metricRepository = new MetricRepositoryRule() | |||
@@ -84,6 +89,11 @@ public class DuplicationMeasuresTest { | |||
private DuplicationMeasures underTest = new DuplicationMeasures(treeRootHolder, metricRepository, measureRepository, duplicationRepository); | |||
@Before | |||
public void before() { | |||
when(FILE_5_ATTRS.isUnitTest()).thenReturn(true); | |||
} | |||
@Test | |||
public void compute_duplicated_blocks_one_for_original_one_for_each_InnerDuplicate() { | |||
TextBlock original = new TextBlock(1, 1); | |||
@@ -94,6 +104,18 @@ public class DuplicationMeasuresTest { | |||
assertRawMeasureValue(FILE_1_REF, DUPLICATED_BLOCKS_KEY, 4); | |||
} | |||
@Test | |||
public void dont_compute_duplicated_blocks_for_test_files() { | |||
duplicationRepository.addDuplication(FILE_5_REF, new TextBlock(1, 1), new TextBlock(3, 3)); | |||
duplicationRepository.addDuplication(FILE_5_REF, new TextBlock(2, 2), new TextBlock(3, 3)); | |||
underTest.execute(); | |||
assertRawMeasureValue(FILE_5_REF, DUPLICATED_BLOCKS_KEY, 0); | |||
assertRawMeasureValue(FILE_5_REF, DUPLICATED_FILES_KEY, 0); | |||
} | |||
@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)); | |||
@@ -250,6 +272,9 @@ public class DuplicationMeasuresTest { | |||
when(FILE_1_ATTRS.getLines()).thenReturn(10); | |||
when(FILE_2_ATTRS.getLines()).thenReturn(40); | |||
// this should have no effect as it's a test file | |||
when(FILE_5_ATTRS.getLines()).thenReturn(1_000_000); | |||
underTest.execute(); | |||
assertRawMeasureValue(FILE_1_REF, DUPLICATED_LINES_DENSITY_KEY, 20d); | |||
@@ -276,7 +301,7 @@ public class DuplicationMeasuresTest { | |||
} | |||
@Test | |||
public void not_compute_duplicated_lines_density_when_lines_is_zero() { | |||
public void dont_compute_duplicated_lines_density_when_lines_is_zero() { | |||
when(FILE_1_ATTRS.getLines()).thenReturn(0); | |||
when(FILE_2_ATTRS.getLines()).thenReturn(0); | |||
underTest.execute(); |
@@ -27,20 +27,23 @@ import org.sonar.api.batch.fs.internal.DefaultInputFile; | |||
import org.sonar.api.batch.sensor.cpd.NewCpdTokens; | |||
import org.sonar.api.batch.sensor.internal.DefaultStorable; | |||
import org.sonar.api.batch.sensor.internal.SensorStorage; | |||
import org.sonar.api.utils.log.Logger; | |||
import org.sonar.api.utils.log.Loggers; | |||
import static com.google.common.base.Preconditions.checkState; | |||
import static java.util.Collections.unmodifiableList; | |||
import static java.util.Objects.requireNonNull; | |||
public class DefaultCpdTokens extends DefaultStorable implements NewCpdTokens { | |||
private static final Logger LOG = Loggers.get(DefaultCpdTokens.class); | |||
private final List<TokensLine> result = new ArrayList<>(); | |||
private InputFile inputFile; | |||
private DefaultInputFile inputFile; | |||
private int startLine = Integer.MIN_VALUE; | |||
private int startIndex = 0; | |||
private int currentIndex = 0; | |||
private StringBuilder sb = new StringBuilder(); | |||
private TextRange lastRange; | |||
private boolean loggedTestCpdWarning = false; | |||
public DefaultCpdTokens(SensorStorage storage) { | |||
super(storage); | |||
@@ -48,7 +51,7 @@ public class DefaultCpdTokens extends DefaultStorable implements NewCpdTokens { | |||
@Override | |||
public DefaultCpdTokens onFile(InputFile inputFile) { | |||
this.inputFile = requireNonNull(inputFile, "file can't be null"); | |||
this.inputFile = (DefaultInputFile) requireNonNull(inputFile, "file can't be null"); | |||
return this; | |||
} | |||
@@ -79,8 +82,6 @@ public class DefaultCpdTokens extends DefaultStorable implements NewCpdTokens { | |||
checkState(lastRange == null || lastRange.end().compareTo(range.start()) <= 0, | |||
"Tokens of file %s should be provided in order.\nPrevious token: %s\nLast token: %s", inputFile, lastRange, range); | |||
String value = image; | |||
int line = range.start().line(); | |||
if (line != startLine) { | |||
addNewTokensLine(result, startIndex, currentIndex, startLine, sb); | |||
@@ -88,14 +89,24 @@ public class DefaultCpdTokens extends DefaultStorable implements NewCpdTokens { | |||
startLine = line; | |||
} | |||
currentIndex++; | |||
sb.append(value); | |||
sb.append(image); | |||
lastRange = range; | |||
return this; | |||
} | |||
private boolean isExcludedForDuplication() { | |||
return ((DefaultInputFile) inputFile).isExcludedForDuplication(); | |||
if (inputFile.isExcludedForDuplication()) { | |||
return true; | |||
} | |||
if (inputFile.type() == InputFile.Type.TEST) { | |||
if (!loggedTestCpdWarning) { | |||
LOG.warn("Duplication reported for '{}' will be ignored because it's a test file.", inputFile); | |||
loggedTestCpdWarning = true; | |||
} | |||
return true; | |||
} | |||
return false; | |||
} | |||
public List<TokensLine> getTokenLines() { |
@@ -20,6 +20,7 @@ | |||
package org.sonar.api.batch.sensor.cpd.internal; | |||
import org.junit.Test; | |||
import org.sonar.api.batch.fs.InputFile; | |||
import org.sonar.api.batch.fs.internal.DefaultInputFile; | |||
import org.sonar.api.batch.fs.internal.TestInputFileBuilder; | |||
import org.sonar.api.batch.sensor.internal.SensorStorage; | |||
@@ -32,6 +33,7 @@ import static org.mockito.Mockito.verify; | |||
import static org.mockito.Mockito.verifyZeroInteractions; | |||
public class DefaultCpdTokensTest { | |||
private final SensorStorage sensorStorage = mock(SensorStorage.class); | |||
private final DefaultInputFile inputFile = new TestInputFileBuilder("foo", "src/Foo.java") | |||
.setLines(2) | |||
@@ -42,7 +44,6 @@ public class DefaultCpdTokensTest { | |||
@Test | |||
public void save_no_tokens() { | |||
SensorStorage sensorStorage = mock(SensorStorage.class); | |||
DefaultCpdTokens tokens = new DefaultCpdTokens(sensorStorage) | |||
.onFile(inputFile); | |||
@@ -55,7 +56,6 @@ public class DefaultCpdTokensTest { | |||
@Test | |||
public void save_one_token() { | |||
SensorStorage sensorStorage = mock(SensorStorage.class); | |||
DefaultCpdTokens tokens = new DefaultCpdTokens(sensorStorage) | |||
.onFile(inputFile) | |||
.addToken(inputFile.newRange(1, 2, 1, 5), "foo"); | |||
@@ -69,7 +69,6 @@ public class DefaultCpdTokensTest { | |||
@Test | |||
public void handle_exclusions() { | |||
SensorStorage sensorStorage = mock(SensorStorage.class); | |||
inputFile.setExcludedForDuplication(true); | |||
DefaultCpdTokens tokens = new DefaultCpdTokens(sensorStorage) | |||
.onFile(inputFile) | |||
@@ -82,9 +81,27 @@ public class DefaultCpdTokensTest { | |||
assertThat(tokens.getTokenLines()).isEmpty(); | |||
} | |||
@Test | |||
public void dont_save_for_test_files() { | |||
DefaultInputFile testInputFile = new TestInputFileBuilder("foo", "src/Foo.java") | |||
.setLines(2) | |||
.setOriginalLineStartOffsets(new int[] {0, 50}) | |||
.setOriginalLineEndOffsets(new int[] {49, 100}) | |||
.setLastValidOffset(101) | |||
.setType(InputFile.Type.TEST) | |||
.build(); | |||
DefaultCpdTokens tokens = new DefaultCpdTokens(sensorStorage) | |||
.onFile(testInputFile) | |||
.addToken(testInputFile.newRange(1, 2, 1, 5), "foo"); | |||
tokens.save(); | |||
verifyZeroInteractions(sensorStorage); | |||
assertThat(tokens.getTokenLines()).isEmpty(); | |||
} | |||
@Test | |||
public void save_many_tokens() { | |||
SensorStorage sensorStorage = mock(SensorStorage.class); | |||
DefaultCpdTokens tokens = new DefaultCpdTokens(sensorStorage) | |||
.onFile(inputFile) | |||
.addToken(inputFile.newRange(1, 2, 1, 5), "foo") |