aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/DefaultInputFile.java10
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/cpd/internal/DefaultCpdTokens.java24
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/internal/SensorContextTester.java2
-rw-r--r--sonar-plugin-api/src/test/java/org/sonar/api/batch/sensor/cpd/internal/DefaultCpdTokensTest.java55
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/scanner/cpd/JavaCpdBlockIndexerSensor.java23
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ProjectScanContainer.java4
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/AbstractCoverageAndDuplicationExclusions.java (renamed from sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/AbstractCoverageExclusions.java)56
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/FileIndexer.java58
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/ModuleCoverageAndDuplicationExclusions.java (renamed from sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/ModuleCoverageExclusions.java)4
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/ProjectCoverageAndDuplicationExclusions.java (renamed from sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/ProjectCoverageExclusions.java)4
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/ProjectFileIndexer.java30
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/ProjectSensorContext.java2
-rw-r--r--sonar-scanner-engine/src/test/java/org/sonar/scanner/cpd/JavaCpdBlockIndexerSensorTest.java7
-rw-r--r--sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/coverage/CoverageMediumTest.java25
-rw-r--r--sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/cpd/CpdMediumTest.java91
-rw-r--r--sonar-scanner-engine/src/test/java/org/sonar/scanner/phases/ModuleCoverageAndDuplicationExclusionsTest.java (renamed from sonar-scanner-engine/src/test/java/org/sonar/scanner/phases/ModuleCoverageExclusionsTest.java)20
-rw-r--r--sonar-scanner-engine/src/test/java/org/sonar/scanner/phases/ProjectCoverageExclusionsTest.java44
17 files changed, 307 insertions, 152 deletions
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/DefaultInputFile.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/DefaultInputFile.java
index 0b60c5e227c..c0fd7c38bcc 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/DefaultInputFile.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/DefaultInputFile.java
@@ -60,6 +60,7 @@ public class DefaultInputFile extends DefaultInputComponent implements InputFile
private Metadata metadata;
private boolean published;
private boolean excludedForCoverage;
+ private boolean excludedForDuplication;
private final Set<Integer> noSonarLines = new HashSet<>();
private boolean ignoreAllIssues;
private Collection<int[]> ignoreIssuesOnlineRanges = new ArrayList<>();
@@ -127,6 +128,15 @@ public class DefaultInputFile extends DefaultInputComponent implements InputFile
return excludedForCoverage;
}
+ public DefaultInputFile setExcludedForDuplication(boolean excludedForDuplication) {
+ this.excludedForDuplication = excludedForDuplication;
+ return this;
+ }
+
+ public boolean isExcludedForDuplication() {
+ return excludedForDuplication;
+ }
+
/**
* @deprecated since 6.6
*/
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/cpd/internal/DefaultCpdTokens.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/cpd/internal/DefaultCpdTokens.java
index d2cae805cac..a30a4accc76 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/cpd/internal/DefaultCpdTokens.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/cpd/internal/DefaultCpdTokens.java
@@ -19,17 +19,14 @@
*/
package org.sonar.api.batch.sensor.cpd.internal;
-import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
-import org.sonar.api.CoreProperties;
import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.batch.fs.TextRange;
-import org.sonar.api.batch.fs.internal.PathPattern;
+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.config.Configuration;
import static com.google.common.base.Preconditions.checkState;
import static java.util.Collections.unmodifiableList;
@@ -37,7 +34,6 @@ import static java.util.Objects.requireNonNull;
public class DefaultCpdTokens extends DefaultStorable implements NewCpdTokens {
- private final Configuration config;
private final List<TokensLine> result = new ArrayList<>();
private InputFile inputFile;
private int startLine = Integer.MIN_VALUE;
@@ -45,22 +41,14 @@ public class DefaultCpdTokens extends DefaultStorable implements NewCpdTokens {
private int currentIndex = 0;
private StringBuilder sb = new StringBuilder();
private TextRange lastRange;
- private boolean excluded;
- public DefaultCpdTokens(Configuration config, SensorStorage storage) {
+ public DefaultCpdTokens(SensorStorage storage) {
super(storage);
- this.config = config;
}
@Override
public DefaultCpdTokens onFile(InputFile inputFile) {
this.inputFile = requireNonNull(inputFile, "file can't be null");
- String[] cpdExclusions = config.getStringArray(CoreProperties.CPD_EXCLUSIONS);
- for (PathPattern cpdExclusion : PathPattern.create(cpdExclusions)) {
- if (cpdExclusion.match(inputFile.path(), Paths.get(inputFile.relativePath()))) {
- this.excluded = true;
- }
- }
return this;
}
@@ -85,7 +73,7 @@ public class DefaultCpdTokens extends DefaultStorable implements NewCpdTokens {
requireNonNull(range, "Range should not be null");
requireNonNull(image, "Image should not be null");
checkInputFileNotNull();
- if (excluded) {
+ if (isExcludedForDuplication()) {
return this;
}
checkState(lastRange == null || lastRange.end().compareTo(range.start()) <= 0,
@@ -106,6 +94,10 @@ public class DefaultCpdTokens extends DefaultStorable implements NewCpdTokens {
return this;
}
+ private boolean isExcludedForDuplication() {
+ return ((DefaultInputFile) inputFile).isExcludedForDuplication();
+ }
+
public List<TokensLine> getTokenLines() {
return unmodifiableList(new ArrayList<>(result));
}
@@ -120,7 +112,7 @@ public class DefaultCpdTokens extends DefaultStorable implements NewCpdTokens {
@Override
protected void doSave() {
checkState(inputFile != null, "Call onFile() first");
- if (excluded) {
+ if (isExcludedForDuplication()) {
return;
}
addNewTokensLine(result, startIndex, currentIndex, startLine, sb);
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/internal/SensorContextTester.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/internal/SensorContextTester.java
index e8cc9f81b8f..0ee4c211f7b 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/internal/SensorContextTester.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/internal/SensorContextTester.java
@@ -323,7 +323,7 @@ public class SensorContextTester implements SensorContext {
@Override
public NewCpdTokens newCpdTokens() {
- return new DefaultCpdTokens(config(), sensorStorage);
+ return new DefaultCpdTokens(sensorStorage);
}
@Override
diff --git a/sonar-plugin-api/src/test/java/org/sonar/api/batch/sensor/cpd/internal/DefaultCpdTokensTest.java b/sonar-plugin-api/src/test/java/org/sonar/api/batch/sensor/cpd/internal/DefaultCpdTokensTest.java
index 2ccd9fd01cf..44827ebcebb 100644
--- a/sonar-plugin-api/src/test/java/org/sonar/api/batch/sensor/cpd/internal/DefaultCpdTokensTest.java
+++ b/sonar-plugin-api/src/test/java/org/sonar/api/batch/sensor/cpd/internal/DefaultCpdTokensTest.java
@@ -19,12 +19,10 @@
*/
package org.sonar.api.batch.sensor.cpd.internal;
-import java.io.File;
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;
-import org.sonar.api.config.internal.MapSettings;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.fail;
@@ -35,7 +33,7 @@ import static org.mockito.Mockito.verifyZeroInteractions;
public class DefaultCpdTokensTest {
- private static final InputFile INPUT_FILE = new TestInputFileBuilder("foo", "src/Foo.java")
+ private final DefaultInputFile inputFile = new TestInputFileBuilder("foo", "src/Foo.java")
.setLines(2)
.setOriginalLineStartOffsets(new int[] {0, 50})
.setOriginalLineEndOffsets(new int[] {49, 100})
@@ -45,22 +43,22 @@ public class DefaultCpdTokensTest {
@Test
public void save_no_tokens() {
SensorStorage sensorStorage = mock(SensorStorage.class);
- DefaultCpdTokens tokens = new DefaultCpdTokens(new MapSettings().asConfig(), sensorStorage)
- .onFile(INPUT_FILE);
+ DefaultCpdTokens tokens = new DefaultCpdTokens(sensorStorage)
+ .onFile(inputFile);
tokens.save();
verify(sensorStorage).store(tokens);
- assertThat(tokens.inputFile()).isEqualTo(INPUT_FILE);
+ assertThat(tokens.inputFile()).isEqualTo(inputFile);
}
@Test
public void save_one_token() {
SensorStorage sensorStorage = mock(SensorStorage.class);
- DefaultCpdTokens tokens = new DefaultCpdTokens(new MapSettings().asConfig(), sensorStorage)
- .onFile(INPUT_FILE)
- .addToken(INPUT_FILE.newRange(1, 2, 1, 5), "foo");
+ DefaultCpdTokens tokens = new DefaultCpdTokens(sensorStorage)
+ .onFile(inputFile)
+ .addToken(inputFile.newRange(1, 2, 1, 5), "foo");
tokens.save();
@@ -70,13 +68,12 @@ public class DefaultCpdTokensTest {
}
@Test
- public void handle_exclusions_by_pattern() {
+ public void handle_exclusions() {
SensorStorage sensorStorage = mock(SensorStorage.class);
- MapSettings settings = new MapSettings();
- settings.setProperty("sonar.cpd.exclusions", "src/Foo.java,another");
- DefaultCpdTokens tokens = new DefaultCpdTokens(settings.asConfig(), sensorStorage)
- .onFile(INPUT_FILE)
- .addToken(INPUT_FILE.newRange(1, 2, 1, 5), "foo");
+ inputFile.setExcludedForDuplication(true);
+ DefaultCpdTokens tokens = new DefaultCpdTokens(sensorStorage)
+ .onFile(inputFile)
+ .addToken(inputFile.newRange(1, 2, 1, 5), "foo");
tokens.save();
@@ -88,12 +85,12 @@ public class DefaultCpdTokensTest {
@Test
public void save_many_tokens() {
SensorStorage sensorStorage = mock(SensorStorage.class);
- DefaultCpdTokens tokens = new DefaultCpdTokens(new MapSettings().asConfig(), sensorStorage)
- .onFile(INPUT_FILE)
- .addToken(INPUT_FILE.newRange(1, 2, 1, 5), "foo")
- .addToken(INPUT_FILE.newRange(1, 6, 1, 10), "bar")
- .addToken(INPUT_FILE.newRange(1, 20, 1, 25), "biz")
- .addToken(INPUT_FILE.newRange(2, 1, 2, 10), "next");
+ DefaultCpdTokens tokens = new DefaultCpdTokens(sensorStorage)
+ .onFile(inputFile)
+ .addToken(inputFile.newRange(1, 2, 1, 5), "foo")
+ .addToken(inputFile.newRange(1, 6, 1, 10), "bar")
+ .addToken(inputFile.newRange(1, 20, 1, 25), "biz")
+ .addToken(inputFile.newRange(2, 1, 2, 10), "next");
tokens.save();
@@ -109,7 +106,7 @@ public class DefaultCpdTokensTest {
@Test
public void basic_validation() {
SensorStorage sensorStorage = mock(SensorStorage.class);
- DefaultCpdTokens tokens = new DefaultCpdTokens(new MapSettings().asConfig(), sensorStorage);
+ DefaultCpdTokens tokens = new DefaultCpdTokens(sensorStorage);
try {
tokens.save();
fail("Expected exception");
@@ -117,7 +114,7 @@ public class DefaultCpdTokensTest {
assertThat(e).hasMessage("Call onFile() first");
}
try {
- tokens.addToken(INPUT_FILE.newRange(1, 2, 1, 5), "foo");
+ tokens.addToken(inputFile.newRange(1, 2, 1, 5), "foo");
fail("Expected exception");
} catch (Exception e) {
assertThat(e).hasMessage("Call onFile() first");
@@ -129,7 +126,7 @@ public class DefaultCpdTokensTest {
assertThat(e).hasMessage("Range should not be null");
}
try {
- tokens.addToken(INPUT_FILE.newRange(1, 2, 1, 5), null);
+ tokens.addToken(inputFile.newRange(1, 2, 1, 5), null);
fail("Expected exception");
} catch (Exception e) {
assertThat(e).hasMessage("Image should not be null");
@@ -139,12 +136,12 @@ public class DefaultCpdTokensTest {
@Test
public void validate_tokens_order() {
SensorStorage sensorStorage = mock(SensorStorage.class);
- DefaultCpdTokens tokens = new DefaultCpdTokens(new MapSettings().asConfig(), sensorStorage)
- .onFile(INPUT_FILE)
- .addToken(INPUT_FILE.newRange(1, 6, 1, 10), "bar");
+ DefaultCpdTokens tokens = new DefaultCpdTokens(sensorStorage)
+ .onFile(inputFile)
+ .addToken(inputFile.newRange(1, 6, 1, 10), "bar");
try {
- tokens.addToken(INPUT_FILE.newRange(1, 2, 1, 5), "foo");
+ tokens.addToken(inputFile.newRange(1, 2, 1, 5), "foo");
fail("Expected exception");
} catch (Exception e) {
assertThat(e).hasMessage("Tokens of file src/Foo.java should be provided in order.\n" +
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/cpd/JavaCpdBlockIndexerSensor.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/cpd/JavaCpdBlockIndexerSensor.java
index 5770e8869ab..13c59fc40dd 100644
--- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/cpd/JavaCpdBlockIndexerSensor.java
+++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/cpd/JavaCpdBlockIndexerSensor.java
@@ -19,22 +19,23 @@
*/
package org.sonar.scanner.cpd;
-import com.google.common.collect.Lists;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.StreamSupport;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import org.sonar.api.CoreProperties;
import org.sonar.api.batch.Phase;
import org.sonar.api.batch.fs.FilePredicates;
import org.sonar.api.batch.fs.InputFile;
-import org.sonar.api.batch.sensor.Sensor;
+import org.sonar.api.batch.fs.internal.DefaultInputFile;
import org.sonar.api.batch.sensor.SensorContext;
import org.sonar.api.batch.sensor.SensorDescriptor;
+import org.sonar.api.scanner.sensor.ProjectSensor;
import org.sonar.duplications.block.Block;
import org.sonar.duplications.block.BlockChunker;
import org.sonar.duplications.java.JavaStatementBuilder;
@@ -48,7 +49,7 @@ import org.sonar.scanner.cpd.index.SonarCpdBlockIndex;
* Special case for Java that use a dedicated block indexer.
*/
@Phase(name = Phase.Name.POST)
-public class JavaCpdBlockIndexerSensor implements Sensor {
+public class JavaCpdBlockIndexerSensor implements ProjectSensor {
private static final int BLOCK_SIZE = 10;
private static final Logger LOG = LoggerFactory.getLogger(JavaCpdBlockIndexerSensor.class);
@@ -66,12 +67,16 @@ public class JavaCpdBlockIndexerSensor implements Sensor {
@Override
public void execute(SensorContext context) {
- String[] cpdExclusions = context.config().getStringArray(CoreProperties.CPD_EXCLUSIONS);
FilePredicates p = context.fileSystem().predicates();
- List<InputFile> sourceFiles = Lists.newArrayList(context.fileSystem().inputFiles(p.and(
- p.hasType(InputFile.Type.MAIN),
- p.hasLanguage("java"),
- p.doesNotMatchPathPatterns(cpdExclusions))));
+ List<InputFile> sourceFiles = StreamSupport.stream(
+ context.fileSystem().inputFiles(
+ p.and(
+ p.hasType(InputFile.Type.MAIN),
+ p.hasLanguage("java")
+ )
+ ).spliterator(), false)
+ .filter(f -> !((DefaultInputFile) f).isExcludedForDuplication())
+ .collect(Collectors.toList());
if (sourceFiles.isEmpty()) {
return;
}
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ProjectScanContainer.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ProjectScanContainer.java
index 6171c2793de..26b6ffa8079 100644
--- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ProjectScanContainer.java
+++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ProjectScanContainer.java
@@ -109,7 +109,7 @@ import org.sonar.scanner.scan.filesystem.FileIndexer;
import org.sonar.scanner.scan.filesystem.InputComponentStore;
import org.sonar.scanner.scan.filesystem.LanguageDetection;
import org.sonar.scanner.scan.filesystem.MetadataGenerator;
-import org.sonar.scanner.scan.filesystem.ProjectCoverageExclusions;
+import org.sonar.scanner.scan.filesystem.ProjectCoverageAndDuplicationExclusions;
import org.sonar.scanner.scan.filesystem.ProjectExclusionFilters;
import org.sonar.scanner.scan.filesystem.ProjectFileIndexer;
import org.sonar.scanner.scan.filesystem.ScannerComponentIdGenerator;
@@ -244,7 +244,7 @@ public class ProjectScanContainer extends ComponentContainer {
ScannerProperties.class,
new ProjectConfigurationProvider(),
- ProjectCoverageExclusions.class,
+ ProjectCoverageAndDuplicationExclusions.class,
// Report
ScannerMetrics.class,
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/AbstractCoverageExclusions.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/AbstractCoverageAndDuplicationExclusions.java
index 2d1abe07a67..c061aa5add0 100644
--- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/AbstractCoverageExclusions.java
+++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/AbstractCoverageAndDuplicationExclusions.java
@@ -19,11 +19,9 @@
*/
package org.sonar.scanner.scan.filesystem;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableList.Builder;
import java.util.Collection;
-import java.util.Iterator;
import java.util.function.Function;
+import java.util.stream.Stream;
import javax.annotation.concurrent.Immutable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -31,41 +29,59 @@ import org.sonar.api.CoreProperties;
import org.sonar.api.batch.fs.internal.DefaultInputFile;
import org.sonar.api.utils.WildcardPattern;
+import static java.util.stream.Collectors.toList;
+
@Immutable
-public abstract class AbstractCoverageExclusions {
- private static final Logger LOG = LoggerFactory.getLogger(AbstractCoverageExclusions.class);
+public abstract class AbstractCoverageAndDuplicationExclusions {
+ private static final Logger LOG = LoggerFactory.getLogger(AbstractCoverageAndDuplicationExclusions.class);
private final Function<DefaultInputFile, String> pathExtractor;
private final String[] coverageExclusionConfig;
+ private final String[] duplicationExclusionConfig;
- private Collection<WildcardPattern> exclusionPatterns;
+ private final Collection<WildcardPattern> coverageExclusionPatterns;
+ private final Collection<WildcardPattern> duplicationExclusionPatterns;
- public AbstractCoverageExclusions(Function<String, String[]> configProvider, Function<DefaultInputFile, String> pathExtractor) {
+ public AbstractCoverageAndDuplicationExclusions(Function<String, String[]> configProvider, Function<DefaultInputFile, String> pathExtractor) {
this.pathExtractor = pathExtractor;
- Builder<WildcardPattern> builder = ImmutableList.builder();
coverageExclusionConfig = configProvider.apply(CoreProperties.PROJECT_COVERAGE_EXCLUSIONS_PROPERTY);
- for (String pattern : coverageExclusionConfig) {
- builder.add(WildcardPattern.create(pattern));
- }
- exclusionPatterns = builder.build();
+ coverageExclusionPatterns = Stream.of(coverageExclusionConfig).map(WildcardPattern::create).collect(toList());
+ duplicationExclusionConfig = configProvider.apply(CoreProperties.CPD_EXCLUSIONS);
+ duplicationExclusionPatterns = Stream.of(duplicationExclusionConfig).map(WildcardPattern::create).collect(toList());
}
public String[] getCoverageExclusionConfig() {
return coverageExclusionConfig;
}
+ public String[] getDuplicationExclusionConfig() {
+ return duplicationExclusionConfig;
+ }
+
void log() {
- if (!exclusionPatterns.isEmpty()) {
- log("Excluded sources for coverage: ", exclusionPatterns);
+ if (!coverageExclusionPatterns.isEmpty()) {
+ log("Excluded sources for coverage: ", coverageExclusionPatterns);
+ }
+ if (!duplicationExclusionPatterns.isEmpty()) {
+ log("Excluded sources for duplication: ", duplicationExclusionPatterns);
}
}
- public boolean isExcluded(DefaultInputFile file) {
- boolean found = false;
- Iterator<WildcardPattern> iterator = exclusionPatterns.iterator();
- while (!found && iterator.hasNext()) {
- found = iterator.next().match(pathExtractor.apply(file));
+ public boolean isExcludedForCoverage(DefaultInputFile file) {
+ return isExcluded(file, coverageExclusionPatterns);
+ }
+
+ public boolean isExcludedForDuplication(DefaultInputFile file) {
+ return isExcluded(file, duplicationExclusionPatterns);
+ }
+
+ private boolean isExcluded(DefaultInputFile file, Collection<WildcardPattern> patterns) {
+ if (patterns.isEmpty()) {
+ return false;
}
- return found;
+ final String path = pathExtractor.apply(file);
+ return patterns
+ .stream()
+ .anyMatch(p -> p.match(path));
}
private static void log(String title, Collection<WildcardPattern> patterns) {
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/FileIndexer.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/FileIndexer.java
index aba73c172a4..60798fe990b 100644
--- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/FileIndexer.java
+++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/FileIndexer.java
@@ -51,7 +51,7 @@ public class FileIndexer {
private final ScanProperties properties;
private final InputFileFilter[] filters;
private final ProjectExclusionFilters projectExclusionFilters;
- private final ProjectCoverageExclusions projectCoverageExclusions;
+ private final ProjectCoverageAndDuplicationExclusions projectCoverageAndDuplicationExclusions;
private final IssueExclusionsLoader issueExclusionsLoader;
private final MetadataGenerator metadataGenerator;
private final DefaultInputProject project;
@@ -62,15 +62,16 @@ public class FileIndexer {
private boolean warnExclusionsAlreadyLogged;
private boolean warnCoverageExclusionsAlreadyLogged;
+ private boolean warnDuplicationExclusionsAlreadyLogged;
public FileIndexer(DefaultInputProject project, ScannerComponentIdGenerator scannerComponentIdGenerator, InputComponentStore componentStore,
- ProjectExclusionFilters projectExclusionFilters, ProjectCoverageExclusions projectCoverageExclusions, IssueExclusionsLoader issueExclusionsLoader,
- MetadataGenerator metadataGenerator, SensorStrategy sensorStrategy, LanguageDetection languageDetection, AnalysisWarnings analysisWarnings, ScanProperties properties,
- InputFileFilter[] filters) {
+ ProjectExclusionFilters projectExclusionFilters, ProjectCoverageAndDuplicationExclusions projectCoverageAndDuplicationExclusions, IssueExclusionsLoader issueExclusionsLoader,
+ MetadataGenerator metadataGenerator, SensorStrategy sensorStrategy, LanguageDetection languageDetection, AnalysisWarnings analysisWarnings, ScanProperties properties,
+ InputFileFilter[] filters) {
this.project = project;
this.scannerComponentIdGenerator = scannerComponentIdGenerator;
this.componentStore = componentStore;
- this.projectCoverageExclusions = projectCoverageExclusions;
+ this.projectCoverageAndDuplicationExclusions = projectCoverageAndDuplicationExclusions;
this.issueExclusionsLoader = issueExclusionsLoader;
this.metadataGenerator = metadataGenerator;
this.sensorStrategy = sensorStrategy;
@@ -82,17 +83,17 @@ public class FileIndexer {
}
public FileIndexer(DefaultInputProject project, ScannerComponentIdGenerator scannerComponentIdGenerator, InputComponentStore componentStore,
- ProjectExclusionFilters projectExclusionFilters, ProjectCoverageExclusions projectCoverageExclusions, IssueExclusionsLoader issueExclusionsLoader,
- MetadataGenerator metadataGenerator, SensorStrategy sensorStrategy, LanguageDetection languageDetection, AnalysisWarnings analysisWarnings, ScanProperties properties) {
- this(project, scannerComponentIdGenerator, componentStore, projectExclusionFilters, projectCoverageExclusions, issueExclusionsLoader, metadataGenerator, sensorStrategy,
+ ProjectExclusionFilters projectExclusionFilters, ProjectCoverageAndDuplicationExclusions projectCoverageAndDuplicationExclusions, IssueExclusionsLoader issueExclusionsLoader,
+ MetadataGenerator metadataGenerator, SensorStrategy sensorStrategy, LanguageDetection languageDetection, AnalysisWarnings analysisWarnings, ScanProperties properties) {
+ this(project, scannerComponentIdGenerator, componentStore, projectExclusionFilters, projectCoverageAndDuplicationExclusions, issueExclusionsLoader, metadataGenerator, sensorStrategy,
languageDetection,
analysisWarnings,
properties, new InputFileFilter[0]);
}
- public void indexFile(DefaultInputModule module, ModuleExclusionFilters moduleExclusionFilters, ModuleCoverageExclusions moduleCoverageExclusions, Path sourceFile,
- InputFile.Type type, ProgressReport progressReport,
- AtomicInteger excludedByPatternsCount)
+ public void indexFile(DefaultInputModule module, ModuleExclusionFilters moduleExclusionFilters, ModuleCoverageAndDuplicationExclusions moduleCoverageAndDuplicationExclusions, Path sourceFile,
+ InputFile.Type type, ProgressReport progressReport,
+ AtomicInteger excludedByPatternsCount)
throws IOException {
// get case of real file without resolving link
Path realAbsoluteFile = sourceFile.toRealPath(LinkOption.NOFOLLOW_LINKS).toAbsolutePath().normalize();
@@ -136,7 +137,8 @@ public class FileIndexer {
componentStore.put(module.key(), inputFile);
issueExclusionsLoader.addMulticriteriaPatterns(inputFile);
LOG.debug("'{}' indexed {}with language '{}'", projectRelativePath, type == Type.TEST ? "as test " : "", inputFile.language());
- evaluateCoverageExclusions(moduleCoverageExclusions, inputFile);
+ evaluateCoverageExclusions(moduleCoverageAndDuplicationExclusions, inputFile);
+ evaluateDuplicationExclusions(moduleCoverageAndDuplicationExclusions, inputFile);
if (properties.preloadFileMetadata()) {
inputFile.checkMetadata();
}
@@ -151,14 +153,14 @@ public class FileIndexer {
}
}
- private void evaluateCoverageExclusions(ModuleCoverageExclusions moduleCoverageExclusions, DefaultInputFile inputFile) {
- boolean excludedByProjectConfiguration = projectCoverageExclusions.isExcluded(inputFile);
+ private void evaluateCoverageExclusions(ModuleCoverageAndDuplicationExclusions moduleCoverageAndDuplicationExclusions, DefaultInputFile inputFile) {
+ boolean excludedByProjectConfiguration = projectCoverageAndDuplicationExclusions.isExcludedForCoverage(inputFile);
if (excludedByProjectConfiguration) {
inputFile.setExcludedForCoverage(true);
LOG.debug("File {} excluded for coverage", inputFile);
- } else if (moduleCoverageExclusions.isExcluded(inputFile)) {
+ } else if (moduleCoverageAndDuplicationExclusions.isExcludedForCoverage(inputFile)) {
inputFile.setExcludedForCoverage(true);
- if (Arrays.equals(moduleCoverageExclusions.getCoverageExclusionConfig(), projectCoverageExclusions.getCoverageExclusionConfig())) {
+ if (Arrays.equals(moduleCoverageAndDuplicationExclusions.getCoverageExclusionConfig(), projectCoverageAndDuplicationExclusions.getCoverageExclusionConfig())) {
warnOnceDeprecatedCoverageExclusion(
"Specifying module-relative paths at project level in the property '" + CoreProperties.PROJECT_COVERAGE_EXCLUSIONS_PROPERTY + "' is deprecated. " +
"To continue matching files like '" + inputFile + "', update this property so that patterns refer to project-relative paths.");
@@ -167,6 +169,22 @@ public class FileIndexer {
}
}
+ private void evaluateDuplicationExclusions(ModuleCoverageAndDuplicationExclusions moduleCoverageAndDuplicationExclusions, DefaultInputFile inputFile) {
+ boolean excludedByProjectConfiguration = projectCoverageAndDuplicationExclusions.isExcludedForDuplication(inputFile);
+ if (excludedByProjectConfiguration) {
+ inputFile.setExcludedForDuplication(true);
+ LOG.debug("File {} excluded for duplication", inputFile);
+ } else if (moduleCoverageAndDuplicationExclusions.isExcludedForDuplication(inputFile)) {
+ inputFile.setExcludedForDuplication(true);
+ if (Arrays.equals(moduleCoverageAndDuplicationExclusions.getDuplicationExclusionConfig(), projectCoverageAndDuplicationExclusions.getDuplicationExclusionConfig())) {
+ warnOnceDeprecatedDuplicationExclusion(
+ "Specifying module-relative paths at project level in the property '" + CoreProperties.CPD_EXCLUSIONS + "' is deprecated. " +
+ "To continue matching files like '" + inputFile + "', update this property so that patterns refer to project-relative paths.");
+ }
+ LOG.debug("File {} excluded for duplication", inputFile);
+ }
+ }
+
private void warnOnceDeprecatedExclusion(String msg) {
if (!warnExclusionsAlreadyLogged) {
LOG.warn(msg);
@@ -183,6 +201,14 @@ public class FileIndexer {
}
}
+ private void warnOnceDeprecatedDuplicationExclusion(String msg) {
+ if (!warnDuplicationExclusionsAlreadyLogged) {
+ LOG.warn(msg);
+ analysisWarnings.addUnique(msg);
+ warnDuplicationExclusionsAlreadyLogged = true;
+ }
+ }
+
private boolean accept(InputFile indexedFile) {
// InputFileFilter extensions. Might trigger generation of metadata
for (InputFileFilter filter : filters) {
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/ModuleCoverageExclusions.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/ModuleCoverageAndDuplicationExclusions.java
index d49f5aff482..6c9dd27c8d5 100644
--- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/ModuleCoverageExclusions.java
+++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/ModuleCoverageAndDuplicationExclusions.java
@@ -24,9 +24,9 @@ import org.sonar.api.batch.fs.internal.DefaultInputFile;
import org.sonar.scanner.scan.ModuleConfiguration;
@Immutable
-public class ModuleCoverageExclusions extends AbstractCoverageExclusions {
+public class ModuleCoverageAndDuplicationExclusions extends AbstractCoverageAndDuplicationExclusions {
- public ModuleCoverageExclusions(ModuleConfiguration moduleConfiguration) {
+ public ModuleCoverageAndDuplicationExclusions(ModuleConfiguration moduleConfiguration) {
super(moduleConfiguration::getStringArray, DefaultInputFile::getModuleRelativePath);
}
}
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/ProjectCoverageExclusions.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/ProjectCoverageAndDuplicationExclusions.java
index e100450144d..78359037b68 100644
--- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/ProjectCoverageExclusions.java
+++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/ProjectCoverageAndDuplicationExclusions.java
@@ -24,9 +24,9 @@ import org.sonar.api.batch.fs.internal.DefaultInputFile;
import org.sonar.scanner.scan.ProjectConfiguration;
@Immutable
-public class ProjectCoverageExclusions extends AbstractCoverageExclusions {
+public class ProjectCoverageAndDuplicationExclusions extends AbstractCoverageAndDuplicationExclusions {
- public ProjectCoverageExclusions(ProjectConfiguration projectConfig) {
+ public ProjectCoverageAndDuplicationExclusions(ProjectConfiguration projectConfig) {
super(projectConfig::getStringArray, DefaultInputFile::getProjectRelativePath);
log();
}
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/ProjectFileIndexer.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/ProjectFileIndexer.java
index ece4b46784b..1db64920c9e 100644
--- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/ProjectFileIndexer.java
+++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/ProjectFileIndexer.java
@@ -105,9 +105,9 @@ public class ProjectFileIndexer {
// Emulate creation of module level settings
ModuleConfiguration moduleConfig = new ModuleConfigurationProvider().provide(globalConfig, module, projectServerSettings);
ModuleExclusionFilters moduleExclusionFilters = new ModuleExclusionFilters(moduleConfig);
- ModuleCoverageExclusions moduleCoverageExclusions = new ModuleCoverageExclusions(moduleConfig);
- indexFiles(module, moduleExclusionFilters, moduleCoverageExclusions, module.getSourceDirsOrFiles(), Type.MAIN, excludedByPatternsCount);
- indexFiles(module, moduleExclusionFilters, moduleCoverageExclusions, module.getTestDirsOrFiles(), Type.TEST, excludedByPatternsCount);
+ ModuleCoverageAndDuplicationExclusions moduleCoverageAndDuplicationExclusions = new ModuleCoverageAndDuplicationExclusions(moduleConfig);
+ indexFiles(module, moduleExclusionFilters, moduleCoverageAndDuplicationExclusions, module.getSourceDirsOrFiles(), Type.MAIN, excludedByPatternsCount);
+ indexFiles(module, moduleExclusionFilters, moduleCoverageAndDuplicationExclusions, module.getTestDirsOrFiles(), Type.TEST, excludedByPatternsCount);
}
private static void logPaths(String label, Path baseDir, List<Path> paths) {
@@ -139,14 +139,14 @@ public class ProjectFileIndexer {
return count == 1 ? "file" : "files";
}
- private void indexFiles(DefaultInputModule module, ModuleExclusionFilters moduleExclusionFilters, ModuleCoverageExclusions moduleCoverageExclusions, List<Path> sources,
- Type type, AtomicInteger excludedByPatternsCount) {
+ private void indexFiles(DefaultInputModule module, ModuleExclusionFilters moduleExclusionFilters, ModuleCoverageAndDuplicationExclusions moduleCoverageAndDuplicationExclusions, List<Path> sources,
+ Type type, AtomicInteger excludedByPatternsCount) {
try {
for (Path dirOrFile : sources) {
if (dirOrFile.toFile().isDirectory()) {
- indexDirectory(module, moduleExclusionFilters, moduleCoverageExclusions, dirOrFile, type, excludedByPatternsCount);
+ indexDirectory(module, moduleExclusionFilters, moduleCoverageAndDuplicationExclusions, dirOrFile, type, excludedByPatternsCount);
} else {
- fileIndexer.indexFile(module, moduleExclusionFilters, moduleCoverageExclusions, dirOrFile, type, progressReport, excludedByPatternsCount);
+ fileIndexer.indexFile(module, moduleExclusionFilters, moduleCoverageAndDuplicationExclusions, dirOrFile, type, progressReport, excludedByPatternsCount);
}
}
} catch (IOException e) {
@@ -154,25 +154,25 @@ public class ProjectFileIndexer {
}
}
- private void indexDirectory(DefaultInputModule module, ModuleExclusionFilters moduleExclusionFilters, ModuleCoverageExclusions moduleCoverageExclusions, Path dirToIndex,
- Type type, AtomicInteger excludedByPatternsCount)
+ private void indexDirectory(DefaultInputModule module, ModuleExclusionFilters moduleExclusionFilters, ModuleCoverageAndDuplicationExclusions moduleCoverageAndDuplicationExclusions, Path dirToIndex,
+ Type type, AtomicInteger excludedByPatternsCount)
throws IOException {
Files.walkFileTree(dirToIndex.normalize(), Collections.singleton(FileVisitOption.FOLLOW_LINKS), Integer.MAX_VALUE,
- new IndexFileVisitor(module, moduleExclusionFilters, moduleCoverageExclusions, type, excludedByPatternsCount));
+ new IndexFileVisitor(module, moduleExclusionFilters, moduleCoverageAndDuplicationExclusions, type, excludedByPatternsCount));
}
private class IndexFileVisitor implements FileVisitor<Path> {
private final DefaultInputModule module;
private final ModuleExclusionFilters moduleExclusionFilters;
- private final ModuleCoverageExclusions moduleCoverageExclusions;
+ private final ModuleCoverageAndDuplicationExclusions moduleCoverageAndDuplicationExclusions;
private final Type type;
private final AtomicInteger excludedByPatternsCount;
- IndexFileVisitor(DefaultInputModule module, ModuleExclusionFilters moduleExclusionFilters, ModuleCoverageExclusions moduleCoverageExclusions, Type type,
- AtomicInteger excludedByPatternsCount) {
+ IndexFileVisitor(DefaultInputModule module, ModuleExclusionFilters moduleExclusionFilters, ModuleCoverageAndDuplicationExclusions moduleCoverageAndDuplicationExclusions, Type type,
+ AtomicInteger excludedByPatternsCount) {
this.module = module;
this.moduleExclusionFilters = moduleExclusionFilters;
- this.moduleCoverageExclusions = moduleCoverageExclusions;
+ this.moduleCoverageAndDuplicationExclusions = moduleCoverageAndDuplicationExclusions;
this.type = type;
this.excludedByPatternsCount = excludedByPatternsCount;
}
@@ -193,7 +193,7 @@ public class ProjectFileIndexer {
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
if (!Files.isHidden(file)) {
- fileIndexer.indexFile(module, moduleExclusionFilters, moduleCoverageExclusions, file, type, progressReport, excludedByPatternsCount);
+ fileIndexer.indexFile(module, moduleExclusionFilters, moduleCoverageAndDuplicationExclusions, file, type, progressReport, excludedByPatternsCount);
}
return FileVisitResult.CONTINUE;
}
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/ProjectSensorContext.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/ProjectSensorContext.java
index ba2418dd296..3e06892cf84 100644
--- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/ProjectSensorContext.java
+++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/ProjectSensorContext.java
@@ -186,7 +186,7 @@ public class ProjectSensorContext implements SensorContext {
if (analysisMode.isIssues()) {
return NO_OP_NEW_CPD_TOKENS;
}
- return new DefaultCpdTokens(config, sensorStorage);
+ return new DefaultCpdTokens(sensorStorage);
}
@Override
diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/cpd/JavaCpdBlockIndexerSensorTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/cpd/JavaCpdBlockIndexerSensorTest.java
index 203e5b715b0..7a0a2f21695 100644
--- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/cpd/JavaCpdBlockIndexerSensorTest.java
+++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/cpd/JavaCpdBlockIndexerSensorTest.java
@@ -32,8 +32,7 @@ import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
-import org.sonar.api.CoreProperties;
-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.SensorContextTester;
import org.sonar.duplications.block.Block;
@@ -57,7 +56,7 @@ public class JavaCpdBlockIndexerSensorTest {
@Captor
private ArgumentCaptor<List<Block>> blockCaptor;
- private InputFile file;
+ private DefaultInputFile file;
@Before
public void prepare() throws IOException {
@@ -75,7 +74,7 @@ public class JavaCpdBlockIndexerSensorTest {
@Test
public void testExclusions() {
- context.settings().setProperty(CoreProperties.CPD_EXCLUSIONS, "**");
+ file.setExcludedForDuplication(true);
new JavaCpdBlockIndexerSensor(index).execute(context);
verifyZeroInteractions(index);
}
diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/coverage/CoverageMediumTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/coverage/CoverageMediumTest.java
index 9226bf38199..6b622327bcc 100644
--- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/coverage/CoverageMediumTest.java
+++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/coverage/CoverageMediumTest.java
@@ -67,7 +67,6 @@ public class CoverageMediumTest {
AnalysisResult result = tester.newAnalysis()
.properties(ImmutableMap.<String, String>builder()
- .put("sonar.task", "scan")
.put("sonar.projectBaseDir", baseDir.getAbsolutePath())
.put("sonar.projectKey", "com.foo.project")
.put("sonar.sources", "src")
@@ -103,7 +102,6 @@ public class CoverageMediumTest {
AnalysisResult result = tester.newAnalysis()
.properties(ImmutableMap.<String, String>builder()
- .put("sonar.task", "scan")
.put("sonar.projectBaseDir", baseDir.getAbsolutePath())
.put("sonar.projectKey", "com.foo.project")
.put("sonar.sources", "src")
@@ -141,7 +139,6 @@ public class CoverageMediumTest {
AnalysisResult result = tester.newAnalysis()
.properties(ImmutableMap.<String, String>builder()
- .put("sonar.task", "scan")
.put("sonar.projectBaseDir", baseDir.getAbsolutePath())
.put("sonar.projectKey", "com.foo.project")
.put("sonar.sources", "src")
@@ -169,35 +166,34 @@ public class CoverageMediumTest {
File srcDirB = new File(baseDirModuleB, "src");
srcDirB.mkdirs();
- File xooFileA = new File(srcDirA, "sample.xoo");
- File xooUtCoverageFileA = new File(srcDirA, "sample.xoo.coverage");
+ File xooFileA = new File(srcDirA, "sampleA.xoo");
+ File xooUtCoverageFileA = new File(srcDirA, "sampleA.xoo.coverage");
FileUtils.write(xooFileA, "function foo() {\n if (a && b) {\nalert('hello');\n}\n}", StandardCharsets.UTF_8);
FileUtils.write(xooUtCoverageFileA, "2:2:2:1\n3:1", StandardCharsets.UTF_8);
- File xooFileB = new File(srcDirB, "sample.xoo");
- File xooUtCoverageFileB = new File(srcDirB, "sample.xoo.coverage");
+ File xooFileB = new File(srcDirB, "sampleB.xoo");
+ File xooUtCoverageFileB = new File(srcDirB, "sampleB.xoo.coverage");
FileUtils.write(xooFileB, "function foo() {\n if (a && b) {\nalert('hello');\n}\n}", StandardCharsets.UTF_8);
FileUtils.write(xooUtCoverageFileB, "2:2:2:1\n3:1", StandardCharsets.UTF_8);
AnalysisResult result = tester.newAnalysis()
.properties(ImmutableMap.<String, String>builder()
- .put("sonar.task", "scan")
.put("sonar.projectBaseDir", baseDir.getAbsolutePath())
.put("sonar.projectKey", "com.foo.project")
.put("sonar.sources", "src")
.put("sonar.modules", "moduleA,moduleB")
- .put("sonar.coverage.exclusions", "src/sample.xoo")
+ .put("sonar.coverage.exclusions", "src/sampleA.xoo")
.build())
.execute();
- InputFile fileA = result.inputFile("moduleA/src/sample.xoo");
+ InputFile fileA = result.inputFile("moduleA/src/sampleA.xoo");
assertThat(result.coverageFor(fileA, 2)).isNull();
- InputFile fileB = result.inputFile("moduleB/src/sample.xoo");
- assertThat(result.coverageFor(fileB, 2)).isNull();
+ InputFile fileB = result.inputFile("moduleB/src/sampleB.xoo");
+ assertThat(result.coverageFor(fileB, 2)).isNotNull();
assertThat(logTester.logs(LoggerLevel.WARN)).contains("Specifying module-relative paths at project level in the property 'sonar.coverage.exclusions' is deprecated. " +
- "To continue matching files like 'moduleA/src/sample.xoo', update this property so that patterns refer to project-relative paths.");
+ "To continue matching files like 'moduleA/src/sampleA.xoo', update this property so that patterns refer to project-relative paths.");
}
@Test
@@ -225,7 +221,6 @@ public class CoverageMediumTest {
AnalysisResult result = tester.newAnalysis()
.properties(ImmutableMap.<String, String>builder()
- .put("sonar.task", "scan")
.put("sonar.projectBaseDir", baseDir.getAbsolutePath())
.put("sonar.projectKey", "com.foo.project")
.put("sonar.sources", "src")
@@ -257,7 +252,6 @@ public class CoverageMediumTest {
AnalysisResult result = tester.newAnalysis()
.properties(ImmutableMap.<String, String>builder()
- .put("sonar.task", "scan")
.put("sonar.projectBaseDir", baseDir.getAbsolutePath())
.put("sonar.projectKey", "com.foo.project")
.put("sonar.sources", "src")
@@ -302,7 +296,6 @@ public class CoverageMediumTest {
AnalysisResult result = tester.newAnalysis()
.properties(ImmutableMap.<String, String>builder()
- .put("sonar.task", "scan")
.put("sonar.projectBaseDir", baseDir.getAbsolutePath())
.put("sonar.projectKey", "com.foo.project")
.put("sonar.modules", "module1")
diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/cpd/CpdMediumTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/cpd/CpdMediumTest.java
index e31dfbb1b4e..d8900cfa569 100644
--- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/cpd/CpdMediumTest.java
+++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/cpd/CpdMediumTest.java
@@ -32,6 +32,7 @@ import org.junit.rules.ExpectedException;
import org.junit.rules.TemporaryFolder;
import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.utils.log.LogTester;
+import org.sonar.api.utils.log.LoggerLevel;
import org.sonar.scanner.mediumtest.ScannerMediumTester;
import org.sonar.scanner.mediumtest.AnalysisResult;
import org.sonar.scanner.protocol.output.ScannerReport;
@@ -263,6 +264,96 @@ public class CpdMediumTest {
}
@Test
+ public void cross_module_duplication() throws IOException {
+
+ String duplicatedStuff = "Sample xoo\ncontent\n"
+ + "foo\nbar\ntoto\ntiti\n"
+ + "foo\nbar\ntoto\ntiti\n"
+ + "bar\ntoto\ntiti\n"
+ + "foo\nbar\ntoto\ntiti";
+
+ File baseDir = temp.getRoot();
+ File baseDirModuleA = new File(baseDir, "moduleA");
+ File baseDirModuleB = new File(baseDir, "moduleB");
+ File srcDirA = new File(baseDirModuleA, "src");
+ srcDirA.mkdirs();
+ File srcDirB = new File(baseDirModuleB, "src");
+ srcDirB.mkdirs();
+
+ File xooFileA = new File(srcDirA, "sampleA.xoo");
+ FileUtils.write(xooFileA, duplicatedStuff, StandardCharsets.UTF_8);
+
+ File xooFileB = new File(srcDirB, "sampleB.xoo");
+ FileUtils.write(xooFileB, duplicatedStuff, StandardCharsets.UTF_8);
+
+ AnalysisResult result = tester.newAnalysis()
+ .properties(ImmutableMap.<String, String>builder()
+ .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
+ .put("sonar.projectKey", "com.foo.project")
+ .put("sonar.sources", "src")
+ .put("sonar.modules", "moduleA,moduleB")
+ .put("sonar.cpd.xoo.minimumTokens", "10")
+ .build())
+ .execute();
+
+ InputFile inputFile1 = result.inputFile("moduleA/src/sampleA.xoo");
+ InputFile inputFile2 = result.inputFile("moduleB/src/sampleB.xoo");
+
+ List<ScannerReport.Duplication> duplicationGroupsFile1 = result.duplicationsFor(inputFile1);
+ assertThat(duplicationGroupsFile1).isNotEmpty();
+
+ List<ScannerReport.Duplication> duplicationGroupsFile2 = result.duplicationsFor(inputFile2);
+ assertThat(duplicationGroupsFile2).isNotEmpty();
+ }
+
+ @Test
+ public void warn_user_for_outdated_inherited_scanner_side_exclusions_for_multi_module_project() throws IOException {
+
+ String duplicatedStuff = "Sample xoo\ncontent\n"
+ + "foo\nbar\ntoto\ntiti\n"
+ + "foo\nbar\ntoto\ntiti\n"
+ + "bar\ntoto\ntiti\n"
+ + "foo\nbar\ntoto\ntiti";
+
+ File baseDir = temp.getRoot();
+ File baseDirModuleA = new File(baseDir, "moduleA");
+ File baseDirModuleB = new File(baseDir, "moduleB");
+ File srcDirA = new File(baseDirModuleA, "src");
+ srcDirA.mkdirs();
+ File srcDirB = new File(baseDirModuleB, "src");
+ srcDirB.mkdirs();
+
+ File xooFileA = new File(srcDirA, "sampleA.xoo");
+ FileUtils.write(xooFileA, duplicatedStuff, StandardCharsets.UTF_8);
+
+ File xooFileB = new File(srcDirB, "sampleB.xoo");
+ FileUtils.write(xooFileB, duplicatedStuff, StandardCharsets.UTF_8);
+
+ AnalysisResult result = tester.newAnalysis()
+ .properties(ImmutableMap.<String, String>builder()
+ .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
+ .put("sonar.projectKey", "com.foo.project")
+ .put("sonar.sources", "src")
+ .put("sonar.modules", "moduleA,moduleB")
+ .put("sonar.cpd.xoo.minimumTokens", "10")
+ .put("sonar.cpd.exclusions", "src/sampleA.xoo")
+ .build())
+ .execute();
+
+ InputFile inputFile1 = result.inputFile("moduleA/src/sampleA.xoo");
+ InputFile inputFile2 = result.inputFile("moduleB/src/sampleB.xoo");
+
+ List<ScannerReport.Duplication> duplicationGroupsFile1 = result.duplicationsFor(inputFile1);
+ assertThat(duplicationGroupsFile1).isEmpty();
+
+ List<ScannerReport.Duplication> duplicationGroupsFile2 = result.duplicationsFor(inputFile2);
+ assertThat(duplicationGroupsFile2).isEmpty();
+
+ assertThat(logTester.logs(LoggerLevel.WARN)).contains("Specifying module-relative paths at project level in the property 'sonar.cpd.exclusions' is deprecated. " +
+ "To continue matching files like 'moduleA/src/sampleA.xoo', update this property so that patterns refer to project-relative paths.");
+ }
+
+ @Test
public void enableCrossProjectDuplication() throws IOException {
File srcDir = new File(baseDir, "src");
srcDir.mkdir();
diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/phases/ModuleCoverageExclusionsTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/phases/ModuleCoverageAndDuplicationExclusionsTest.java
index 7a3287dd882..63239c0924a 100644
--- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/phases/ModuleCoverageExclusionsTest.java
+++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/phases/ModuleCoverageAndDuplicationExclusionsTest.java
@@ -24,21 +24,22 @@ import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
+import org.sonar.api.CoreProperties;
import org.sonar.api.batch.fs.internal.DefaultInputFile;
import org.sonar.api.batch.fs.internal.TestInputFileBuilder;
import org.sonar.scanner.scan.ModuleConfiguration;
-import org.sonar.scanner.scan.filesystem.ModuleCoverageExclusions;
+import org.sonar.scanner.scan.filesystem.ModuleCoverageAndDuplicationExclusions;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
-public class ModuleCoverageExclusionsTest {
+public class ModuleCoverageAndDuplicationExclusionsTest {
@Rule
public TemporaryFolder temp = new TemporaryFolder();
- private ModuleCoverageExclusions coverageExclusions;
+ private ModuleCoverageAndDuplicationExclusions coverageExclusions;
private File baseDir;
@Before
@@ -51,8 +52,8 @@ public class ModuleCoverageExclusionsTest {
DefaultInputFile file = TestInputFileBuilder.create("foo", new File(baseDir, "moduleA"), new File(baseDir, "moduleA/src/org/polop/File.php"))
.setProjectBaseDir(baseDir.toPath())
.build();
- coverageExclusions = new ModuleCoverageExclusions(mockConfig("src/org/polop/*"));
- assertThat(coverageExclusions.isExcluded(file)).isTrue();
+ coverageExclusions = new ModuleCoverageAndDuplicationExclusions(mockConfig("src/org/polop/*", ""));
+ assertThat(coverageExclusions.isExcludedForCoverage(file)).isTrue();
}
@Test
@@ -60,13 +61,14 @@ public class ModuleCoverageExclusionsTest {
DefaultInputFile file = TestInputFileBuilder.create("foo", new File(baseDir, "moduleA"), new File(baseDir, "moduleA/src/org/polop/File.php"))
.setProjectBaseDir(baseDir.toPath())
.build();
- coverageExclusions = new ModuleCoverageExclusions(mockConfig("src/org/other/*"));
- assertThat(coverageExclusions.isExcluded(file)).isFalse();
+ coverageExclusions = new ModuleCoverageAndDuplicationExclusions(mockConfig("src/org/other/*", ""));
+ assertThat(coverageExclusions.isExcludedForCoverage(file)).isFalse();
}
- private ModuleConfiguration mockConfig(String... values) {
+ private ModuleConfiguration mockConfig(String coverageExclusions, String cpdExclusions) {
ModuleConfiguration config = mock(ModuleConfiguration.class);
- when(config.getStringArray("sonar.coverage.exclusions")).thenReturn(values);
+ when(config.getStringArray(CoreProperties.PROJECT_COVERAGE_EXCLUSIONS_PROPERTY)).thenReturn(new String[] {coverageExclusions});
+ when(config.getStringArray(CoreProperties.CPD_EXCLUSIONS)).thenReturn(new String[] {cpdExclusions});
return config;
}
}
diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/phases/ProjectCoverageExclusionsTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/phases/ProjectCoverageExclusionsTest.java
index 822c44b6c03..df7fe533b6f 100644
--- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/phases/ProjectCoverageExclusionsTest.java
+++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/phases/ProjectCoverageExclusionsTest.java
@@ -24,10 +24,11 @@ import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
+import org.sonar.api.CoreProperties;
import org.sonar.api.batch.fs.internal.DefaultInputFile;
import org.sonar.api.batch.fs.internal.TestInputFileBuilder;
import org.sonar.scanner.scan.ProjectConfiguration;
-import org.sonar.scanner.scan.filesystem.ProjectCoverageExclusions;
+import org.sonar.scanner.scan.filesystem.ProjectCoverageAndDuplicationExclusions;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
@@ -38,7 +39,7 @@ public class ProjectCoverageExclusionsTest {
@Rule
public TemporaryFolder temp = new TemporaryFolder();
- private ProjectCoverageExclusions coverageExclusions;
+ private ProjectCoverageAndDuplicationExclusions underTest;
private File baseDir;
@Before
@@ -47,26 +48,49 @@ public class ProjectCoverageExclusionsTest {
}
@Test
- public void shouldExcludeFileBasedOnPattern() {
+ public void shouldExcludeFileCoverageBasedOnPattern() {
DefaultInputFile file = TestInputFileBuilder.create("foo", new File(baseDir, "moduleA"), new File(baseDir, "moduleA/src/org/polop/File.php"))
.setProjectBaseDir(baseDir.toPath())
.build();
- coverageExclusions = new ProjectCoverageExclusions(mockConfig("moduleA/src/org/polop/*"));
- assertThat(coverageExclusions.isExcluded(file)).isTrue();
+ underTest = new ProjectCoverageAndDuplicationExclusions(mockConfig("moduleA/src/org/polop/*", ""));
+ assertThat(underTest.isExcludedForCoverage(file)).isTrue();
+ assertThat(underTest.isExcludedForDuplication(file)).isFalse();
}
@Test
- public void shouldNotExcludeFileBasedOnPattern() {
+ public void shouldNotExcludeFileCoverageBasedOnPattern() {
DefaultInputFile file = TestInputFileBuilder.create("foo", new File(baseDir, "moduleA"), new File(baseDir, "moduleA/src/org/polop/File.php"))
.setProjectBaseDir(baseDir.toPath())
.build();
- coverageExclusions = new ProjectCoverageExclusions(mockConfig("moduleA/src/org/other/*"));
- assertThat(coverageExclusions.isExcluded(file)).isFalse();
+ underTest = new ProjectCoverageAndDuplicationExclusions(mockConfig("moduleA/src/org/other/*", ""));
+ assertThat(underTest.isExcludedForCoverage(file)).isFalse();
+ assertThat(underTest.isExcludedForDuplication(file)).isFalse();
}
- private ProjectConfiguration mockConfig(String... values) {
+ @Test
+ public void shouldExcludeFileDuplicationBasedOnPattern() {
+ DefaultInputFile file = TestInputFileBuilder.create("foo", new File(baseDir, "moduleA"), new File(baseDir, "moduleA/src/org/polop/File.php"))
+ .setProjectBaseDir(baseDir.toPath())
+ .build();
+ underTest = new ProjectCoverageAndDuplicationExclusions(mockConfig("", "moduleA/src/org/polop/*"));
+ assertThat(underTest.isExcludedForCoverage(file)).isFalse();
+ assertThat(underTest.isExcludedForDuplication(file)).isTrue();
+ }
+
+ @Test
+ public void shouldNotExcludeFileDuplicationBasedOnPattern() {
+ DefaultInputFile file = TestInputFileBuilder.create("foo", new File(baseDir, "moduleA"), new File(baseDir, "moduleA/src/org/polop/File.php"))
+ .setProjectBaseDir(baseDir.toPath())
+ .build();
+ underTest = new ProjectCoverageAndDuplicationExclusions(mockConfig("", "moduleA/src/org/other/*"));
+ assertThat(underTest.isExcludedForCoverage(file)).isFalse();
+ assertThat(underTest.isExcludedForDuplication(file)).isFalse();
+ }
+
+ private ProjectConfiguration mockConfig(String coverageExclusions, String cpdExclusions) {
ProjectConfiguration config = mock(ProjectConfiguration.class);
- when(config.getStringArray("sonar.coverage.exclusions")).thenReturn(values);
+ when(config.getStringArray(CoreProperties.PROJECT_COVERAGE_EXCLUSIONS_PROPERTY)).thenReturn(new String[] {coverageExclusions});
+ when(config.getStringArray(CoreProperties.CPD_EXCLUSIONS)).thenReturn(new String[] {cpdExclusions});
return config;
}