From 964fff7ca9f072e6e084c0fac605980f19bc0278 Mon Sep 17 00:00:00 2001 From: Duarte Meneses Date: Wed, 5 Apr 2017 14:21:53 +0200 Subject: [PATCH] SONAR-9025 Optimize computation issue exclusions --- .../IssueExclusionsTest.java | 2 +- .../api/batch/fs/internal/FileMetadata.java | 31 +++- .../scan/issue/filter/FilterableIssue.java | 5 + .../org/sonar/scanner/issue/ModuleIssues.java | 13 +- .../issue/ignore/EnforceIssuesFilter.java | 27 ++- .../issue/ignore/IgnoreIssuesFilter.java | 7 +- .../pattern/AbstractPatternInitializer.java | 10 +- .../ignore/pattern/BlockIssuePattern.java | 38 ++++ .../IssueExclusionPatternInitializer.java | 37 ++-- .../IssueInclusionPatternInitializer.java | 15 -- .../issue/ignore/pattern/IssuePattern.java | 92 +++------- .../issue/ignore/pattern/LineRange.java | 24 ++- .../issue/ignore/pattern/PatternDecoder.java | 81 +++------ .../issue/ignore/pattern/PatternMatcher.java | 38 ++-- .../ignore/scanner/IssueExclusionsLoader.java | 98 ++++++---- .../scanner/IssueExclusionsRegexpScanner.java | 168 +++++++----------- .../scanner/phases/AbstractPhaseExecutor.java | 15 +- .../scanner/phases/IssuesPhaseExecutor.java | 5 +- .../scanner/phases/PublishPhaseExecutor.java | 5 +- .../scanner/scan/ModuleScanContainer.java | 4 +- .../scan/filesystem/MetadataGenerator.java | 10 +- .../filesystem/MetadataGeneratorProvider.java | 6 +- .../sonar/scanner/issue/ModuleIssuesTest.java | 9 +- .../issue/ignore/EnforceIssuesFilterTest.java | 17 +- .../issue/ignore/IgnoreIssuesFilterTest.java | 13 +- .../IssueExclusionPatternInitializerTest.java | 53 ++---- .../IssueInclusionPatternInitializerTest.java | 9 - .../ignore/pattern/IssuePatternTest.java | 39 ++-- .../ignore/pattern/PatternDecoderTest.java | 131 -------------- .../ignore/pattern/PatternMatcherTest.java | 44 ++--- .../scanner/IssueExclusionsLoaderTest.java | 162 +++++------------ .../IssueExclusionsRegexpScannerTest.java | 118 ++++++------ .../mediumtest/fs/FileSystemMediumTest.java | 11 +- .../MetadataGeneratorProviderTest.java | 6 +- .../filesystem/MetadataGeneratorTest.java | 7 +- .../file-with-single-regexp-last-line.txt | 33 ++++ .../file-with-single-regexp.txt | 6 +- 37 files changed, 555 insertions(+), 834 deletions(-) create mode 100644 sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/pattern/BlockIssuePattern.java create mode 100644 sonar-scanner-engine/src/test/resources/org/sonar/scanner/issue/ignore/scanner/IssueExclusionsRegexpScannerTest/file-with-single-regexp-last-line.txt diff --git a/it/it-tests/src/test/java/it/analysisExclusion/IssueExclusionsTest.java b/it/it-tests/src/test/java/it/analysisExclusion/IssueExclusionsTest.java index 42e9951edef..46292024bd5 100644 --- a/it/it-tests/src/test/java/it/analysisExclusion/IssueExclusionsTest.java +++ b/it/it-tests/src/test/java/it/analysisExclusion/IssueExclusionsTest.java @@ -258,6 +258,6 @@ public class IssueExclusionsTest { private void checkAnalysisFails(String... properties) { BuildResult buildResult = scan(properties); assertThat(buildResult.getStatus()).isNotEqualTo(0); - assertThat(buildResult.getLogs().indexOf("SonarException")).isGreaterThan(0); + assertThat(buildResult.getLogs().indexOf("IllegalStateException")).isGreaterThan(0); } } diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/FileMetadata.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/FileMetadata.java index cf962b2c796..4ddcf1d8d4e 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/FileMetadata.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/FileMetadata.java @@ -33,8 +33,10 @@ import java.nio.charset.CharsetEncoder; import java.nio.charset.CodingErrorAction; import java.nio.charset.StandardCharsets; import java.security.MessageDigest; + import javax.annotation.CheckForNull; import javax.annotation.Nullable; + import org.apache.commons.codec.binary.Hex; import org.apache.commons.codec.digest.DigestUtils; import org.apache.commons.io.ByteOrderMark; @@ -270,15 +272,26 @@ public class FileMetadata { * Compute hash of a file ignoring line ends differences. * Maximum performance is needed. */ - public Metadata readMetadata(File file, Charset encoding) { + public Metadata readMetadata(File file, Charset encoding, @Nullable CharHandler otherHandler) { LineCounter lineCounter = new LineCounter(file, encoding); FileHashComputer fileHashComputer = new FileHashComputer(file); LineOffsetCounter lineOffsetCounter = new LineOffsetCounter(); - readFile(file, encoding, lineCounter, fileHashComputer, lineOffsetCounter); + + if (otherHandler != null) { + CharHandler[] handlers = {lineCounter, fileHashComputer, lineOffsetCounter, otherHandler}; + readFile(file, encoding, handlers); + } else { + CharHandler[] handlers = {lineCounter, fileHashComputer, lineOffsetCounter}; + readFile(file, encoding, handlers); + } return new Metadata(lineCounter.lines(), lineCounter.nonBlankLines(), fileHashComputer.getHash(), lineOffsetCounter.getOriginalLineOffsets(), lineOffsetCounter.getLastValidOffset()); } + public Metadata readMetadata(File file, Charset encoding) { + return readMetadata(file, encoding, null); + } + /** * For testing purpose */ @@ -286,16 +299,18 @@ public class FileMetadata { LineCounter lineCounter = new LineCounter(new File("fromString"), StandardCharsets.UTF_16); FileHashComputer fileHashComputer = new FileHashComputer(new File("fromString")); LineOffsetCounter lineOffsetCounter = new LineOffsetCounter(); + CharHandler[] handlers = {lineCounter, fileHashComputer, lineOffsetCounter}; + try { - read(reader, lineCounter, fileHashComputer, lineOffsetCounter); + read(reader, handlers); } catch (IOException e) { - throw new IllegalStateException("Should never occurs", e); + throw new IllegalStateException("Should never occur", e); } return new Metadata(lineCounter.lines(), lineCounter.nonBlankLines(), fileHashComputer.getHash(), lineOffsetCounter.getOriginalLineOffsets(), lineOffsetCounter.getLastValidOffset()); } - public static void readFile(File file, Charset encoding, CharHandler... handlers) { + public static void readFile(File file, Charset encoding, CharHandler[] handlers) { try (BOMInputStream bomIn = new BOMInputStream(new FileInputStream(file), ByteOrderMark.UTF_8, ByteOrderMark.UTF_16LE, ByteOrderMark.UTF_16BE, ByteOrderMark.UTF_32LE, ByteOrderMark.UTF_32BE); Reader reader = new BufferedReader(new InputStreamReader(bomIn, encoding))) { @@ -305,7 +320,7 @@ public class FileMetadata { } } - private static void read(Reader reader, CharHandler... handlers) throws IOException { + private static void read(Reader reader, CharHandler[] handlers) throws IOException { char c; int i = reader.read(); boolean afterCR = false; @@ -354,15 +369,13 @@ public class FileMetadata { @FunctionalInterface public interface LineHashConsumer { - void consume(int lineIdx, @Nullable byte[] hash); - } /** * Compute a MD5 hash of each line of the file after removing of all blank chars */ public static void computeLineHashesForIssueTracking(InputFile f, LineHashConsumer consumer) { - readFile(f.file(), f.charset(), new LineHashComputer(consumer, f.file())); + readFile(f.file(), f.charset(), new CharHandler[] {new LineHashComputer(consumer, f.file())}); } } diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/scan/issue/filter/FilterableIssue.java b/sonar-plugin-api/src/main/java/org/sonar/api/scan/issue/filter/FilterableIssue.java index 2068d49a24b..6928b75e036 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/scan/issue/filter/FilterableIssue.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/scan/issue/filter/FilterableIssue.java @@ -20,6 +20,9 @@ package org.sonar.api.scan.issue.filter; import java.util.Date; + +import javax.annotation.CheckForNull; + import org.sonar.api.rule.RuleKey; /** @@ -35,6 +38,7 @@ public interface FilterableIssue { String message(); + @CheckForNull Integer line(); /** @@ -46,6 +50,7 @@ public interface FilterableIssue { /** * @since 5.5 */ + @CheckForNull Double gap(); Date creationDate(); diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ModuleIssues.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ModuleIssues.java index 5e34e44d6be..958b1e63843 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ModuleIssues.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ModuleIssues.java @@ -21,7 +21,6 @@ package org.sonar.scanner.issue; import com.google.common.base.Strings; -import org.sonar.api.batch.fs.InputFile; import org.sonar.api.batch.fs.TextRange; import org.sonar.api.batch.fs.internal.DefaultInputComponent; import org.sonar.api.batch.rule.ActiveRule; @@ -32,7 +31,6 @@ import org.sonar.api.batch.sensor.issue.Issue; import org.sonar.api.batch.sensor.issue.Issue.Flow; import org.sonar.api.rule.RuleKey; import org.sonar.api.utils.MessageException; -import org.sonar.scanner.issue.ignore.scanner.IssueExclusionsLoader; import org.sonar.scanner.protocol.Constants.Severity; import org.sonar.scanner.protocol.output.ScannerReport; import org.sonar.scanner.protocol.output.ScannerReport.IssueLocation; @@ -47,14 +45,12 @@ public class ModuleIssues { private final Rules rules; private final IssueFilters filters; private final ReportPublisher reportPublisher; - private final IssueExclusionsLoader issueExclusionsLoader; - public ModuleIssues(ActiveRules activeRules, Rules rules, IssueFilters filters, ReportPublisher reportPublisher, IssueExclusionsLoader issueExclusionsLoader) { + public ModuleIssues(ActiveRules activeRules, Rules rules, IssueFilters filters, ReportPublisher reportPublisher) { this.activeRules = activeRules; this.rules = rules; this.filters = filters; this.reportPublisher = reportPublisher; - this.issueExclusionsLoader = issueExclusionsLoader; } public boolean initAndAddIssue(Issue issue) { @@ -93,13 +89,6 @@ public class ModuleIssues { applyFlows(builder, locationBuilder, textRangeBuilder, issue); ScannerReport.Issue rawIssue = builder.build(); - if (issueExclusionsLoader.shouldExecute() && inputComponent.isFile()) { - InputFile inputFile = (InputFile) inputComponent; - if (!issueExclusionsLoader.isLoaded(inputFile)) { - issueExclusionsLoader.loadFile(inputFile); - } - } - if (filters.accept(inputComponent.key(), rawIssue)) { write(inputComponent.batchId(), rawIssue); return true; diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/EnforceIssuesFilter.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/EnforceIssuesFilter.java index b22aa81a516..5c6e4caf409 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/EnforceIssuesFilter.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/EnforceIssuesFilter.java @@ -19,22 +19,29 @@ */ package org.sonar.scanner.issue.ignore; +import org.sonar.api.batch.fs.InputComponent; +import org.sonar.api.batch.fs.InputFile; import org.sonar.api.scan.issue.filter.FilterableIssue; + +import javax.annotation.CheckForNull; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.sonar.api.scan.issue.filter.IssueFilter; import org.sonar.api.scan.issue.filter.IssueFilterChain; import org.sonar.scanner.issue.ignore.pattern.IssueInclusionPatternInitializer; import org.sonar.scanner.issue.ignore.pattern.IssuePattern; +import org.sonar.scanner.scan.filesystem.InputComponentStore; public class EnforceIssuesFilter implements IssueFilter { + private static final Logger LOG = LoggerFactory.getLogger(EnforceIssuesFilter.class); private IssueInclusionPatternInitializer patternInitializer; + private InputComponentStore componentStore; - private static final Logger LOG = LoggerFactory.getLogger(EnforceIssuesFilter.class); - - public EnforceIssuesFilter(IssueInclusionPatternInitializer patternInitializer) { + public EnforceIssuesFilter(IssueInclusionPatternInitializer patternInitializer, InputComponentStore componentStore) { this.patternInitializer = patternInitializer; + this.componentStore = componentStore; } @Override @@ -46,8 +53,8 @@ public class EnforceIssuesFilter implements IssueFilter { for (IssuePattern pattern : patternInitializer.getMulticriteriaPatterns()) { if (pattern.getRulePattern().match(issue.ruleKey().toString())) { atLeastOneRuleMatched = true; - String pathForComponent = patternInitializer.getPathForComponent(issue.componentKey()); - if (pathForComponent != null && pattern.getResourcePattern().match(pathForComponent)) { + String relativePath = getRelativePath(issue.componentKey()); + if (relativePath != null && pattern.getResourcePattern().match(relativePath)) { atLeastOnePatternFullyMatched = true; matchingPattern = pattern; } @@ -63,4 +70,14 @@ public class EnforceIssuesFilter implements IssueFilter { return chain.accept(issue); } } + + @CheckForNull + private String getRelativePath(String componentKey) { + InputComponent component = componentStore.getByKey(componentKey); + if (component == null || !component.isFile()) { + return null; + } + InputFile inputPath = (InputFile) component; + return inputPath.relativePath(); + } } diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/IgnoreIssuesFilter.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/IgnoreIssuesFilter.java index 0eaf1193cb6..0c543eab505 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/IgnoreIssuesFilter.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/IgnoreIssuesFilter.java @@ -24,7 +24,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.sonar.api.scan.issue.filter.IssueFilter; import org.sonar.api.scan.issue.filter.IssueFilterChain; -import org.sonar.scanner.issue.ignore.pattern.IssueExclusionPatternInitializer; import org.sonar.scanner.issue.ignore.pattern.IssuePattern; import org.sonar.scanner.issue.ignore.pattern.PatternMatcher; @@ -34,8 +33,8 @@ public class IgnoreIssuesFilter implements IssueFilter { private static final Logger LOG = LoggerFactory.getLogger(IgnoreIssuesFilter.class); - public IgnoreIssuesFilter(IssueExclusionPatternInitializer patternInitializer) { - this.patternMatcher = patternInitializer.getPatternMatcher(); + public IgnoreIssuesFilter(PatternMatcher patternMatcher) { + this.patternMatcher = patternMatcher; } @Override @@ -48,7 +47,7 @@ public class IgnoreIssuesFilter implements IssueFilter { } private boolean hasMatchFor(FilterableIssue issue) { - IssuePattern pattern = patternMatcher.getMatchingPattern(issue); + IssuePattern pattern = patternMatcher.getMatchingPattern(issue.componentKey(), issue.ruleKey(), issue.line()); if (pattern != null) { logExclusion(issue, pattern); return true; diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/pattern/AbstractPatternInitializer.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/pattern/AbstractPatternInitializer.java index 765085967d6..b77a921e27f 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/pattern/AbstractPatternInitializer.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/pattern/AbstractPatternInitializer.java @@ -26,14 +26,13 @@ import org.sonar.api.config.Settings; import java.util.ArrayList; import java.util.List; +import java.util.Set; import static com.google.common.base.MoreObjects.firstNonNull; @ScannerSide public abstract class AbstractPatternInitializer { - private Settings settings; - private List multicriteriaPatterns; protected AbstractPatternInitializer(Settings settings) { @@ -57,8 +56,6 @@ public abstract class AbstractPatternInitializer { return !multicriteriaPatterns.isEmpty(); } - public abstract void initializePatternsForPath(String relativePath, String componentKey); - @VisibleForTesting protected final void initPatterns() { // Patterns Multicriteria @@ -71,8 +68,9 @@ public abstract class AbstractPatternInitializer { String lineRange = "*"; String[] fields = new String[] {resourceKeyPattern, ruleKeyPattern, lineRange}; PatternDecoder.checkRegularLineConstraints(StringUtils.join(fields, ","), fields); - IssuePattern pattern = new IssuePattern(firstNonNull(resourceKeyPattern, "*"), firstNonNull(ruleKeyPattern, "*")); - PatternDecoder.decodeRangeOfLines(pattern, firstNonNull(lineRange, "*")); + Set rangeOfLines = PatternDecoder.decodeRangeOfLines(firstNonNull(lineRange, "*")); + IssuePattern pattern = new IssuePattern(firstNonNull(resourceKeyPattern, "*"), firstNonNull(ruleKeyPattern, "*"), rangeOfLines); + multicriteriaPatterns.add(pattern); } } diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/pattern/BlockIssuePattern.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/pattern/BlockIssuePattern.java new file mode 100644 index 00000000000..e221a70ef91 --- /dev/null +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/pattern/BlockIssuePattern.java @@ -0,0 +1,38 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 SonarSource SA + * mailto:info 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.scanner.issue.ignore.pattern; + +public class BlockIssuePattern { + private String beginBlockRegexp; + private String endBlockRegexp; + + public BlockIssuePattern(String beginBlockRegexp, String endBlockRegexp) { + this.beginBlockRegexp = beginBlockRegexp; + this.endBlockRegexp = endBlockRegexp; + } + + public String getBeginBlockRegexp() { + return beginBlockRegexp; + } + + public String getEndBlockRegexp() { + return endBlockRegexp; + } +} diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/pattern/IssueExclusionPatternInitializer.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/pattern/IssueExclusionPatternInitializer.java index 55aac19be3f..37d16ef51c5 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/pattern/IssueExclusionPatternInitializer.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/pattern/IssueExclusionPatternInitializer.java @@ -19,25 +19,23 @@ */ package org.sonar.scanner.issue.ignore.pattern; -import com.google.common.annotations.VisibleForTesting; import org.apache.commons.lang.StringUtils; import org.sonar.api.config.Settings; import org.sonar.core.config.IssueExclusionProperties; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import static com.google.common.base.Strings.nullToEmpty; public class IssueExclusionPatternInitializer extends AbstractPatternInitializer { - private List blockPatterns; - private List allFilePatterns; - private PatternMatcher patternMatcher; + private List blockPatterns; + private List allFilePatterns; public IssueExclusionPatternInitializer(Settings settings) { super(settings); - patternMatcher = new PatternMatcher(); loadFileContentPatterns(); } @@ -46,26 +44,12 @@ public class IssueExclusionPatternInitializer extends AbstractPatternInitializer return "sonar.issue.ignore" + ".multicriteria"; } - public PatternMatcher getPatternMatcher() { - return patternMatcher; - } - - @Override - public void initializePatternsForPath(String relativePath, String componentKey) { - for (IssuePattern pattern : getMulticriteriaPatterns()) { - if (pattern.matchResource(relativePath)) { - getPatternMatcher().addPatternForComponent(componentKey, pattern); - } - } - } - @Override public boolean hasConfiguredPatterns() { return hasFileContentPattern() || hasMulticriteriaPatterns(); } - @VisibleForTesting - protected final void loadFileContentPatterns() { + private final void loadFileContentPatterns() { // Patterns Block blockPatterns = new ArrayList<>(); String patternConf = StringUtils.defaultIfBlank(getSettings().getString(IssueExclusionProperties.PATTERNS_BLOCK_KEY), ""); @@ -73,11 +57,12 @@ public class IssueExclusionPatternInitializer extends AbstractPatternInitializer String propPrefix = IssueExclusionProperties.PATTERNS_BLOCK_KEY + "." + id + "."; String beginBlockRegexp = getSettings().getString(propPrefix + IssueExclusionProperties.BEGIN_BLOCK_REGEXP); String endBlockRegexp = getSettings().getString(propPrefix + IssueExclusionProperties.END_BLOCK_REGEXP); - String[] fields = new String[]{beginBlockRegexp, endBlockRegexp}; + String[] fields = new String[] {beginBlockRegexp, endBlockRegexp}; PatternDecoder.checkDoubleRegexpLineConstraints(StringUtils.join(fields, ","), fields); - IssuePattern pattern = new IssuePattern().setBeginBlockRegexp(nullToEmpty(beginBlockRegexp)).setEndBlockRegexp(nullToEmpty(endBlockRegexp)); + BlockIssuePattern pattern = new BlockIssuePattern(nullToEmpty(beginBlockRegexp), nullToEmpty(endBlockRegexp)); blockPatterns.add(pattern); } + blockPatterns = Collections.unmodifiableList(blockPatterns); // Patterns All File allFilePatterns = new ArrayList<>(); @@ -86,16 +71,16 @@ public class IssueExclusionPatternInitializer extends AbstractPatternInitializer String propPrefix = IssueExclusionProperties.PATTERNS_ALLFILE_KEY + "." + id + "."; String allFileRegexp = getSettings().getString(propPrefix + IssueExclusionProperties.FILE_REGEXP); PatternDecoder.checkWholeFileRegexp(allFileRegexp); - IssuePattern pattern = new IssuePattern().setAllFileRegexp(nullToEmpty(allFileRegexp)); - allFilePatterns.add(pattern); + allFilePatterns.add(nullToEmpty(allFileRegexp)); } + allFilePatterns = Collections.unmodifiableList(allFilePatterns); } - public List getBlockPatterns() { + public List getBlockPatterns() { return blockPatterns; } - public List getAllFilePatterns() { + public List getAllFilePatterns() { return allFilePatterns; } diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/pattern/IssueInclusionPatternInitializer.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/pattern/IssueInclusionPatternInitializer.java index c674c45aaff..7e3992e493c 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/pattern/IssueInclusionPatternInitializer.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/pattern/IssueInclusionPatternInitializer.java @@ -19,31 +19,16 @@ */ package org.sonar.scanner.issue.ignore.pattern; -import com.google.common.collect.Maps; import org.sonar.api.config.Settings; -import java.util.Map; - public class IssueInclusionPatternInitializer extends AbstractPatternInitializer { - private Map pathForComponent; - public IssueInclusionPatternInitializer(Settings settings) { super(settings); - pathForComponent = Maps.newHashMap(); } @Override protected String getMulticriteriaConfigurationKey() { return "sonar.issue.enforce" + ".multicriteria"; } - - @Override - public void initializePatternsForPath(String relativePath, String componentKey) { - pathForComponent.put(componentKey, relativePath); - } - - public String getPathForComponent(String componentKey) { - return pathForComponent.get(componentKey); - } } diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/pattern/IssuePattern.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/pattern/IssuePattern.java index 14867725dcd..9ef0d64c9d4 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/pattern/IssuePattern.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/pattern/IssuePattern.java @@ -20,36 +20,39 @@ package org.sonar.scanner.issue.ignore.pattern; import com.google.common.collect.Sets; + +import java.util.Collections; +import java.util.LinkedHashSet; import java.util.Set; import javax.annotation.Nullable; import org.apache.commons.lang.builder.ToStringBuilder; import org.apache.commons.lang.builder.ToStringStyle; import org.sonar.api.rule.RuleKey; -import org.sonar.api.scan.issue.filter.FilterableIssue; import org.sonar.api.utils.WildcardPattern; public class IssuePattern { - private WildcardPattern resourcePattern; - private WildcardPattern rulePattern; - private Set lines = Sets.newLinkedHashSet(); - private Set lineRanges = Sets.newLinkedHashSet(); - private String beginBlockRegexp; - private String endBlockRegexp; - private String allFileRegexp; - private boolean checkLines = true; - - public IssuePattern() { - } + private final WildcardPattern resourcePattern; + private final WildcardPattern rulePattern; + private final Set lines = new LinkedHashSet<>(); + private final Set lineRanges = new LinkedHashSet<>(); + private final boolean checkLines; public IssuePattern(String resourcePattern, String rulePattern) { - this.resourcePattern = WildcardPattern.create(resourcePattern); - this.rulePattern = WildcardPattern.create(rulePattern); + this(resourcePattern, rulePattern, Collections.emptySet()); } public IssuePattern(String resourcePattern, String rulePattern, Set lineRanges) { - this(resourcePattern, rulePattern); - this.lineRanges = lineRanges; + this.resourcePattern = WildcardPattern.create(resourcePattern); + this.rulePattern = WildcardPattern.create(rulePattern); + this.checkLines = !lineRanges.isEmpty(); + for (LineRange range : lineRanges) { + if (range.from() == range.to()) { + this.lines.add(range.from()); + } else { + this.lineRanges.add(range); + } + } } public WildcardPattern getResourcePattern() { @@ -60,52 +63,10 @@ public class IssuePattern { return rulePattern; } - public String getBeginBlockRegexp() { - return beginBlockRegexp; - } - - public String getEndBlockRegexp() { - return endBlockRegexp; - } - - public String getAllFileRegexp() { - return allFileRegexp; - } - - IssuePattern addLineRange(int fromLineId, int toLineId) { - lineRanges.add(new LineRange(fromLineId, toLineId)); - return this; - } - - IssuePattern addLine(int lineId) { - lines.add(lineId); - return this; - } - boolean isCheckLines() { return checkLines; } - IssuePattern setCheckLines(boolean b) { - this.checkLines = b; - return this; - } - - IssuePattern setBeginBlockRegexp(String beginBlockRegexp) { - this.beginBlockRegexp = beginBlockRegexp; - return this; - } - - IssuePattern setEndBlockRegexp(String endBlockRegexp) { - this.endBlockRegexp = endBlockRegexp; - return this; - } - - IssuePattern setAllFileRegexp(String allFileRegexp) { - this.allFileRegexp = allFileRegexp; - return this; - } - Set getAllLines() { Set allLines = Sets.newLinkedHashSet(lines); for (LineRange lineRange : lineRanges) { @@ -114,18 +75,15 @@ public class IssuePattern { return allLines; } - public boolean match(FilterableIssue issue) { - boolean match = matchResource(issue.componentKey()) - && matchRule(issue.ruleKey()); + public boolean match(@Nullable String componentKey, RuleKey ruleKey, @Nullable Integer line) { if (checkLines) { - Integer line = issue.line(); if (line == null) { - match = false; + return false; } else { - match = match && matchLine(line); + return matchResource(componentKey) && matchRule(ruleKey) && matchLine(line); } } - return match; + return matchResource(componentKey) && matchRule(ruleKey); } boolean matchLine(int lineId) { @@ -147,12 +105,12 @@ public class IssuePattern { return rulePattern.match(key); } - boolean matchResource(@Nullable String resource) { + public boolean matchResource(@Nullable String resource) { return resource != null && resourcePattern.match(resource); } public IssuePattern forResource(String resource) { - return new IssuePattern(resource, rulePattern.toString(), lineRanges).setCheckLines(isCheckLines()); + return new IssuePattern(resource, rulePattern.toString(), lineRanges); } @Override diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/pattern/LineRange.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/pattern/LineRange.java index 0c76bd5cf2a..b252484fb7a 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/pattern/LineRange.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/pattern/LineRange.java @@ -28,8 +28,12 @@ public class LineRange { private int from; private int to; + public LineRange(int line) { + this(line, line); + } + public LineRange(int from, int to) { - Preconditions.checkArgument(from <= to, "Line range is not valid: %s must be greater than %s", from, to); + Preconditions.checkArgument(from <= to, "Line range is not valid: %s must be greater or equal than %s", to, from); this.from = from; this.to = to; @@ -40,13 +44,21 @@ public class LineRange { } public Set toLines() { - Set lines = new LinkedHashSet<>(to-from+1); + Set lines = new LinkedHashSet<>(to - from + 1); for (int index = from; index <= to; index++) { lines.add(index); } return lines; } + public int from() { + return from; + } + + public int to() { + return to; + } + @Override public String toString() { return "[" + from + "-" + to + "]"; @@ -79,12 +91,6 @@ public class LineRange { } private boolean fieldsDiffer(LineRange other) { - if (from != other.from) { - return true; - } - if (to != other.to) { - return true; - } - return false; + return from != other.from || to != other.to; } } diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/pattern/PatternDecoder.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/pattern/PatternDecoder.java index 32fde5bdd0a..f0ce08b2a19 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/pattern/PatternDecoder.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/pattern/PatternDecoder.java @@ -19,100 +19,64 @@ */ package org.sonar.scanner.issue.ignore.pattern; -import com.google.common.annotations.VisibleForTesting; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + import org.apache.commons.lang.StringUtils; -import org.sonar.api.utils.SonarException; -import java.util.LinkedList; -import java.util.List; +import com.google.common.annotations.VisibleForTesting; public class PatternDecoder { - - private static final int THREE_FIELDS_PER_LINE = 3; private static final String LINE_RANGE_REGEXP = "\\[((\\d+|\\d+-\\d+),?)*\\]"; private static final String CONFIG_FORMAT_ERROR_PREFIX = "Exclusions > Issues : Invalid format. "; - public List decode(String patternsList) { - List patterns = new LinkedList<>(); - String[] patternsLines = StringUtils.split(patternsList, "\n"); - for (String patternLine : patternsLines) { - IssuePattern pattern = decodeLine(patternLine.trim()); - if (pattern != null) { - patterns.add(pattern); - } - } - return patterns; + private PatternDecoder() { + // static only } - - /** - * Main method that decodes a line which defines a pattern - */ - public IssuePattern decodeLine(String line) { - if (isBlankOrComment(line)) { - return null; - } - - String[] fields = StringUtils.splitPreserveAllTokens(line, ';'); - if (fields.length > THREE_FIELDS_PER_LINE) { - throw new SonarException(CONFIG_FORMAT_ERROR_PREFIX + "The following line has more than 3 fields separated by comma: " + line); - } - - IssuePattern pattern; - if (fields.length == THREE_FIELDS_PER_LINE) { - checkRegularLineConstraints(line, fields); - pattern = new IssuePattern(StringUtils.trim(fields[0]), StringUtils.trim(fields[1])); - decodeRangeOfLines(pattern, fields[2]); - } else if (fields.length == 2) { - checkDoubleRegexpLineConstraints(line, fields); - pattern = new IssuePattern().setBeginBlockRegexp(fields[0]).setEndBlockRegexp(fields[1]); - } else { - checkWholeFileRegexp(fields[0]); - pattern = new IssuePattern().setAllFileRegexp(fields[0]); - } - - return pattern; - } - + static void checkRegularLineConstraints(String line, String[] fields) { if (!isResource(fields[0])) { - throw new SonarException(CONFIG_FORMAT_ERROR_PREFIX + "The first field does not define a resource pattern: " + line); + throw new IllegalStateException(CONFIG_FORMAT_ERROR_PREFIX + "The first field does not define a resource pattern: " + line); } if (!isRule(fields[1])) { - throw new SonarException(CONFIG_FORMAT_ERROR_PREFIX + "The second field does not define a rule pattern: " + line); + throw new IllegalStateException(CONFIG_FORMAT_ERROR_PREFIX + "The second field does not define a rule pattern: " + line); } if (!isLinesRange(fields[2])) { - throw new SonarException(CONFIG_FORMAT_ERROR_PREFIX + "The third field does not define a range of lines: " + line); + throw new IllegalStateException(CONFIG_FORMAT_ERROR_PREFIX + "The third field does not define a range of lines: " + line); } } static void checkDoubleRegexpLineConstraints(String line, String[] fields) { if (!isRegexp(fields[0])) { - throw new SonarException(CONFIG_FORMAT_ERROR_PREFIX + "The first field does not define a regular expression: " + line); + throw new IllegalStateException(CONFIG_FORMAT_ERROR_PREFIX + "The first field does not define a regular expression: " + line); } // As per configuration help, missing second field means: from start regexp to EOF } static void checkWholeFileRegexp(String regexp) { if (!isRegexp(regexp)) { - throw new SonarException(CONFIG_FORMAT_ERROR_PREFIX + "The field does not define a regular expression: " + regexp); + throw new IllegalStateException(CONFIG_FORMAT_ERROR_PREFIX + "The field does not define a regular expression: " + regexp); } } - public static void decodeRangeOfLines(IssuePattern pattern, String field) { + public static Set decodeRangeOfLines(String field) { if (StringUtils.equals(field, "*")) { - pattern.setCheckLines(false); + return Collections.emptySet(); } else { - pattern.setCheckLines(true); + Set lineRanges = new HashSet<>(); + String s = StringUtils.substringBetween(StringUtils.trim(field), "[", "]"); String[] parts = StringUtils.split(s, ','); for (String part : parts) { if (StringUtils.contains(part, '-')) { String[] range = StringUtils.split(part, '-'); - pattern.addLineRange(Integer.valueOf(range[0]), Integer.valueOf(range[1])); + lineRanges.add(new LineRange(Integer.valueOf(range[0]), Integer.valueOf(range[1]))); } else { - pattern.addLine(Integer.valueOf(part)); + lineRanges.add(new LineRange(Integer.valueOf(part), Integer.valueOf(part))); } } + return lineRanges; } } @@ -121,11 +85,6 @@ public class PatternDecoder { return StringUtils.equals(field, "*") || java.util.regex.Pattern.matches(LINE_RANGE_REGEXP, field); } - @VisibleForTesting - static boolean isBlankOrComment(String line) { - return StringUtils.isBlank(line) ^ StringUtils.startsWith(line, "#"); - } - @VisibleForTesting static boolean isResource(String field) { return StringUtils.isNotBlank(field); diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/pattern/PatternMatcher.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/pattern/PatternMatcher.java index 02149148258..2d008410cbe 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/pattern/PatternMatcher.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/pattern/PatternMatcher.java @@ -19,45 +19,47 @@ */ package org.sonar.scanner.issue.ignore.pattern; -import org.sonar.api.scan.issue.filter.FilterableIssue; +import org.sonar.api.rule.RuleKey; +import com.google.common.annotations.VisibleForTesting; import com.google.common.collect.LinkedHashMultimap; import com.google.common.collect.Multimap; import java.util.Collection; -import java.util.Iterator; import java.util.Set; +import javax.annotation.CheckForNull; +import javax.annotation.Nullable; + public class PatternMatcher { - private Multimap patternByComponent = LinkedHashMultimap.create(); + private Multimap excludePatternByComponent = LinkedHashMultimap.create(); - public IssuePattern getMatchingPattern(FilterableIssue issue) { - IssuePattern matchingPattern = null; - Iterator patternIterator = getPatternsForComponent(issue.componentKey()).iterator(); - while(matchingPattern == null && patternIterator.hasNext()) { - IssuePattern nextPattern = patternIterator.next(); - if (nextPattern.match(issue)) { - matchingPattern = nextPattern; + @CheckForNull + public IssuePattern getMatchingPattern(String componentKey, RuleKey ruleKey, @Nullable Integer line) { + for (IssuePattern pattern : getPatternsForComponent(componentKey)) { + if (pattern.match(componentKey, ruleKey, line)) { + return pattern; } } - return matchingPattern; + return null; } + @VisibleForTesting public Collection getPatternsForComponent(String componentKey) { - return patternByComponent.get(componentKey); + return excludePatternByComponent.get(componentKey); } - public void addPatternForComponent(String component, IssuePattern pattern) { - patternByComponent.put(component, pattern.forResource(component)); + public void addPatternForComponent(String componentKey, IssuePattern pattern) { + excludePatternByComponent.put(componentKey, pattern.forResource(componentKey)); } - public void addPatternToExcludeResource(String resource) { - addPatternForComponent(resource, new IssuePattern(resource, "*").setCheckLines(false)); + public void addPatternToExcludeResource(String componentKey) { + addPatternForComponent(componentKey, new IssuePattern(componentKey, "*")); } - public void addPatternToExcludeLines(String resource, Set lineRanges) { - addPatternForComponent(resource, new IssuePattern(resource, "*", lineRanges).setCheckLines(true)); + public void addPatternToExcludeLines(String componentKey, Set lineRanges) { + addPatternForComponent(componentKey, new IssuePattern(componentKey, "*", lineRanges)); } } diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/scanner/IssueExclusionsLoader.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/scanner/IssueExclusionsLoader.java index 433e8c5ccbf..30cdeb0c582 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/scanner/IssueExclusionsLoader.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/scanner/IssueExclusionsLoader.java @@ -19,55 +19,82 @@ */ package org.sonar.scanner.issue.ignore.scanner; -import org.sonar.api.batch.fs.FileSystem; -import org.sonar.api.batch.fs.InputFile; -import org.sonar.api.batch.fs.internal.DefaultInputFile; +import java.util.ArrayList; +import java.util.List; + +import javax.annotation.CheckForNull; + +import org.apache.commons.lang.StringUtils; +import org.sonar.api.batch.fs.internal.FileMetadata.CharHandler; +import org.sonar.scanner.issue.ignore.pattern.BlockIssuePattern; import org.sonar.scanner.issue.ignore.pattern.IssueExclusionPatternInitializer; -import org.sonar.scanner.issue.ignore.pattern.IssueInclusionPatternInitializer; +import org.sonar.scanner.issue.ignore.pattern.IssuePattern; +import org.sonar.scanner.issue.ignore.pattern.PatternMatcher; public final class IssueExclusionsLoader { + private final List allFilePatterns; + private final List blockMatchers; + private final PatternMatcher patternMatcher; + private final IssueExclusionPatternInitializer patternsInitializer; + private final boolean enableCharHandler; + + public IssueExclusionsLoader(IssueExclusionPatternInitializer patternsInitializer, PatternMatcher patternMatcher) { + this.patternsInitializer = patternsInitializer; + this.patternMatcher = patternMatcher; + this.allFilePatterns = new ArrayList<>(); + this.blockMatchers = new ArrayList<>(); - private final IssueExclusionsRegexpScanner regexpScanner; - private final IssueExclusionPatternInitializer exclusionPatternInitializer; - private final IssueInclusionPatternInitializer inclusionPatternInitializer; - private final FileSystem fileSystem; - - public IssueExclusionsLoader(IssueExclusionsRegexpScanner regexpScanner, IssueExclusionPatternInitializer exclusionPatternInitializer, - IssueInclusionPatternInitializer inclusionPatternInitializer, FileSystem fileSystem) { - this.regexpScanner = regexpScanner; - this.exclusionPatternInitializer = exclusionPatternInitializer; - this.inclusionPatternInitializer = inclusionPatternInitializer; - this.fileSystem = fileSystem; + for (String pattern : patternsInitializer.getAllFilePatterns()) { + allFilePatterns.add(java.util.regex.Pattern.compile(pattern)); + } + for (BlockIssuePattern pattern : patternsInitializer.getBlockPatterns()) { + blockMatchers.add(new DoubleRegexpMatcher( + java.util.regex.Pattern.compile(pattern.getBeginBlockRegexp()), + java.util.regex.Pattern.compile(pattern.getEndBlockRegexp()))); + } + enableCharHandler = !allFilePatterns.isEmpty() || !blockMatchers.isEmpty(); } public boolean shouldExecute() { - return inclusionPatternInitializer.hasConfiguredPatterns() - || exclusionPatternInitializer.hasConfiguredPatterns(); + return patternsInitializer.hasMulticriteriaPatterns(); } - public void preLoadAllFiles() { - for (InputFile inputFile : fileSystem.inputFiles(fileSystem.predicates().all())) { - loadFile(inputFile); + public void addMulticriteriaPatterns(String relativePath, String componentKey) { + for (IssuePattern pattern : patternsInitializer.getMulticriteriaPatterns()) { + if (pattern.matchResource(relativePath)) { + patternMatcher.addPatternForComponent(componentKey, pattern); + } } } - public boolean isLoaded(InputFile inputFile) { - String componentEffectiveKey = ((DefaultInputFile) inputFile).key(); - return inclusionPatternInitializer.getPathForComponent(componentEffectiveKey) != null; + @CheckForNull + public CharHandler createCharHandlerFor(String componentKey) { + if (enableCharHandler) { + return new IssueExclusionsRegexpScanner(componentKey, allFilePatterns, blockMatchers, patternMatcher); + } + return null; } - public void loadFile(InputFile inputFile) { - try { - String componentEffectiveKey = ((DefaultInputFile) inputFile).key(); - String path = inputFile.relativePath(); - inclusionPatternInitializer.initializePatternsForPath(path, componentEffectiveKey); - exclusionPatternInitializer.initializePatternsForPath(path, componentEffectiveKey); - if (exclusionPatternInitializer.hasFileContentPattern()) { - regexpScanner.scan(componentEffectiveKey, inputFile.path(), inputFile.charset()); - } - } catch (Exception e) { - throw new IllegalStateException("Unable to read the source file : '" + inputFile.absolutePath() + "' with the charset : '" - + inputFile.charset().name() + "'.", e); + public static class DoubleRegexpMatcher { + + private java.util.regex.Pattern firstPattern; + private java.util.regex.Pattern secondPattern; + + DoubleRegexpMatcher(java.util.regex.Pattern firstPattern, java.util.regex.Pattern secondPattern) { + this.firstPattern = firstPattern; + this.secondPattern = secondPattern; + } + + boolean matchesFirstPattern(String line) { + return firstPattern.matcher(line).find(); + } + + boolean matchesSecondPattern(String line) { + return hasSecondPattern() && secondPattern.matcher(line).find(); + } + + boolean hasSecondPattern() { + return StringUtils.isNotEmpty(secondPattern.toString()); } } @@ -75,5 +102,4 @@ public final class IssueExclusionsLoader { public String toString() { return "Issues Exclusions - Source Scanner"; } - } diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/scanner/IssueExclusionsRegexpScanner.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/scanner/IssueExclusionsRegexpScanner.java index 0c4794cb2b9..0ad4373665a 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/scanner/IssueExclusionsRegexpScanner.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/scanner/IssueExclusionsRegexpScanner.java @@ -19,92 +19,59 @@ */ package org.sonar.scanner.issue.ignore.scanner; -import org.apache.commons.lang.StringUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.sonar.api.batch.ScannerSide; -import org.sonar.scanner.issue.ignore.pattern.IssueExclusionPatternInitializer; -import org.sonar.scanner.issue.ignore.pattern.IssuePattern; -import org.sonar.scanner.issue.ignore.pattern.LineRange; - -import java.io.BufferedReader; -import java.io.IOException; -import java.nio.charset.Charset; -import java.nio.file.Files; -import java.nio.file.Path; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; +import java.util.regex.Pattern; -@ScannerSide -public class IssueExclusionsRegexpScanner { - - private static final Logger LOG = LoggerFactory.getLogger(IssueExclusionsRegexpScanner.class); - - private IssueExclusionPatternInitializer exclusionPatternInitializer; - private List allFilePatterns; - private List blockMatchers; - - // fields to be reset at every new scan +import org.apache.commons.lang.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.sonar.api.batch.fs.internal.FileMetadata.CharHandler; +import org.sonar.scanner.issue.ignore.pattern.LineRange; +import org.sonar.scanner.issue.ignore.pattern.PatternMatcher; +import org.sonar.scanner.issue.ignore.scanner.IssueExclusionsLoader.DoubleRegexpMatcher; + +public class IssueExclusionsRegexpScanner extends CharHandler { + private static final Logger LOG = LoggerFactory.getLogger(IssueExclusionsLoader.class); + + private final StringBuilder sb = new StringBuilder(); + private final List allFilePatterns; + private final List blockMatchers; + private final String componentKey; + private final PatternMatcher patternMatcher; + + private int lineIndex = 1; + private List lineExclusions = new ArrayList<>(); + private LineExclusion currentLineExclusion = null; + private int fileLength = 0; private DoubleRegexpMatcher currentMatcher; - private int fileLength; - private List lineExclusions; - private LineExclusion currentLineExclusion; - public IssueExclusionsRegexpScanner(IssueExclusionPatternInitializer patternsInitializer) { - this.exclusionPatternInitializer = patternsInitializer; - - lineExclusions = new ArrayList<>(); - allFilePatterns = new ArrayList<>(); - blockMatchers = new ArrayList<>(); - - for (IssuePattern pattern : patternsInitializer.getAllFilePatterns()) { - allFilePatterns.add(java.util.regex.Pattern.compile(pattern.getAllFileRegexp())); - } - for (IssuePattern pattern : patternsInitializer.getBlockPatterns()) { - blockMatchers.add(new DoubleRegexpMatcher( - java.util.regex.Pattern.compile(pattern.getBeginBlockRegexp()), - java.util.regex.Pattern.compile(pattern.getEndBlockRegexp()))); - } - - init(); + IssueExclusionsRegexpScanner(String componentKey, List allFilePatterns, List blockMatchers, PatternMatcher patternMatcher) { + this.allFilePatterns = allFilePatterns; + this.blockMatchers = blockMatchers; + this.patternMatcher = patternMatcher; + this.componentKey = componentKey; + String relativePath = StringUtils.substringAfterLast(componentKey, ":"); + LOG.info("'{}' generating issue exclusions", relativePath); } - private void init() { - currentMatcher = null; - fileLength = 0; - lineExclusions.clear(); - currentLineExclusion = null; + @Override + protected void handleIgnoreEoL(char c) { + sb.append(c); } - public void scan(String resource, Path filePath, Charset encoding) throws IOException { - LOG.debug("Scanning {}", resource); - init(); - - int lineIndex = 0; - try (BufferedReader br = Files.newBufferedReader(filePath, encoding)) { - String line; - while ((line = br.readLine()) != null) { - lineIndex++; - if (line.trim().length() == 0) { - continue; - } + @Override + protected void newLine() { + processLine(sb.toString()); + sb.setLength(0); + lineIndex++; + } - // first check the single regexp patterns that can be used to totally exclude a file - for (java.util.regex.Pattern pattern : allFilePatterns) { - if (pattern.matcher(line).find()) { - exclusionPatternInitializer.getPatternMatcher().addPatternToExcludeResource(resource); - // nothing more to do on this file - LOG.debug("- Exclusion pattern '{}': every issue in this file will be ignored.", pattern); - return; - } - } - - // then check the double regexps if we're still here - checkDoubleRegexps(line, lineIndex); - } - } + @Override + protected void eof() { + processLine(sb.toString()); if (currentMatcher != null && !currentMatcher.hasSecondPattern()) { // this will happen when there is a start block regexp but no end block regexp @@ -116,14 +83,33 @@ public class IssueExclusionsRegexpScanner { if (!lineExclusions.isEmpty()) { Set lineRanges = convertLineExclusionsToLineRanges(); LOG.debug("- Line exclusions found: {}", lineRanges); - exclusionPatternInitializer.getPatternMatcher().addPatternToExcludeLines(resource, lineRanges); + patternMatcher.addPatternToExcludeLines(componentKey, lineRanges); } } + private void processLine(String line) { + if (line.trim().length() == 0) { + return; + } + + // first check the single regexp patterns that can be used to totally exclude a file + for (Pattern pattern : allFilePatterns) { + if (pattern.matcher(line).find()) { + patternMatcher.addPatternToExcludeResource(componentKey); + // nothing more to do on this file + LOG.debug("- Exclusion pattern '{}': every issue in this file will be ignored.", pattern); + return; + } + } + + // then check the double regexps if we're still here + checkDoubleRegexps(line, lineIndex); + } + private Set convertLineExclusionsToLineRanges() { Set lineRanges = new HashSet<>(lineExclusions.size()); for (LineExclusion lineExclusion : lineExclusions) { - lineRanges.add(lineExclusion.toLineRange()); + lineRanges.add(lineExclusion.toLineRange(fileLength)); } return lineRanges; } @@ -155,8 +141,7 @@ public class IssueExclusionsRegexpScanner { currentLineExclusion = null; } - private class LineExclusion { - + private static class LineExclusion { private int start; private int end; @@ -169,33 +154,8 @@ public class IssueExclusionsRegexpScanner { this.end = end; } - public LineRange toLineRange() { + public LineRange toLineRange(int fileLength) { return new LineRange(start, end == -1 ? fileLength : end); } - - } - - private static class DoubleRegexpMatcher { - - private java.util.regex.Pattern firstPattern; - private java.util.regex.Pattern secondPattern; - - DoubleRegexpMatcher(java.util.regex.Pattern firstPattern, java.util.regex.Pattern secondPattern) { - this.firstPattern = firstPattern; - this.secondPattern = secondPattern; - } - - boolean matchesFirstPattern(String line) { - return firstPattern.matcher(line).find(); - } - - boolean matchesSecondPattern(String line) { - return hasSecondPattern() && secondPattern.matcher(line).find(); - } - - boolean hasSecondPattern() { - return StringUtils.isNotEmpty(secondPattern.toString()); - } } - } diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/phases/AbstractPhaseExecutor.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/phases/AbstractPhaseExecutor.java index e48247aee05..46acfff0279 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/phases/AbstractPhaseExecutor.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/phases/AbstractPhaseExecutor.java @@ -20,15 +20,14 @@ package org.sonar.scanner.phases; import org.sonar.api.batch.SensorContext; +import org.sonar.api.batch.fs.InputFile; import org.sonar.api.batch.fs.internal.DefaultInputModule; -import org.sonar.api.config.Settings; import org.sonar.scanner.events.BatchStepEvent; import org.sonar.scanner.events.EventBus; import org.sonar.scanner.issue.ignore.scanner.IssueExclusionsLoader; import org.sonar.scanner.rule.QProfileVerifier; import org.sonar.scanner.scan.filesystem.DefaultModuleFileSystem; import org.sonar.scanner.scan.filesystem.FileSystemLogger; -import org.sonar.scanner.scan.filesystem.InputFileBuilder; public abstract class AbstractPhaseExecutor { @@ -41,11 +40,10 @@ public abstract class AbstractPhaseExecutor { private final DefaultModuleFileSystem fs; private final QProfileVerifier profileVerifier; private final IssueExclusionsLoader issueExclusionsLoader; - private final boolean preloadIssueExclusions; public AbstractPhaseExecutor(InitializersExecutor initializersExecutor, PostJobsExecutor postJobsExecutor, SensorsExecutor sensorsExecutor, SensorContext sensorContext, EventBus eventBus, FileSystemLogger fsLogger, DefaultModuleFileSystem fs, QProfileVerifier profileVerifier, - IssueExclusionsLoader issueExclusionsLoader, Settings settings) { + IssueExclusionsLoader issueExclusionsLoader) { this.postJobsExecutor = postJobsExecutor; this.initializersExecutor = initializersExecutor; this.sensorsExecutor = sensorsExecutor; @@ -55,7 +53,6 @@ public abstract class AbstractPhaseExecutor { this.fs = fs; this.profileVerifier = profileVerifier; this.issueExclusionsLoader = issueExclusionsLoader; - this.preloadIssueExclusions = settings.getBoolean(InputFileBuilder.PRELOAD_FILE_METADATA_KEY); } /** @@ -92,10 +89,14 @@ public abstract class AbstractPhaseExecutor { protected abstract void executeOnRoot(); private void initIssueExclusions() { - if (preloadIssueExclusions && issueExclusionsLoader.shouldExecute()) { + if (issueExclusionsLoader.shouldExecute()) { String stepName = "Init issue exclusions"; eventBus.fireEvent(new BatchStepEvent(stepName, true)); - issueExclusionsLoader.preLoadAllFiles(); + + for (InputFile inputFile : fs.inputFiles(fs.predicates().all())) { + issueExclusionsLoader.addMulticriteriaPatterns(inputFile.relativePath(), inputFile.key()); + } + eventBus.fireEvent(new BatchStepEvent(stepName, false)); } } diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/phases/IssuesPhaseExecutor.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/phases/IssuesPhaseExecutor.java index b650656b592..7893e6a0024 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/phases/IssuesPhaseExecutor.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/phases/IssuesPhaseExecutor.java @@ -22,7 +22,6 @@ package org.sonar.scanner.phases; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.sonar.api.batch.SensorContext; -import org.sonar.api.config.Settings; import org.sonar.scanner.events.BatchStepEvent; import org.sonar.scanner.events.EventBus; import org.sonar.scanner.issue.IssueCallback; @@ -44,8 +43,8 @@ public final class IssuesPhaseExecutor extends AbstractPhaseExecutor { public IssuesPhaseExecutor(InitializersExecutor initializersExecutor, PostJobsExecutor postJobsExecutor, SensorsExecutor sensorsExecutor, SensorContext sensorContext, EventBus eventBus, FileSystemLogger fsLogger, IssuesReports jsonReport, DefaultModuleFileSystem fs, QProfileVerifier profileVerifier, - IssueExclusionsLoader issueExclusionsLoader, IssueTransition localIssueTracking, IssueCallback issueCallback, Settings settings) { - super(initializersExecutor, postJobsExecutor, sensorsExecutor, sensorContext, eventBus, fsLogger, fs, profileVerifier, issueExclusionsLoader, settings); + IssueExclusionsLoader issueExclusionsLoader, IssueTransition localIssueTracking, IssueCallback issueCallback) { + super(initializersExecutor, postJobsExecutor, sensorsExecutor, sensorContext, eventBus, fsLogger, fs, profileVerifier, issueExclusionsLoader); this.eventBus = eventBus; this.issuesReport = jsonReport; this.localIssueTracking = localIssueTracking; diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/phases/PublishPhaseExecutor.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/phases/PublishPhaseExecutor.java index e8bf655674d..434c88a96dd 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/phases/PublishPhaseExecutor.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/phases/PublishPhaseExecutor.java @@ -20,7 +20,6 @@ package org.sonar.scanner.phases; import org.sonar.api.batch.SensorContext; -import org.sonar.api.config.Settings; import org.sonar.scanner.cpd.CpdExecutor; import org.sonar.scanner.events.BatchStepEvent; import org.sonar.scanner.events.EventBus; @@ -39,9 +38,9 @@ public final class PublishPhaseExecutor extends AbstractPhaseExecutor { private final ScmPublisher scm; public PublishPhaseExecutor(InitializersExecutor initializersExecutor, PostJobsExecutor postJobsExecutor, SensorsExecutor sensorsExecutor, SensorContext sensorContext, - EventBus eventBus, ReportPublisher reportPublisher, FileSystemLogger fsLogger, DefaultModuleFileSystem fs, Settings settings, + EventBus eventBus, ReportPublisher reportPublisher, FileSystemLogger fsLogger, DefaultModuleFileSystem fs, QProfileVerifier profileVerifier, IssueExclusionsLoader issueExclusionsLoader, CpdExecutor cpdExecutor, ScmPublisher scm) { - super(initializersExecutor, postJobsExecutor, sensorsExecutor, sensorContext, eventBus, fsLogger, fs, profileVerifier, issueExclusionsLoader, settings); + super(initializersExecutor, postJobsExecutor, sensorsExecutor, sensorContext, eventBus, fsLogger, fs, profileVerifier, issueExclusionsLoader); this.eventBus = eventBus; this.reportPublisher = reportPublisher; this.cpdExecutor = cpdExecutor; diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ModuleScanContainer.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ModuleScanContainer.java index 9053ad07f89..b7ba4b5cf0b 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ModuleScanContainer.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ModuleScanContainer.java @@ -44,8 +44,8 @@ import org.sonar.scanner.issue.ignore.EnforceIssuesFilter; import org.sonar.scanner.issue.ignore.IgnoreIssuesFilter; import org.sonar.scanner.issue.ignore.pattern.IssueExclusionPatternInitializer; import org.sonar.scanner.issue.ignore.pattern.IssueInclusionPatternInitializer; +import org.sonar.scanner.issue.ignore.pattern.PatternMatcher; import org.sonar.scanner.issue.ignore.scanner.IssueExclusionsLoader; -import org.sonar.scanner.issue.ignore.scanner.IssueExclusionsRegexpScanner; import org.sonar.scanner.phases.AbstractPhaseExecutor; import org.sonar.scanner.phases.InitializersExecutor; import org.sonar.scanner.phases.IssuesPhaseExecutor; @@ -152,7 +152,7 @@ public class ModuleScanContainer extends ComponentContainer { // issue exclusions IssueInclusionPatternInitializer.class, IssueExclusionPatternInitializer.class, - IssueExclusionsRegexpScanner.class, + PatternMatcher.class, IssueExclusionsLoader.class, EnforceIssuesFilter.class, IgnoreIssuesFilter.class, diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/MetadataGenerator.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/MetadataGenerator.java index 5e814625b52..c04483cc784 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/MetadataGenerator.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/MetadataGenerator.java @@ -35,6 +35,7 @@ import org.sonar.api.batch.fs.internal.DefaultInputFile; import org.sonar.api.batch.fs.internal.DefaultInputModule; import org.sonar.api.batch.fs.internal.FileMetadata; import org.sonar.api.batch.fs.internal.Metadata; +import org.sonar.scanner.issue.ignore.scanner.IssueExclusionsLoader; class MetadataGenerator { private static final Logger LOG = LoggerFactory.getLogger(MetadataGenerator.class); @@ -47,11 +48,13 @@ class MetadataGenerator { private final StatusDetection statusDetection; private final FileMetadata fileMetadata; private final DefaultInputModule inputModule; + private final IssueExclusionsLoader exclusionsScanner; - MetadataGenerator(DefaultInputModule inputModule, StatusDetection statusDetection, FileMetadata fileMetadata) { + MetadataGenerator(DefaultInputModule inputModule, StatusDetection statusDetection, FileMetadata fileMetadata, IssueExclusionsLoader exclusionsScanner) { this.inputModule = inputModule; this.statusDetection = statusDetection; this.fileMetadata = fileMetadata; + this.exclusionsScanner = exclusionsScanner; } /** @@ -62,11 +65,10 @@ class MetadataGenerator { try { Charset charset = detectCharset(inputFile.path(), defaultEncoding); inputFile.setCharset(charset); - Metadata metadata = fileMetadata.readMetadata(inputFile.file(), charset); + Metadata metadata = fileMetadata.readMetadata(inputFile.file(), charset, exclusionsScanner.createCharHandlerFor(inputFile.key())); inputFile.setMetadata(metadata); inputFile.setStatus(statusDetection.status(inputModule.definition().getKeyWithBranch(), inputFile.relativePath(), metadata.hash())); - LOG.debug("'{}' generated metadata {} with charset '{}'", - inputFile.relativePath(), inputFile.type() == Type.TEST ? "as test " : "", charset); + LOG.debug("'{}' generated metadata {} with charset '{}'", inputFile.relativePath(), inputFile.type() == Type.TEST ? "as test " : "", charset); } catch (Exception e) { throw new IllegalStateException(e); } diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/MetadataGeneratorProvider.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/MetadataGeneratorProvider.java index 59d89e38539..4e935f1905e 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/MetadataGeneratorProvider.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/MetadataGeneratorProvider.java @@ -23,10 +23,12 @@ import org.picocontainer.injectors.ProviderAdapter; import org.sonar.api.batch.ScannerSide; import org.sonar.api.batch.fs.internal.DefaultInputModule; import org.sonar.api.batch.fs.internal.FileMetadata; +import org.sonar.scanner.issue.ignore.scanner.IssueExclusionsLoader; @ScannerSide public class MetadataGeneratorProvider extends ProviderAdapter { - public MetadataGenerator provide(DefaultInputModule inputModule, StatusDetectionFactory statusDetectionFactory, FileMetadata fileMetadata) { - return new MetadataGenerator(inputModule, statusDetectionFactory.create(), fileMetadata); + public MetadataGenerator provide(DefaultInputModule inputModule, StatusDetectionFactory statusDetectionFactory, FileMetadata fileMetadata, + IssueExclusionsLoader exclusionsScanner) { + return new MetadataGenerator(inputModule, statusDetectionFactory.create(), fileMetadata, exclusionsScanner); } } diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/ModuleIssuesTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/ModuleIssuesTest.java index af240c47660..c180e8e1da6 100644 --- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/ModuleIssuesTest.java +++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/ModuleIssuesTest.java @@ -24,7 +24,6 @@ import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.runners.MockitoJUnitRunner; -import org.sonar.api.batch.fs.FileSystem; import org.sonar.api.batch.fs.internal.DefaultInputFile; import org.sonar.api.batch.fs.internal.TestInputFileBuilder; import org.sonar.api.batch.rule.internal.ActiveRulesBuilder; @@ -36,10 +35,6 @@ import org.sonar.api.rule.Severity; import org.sonar.api.utils.MessageException; import org.sonar.scanner.issue.IssueFilters; import org.sonar.scanner.issue.ModuleIssues; -import org.sonar.scanner.issue.ignore.pattern.IssueExclusionPatternInitializer; -import org.sonar.scanner.issue.ignore.pattern.IssueInclusionPatternInitializer; -import org.sonar.scanner.issue.ignore.scanner.IssueExclusionsLoader; -import org.sonar.scanner.issue.ignore.scanner.IssueExclusionsRegexpScanner; import org.sonar.scanner.protocol.output.ScannerReport; import org.sonar.scanner.report.ReportPublisher; @@ -211,9 +206,7 @@ public class ModuleIssuesTest { * Every rules and active rules has to be added in builders before creating ModuleIssues */ private void initModuleIssues() { - IssueExclusionsLoader issueExclusionsLoader = new IssueExclusionsLoader(mock(IssueExclusionsRegexpScanner.class), mock(IssueExclusionPatternInitializer.class), - mock(IssueInclusionPatternInitializer.class), mock(FileSystem.class)); - moduleIssues = new ModuleIssues(activeRulesBuilder.build(), ruleBuilder.build(), filters, reportPublisher, issueExclusionsLoader); + moduleIssues = new ModuleIssues(activeRulesBuilder.build(), ruleBuilder.build(), filters, reportPublisher); } } diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/ignore/EnforceIssuesFilterTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/ignore/EnforceIssuesFilterTest.java index dab1de1df03..d3089b298fa 100644 --- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/ignore/EnforceIssuesFilterTest.java +++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/ignore/EnforceIssuesFilterTest.java @@ -25,11 +25,14 @@ import com.google.common.collect.ImmutableList; import org.junit.Before; import org.junit.Test; import org.sonar.api.scan.issue.filter.IssueFilterChain; +import org.sonar.api.batch.fs.InputComponent; +import org.sonar.api.batch.fs.internal.TestInputFileBuilder; import org.sonar.api.rule.RuleKey; import org.sonar.api.utils.WildcardPattern; import org.sonar.scanner.issue.ignore.EnforceIssuesFilter; import org.sonar.scanner.issue.ignore.pattern.IssueInclusionPatternInitializer; import org.sonar.scanner.issue.ignore.pattern.IssuePattern; +import org.sonar.scanner.scan.filesystem.InputComponentStore; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.mock; @@ -40,18 +43,20 @@ import static org.mockito.Mockito.when; public class EnforceIssuesFilterTest { private IssueInclusionPatternInitializer exclusionPatternInitializer; + private InputComponentStore inputComponentStore; private EnforceIssuesFilter ignoreFilter; private FilterableIssue issue; private IssueFilterChain chain; @Before public void init() { + inputComponentStore = mock(InputComponentStore.class); exclusionPatternInitializer = mock(IssueInclusionPatternInitializer.class); issue = mock(FilterableIssue.class); chain = mock(IssueFilterChain.class); when(chain.accept(issue)).thenReturn(true); - ignoreFilter = new EnforceIssuesFilter(exclusionPatternInitializer); + ignoreFilter = new EnforceIssuesFilter(exclusionPatternInitializer, inputComponentStore); } @Test @@ -95,12 +100,16 @@ public class EnforceIssuesFilterTest { when(matching.getResourcePattern()).thenReturn(pathPattern); when(pathPattern.match(path)).thenReturn(true); when(exclusionPatternInitializer.getMulticriteriaPatterns()).thenReturn(ImmutableList.of(matching)); - when(exclusionPatternInitializer.getPathForComponent(componentKey)).thenReturn(path); + when(inputComponentStore.getByKey(componentKey)).thenReturn(createComponentWithPath(path)); assertThat(ignoreFilter.accept(issue, chain)).isTrue(); verifyZeroInteractions(chain); } + private InputComponent createComponentWithPath(String path) { + return new TestInputFileBuilder("", path).build(); + } + @Test public void shouldRefuseIssueIfRuleMatchesButNotPath() { String rule = "rule"; @@ -119,7 +128,7 @@ public class EnforceIssuesFilterTest { when(matching.getResourcePattern()).thenReturn(pathPattern); when(pathPattern.match(path)).thenReturn(false); when(exclusionPatternInitializer.getMulticriteriaPatterns()).thenReturn(ImmutableList.of(matching)); - when(exclusionPatternInitializer.getPathForComponent(componentKey)).thenReturn(path); + when(inputComponentStore.getByKey(componentKey)).thenReturn(createComponentWithPath(path)); assertThat(ignoreFilter.accept(issue, chain)).isFalse(); verifyZeroInteractions(chain); @@ -143,7 +152,7 @@ public class EnforceIssuesFilterTest { when(matching.getResourcePattern()).thenReturn(pathPattern); when(pathPattern.match(path)).thenReturn(false); when(exclusionPatternInitializer.getMulticriteriaPatterns()).thenReturn(ImmutableList.of(matching)); - when(exclusionPatternInitializer.getPathForComponent(componentKey)).thenReturn(null); + when(inputComponentStore.getByKey(componentKey)).thenReturn(null); assertThat(ignoreFilter.accept(issue, chain)).isFalse(); verifyZeroInteractions(chain); diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/ignore/IgnoreIssuesFilterTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/ignore/IgnoreIssuesFilterTest.java index b1a88ce858c..ccf1ed016c6 100644 --- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/ignore/IgnoreIssuesFilterTest.java +++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/ignore/IgnoreIssuesFilterTest.java @@ -19,23 +19,24 @@ */ package org.sonar.scanner.issue.ignore; +import org.sonar.api.rule.RuleKey; import org.sonar.api.scan.issue.filter.FilterableIssue; import org.junit.Before; import org.junit.Test; import org.sonar.api.scan.issue.filter.IssueFilterChain; import org.sonar.scanner.issue.ignore.IgnoreIssuesFilter; -import org.sonar.scanner.issue.ignore.pattern.IssueExclusionPatternInitializer; import org.sonar.scanner.issue.ignore.pattern.IssuePattern; import org.sonar.scanner.issue.ignore.pattern.PatternMatcher; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.mock; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyString; import static org.mockito.Mockito.when; public class IgnoreIssuesFilterTest { - private IssueExclusionPatternInitializer exclusionPatternInitializer; private PatternMatcher exclusionPatternMatcher; private IgnoreIssuesFilter ignoreFilter; private FilterableIssue issue; @@ -44,25 +45,23 @@ public class IgnoreIssuesFilterTest { @Before public void init() { exclusionPatternMatcher = mock(PatternMatcher.class); - exclusionPatternInitializer = mock(IssueExclusionPatternInitializer.class); - when(exclusionPatternInitializer.getPatternMatcher()).thenReturn(exclusionPatternMatcher); issue = mock(FilterableIssue.class); chain = mock(IssueFilterChain.class); when(chain.accept(issue)).thenReturn(true); - ignoreFilter = new IgnoreIssuesFilter(exclusionPatternInitializer); + ignoreFilter = new IgnoreIssuesFilter(exclusionPatternMatcher); } @Test public void shouldPassToChainIfMatcherHasNoPatternForIssue() { - when(exclusionPatternMatcher.getMatchingPattern(issue)).thenReturn(null); + when(exclusionPatternMatcher.getMatchingPattern(anyString(), any(RuleKey.class), any(Integer.class))).thenReturn(null); assertThat(ignoreFilter.accept(issue, chain)).isTrue(); } @Test public void shouldAcceptOrRefuseIfMatcherHasPatternForIssue() { - when(exclusionPatternMatcher.getMatchingPattern(issue)).thenReturn(mock(IssuePattern.class)); + when(exclusionPatternMatcher.getMatchingPattern(anyString(), any(RuleKey.class), any(Integer.class))).thenReturn(mock(IssuePattern.class)); assertThat(ignoreFilter.accept(issue, chain)).isFalse(); } diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/ignore/pattern/IssueExclusionPatternInitializerTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/ignore/pattern/IssueExclusionPatternInitializerTest.java index a298c822a2e..7fadd593235 100644 --- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/ignore/pattern/IssueExclusionPatternInitializerTest.java +++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/ignore/pattern/IssueExclusionPatternInitializerTest.java @@ -19,76 +19,45 @@ */ package org.sonar.scanner.issue.ignore.pattern; - import org.junit.Before; import org.junit.Test; import org.sonar.api.config.PropertyDefinitions; import org.sonar.api.config.Settings; import org.sonar.api.config.MapSettings; -import org.sonar.api.utils.SonarException; import org.sonar.core.config.IssueExclusionProperties; import static org.assertj.core.api.Assertions.assertThat; public class IssueExclusionPatternInitializerTest { - private IssueExclusionPatternInitializer patternsInitializer; - private Settings settings; @Before public void init() { settings = new MapSettings(new PropertyDefinitions(IssueExclusionProperties.all())); - patternsInitializer = new IssueExclusionPatternInitializer(settings); } @Test public void testNoConfiguration() { - patternsInitializer.initPatterns(); + patternsInitializer = new IssueExclusionPatternInitializer(settings); assertThat(patternsInitializer.hasConfiguredPatterns()).isFalse(); assertThat(patternsInitializer.getMulticriteriaPatterns().size()).isEqualTo(0); } - @Test - public void shouldHavePatternsBasedOnMulticriteriaPattern() { - settings.setProperty("sonar.issue.ignore" + ".multicriteria", "1,2"); - settings.setProperty("sonar.issue.ignore" + ".multicriteria" + ".1." + "resourceKey", "org/foo/Bar.java"); - settings.setProperty("sonar.issue.ignore" + ".multicriteria" + ".1." + "ruleKey", "*"); - settings.setProperty("sonar.issue.ignore" + ".multicriteria" + ".2." + "resourceKey", "org/foo/Hello.java"); - settings.setProperty("sonar.issue.ignore" + ".multicriteria" + ".2." + "ruleKey", "checkstyle:MagicNumber"); - patternsInitializer.initPatterns(); - - assertThat(patternsInitializer.hasConfiguredPatterns()).isTrue(); - assertThat(patternsInitializer.hasFileContentPattern()).isFalse(); - assertThat(patternsInitializer.hasMulticriteriaPatterns()).isTrue(); - assertThat(patternsInitializer.getMulticriteriaPatterns().size()).isEqualTo(2); - assertThat(patternsInitializer.getBlockPatterns().size()).isEqualTo(0); - assertThat(patternsInitializer.getAllFilePatterns().size()).isEqualTo(0); - - patternsInitializer.initializePatternsForPath("org/foo/Bar.java", "org.foo.Bar"); - patternsInitializer.initializePatternsForPath("org/foo/Baz.java", "org.foo.Baz"); - patternsInitializer.initializePatternsForPath("org/foo/Hello.java", "org.foo.Hello"); - - assertThat(patternsInitializer.getPatternMatcher().getPatternsForComponent("org.foo.Bar")).hasSize(1); - assertThat(patternsInitializer.getPatternMatcher().getPatternsForComponent("org.foo.Baz")).hasSize(0); - assertThat(patternsInitializer.getPatternMatcher().getPatternsForComponent("org.foo.Hello")).hasSize(1); - - } - - @Test(expected = SonarException.class) + @Test(expected = IllegalStateException.class) public void shouldLogInvalidResourceKey() { settings.setProperty("sonar.issue.ignore" + ".multicriteria", "1"); settings.setProperty("sonar.issue.ignore" + ".multicriteria" + ".1." + "resourceKey", ""); settings.setProperty("sonar.issue.ignore" + ".multicriteria" + ".1." + "ruleKey", "*"); - patternsInitializer.initPatterns(); + patternsInitializer = new IssueExclusionPatternInitializer(settings); } - @Test(expected = SonarException.class) + @Test(expected = IllegalStateException.class) public void shouldLogInvalidRuleKey() { settings.setProperty("sonar.issue.ignore" + ".multicriteria", "1"); settings.setProperty("sonar.issue.ignore" + ".multicriteria" + ".1." + "resourceKey", "*"); settings.setProperty("sonar.issue.ignore" + ".multicriteria" + ".1." + "ruleKey", ""); - patternsInitializer.initPatterns(); + patternsInitializer = new IssueExclusionPatternInitializer(settings); } @Test @@ -100,7 +69,7 @@ public class IssueExclusionPatternInitializerTest { settings.setProperty(IssueExclusionProperties.PATTERNS_BLOCK_KEY + ".2." + IssueExclusionProperties.END_BLOCK_REGEXP, "// FOO-ON"); settings.setProperty(IssueExclusionProperties.PATTERNS_BLOCK_KEY + ".3." + IssueExclusionProperties.BEGIN_BLOCK_REGEXP, "// IGNORE-TO-EOF"); settings.setProperty(IssueExclusionProperties.PATTERNS_BLOCK_KEY + ".3." + IssueExclusionProperties.END_BLOCK_REGEXP, ""); - patternsInitializer.loadFileContentPatterns(); + patternsInitializer = new IssueExclusionPatternInitializer(settings); assertThat(patternsInitializer.hasConfiguredPatterns()).isTrue(); assertThat(patternsInitializer.hasFileContentPattern()).isTrue(); @@ -110,12 +79,12 @@ public class IssueExclusionPatternInitializerTest { assertThat(patternsInitializer.getAllFilePatterns().size()).isEqualTo(0); } - @Test(expected = SonarException.class) + @Test(expected = IllegalStateException.class) public void shouldLogInvalidStartBlockPattern() { settings.setProperty(IssueExclusionProperties.PATTERNS_BLOCK_KEY, "1"); settings.setProperty(IssueExclusionProperties.PATTERNS_BLOCK_KEY + ".1." + IssueExclusionProperties.BEGIN_BLOCK_REGEXP, ""); settings.setProperty(IssueExclusionProperties.PATTERNS_BLOCK_KEY + ".1." + IssueExclusionProperties.END_BLOCK_REGEXP, "// SONAR-ON"); - patternsInitializer.loadFileContentPatterns(); + patternsInitializer = new IssueExclusionPatternInitializer(settings); } @Test @@ -123,7 +92,7 @@ public class IssueExclusionPatternInitializerTest { settings.setProperty(IssueExclusionProperties.PATTERNS_ALLFILE_KEY, "1,2"); settings.setProperty(IssueExclusionProperties.PATTERNS_ALLFILE_KEY + ".1." + IssueExclusionProperties.FILE_REGEXP, "@SONAR-IGNORE-ALL"); settings.setProperty(IssueExclusionProperties.PATTERNS_ALLFILE_KEY + ".2." + IssueExclusionProperties.FILE_REGEXP, "//FOO-IGNORE-ALL"); - patternsInitializer.loadFileContentPatterns(); + patternsInitializer = new IssueExclusionPatternInitializer(settings); assertThat(patternsInitializer.hasConfiguredPatterns()).isTrue(); assertThat(patternsInitializer.hasFileContentPattern()).isTrue(); @@ -133,10 +102,10 @@ public class IssueExclusionPatternInitializerTest { assertThat(patternsInitializer.getAllFilePatterns().size()).isEqualTo(2); } - @Test(expected = SonarException.class) + @Test(expected = IllegalStateException.class) public void shouldLogInvalidAllFilePattern() { settings.setProperty(IssueExclusionProperties.PATTERNS_ALLFILE_KEY, "1"); settings.setProperty(IssueExclusionProperties.PATTERNS_ALLFILE_KEY + ".1." + IssueExclusionProperties.FILE_REGEXP, ""); - patternsInitializer.loadFileContentPatterns(); + patternsInitializer = new IssueExclusionPatternInitializer(settings); } } diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/ignore/pattern/IssueInclusionPatternInitializerTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/ignore/pattern/IssueInclusionPatternInitializerTest.java index de3982e504e..6feecb28637 100644 --- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/ignore/pattern/IssueInclusionPatternInitializerTest.java +++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/ignore/pattern/IssueInclusionPatternInitializerTest.java @@ -31,7 +31,6 @@ import static org.assertj.core.api.Assertions.assertThat; public class IssueInclusionPatternInitializerTest { private IssueInclusionPatternInitializer patternsInitializer; - private Settings settings; @Before @@ -58,14 +57,6 @@ public class IssueInclusionPatternInitializerTest { assertThat(patternsInitializer.hasConfiguredPatterns()).isTrue(); assertThat(patternsInitializer.hasMulticriteriaPatterns()).isTrue(); assertThat(patternsInitializer.getMulticriteriaPatterns().size()).isEqualTo(2); - - patternsInitializer.initializePatternsForPath("org/foo/Bar.java", "org.foo.Bar"); - patternsInitializer.initializePatternsForPath("org/foo/Baz.java", "org.foo.Baz"); - patternsInitializer.initializePatternsForPath("org/foo/Hello.java", "org.foo.Hello"); - - assertThat(patternsInitializer.getPathForComponent("org.foo.Bar")).isEqualTo("org/foo/Bar.java"); - assertThat(patternsInitializer.getPathForComponent("org.foo.Baz")).isEqualTo("org/foo/Baz.java"); - assertThat(patternsInitializer.getPathForComponent("org.foo.Hello")).isEqualTo("org/foo/Hello.java"); } } diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/ignore/pattern/IssuePatternTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/ignore/pattern/IssuePatternTest.java index b14cc76e4a3..d6c6f778b53 100644 --- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/ignore/pattern/IssuePatternTest.java +++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/ignore/pattern/IssuePatternTest.java @@ -22,18 +22,23 @@ package org.sonar.scanner.issue.ignore.pattern; import org.junit.Test; import org.sonar.api.rule.RuleKey; import org.sonar.api.rules.Rule; -import org.sonar.api.scan.issue.filter.FilterableIssue; import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; public class IssuePatternTest { @Test public void shouldMatchLines() { - IssuePattern pattern = new IssuePattern("*", "*"); - pattern.addLine(12).addLine(15).addLineRange(20, 25); + Set lineRanges = new HashSet<>(); + lineRanges.add(new LineRange(12)); + lineRanges.add(new LineRange(15)); + lineRanges.add(new LineRange(20, 25)); + + IssuePattern pattern = new IssuePattern("*", "*", lineRanges); assertThat(pattern.matchLine(3)).isFalse(); assertThat(pattern.matchLine(12)).isTrue(); @@ -77,31 +82,17 @@ public class IssuePatternTest { Rule rule = Rule.create("checkstyle", "IllegalRegexp", ""); String javaFile = "org.foo.Bar"; - IssuePattern pattern = new IssuePattern("*", "*"); - pattern.addLine(12); - - assertThat(pattern.match(create(rule, javaFile, null))).isFalse(); - assertThat(pattern.match(create(rule, javaFile, 12))).isTrue(); - assertThat(pattern.match(create(rule, null, null))).isFalse(); - } + IssuePattern pattern = new IssuePattern("*", "*", Collections.singleton(new LineRange(12))); - private FilterableIssue create(Rule rule, String component, Integer line) { - FilterableIssue mockIssue = mock(FilterableIssue.class); - RuleKey ruleKey = null; - if (rule != null) { - ruleKey = rule.ruleKey(); - } - when(mockIssue.ruleKey()).thenReturn(ruleKey); - when(mockIssue.componentKey()).thenReturn(component); - when(mockIssue.line()).thenReturn(line); - return mockIssue; + assertThat(pattern.match(javaFile, rule.ruleKey(), null)).isFalse(); + assertThat(pattern.match(javaFile, rule.ruleKey(), 12)).isTrue(); + assertThat(pattern.match(null, rule.ruleKey(), null)).isFalse(); } @Test public void shouldPrintPatternToString() { IssuePattern pattern = new IssuePattern("*", "checkstyle:*"); - assertThat(pattern.toString()).isEqualTo( - "IssuePattern[resourcePattern=*,rulePattern=checkstyle:*,lines=[],lineRanges=[],beginBlockRegexp=,endBlockRegexp=,allFileRegexp=,checkLines=true]"); + assertThat(pattern.toString()).isEqualTo("IssuePattern[resourcePattern=*,rulePattern=checkstyle:*,lines=[],lineRanges=[],checkLines=false]"); } } diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/ignore/pattern/PatternDecoderTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/ignore/pattern/PatternDecoderTest.java index 056451fb3e2..f4ca8b9c745 100644 --- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/ignore/pattern/PatternDecoderTest.java +++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/ignore/pattern/PatternDecoderTest.java @@ -19,41 +19,12 @@ */ package org.sonar.scanner.issue.ignore.pattern; -import org.junit.Rule; import org.junit.Test; -import org.junit.rules.ExpectedException; -import org.sonar.api.utils.SonarException; -import org.sonar.scanner.issue.ignore.pattern.IssuePattern; import org.sonar.scanner.issue.ignore.pattern.PatternDecoder; -import java.util.List; import static org.assertj.core.api.Assertions.assertThat; public class PatternDecoderTest { - - private PatternDecoder decoder = new PatternDecoder(); - - @Rule - public ExpectedException thrown = ExpectedException.none(); - - @Test - public void shouldReadString() { - String patternsList = "# a comment followed by a blank line\n\n" + - "# suppress all violations\n" + - "*;*;*\n\n" + - "# exclude a Java file\n" + - "com.foo.Bar;*;*\n\n" + - "# exclude a Java package\n" + - "com.foo.*;*;*\n\n" + - "# exclude a specific rule\n" + - "*;checkstyle:IllegalRegexp;*\n\n" + - "# exclude a specific rule on a specific file\n" + - "com.foo.Bar;checkstyle:IllegalRegexp;*\n"; - List patterns = decoder.decode(patternsList); - - assertThat(patterns).hasSize(5); - } - @Test public void shouldCheckFormatOfResource() { assertThat(PatternDecoder.isResource("")).isFalse(); @@ -83,106 +54,4 @@ public class PatternDecoderTest { assertThat(PatternDecoder.isLinesRange("[24-65]")).isTrue(); assertThat(PatternDecoder.isLinesRange("[13,24-65,84-89,122]")).isTrue(); } - - @Test - public void shouldReadStarPatterns() { - IssuePattern pattern = decoder.decodeLine("*;*;*"); - - assertThat(pattern.getResourcePattern().toString()).isEqualTo("*"); - assertThat(pattern.getRulePattern().toString()).isEqualTo("*"); - assertThat(pattern.isCheckLines()).isFalse(); - } - - @Test - public void shouldReadLineIds() { - IssuePattern pattern = decoder.decodeLine("*;*;[10,25,98]"); - - assertThat(pattern.isCheckLines()).isTrue(); - assertThat(pattern.getAllLines()).containsOnly(10, 25, 98); - } - - @Test - public void shouldReadRangeOfLineIds() { - IssuePattern pattern = decoder.decodeLine("*;*;[10-12,25,97-100]"); - - assertThat(pattern.isCheckLines()).isTrue(); - assertThat(pattern.getAllLines()).containsOnly(10, 11, 12, 25, 97, 98, 99, 100); - } - - @Test - public void shouldNotExcludeLines() { - // [] is different than * - // - all violations are excluded on * - // * no violations are excluded on [] - IssuePattern pattern = decoder.decodeLine("*;*;[]"); - - assertThat(pattern.isCheckLines()).isTrue(); - assertThat(pattern.getAllLines()).isEmpty(); - } - - @Test - public void shouldReadBlockPattern() { - IssuePattern pattern = decoder.decodeLine("SONAR-OFF;SONAR-ON"); - - assertThat(pattern.getResourcePattern()).isNull(); - assertThat(pattern.getBeginBlockRegexp()).isEqualTo("SONAR-OFF"); - assertThat(pattern.getEndBlockRegexp()).isEqualTo("SONAR-ON"); - } - - @Test - public void shouldReadAllFilePattern() { - IssuePattern pattern = decoder.decodeLine("SONAR-ALL-OFF"); - - assertThat(pattern.getResourcePattern()).isNull(); - assertThat(pattern.getAllFileRegexp()).isEqualTo("SONAR-ALL-OFF"); - } - - @Test - public void shouldFailToReadUncorrectLine1() { - thrown.expect(SonarException.class); - thrown.expectMessage("Exclusions > Issues : Invalid format. The following line has more than 3 fields separated by comma"); - - decoder.decode(";;;;"); - } - - @Test - public void shouldFailToReadUncorrectLine3() { - thrown.expect(SonarException.class); - thrown.expectMessage("Exclusions > Issues : Invalid format. The first field does not define a resource pattern"); - - decoder.decode(";*;*"); - } - - @Test - public void shouldFailToReadUncorrectLine4() { - thrown.expect(SonarException.class); - thrown.expectMessage("Exclusions > Issues : Invalid format. The second field does not define a rule pattern"); - - decoder.decode("*;;*"); - } - - @Test - public void shouldFailToReadUncorrectLine5() { - thrown.expect(SonarException.class); - thrown.expectMessage("Exclusions > Issues : Invalid format. The third field does not define a range of lines"); - - decoder.decode("*;*;blabla"); - } - - @Test - public void shouldFailToReadUncorrectLine6() { - thrown.expect(SonarException.class); - thrown.expectMessage("Exclusions > Issues : Invalid format. The first field does not define a regular expression"); - - decoder.decode(";ON"); - } - - @Test - public void shouldAcceptEmptyEndBlockRegexp() { - IssuePattern pattern = decoder.decodeLine("OFF;"); - - assertThat(pattern.getResourcePattern()).isNull(); - assertThat(pattern.getBeginBlockRegexp()).isEqualTo("OFF"); - assertThat(pattern.getEndBlockRegexp()).isEmpty(); - } } diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/ignore/pattern/PatternMatcherTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/ignore/pattern/PatternMatcherTest.java index 2025d0d1fd8..ea9cdb5606c 100644 --- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/ignore/pattern/PatternMatcherTest.java +++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/ignore/pattern/PatternMatcherTest.java @@ -19,22 +19,20 @@ */ package org.sonar.scanner.issue.ignore.pattern; -import org.sonar.api.scan.issue.filter.FilterableIssue; import org.sonar.scanner.issue.ignore.pattern.IssuePattern; import org.sonar.scanner.issue.ignore.pattern.LineRange; -import org.sonar.scanner.issue.ignore.pattern.PatternDecoder; import org.sonar.scanner.issue.ignore.pattern.PatternMatcher; import com.google.common.collect.Sets; import org.junit.Before; import org.junit.Test; -import org.sonar.api.rule.RuleKey; import org.sonar.api.rules.Rule; +import java.util.Collections; import java.util.Set; +import javax.annotation.Nullable; + import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; public class PatternMatcherTest { @@ -72,51 +70,47 @@ public class PatternMatcherTest { @Test public void shouldHaveNoMatcherIfNoneDefined() { - assertThat(patternMatcher.getMatchingPattern(create(CHECKSTYLE_RULE, JAVA_FILE, null))).isNull(); + assertThat(patternMatcher.getMatchingPattern(JAVA_FILE, CHECKSTYLE_RULE.ruleKey(), null)).isNull(); } @Test public void shouldMatchWithStandardPatterns() { - patternMatcher.addPatternForComponent(JAVA_FILE, createPattern("org.foo.Hello;checkstyle:MagicNumber;[15-200]")); + patternMatcher.addPatternForComponent(JAVA_FILE, createPattern("org.foo.Hello", "checkstyle:MagicNumber", createRanges(15, 200))); - assertThat(patternMatcher.getMatchingPattern(create(CHECKSTYLE_RULE, JAVA_FILE, 150))).isNotNull(); + assertThat(patternMatcher.getMatchingPattern(JAVA_FILE, CHECKSTYLE_RULE.ruleKey(), 150)).isNotNull(); } @Test public void shouldNotMatchWithStandardPatterns() { - patternMatcher.addPatternForComponent(JAVA_FILE, createPattern("org.foo.Hello;checkstyle:MagicNumber;[15-200]")); + patternMatcher.addPatternForComponent(JAVA_FILE, createPattern("org.foo.Hello", "checkstyle:MagicNumber", createRanges(15, 200))); - assertThat(patternMatcher.getMatchingPattern(create(CHECKSTYLE_RULE, JAVA_FILE, 5))).isNull(); + assertThat(patternMatcher.getMatchingPattern(JAVA_FILE, CHECKSTYLE_RULE.ruleKey(), 5)).isNull(); } @Test public void shouldMatchWithExtraPattern() { - patternMatcher.addPatternForComponent(JAVA_FILE, createPattern("org.foo.Hello;*;[15-200]")); + patternMatcher.addPatternForComponent(JAVA_FILE, createPattern("org.foo.Hello", "*", createRanges(15, 200))); - assertThat(patternMatcher.getMatchingPattern(create(CHECKSTYLE_RULE, JAVA_FILE, 150))).isNotNull(); + assertThat(patternMatcher.getMatchingPattern(JAVA_FILE, CHECKSTYLE_RULE.ruleKey(), 150)).isNotNull(); } @Test public void shouldNotMatchWithExtraPattern() { - patternMatcher.addPatternForComponent(JAVA_FILE, createPattern("org.foo.Hello;*;[15-200]")); + patternMatcher.addPatternForComponent(JAVA_FILE, createPattern("org.foo.Hello", "*", createRanges(15, 200))); - assertThat(patternMatcher.getMatchingPattern(create(CHECKSTYLE_RULE, JAVA_FILE, 5))).isNull(); + assertThat(patternMatcher.getMatchingPattern(JAVA_FILE, CHECKSTYLE_RULE.ruleKey(), 5)).isNull(); } - private FilterableIssue create(Rule rule, String component, Integer line) { - FilterableIssue mockIssue = mock(FilterableIssue.class); - RuleKey ruleKey = null; - if (rule != null) { - ruleKey = rule.ruleKey(); + private IssuePattern createPattern(String resourcePattern, String rulePattern, @Nullable Set lineRanges) { + if (lineRanges != null) { + return new IssuePattern(resourcePattern, rulePattern, lineRanges); + } else { + return new IssuePattern(resourcePattern, rulePattern); } - when(mockIssue.ruleKey()).thenReturn(ruleKey); - when(mockIssue.componentKey()).thenReturn(component); - when(mockIssue.line()).thenReturn(line); - return mockIssue; } - private IssuePattern createPattern(String line) { - return new PatternDecoder().decode(line).get(0); + private Set createRanges(int from, int to) { + return Collections.singleton(new LineRange(from, to)); } } diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/ignore/scanner/IssueExclusionsLoaderTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/ignore/scanner/IssueExclusionsLoaderTest.java index 1c2922c2141..638e504b6ce 100644 --- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/ignore/scanner/IssueExclusionsLoaderTest.java +++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/ignore/scanner/IssueExclusionsLoaderTest.java @@ -20,31 +20,23 @@ package org.sonar.scanner.issue.ignore.scanner; import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.nio.file.Path; +import java.util.Arrays; +import java.util.Collections; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; -import org.junit.rules.TemporaryFolder; import org.mockito.Mock; import org.mockito.MockitoAnnotations; -import org.sonar.api.batch.fs.InputFile; -import org.sonar.api.batch.fs.internal.DefaultFileSystem; -import org.sonar.api.batch.fs.internal.DefaultInputFile; -import org.sonar.api.batch.fs.internal.TestInputFileBuilder; import org.sonar.scanner.issue.ignore.pattern.IssueExclusionPatternInitializer; -import org.sonar.scanner.issue.ignore.pattern.IssueInclusionPatternInitializer; +import org.sonar.scanner.issue.ignore.pattern.IssuePattern; import org.sonar.scanner.issue.ignore.pattern.PatternMatcher; -import static java.nio.charset.StandardCharsets.UTF_8; import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyZeroInteractions; +import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; public class IssueExclusionsLoaderTest { @@ -52,31 +44,18 @@ public class IssueExclusionsLoaderTest { @Rule public ExpectedException thrown = ExpectedException.none(); - @Rule - public TemporaryFolder temp = new TemporaryFolder(); - - @Mock - private IssueExclusionsRegexpScanner regexpScanner; - - @Mock - private IssueInclusionPatternInitializer inclusionPatternInitializer; - @Mock private IssueExclusionPatternInitializer exclusionPatternInitializer; - @Mock private PatternMatcher patternMatcher; - private DefaultFileSystem fs; private IssueExclusionsLoader scanner; - private Path baseDir; @Before public void before() throws Exception { - baseDir = temp.newFolder().toPath(); - fs = new DefaultFileSystem(baseDir).setEncoding(UTF_8); + patternMatcher = new PatternMatcher(); MockitoAnnotations.initMocks(this); - scanner = new IssueExclusionsLoader(regexpScanner, exclusionPatternInitializer, inclusionPatternInitializer, fs); + scanner = new IssueExclusionsLoader(exclusionPatternInitializer, patternMatcher); } @Test @@ -85,108 +64,55 @@ public class IssueExclusionsLoaderTest { } @Test - public void shouldExecute() { - when(exclusionPatternInitializer.hasConfiguredPatterns()).thenReturn(true); - when(inclusionPatternInitializer.hasConfiguredPatterns()).thenReturn(true); - assertThat(scanner.shouldExecute()).isTrue(); + public void createComputer() { + assertThat(scanner.createCharHandlerFor("src/main/java/Foo.java")).isNull(); - when(exclusionPatternInitializer.hasConfiguredPatterns()).thenReturn(true); - when(inclusionPatternInitializer.hasConfiguredPatterns()).thenReturn(false); - assertThat(scanner.shouldExecute()).isTrue(); + when(exclusionPatternInitializer.getAllFilePatterns()).thenReturn(Collections.singletonList("pattern")); + scanner = new IssueExclusionsLoader(exclusionPatternInitializer, patternMatcher); + assertThat(scanner.createCharHandlerFor("src/main/java/Foo.java")).isNotNull(); - when(exclusionPatternInitializer.hasConfiguredPatterns()).thenReturn(false); - when(inclusionPatternInitializer.hasConfiguredPatterns()).thenReturn(true); - assertThat(scanner.shouldExecute()).isTrue(); - when(exclusionPatternInitializer.hasConfiguredPatterns()).thenReturn(false); - when(inclusionPatternInitializer.hasConfiguredPatterns()).thenReturn(false); - assertThat(scanner.shouldExecute()).isFalse(); } @Test - public void shouldAnalyzeProject() throws IOException { - Path javaFile1 = baseDir.resolve("src/main/java/Foo.java"); - fs.add(new TestInputFileBuilder("polop", "src/main/java/Foo.java") - .setModuleBaseDir(baseDir) - .setCharset(StandardCharsets.UTF_8) - .setType(InputFile.Type.MAIN) - .build()); - Path javaTestFile1 = baseDir.resolve("src/test/java/FooTest.java"); - fs.add(new TestInputFileBuilder("polop", "src/test/java/FooTest.java") - .setModuleBaseDir(baseDir) - .setCharset(StandardCharsets.UTF_8) - .setType(InputFile.Type.TEST) - .build()); - - when(exclusionPatternInitializer.hasFileContentPattern()).thenReturn(true); - - scanner.preLoadAllFiles(); - - verify(inclusionPatternInitializer).initializePatternsForPath("src/main/java/Foo.java", "polop:src/main/java/Foo.java"); - verify(inclusionPatternInitializer).initializePatternsForPath("src/test/java/FooTest.java", "polop:src/test/java/FooTest.java"); - verify(exclusionPatternInitializer).initializePatternsForPath("src/main/java/Foo.java", "polop:src/main/java/Foo.java"); - verify(exclusionPatternInitializer).initializePatternsForPath("src/test/java/FooTest.java", "polop:src/test/java/FooTest.java"); - verify(regexpScanner).scan("polop:src/main/java/Foo.java", javaFile1, UTF_8); - verify(regexpScanner).scan("polop:src/test/java/FooTest.java", javaTestFile1, UTF_8); - } - - @Test - public void isLoaded() { - DefaultInputFile inputFile1 = new TestInputFileBuilder("polop", "src/test/java/FooTest1.java") - .setModuleBaseDir(baseDir) - .setCharset(StandardCharsets.UTF_8) - .setType(InputFile.Type.TEST) - .build(); - DefaultInputFile inputFile2 = new TestInputFileBuilder("polop", "src/test/java/FooTest2.java") - .setModuleBaseDir(baseDir) - .setCharset(StandardCharsets.UTF_8) - .setType(InputFile.Type.TEST) - .build(); - - when(inclusionPatternInitializer.getPathForComponent(inputFile1.key())).thenReturn(null); - when(inclusionPatternInitializer.getPathForComponent(inputFile2.key())).thenReturn("path1"); - - assertFalse(scanner.isLoaded(inputFile1)); - assertTrue(scanner.isLoaded(inputFile2)); - + public void shouldHavePatternsBasedOnMulticriteriaPattern() { + IssuePattern pattern1 = new IssuePattern("org/foo/Bar.java", "*"); + IssuePattern pattern2 = new IssuePattern("org/foo/Hello.java", "checkstyle:MagicNumber"); + when(exclusionPatternInitializer.getMulticriteriaPatterns()).thenReturn(Arrays.asList(new IssuePattern[] {pattern1, pattern2})); + + IssueExclusionsLoader loader = new IssueExclusionsLoader(exclusionPatternInitializer, patternMatcher); + loader.addMulticriteriaPatterns("org/foo/Bar.java", "org.foo.Bar"); + loader.addMulticriteriaPatterns("org/foo/Baz.java", "org.foo.Baz"); + loader.addMulticriteriaPatterns("org/foo/Hello.java", "org.foo.Hello"); + + assertThat(patternMatcher.getPatternsForComponent("org.foo.Bar")).hasSize(1); + assertThat(patternMatcher.getPatternsForComponent("org.foo.Baz")).hasSize(0); + assertThat(patternMatcher.getPatternsForComponent("org.foo.Hello")).hasSize(1); } @Test - public void shouldAnalyseFilesOnlyWhenRegexConfigured() { - fs.add(new TestInputFileBuilder("polop", "src/main/java/Foo.java") - .setType(InputFile.Type.MAIN) - .setCharset(StandardCharsets.UTF_8) - .build()); - fs.add(new TestInputFileBuilder("polop", "src/test/java/FooTest.java") - .setType(InputFile.Type.TEST) - .setCharset(StandardCharsets.UTF_8) - .build()); - when(exclusionPatternInitializer.hasFileContentPattern()).thenReturn(false); - - scanner.preLoadAllFiles(); - - verify(inclusionPatternInitializer).initializePatternsForPath("src/main/java/Foo.java", "polop:src/main/java/Foo.java"); - verify(inclusionPatternInitializer).initializePatternsForPath("src/test/java/FooTest.java", "polop:src/test/java/FooTest.java"); - verify(exclusionPatternInitializer).initializePatternsForPath("src/main/java/Foo.java", "polop:src/main/java/Foo.java"); - verify(exclusionPatternInitializer).initializePatternsForPath("src/test/java/FooTest.java", "polop:src/test/java/FooTest.java"); - verifyZeroInteractions(regexpScanner); + public void shouldAnalyzeProject() throws IOException { + IssuePattern pattern = new IssuePattern("**", "*"); + when(exclusionPatternInitializer.getMulticriteriaPatterns()).thenReturn(Collections.singletonList(pattern)); + when(exclusionPatternInitializer.hasMulticriteriaPatterns()).thenReturn(true); + + PatternMatcher patternMatcher = mock(PatternMatcher.class); + IssueExclusionsLoader loader = new IssueExclusionsLoader(exclusionPatternInitializer, patternMatcher); + assertThat(loader.shouldExecute()).isTrue(); + loader.addMulticriteriaPatterns("src/main/java/Foo.java", "polop:src/main/java/Foo.java"); + loader.addMulticriteriaPatterns("src/test/java/FooTest.java", "polop:src/test/java/FooTest.java"); + + verify(patternMatcher).addPatternForComponent("polop:src/main/java/Foo.java", pattern); + verify(patternMatcher).addPatternForComponent("polop:src/test/java/FooTest.java", pattern); + verifyNoMoreInteractions(patternMatcher); } @Test - public void shouldReportFailure() throws IOException { - Path phpFile1 = baseDir.resolve("src/Foo.php"); - fs.add(new TestInputFileBuilder("polop", "src/Foo.php") - .setModuleBaseDir(baseDir) - .setType(InputFile.Type.MAIN) - .setCharset(StandardCharsets.UTF_8) - .build()); - - when(exclusionPatternInitializer.hasFileContentPattern()).thenReturn(true); - doThrow(new IOException("BUG")).when(regexpScanner).scan("polop:src/Foo.php", phpFile1, UTF_8); - - thrown.expect(IllegalStateException.class); - thrown.expectMessage("Unable to read the source file"); + public void shouldExecute() { + when(exclusionPatternInitializer.hasMulticriteriaPatterns()).thenReturn(true); + assertThat(scanner.shouldExecute()).isTrue(); - scanner.preLoadAllFiles(); + when(exclusionPatternInitializer.hasMulticriteriaPatterns()).thenReturn(false); + assertThat(scanner.shouldExecute()).isFalse(); } } diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/ignore/scanner/IssueExclusionsRegexpScannerTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/ignore/scanner/IssueExclusionsRegexpScannerTest.java index 55581e74adc..37c2b957b65 100644 --- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/ignore/scanner/IssueExclusionsRegexpScannerTest.java +++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/ignore/scanner/IssueExclusionsRegexpScannerTest.java @@ -19,150 +19,146 @@ */ package org.sonar.scanner.issue.ignore.scanner; -import com.google.common.collect.Sets; import com.google.common.io.Resources; import org.junit.Before; import org.junit.Test; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import org.sonar.api.batch.fs.internal.FileMetadata; import org.sonar.scanner.issue.ignore.pattern.IssueExclusionPatternInitializer; -import org.sonar.scanner.issue.ignore.pattern.IssuePattern; import org.sonar.scanner.issue.ignore.pattern.LineRange; import org.sonar.scanner.issue.ignore.pattern.PatternMatcher; import org.sonar.scanner.issue.ignore.scanner.IssueExclusionsRegexpScanner; +import org.sonar.scanner.issue.ignore.scanner.IssueExclusionsLoader.DoubleRegexpMatcher; + +import java.net.URISyntaxException; +import java.nio.file.Path; import java.nio.file.Paths; import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; import java.util.Set; +import java.util.regex.Pattern; import static java.nio.charset.StandardCharsets.UTF_8; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; -import static org.mockito.Mockito.when; public class IssueExclusionsRegexpScannerTest { - - private IssueExclusionsRegexpScanner regexpScanner; - private String javaFile; + @Mock private IssueExclusionPatternInitializer patternsInitializer; @Mock private PatternMatcher patternMatcher; - @Mock - private IssuePattern allFilePattern; - @Mock - private IssuePattern blockPattern1; - @Mock - private IssuePattern blockPattern2; + + private List allFilePatterns; + private List blockPatterns; + private IssueExclusionsRegexpScanner regexpScanner; + private FileMetadata fileMetadata = new FileMetadata(); @Before public void init() { MockitoAnnotations.initMocks(this); - when(allFilePattern.getAllFileRegexp()).thenReturn("@SONAR-IGNORE-ALL"); - when(blockPattern1.getBeginBlockRegexp()).thenReturn("// SONAR-OFF"); - when(blockPattern1.getEndBlockRegexp()).thenReturn("// SONAR-ON"); - when(blockPattern2.getBeginBlockRegexp()).thenReturn("// FOO-OFF"); - when(blockPattern2.getEndBlockRegexp()).thenReturn("// FOO-ON"); - when(patternsInitializer.getAllFilePatterns()).thenReturn(Arrays.asList(allFilePattern)); - when(patternsInitializer.getBlockPatterns()).thenReturn(Arrays.asList(blockPattern1, blockPattern2)); - when(patternsInitializer.getPatternMatcher()).thenReturn(patternMatcher); - - regexpScanner = new IssueExclusionsRegexpScanner(patternsInitializer); - verify(patternsInitializer, times(1)).getAllFilePatterns(); - verify(patternsInitializer, times(1)).getBlockPatterns(); + blockPatterns = Arrays.asList(new DoubleRegexpMatcher[] { + new DoubleRegexpMatcher(Pattern.compile("// SONAR-OFF"), Pattern.compile("// SONAR-ON")), + new DoubleRegexpMatcher(Pattern.compile("// FOO-OFF"), Pattern.compile("// FOO-ON")) + }); + allFilePatterns = Collections.singletonList(Pattern.compile("@SONAR-IGNORE-ALL")); javaFile = "org.sonar.test.MyFile"; + regexpScanner = new IssueExclusionsRegexpScanner(javaFile, allFilePatterns, blockPatterns, patternMatcher); + } + + @Test + public void shouldDetectPatternLastLine() throws URISyntaxException { + fileMetadata.readMetadata(getResource("file-with-single-regexp-last-line.txt").toFile(), UTF_8, regexpScanner); + + verify(patternMatcher, times(1)).addPatternToExcludeResource(javaFile); + verifyNoMoreInteractions(patternMatcher); } @Test public void shouldDoNothing() throws Exception { - regexpScanner.scan(javaFile, Paths.get(Resources.getResource( - "org/sonar/scanner/issue/ignore/scanner/IssueExclusionsRegexpScannerTest/file-with-no-regexp.txt").toURI()), UTF_8); - - verifyNoMoreInteractions(patternsInitializer); + fileMetadata.readMetadata(getResource("file-with-no-regexp.txt").toFile(), UTF_8, regexpScanner); + verifyNoMoreInteractions(patternMatcher); } @Test public void shouldAddPatternToExcludeFile() throws Exception { - regexpScanner.scan(javaFile, Paths.get(Resources.getResource( - "org/sonar/scanner/issue/ignore/scanner/IssueExclusionsRegexpScannerTest/file-with-single-regexp.txt").toURI()), UTF_8); + fileMetadata.readMetadata(getResource("file-with-single-regexp.txt").toFile(), UTF_8, regexpScanner); - verify(patternsInitializer).getPatternMatcher(); verify(patternMatcher, times(1)).addPatternToExcludeResource(javaFile); - verifyNoMoreInteractions(patternsInitializer); + verifyNoMoreInteractions(patternMatcher); } @Test public void shouldAddPatternToExcludeFileEvenIfAlsoDoubleRegexps() throws Exception { - regexpScanner.scan(javaFile, Paths.get(Resources.getResource( - "org/sonar/scanner/issue/ignore/scanner/IssueExclusionsRegexpScannerTest/file-with-single-regexp-and-double-regexp.txt").toURI()), UTF_8); + fileMetadata.readMetadata(getResource("file-with-single-regexp-and-double-regexp.txt").toFile(), UTF_8, regexpScanner); - verify(patternsInitializer).getPatternMatcher(); + Set lineRanges = new HashSet<>(); + lineRanges.add(new LineRange(5, 26)); verify(patternMatcher, times(1)).addPatternToExcludeResource(javaFile); - verifyNoMoreInteractions(patternsInitializer); + verify(patternMatcher, times(1)).addPatternToExcludeLines(javaFile, lineRanges); + verifyNoMoreInteractions(patternMatcher); } @Test public void shouldAddPatternToExcludeLines() throws Exception { - regexpScanner.scan(javaFile, Paths.get(Resources.getResource( - "org/sonar/scanner/issue/ignore/scanner/IssueExclusionsRegexpScannerTest/file-with-double-regexp.txt").toURI()), UTF_8); + fileMetadata.readMetadata(getResource("file-with-double-regexp.txt").toFile(), UTF_8, regexpScanner); - Set lineRanges = Sets.newHashSet(); + Set lineRanges = new HashSet<>(); lineRanges.add(new LineRange(21, 25)); - verify(patternsInitializer).getPatternMatcher(); verify(patternMatcher, times(1)).addPatternToExcludeLines(javaFile, lineRanges); - verifyNoMoreInteractions(patternsInitializer); + verifyNoMoreInteractions(patternMatcher); } @Test public void shouldAddPatternToExcludeLinesTillTheEnd() throws Exception { - regexpScanner.scan(javaFile, Paths.get(Resources.getResource( - "org/sonar/scanner/issue/ignore/scanner/IssueExclusionsRegexpScannerTest/file-with-double-regexp-unfinished.txt").toURI()), UTF_8); + fileMetadata.readMetadata(getResource("file-with-double-regexp-unfinished.txt").toFile(), UTF_8, regexpScanner); - Set lineRanges = Sets.newHashSet(); + Set lineRanges = new HashSet<>(); lineRanges.add(new LineRange(21, 34)); - verify(patternsInitializer).getPatternMatcher(); verify(patternMatcher, times(1)).addPatternToExcludeLines(javaFile, lineRanges); - verifyNoMoreInteractions(patternsInitializer); + verifyNoMoreInteractions(patternMatcher); } @Test public void shouldAddPatternToExcludeSeveralLineRanges() throws Exception { - regexpScanner.scan(javaFile, Paths.get(Resources.getResource( - "org/sonar/scanner/issue/ignore/scanner/IssueExclusionsRegexpScannerTest/file-with-double-regexp-twice.txt").toURI()), UTF_8); + fileMetadata.readMetadata(getResource("file-with-double-regexp-twice.txt").toFile(), UTF_8, regexpScanner); - Set lineRanges = Sets.newHashSet(); + Set lineRanges = new HashSet<>(); lineRanges.add(new LineRange(21, 25)); lineRanges.add(new LineRange(29, 33)); - verify(patternsInitializer).getPatternMatcher(); verify(patternMatcher, times(1)).addPatternToExcludeLines(javaFile, lineRanges); - verifyNoMoreInteractions(patternsInitializer); + verifyNoMoreInteractions(patternMatcher); } @Test public void shouldAddPatternToExcludeLinesWithWrongOrder() throws Exception { - regexpScanner.scan(javaFile, Paths.get(Resources.getResource( - "org/sonar/scanner/issue/ignore/scanner/IssueExclusionsRegexpScannerTest/file-with-double-regexp-wrong-order.txt").toURI()), UTF_8); + fileMetadata.readMetadata(getResource("file-with-double-regexp-wrong-order.txt").toFile(), UTF_8, regexpScanner); - Set lineRanges = Sets.newHashSet(); + Set lineRanges = new HashSet<>(); lineRanges.add(new LineRange(25, 35)); - verify(patternsInitializer).getPatternMatcher(); verify(patternMatcher, times(1)).addPatternToExcludeLines(javaFile, lineRanges); - verifyNoMoreInteractions(patternsInitializer); + verifyNoMoreInteractions(patternMatcher); } @Test public void shouldAddPatternToExcludeLinesWithMess() throws Exception { - regexpScanner.scan(javaFile, Paths.get(Resources.getResource( - "org/sonar/scanner/issue/ignore/scanner/IssueExclusionsRegexpScannerTest/file-with-double-regexp-mess.txt").toURI()), UTF_8); + fileMetadata.readMetadata(getResource("file-with-double-regexp-mess.txt").toFile(), UTF_8, regexpScanner); - Set lineRanges = Sets.newHashSet(); + Set lineRanges = new HashSet<>(); lineRanges.add(new LineRange(21, 29)); - verify(patternsInitializer).getPatternMatcher(); verify(patternMatcher, times(1)).addPatternToExcludeLines(javaFile, lineRanges); - verifyNoMoreInteractions(patternsInitializer); + verifyNoMoreInteractions(patternMatcher); + } + + private Path getResource(String fileName) throws URISyntaxException { + return Paths.get(Resources.getResource("org/sonar/scanner/issue/ignore/scanner/IssueExclusionsRegexpScannerTest/" + fileName).toURI()); } } diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/fs/FileSystemMediumTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/fs/FileSystemMediumTest.java index 6f569def502..d14f205ed8a 100644 --- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/fs/FileSystemMediumTest.java +++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/fs/FileSystemMediumTest.java @@ -349,8 +349,8 @@ public class FileSystemMediumTest { .start(); assertThat(logs.getAllAsString()).containsOnlyOnce("'src/myfile.binary' indexed with language 'null'"); - assertThat(logs.getAllAsString()).doesNotContain("Scanning com.foo.project:src/myfile.binary"); - assertThat(logs.getAllAsString()).containsOnlyOnce("Scanning com.foo.project:src/sample.xoo"); + assertThat(logs.getAllAsString()).doesNotContain("'src/myfile.binary' generating issue exclusions"); + assertThat(logs.getAllAsString()).containsOnlyOnce("'src/sample.xoo' generating issue exclusions"); tester2.stop(); @@ -366,7 +366,7 @@ public class FileSystemMediumTest { srcDir.mkdir(); File xooFile = new File(srcDir, "sample.xoo"); - FileUtils.write(xooFile, "Sample xoo\ncontent"); + FileUtils.write(xooFile, "Sample xoo\npattern"); File unknownFile = new File(srcDir, "myfile.binary"); FileUtils.write(unknownFile, "some text"); @@ -376,8 +376,9 @@ public class FileSystemMediumTest { .put("sonar.sources", "src") .build()) .start(); - - assertThat(logs.getAllAsString()).containsOnlyOnce("Scanning com.foo.project:src/myfile.binary"); + + assertThat(logs.getAllAsString()).containsOnlyOnce("- Exclusion pattern 'pattern'"); + assertThat(logs.getAllAsString()).containsOnlyOnce("'src/myfile.binary' generating issue exclusions"); } @Test diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/filesystem/MetadataGeneratorProviderTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/filesystem/MetadataGeneratorProviderTest.java index 965540c1047..c9c7312fab5 100644 --- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/filesystem/MetadataGeneratorProviderTest.java +++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/filesystem/MetadataGeneratorProviderTest.java @@ -23,6 +23,9 @@ import org.junit.Test; import org.mockito.Mockito; import org.sonar.api.batch.fs.internal.DefaultInputModule; import org.sonar.api.batch.fs.internal.FileMetadata; +import org.sonar.scanner.issue.ignore.pattern.IssueExclusionPatternInitializer; +import org.sonar.scanner.issue.ignore.pattern.PatternMatcher; +import org.sonar.scanner.issue.ignore.scanner.IssueExclusionsLoader; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.mock; @@ -31,8 +34,9 @@ public class MetadataGeneratorProviderTest { @Test public void create_builder() { StatusDetectionFactory statusDetectionFactory = mock(StatusDetectionFactory.class, Mockito.RETURNS_MOCKS); + IssueExclusionsLoader issueExclusionsLoader = new IssueExclusionsLoader(mock(IssueExclusionPatternInitializer.class), mock(PatternMatcher.class)); MetadataGeneratorProvider factory = new MetadataGeneratorProvider(); - assertThat(factory.provide(new DefaultInputModule("module"), statusDetectionFactory, new FileMetadata())).isNotNull(); + assertThat(factory.provide(new DefaultInputModule("module"), statusDetectionFactory, new FileMetadata(), issueExclusionsLoader)).isNotNull(); } } diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/filesystem/MetadataGeneratorTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/filesystem/MetadataGeneratorTest.java index 9fddf40b8e1..67b455a9986 100644 --- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/filesystem/MetadataGeneratorTest.java +++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/filesystem/MetadataGeneratorTest.java @@ -20,6 +20,7 @@ package org.sonar.scanner.scan.filesystem; import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import java.nio.charset.StandardCharsets; @@ -40,6 +41,9 @@ import org.sonar.api.batch.fs.internal.DefaultInputModule; import org.sonar.api.batch.fs.internal.FileMetadata; import org.sonar.api.batch.fs.internal.TestInputFileBuilder; import org.sonar.api.utils.PathUtils; +import org.sonar.scanner.issue.ignore.pattern.IssueExclusionPatternInitializer; +import org.sonar.scanner.issue.ignore.pattern.PatternMatcher; +import org.sonar.scanner.issue.ignore.scanner.IssueExclusionsLoader; public class MetadataGeneratorTest { @Rule @@ -57,7 +61,8 @@ public class MetadataGeneratorTest { public void setUp() { MockitoAnnotations.initMocks(this); metadata = new FileMetadata(); - generator = new MetadataGenerator(new DefaultInputModule("module"), statusDetection, metadata); + IssueExclusionsLoader issueExclusionsLoader = new IssueExclusionsLoader(mock(IssueExclusionPatternInitializer.class), mock(PatternMatcher.class)); + generator = new MetadataGenerator(new DefaultInputModule("module"), statusDetection, metadata, issueExclusionsLoader); } @Test diff --git a/sonar-scanner-engine/src/test/resources/org/sonar/scanner/issue/ignore/scanner/IssueExclusionsRegexpScannerTest/file-with-single-regexp-last-line.txt b/sonar-scanner-engine/src/test/resources/org/sonar/scanner/issue/ignore/scanner/IssueExclusionsRegexpScannerTest/file-with-single-regexp-last-line.txt new file mode 100644 index 00000000000..ef135ebc50c --- /dev/null +++ b/sonar-scanner-engine/src/test/resources/org/sonar/scanner/issue/ignore/scanner/IssueExclusionsRegexpScannerTest/file-with-single-regexp-last-line.txt @@ -0,0 +1,33 @@ +package org.sonar.plugins.switchoffviolations.pattern; + +import com.google.common.collect.Sets; + +import java.util.Set; + +/** + * @SONAR-IGNORE-ALL + */ +public class LineRange { + int from, to; + + public LineRange(int from, int to) { + if (to < from) { + throw new IllegalArgumentException("Line range is not valid: " + from + " must be greater than " + to); + } + this.from = from; + this.to = to; + } + + public boolean in(int lineId) { + return from <= lineId && lineId <= to; + } + + public Set toLines() { + Set lines = Sets.newLinkedHashSet(); + for (int index = from; index <= to; index++) { + lines.add(index); + } + return lines; + } + +} \ No newline at end of file diff --git a/sonar-scanner-engine/src/test/resources/org/sonar/scanner/issue/ignore/scanner/IssueExclusionsRegexpScannerTest/file-with-single-regexp.txt b/sonar-scanner-engine/src/test/resources/org/sonar/scanner/issue/ignore/scanner/IssueExclusionsRegexpScannerTest/file-with-single-regexp.txt index ef135ebc50c..88ad675955f 100644 --- a/sonar-scanner-engine/src/test/resources/org/sonar/scanner/issue/ignore/scanner/IssueExclusionsRegexpScannerTest/file-with-single-regexp.txt +++ b/sonar-scanner-engine/src/test/resources/org/sonar/scanner/issue/ignore/scanner/IssueExclusionsRegexpScannerTest/file-with-single-regexp.txt @@ -4,9 +4,6 @@ import com.google.common.collect.Sets; import java.util.Set; -/** - * @SONAR-IGNORE-ALL - */ public class LineRange { int from, to; @@ -30,4 +27,5 @@ public class LineRange { return lines; } -} \ No newline at end of file +} +// @SONAR-IGNORE-ALL \ No newline at end of file -- 2.39.5