diff options
author | Jean-Baptiste Lievremont <jean-baptiste.lievremont@sonarsource.com> | 2013-09-20 17:58:26 +0200 |
---|---|---|
committer | Jean-Baptiste Lievremont <jean-baptiste.lievremont@sonarsource.com> | 2013-09-23 10:17:15 +0200 |
commit | 77c2096d4a2b85cfaede47566cd0aa59bea524dd (patch) | |
tree | 0d477f5f23b316b781e73ae1c62f477f6d0ee93a /plugins | |
parent | 501e92cfd1292455f5d93d91a86bfa0cf69fc73c (diff) | |
download | sonarqube-77c2096d4a2b85cfaede47566cd0aa59bea524dd.tar.gz sonarqube-77c2096d4a2b85cfaede47566cd0aa59bea524dd.zip |
SONAR-4679 Implement include filters by excluding all other resources
Diffstat (limited to 'plugins')
18 files changed, 541 insertions, 219 deletions
diff --git a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/ignore/EnforceIssuesFilter.java b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/ignore/EnforceIssuesFilter.java new file mode 100644 index 00000000000..1a5d89b9a2d --- /dev/null +++ b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/ignore/EnforceIssuesFilter.java @@ -0,0 +1,40 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2013 SonarSource + * mailto:contact AT sonarsource DOT com + * + * SonarQube 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. + * + * SonarQube 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.plugins.core.issue.ignore; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.sonar.api.issue.Issue; +import org.sonar.plugins.core.issue.ignore.pattern.InclusionPatternInitializer; +import org.sonar.plugins.core.issue.ignore.pattern.IssuePattern; + +public final class EnforceIssuesFilter extends IssuesFilterBase { + + private static final Logger LOG = LoggerFactory.getLogger(EnforceIssuesFilter.class); + + public EnforceIssuesFilter(InclusionPatternInitializer patternInitializer) { + super(patternInitializer); + } + + @Override + protected void logExclusion(Issue issue, IssuePattern pattern) { + LOG.debug("Issue {} ignored by inclusion pattern {}", issue, pattern); + } +} diff --git a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/ignore/IgnoreIssuesConfiguration.java b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/ignore/IgnoreIssuesConfiguration.java index 62bba097ae3..a27823d4724 100644 --- a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/ignore/IgnoreIssuesConfiguration.java +++ b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/ignore/IgnoreIssuesConfiguration.java @@ -33,21 +33,26 @@ public final class IgnoreIssuesConfiguration { public static final String SUB_CATEGORY_IGNORE_ISSUES = "issues"; - public static final String CORE_KEY_PREFIX = "sonar.issue.ignore"; + public static final String EXCLUSION_KEY_PREFIX = "sonar.issue.ignore"; + public static final String INCLUSION_KEY_PREFIX = "sonar.issue.enforce"; public static final String MULTICRITERIA_SUFFIX = ".multicriteria"; - public static final String PATTERNS_MULTICRITERIA_KEY = CORE_KEY_PREFIX + MULTICRITERIA_SUFFIX; + public static final String PATTERNS_MULTICRITERIA_EXCLUSION_KEY = EXCLUSION_KEY_PREFIX + MULTICRITERIA_SUFFIX; + public static final String PATTERNS_MULTICRITERIA_INCLUSION_KEY = INCLUSION_KEY_PREFIX + MULTICRITERIA_SUFFIX; public static final String RESOURCE_KEY = "resourceKey"; + private static final String PROPERTY_FILE_PATH_PATTERN = "File Path Pattern"; public static final String RULE_KEY = "ruleKey"; + private static final String PROPERTY_RULE_KEY_PATTERN = "Rule Key Pattern"; public static final String LINE_RANGE_KEY = "lineRange"; + private static final String PROPERTY_LINE_RANGE = "Line Range"; public static final String BLOCK_SUFFIX = ".block"; - public static final String PATTERNS_BLOCK_KEY = CORE_KEY_PREFIX + BLOCK_SUFFIX; + public static final String PATTERNS_BLOCK_KEY = EXCLUSION_KEY_PREFIX + BLOCK_SUFFIX; public static final String BEGIN_BLOCK_REGEXP = "beginBlockRegexp"; public static final String END_BLOCK_REGEXP = "endBlockRegexp"; public static final String ALLFILE_SUFFIX = ".allfile"; - public static final String PATTERNS_ALLFILE_KEY = CORE_KEY_PREFIX + ALLFILE_SUFFIX; + public static final String PATTERNS_ALLFILE_KEY = EXCLUSION_KEY_PREFIX + ALLFILE_SUFFIX; public static final String FILE_REGEXP = "fileRegexp"; private IgnoreIssuesConfiguration() { @@ -59,7 +64,7 @@ public final class IgnoreIssuesConfiguration { public static List<PropertyDefinition> getPropertyDefinitions() { return ImmutableList.of( - PropertyDefinition.builder(PATTERNS_MULTICRITERIA_KEY) + PropertyDefinition.builder(PATTERNS_MULTICRITERIA_EXCLUSION_KEY) .category(CoreProperties.CATEGORY_EXCLUSIONS) .subCategory(SUB_CATEGORY_IGNORE_ISSUES) .name("Multi-criteria Exclusion Patterns") @@ -68,25 +73,25 @@ public final class IgnoreIssuesConfiguration { .index(3) .fields( PropertyFieldDefinition.build(RESOURCE_KEY) - .name("File Path Pattern") + .name(PROPERTY_FILE_PATH_PATTERN) .description("Pattern used to match files which should be ignored.") .type(PropertyType.STRING) .indicativeSize(LARGE_SIZE) .build(), PropertyFieldDefinition.build(RULE_KEY) - .name("Rule Key Pattern") + .name(PROPERTY_RULE_KEY_PATTERN) .description("Pattern used to match rules which should be ignored.") .type(PropertyType.STRING) .indicativeSize(LARGE_SIZE) .build(), PropertyFieldDefinition.build(LINE_RANGE_KEY) - .name("Line Range") + .name(PROPERTY_LINE_RANGE) .description("Range of lines that should be ignored.") .type(PropertyType.STRING) .indicativeSize(SMALL_SIZE) .build()) .build(), - PropertyDefinition.builder(PATTERNS_BLOCK_KEY) + PropertyDefinition.builder(PATTERNS_BLOCK_KEY) .category(CoreProperties.CATEGORY_EXCLUSIONS) .subCategory(SUB_CATEGORY_IGNORE_ISSUES) .name("Block Exclusion Patterns") @@ -107,7 +112,7 @@ public final class IgnoreIssuesConfiguration { .indicativeSize(LARGE_SIZE) .build()) .build(), - PropertyDefinition.builder(PATTERNS_ALLFILE_KEY) + PropertyDefinition.builder(PATTERNS_ALLFILE_KEY) .category(CoreProperties.CATEGORY_EXCLUSIONS) .subCategory(SUB_CATEGORY_IGNORE_ISSUES) .name("File Exclusion Patterns") @@ -121,6 +126,33 @@ public final class IgnoreIssuesConfiguration { .type(PropertyType.STRING) .indicativeSize(LARGE_SIZE) .build()) + .build(), + PropertyDefinition.builder(PATTERNS_MULTICRITERIA_INCLUSION_KEY) + .category(CoreProperties.CATEGORY_EXCLUSIONS) + .subCategory(SUB_CATEGORY_IGNORE_ISSUES) + .name("Multi-criteria Inclusion Patterns") + .description("Patterns used to identify which issues should be enforced on selected resources.") + .onQualifiers(Qualifiers.PROJECT) + .index(4) + .fields( + PropertyFieldDefinition.build(RESOURCE_KEY) + .name(PROPERTY_FILE_PATH_PATTERN) + .description("Pattern used to match files on which issues should be enforced.") + .type(PropertyType.STRING) + .indicativeSize(LARGE_SIZE) + .build(), + PropertyFieldDefinition.build(RULE_KEY) + .name(PROPERTY_RULE_KEY_PATTERN) + .description("Pattern used to match rules which should be enforced.") + .type(PropertyType.STRING) + .indicativeSize(LARGE_SIZE) + .build(), + PropertyFieldDefinition.build(LINE_RANGE_KEY) + .name(PROPERTY_LINE_RANGE) + .description("Range of lines that should be considered.") + .type(PropertyType.STRING) + .indicativeSize(SMALL_SIZE) + .build()) .build()); } } diff --git a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/ignore/IgnoreIssuesFilter.java b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/ignore/IgnoreIssuesFilter.java index 362a7331d1b..7cc8a7f7014 100644 --- a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/ignore/IgnoreIssuesFilter.java +++ b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/ignore/IgnoreIssuesFilter.java @@ -17,37 +17,24 @@ * 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.plugins.core.issue.ignore; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.sonar.api.issue.Issue; -import org.sonar.api.issue.IssueFilter; +import org.sonar.plugins.core.issue.ignore.pattern.ExclusionPatternInitializer; import org.sonar.plugins.core.issue.ignore.pattern.IssuePattern; -import org.sonar.plugins.core.issue.ignore.pattern.PatternMatcher; -public final class IgnoreIssuesFilter implements IssueFilter { +public final class IgnoreIssuesFilter extends IssuesFilterBase { private static final Logger LOG = LoggerFactory.getLogger(IgnoreIssuesFilter.class); - private PatternMatcher patternMatcher; - - public IgnoreIssuesFilter(PatternMatcher patternMatcher) { - this.patternMatcher = patternMatcher; + public IgnoreIssuesFilter(ExclusionPatternInitializer patternInitializer) { + super(patternInitializer); } - public boolean accept(Issue issue) { - IssuePattern pattern = patternMatcher.getMatchingPattern(issue); - if (pattern != null) { - logExclusion(issue, pattern); - return false; - } - return true; + @Override + protected void logExclusion(Issue issue, IssuePattern pattern) { + LOG.debug("Issue {} ignored by exclusion pattern {}", issue, pattern); } - - private void logExclusion(Issue issue, IssuePattern pattern) { - LOG.debug("Issue {} ignored by {}", issue, pattern); - } - } diff --git a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/ignore/IgnoreIssuesPlugin.java b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/ignore/IgnoreIssuesPlugin.java index e083d44aab2..0244c519077 100644 --- a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/ignore/IgnoreIssuesPlugin.java +++ b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/ignore/IgnoreIssuesPlugin.java @@ -20,10 +20,9 @@ package org.sonar.plugins.core.issue.ignore; -import org.sonar.plugins.core.issue.ignore.pattern.PatternMatcher; - import com.google.common.collect.ImmutableList; -import org.sonar.plugins.core.issue.ignore.pattern.PatternsInitializer; +import org.sonar.plugins.core.issue.ignore.pattern.ExclusionPatternInitializer; +import org.sonar.plugins.core.issue.ignore.pattern.InclusionPatternInitializer; import org.sonar.plugins.core.issue.ignore.scanner.RegexpScanner; import org.sonar.plugins.core.issue.ignore.scanner.SourceScanner; @@ -40,10 +39,11 @@ public final class IgnoreIssuesPlugin { extensions.addAll(IgnoreIssuesConfiguration.getPropertyDefinitions()); extensions.add( - PatternsInitializer.class, - PatternMatcher.class, + InclusionPatternInitializer.class, + ExclusionPatternInitializer.class, RegexpScanner.class, SourceScanner.class, + EnforceIssuesFilter.class, IgnoreIssuesFilter.class); return extensions.build(); diff --git a/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/issue/ignore/IgnoreIssuesFilterTest.java b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/ignore/IssuesFilterBase.java index c4b4022dff4..7bb614ed6db 100644 --- a/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/issue/ignore/IgnoreIssuesFilterTest.java +++ b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/ignore/IssuesFilterBase.java @@ -17,44 +17,32 @@ * 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.plugins.core.issue.ignore; -import org.junit.Before; -import org.junit.Test; -import org.sonar.api.issue.Issue; import org.sonar.plugins.core.issue.ignore.pattern.IssuePattern; -import org.sonar.plugins.core.issue.ignore.pattern.PatternMatcher; -import static org.fest.assertions.Assertions.assertThat; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; +import org.sonar.plugins.core.issue.ignore.pattern.PatternMatcher; +import org.sonar.plugins.core.issue.ignore.pattern.AbstractPatternInitializer; +import org.sonar.api.issue.Issue; +import org.sonar.api.issue.IssueFilter; -public class IgnoreIssuesFilterTest { +public abstract class IssuesFilterBase implements IssueFilter { private PatternMatcher patternMatcher; - private IgnoreIssuesFilter filter; - private Issue issue; - @Before - public void init() { - patternMatcher = mock(PatternMatcher.class); - issue = mock(Issue.class); - - filter = new IgnoreIssuesFilter(patternMatcher); + protected IssuesFilterBase(AbstractPatternInitializer patternInitializer) { + this.patternMatcher = patternInitializer.getPatternMatcher(); } - @Test - public void shouldAcceptIfMatcherHasNoPatternForIssue() { - when(patternMatcher.getMatchingPattern(issue)).thenReturn(null); - - assertThat(filter.accept(issue)).isTrue(); + @Override + public boolean accept(Issue issue) { + IssuePattern pattern = patternMatcher.getMatchingPattern(issue); + if (pattern != null) { + logExclusion(issue, pattern); + return false; + } + return true; } - @Test - public void shouldNotAcceptIfMatcherHasPatternForIssue() { - when(patternMatcher.getMatchingPattern(issue)).thenReturn(mock(IssuePattern.class)); - - assertThat(filter.accept(issue)).isFalse(); - } + protected abstract void logExclusion(Issue issue, IssuePattern pattern); } diff --git a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/ignore/pattern/PatternsInitializer.java b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/ignore/pattern/AbstractPatternInitializer.java index d942d45db95..5ce56ec9f0f 100644 --- a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/ignore/pattern/PatternsInitializer.java +++ b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/ignore/pattern/AbstractPatternInitializer.java @@ -17,72 +17,76 @@ * 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.plugins.core.issue.ignore.pattern; import com.google.common.annotations.VisibleForTesting; import com.google.common.collect.Lists; -import org.apache.commons.lang.StringUtils; -import org.sonar.api.BatchExtension; -import org.sonar.api.config.Settings; -import org.sonar.plugins.core.issue.ignore.IgnoreIssuesConfiguration; import java.util.List; +import org.apache.commons.lang.StringUtils; +import org.sonar.plugins.core.issue.ignore.IgnoreIssuesConfiguration; import static com.google.common.base.Objects.firstNonNull; -import static com.google.common.base.Strings.nullToEmpty; +import org.sonar.api.BatchExtension; +import org.sonar.api.config.Settings; -public class PatternsInitializer implements BatchExtension { +public abstract class AbstractPatternInitializer implements BatchExtension { - private final Settings settings; + private Settings settings; private List<IssuePattern> multicriteriaPatterns; - private List<IssuePattern> blockPatterns; - private List<IssuePattern> allFilePatterns; - public PatternsInitializer(Settings settings) { + private PatternMatcher patternMatcher; + + protected AbstractPatternInitializer(Settings settings) { this.settings = settings; + this.patternMatcher = new PatternMatcher(); initPatterns(); } - public List<IssuePattern> getMulticriteriaPatterns() { - return multicriteriaPatterns; + protected Settings getSettings() { + return settings; } - public List<IssuePattern> getBlockPatterns() { - return blockPatterns; + public PatternMatcher getPatternMatcher() { + return patternMatcher; } - public List<IssuePattern> getAllFilePatterns() { - return allFilePatterns; + public List<IssuePattern> getMulticriteriaPatterns() { + return multicriteriaPatterns; } - public boolean hasFileContentPattern() { - return ! (blockPatterns.isEmpty() && allFilePatterns.isEmpty()); + public boolean hasConfiguredPatterns() { + return hasMulticriteriaPatterns(); } public boolean hasMulticriteriaPatterns() { return ! multicriteriaPatterns.isEmpty(); } - public boolean hasConfiguredPatterns() { - return hasFileContentPattern() || hasMulticriteriaPatterns(); + public void initializePatternsForPath(String relativePath, String componentKey) { + for (IssuePattern pattern: getMulticriteriaPatterns()) { + if (shouldAddPatternIfMatch(pattern.matchResource(relativePath))) { + getPatternMatcher().addPatternForComponent(componentKey, pattern); + } + } } + protected abstract boolean shouldAddPatternIfMatch(boolean match); + @VisibleForTesting protected final void initPatterns() { - multicriteriaPatterns = Lists.newArrayList(); - blockPatterns = Lists.newArrayList(); - allFilePatterns = Lists.newArrayList(); - loadPatternsFromNewProperties(); } - private void loadPatternsFromNewProperties() { + protected abstract String getMulticriteriaConfigurationKey(); + + protected void loadPatternsFromNewProperties() { // Patterns Multicriteria - String patternConf = StringUtils.defaultIfBlank(settings.getString(IgnoreIssuesConfiguration.PATTERNS_MULTICRITERIA_KEY), ""); + multicriteriaPatterns = Lists.newArrayList(); + String patternConf = StringUtils.defaultIfBlank(settings.getString(getMulticriteriaConfigurationKey()), ""); for (String id : StringUtils.split(patternConf, ',')) { - String propPrefix = IgnoreIssuesConfiguration.PATTERNS_MULTICRITERIA_KEY + "." + id + "."; + String propPrefix = getMulticriteriaConfigurationKey() + "." + id + "."; String resourceKeyPattern = settings.getString(propPrefix + IgnoreIssuesConfiguration.RESOURCE_KEY); String ruleKeyPattern = settings.getString(propPrefix + IgnoreIssuesConfiguration.RULE_KEY); String lineRange = settings.getString(propPrefix + IgnoreIssuesConfiguration.LINE_RANGE_KEY); @@ -92,27 +96,5 @@ public class PatternsInitializer implements BatchExtension { PatternDecoder.decodeRangeOfLines(pattern, firstNonNull(lineRange, "*")); multicriteriaPatterns.add(pattern); } - - // Patterns Block - patternConf = StringUtils.defaultIfBlank(settings.getString(IgnoreIssuesConfiguration.PATTERNS_BLOCK_KEY), ""); - for (String id : StringUtils.split(patternConf, ',')) { - String propPrefix = IgnoreIssuesConfiguration.PATTERNS_BLOCK_KEY + "." + id + "."; - String beginBlockRegexp = settings.getString(propPrefix + IgnoreIssuesConfiguration.BEGIN_BLOCK_REGEXP); - String endBlockRegexp = settings.getString(propPrefix + IgnoreIssuesConfiguration.END_BLOCK_REGEXP); - String[] fields = new String[] { beginBlockRegexp, endBlockRegexp }; - PatternDecoder.checkDoubleRegexpLineConstraints(StringUtils.join(fields, ","), fields); - IssuePattern pattern = new IssuePattern().setBeginBlockRegexp(nullToEmpty(beginBlockRegexp)).setEndBlockRegexp(nullToEmpty(endBlockRegexp)); - blockPatterns.add(pattern); - } - - // Patterns All File - patternConf = StringUtils.defaultIfBlank(settings.getString(IgnoreIssuesConfiguration.PATTERNS_ALLFILE_KEY), ""); - for (String id : StringUtils.split(patternConf, ',')) { - String propPrefix = IgnoreIssuesConfiguration.PATTERNS_ALLFILE_KEY + "." + id + "."; - String allFileRegexp = settings.getString(propPrefix + IgnoreIssuesConfiguration.FILE_REGEXP); - PatternDecoder.checkWholeFileRegexp(allFileRegexp); - IssuePattern pattern = new IssuePattern().setAllFileRegexp(nullToEmpty(allFileRegexp)); - allFilePatterns.add(pattern); - } } } diff --git a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/ignore/pattern/ExclusionPatternInitializer.java b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/ignore/pattern/ExclusionPatternInitializer.java new file mode 100644 index 00000000000..06ebd7c276f --- /dev/null +++ b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/ignore/pattern/ExclusionPatternInitializer.java @@ -0,0 +1,96 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2013 SonarSource + * mailto:contact AT sonarsource DOT com + * + * SonarQube 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. + * + * SonarQube 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.plugins.core.issue.ignore.pattern; + +import com.google.common.collect.Lists; +import org.apache.commons.lang.StringUtils; +import org.sonar.api.config.Settings; +import org.sonar.plugins.core.issue.ignore.IgnoreIssuesConfiguration; + +import java.util.List; + +import static com.google.common.base.Strings.nullToEmpty; + +public class ExclusionPatternInitializer extends AbstractPatternInitializer { + + private List<IssuePattern> blockPatterns; + private List<IssuePattern> allFilePatterns; + + public ExclusionPatternInitializer(Settings settings) { + super(settings); + } + + @Override + protected String getMulticriteriaConfigurationKey() { + return IgnoreIssuesConfiguration.PATTERNS_MULTICRITERIA_EXCLUSION_KEY; + } + + @Override + protected boolean shouldAddPatternIfMatch(boolean match) { + return match; + } + + @Override + public boolean hasConfiguredPatterns() { + return hasFileContentPattern() || hasMulticriteriaPatterns(); + } + + @Override + protected void loadPatternsFromNewProperties() { + super.loadPatternsFromNewProperties(); + + // Patterns Block + blockPatterns = Lists.newArrayList(); + String patternConf = StringUtils.defaultIfBlank(getSettings().getString(IgnoreIssuesConfiguration.PATTERNS_BLOCK_KEY), ""); + for (String id : StringUtils.split(patternConf, ',')) { + String propPrefix = IgnoreIssuesConfiguration.PATTERNS_BLOCK_KEY + "." + id + "."; + String beginBlockRegexp = getSettings().getString(propPrefix + IgnoreIssuesConfiguration.BEGIN_BLOCK_REGEXP); + String endBlockRegexp = getSettings().getString(propPrefix + IgnoreIssuesConfiguration.END_BLOCK_REGEXP); + String[] fields = new String[] { beginBlockRegexp, endBlockRegexp }; + PatternDecoder.checkDoubleRegexpLineConstraints(StringUtils.join(fields, ","), fields); + IssuePattern pattern = new IssuePattern().setBeginBlockRegexp(nullToEmpty(beginBlockRegexp)).setEndBlockRegexp(nullToEmpty(endBlockRegexp)); + blockPatterns.add(pattern); + } + + // Patterns All File + allFilePatterns = Lists.newArrayList(); + patternConf = StringUtils.defaultIfBlank(getSettings().getString(IgnoreIssuesConfiguration.PATTERNS_ALLFILE_KEY), ""); + for (String id : StringUtils.split(patternConf, ',')) { + String propPrefix = IgnoreIssuesConfiguration.PATTERNS_ALLFILE_KEY + "." + id + "."; + String allFileRegexp = getSettings().getString(propPrefix + IgnoreIssuesConfiguration.FILE_REGEXP); + PatternDecoder.checkWholeFileRegexp(allFileRegexp); + IssuePattern pattern = new IssuePattern().setAllFileRegexp(nullToEmpty(allFileRegexp)); + allFilePatterns.add(pattern); + } + } + + public List<IssuePattern> getBlockPatterns() { + return blockPatterns; + } + + public List<IssuePattern> getAllFilePatterns() { + return allFilePatterns; + } + + public boolean hasFileContentPattern() { + return ! (blockPatterns.isEmpty() && allFilePatterns.isEmpty()); + } +} diff --git a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/ignore/pattern/InclusionPatternInitializer.java b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/ignore/pattern/InclusionPatternInitializer.java new file mode 100644 index 00000000000..292fc33d2df --- /dev/null +++ b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/ignore/pattern/InclusionPatternInitializer.java @@ -0,0 +1,42 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2013 SonarSource + * mailto:contact AT sonarsource DOT com + * + * SonarQube 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. + * + * SonarQube 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.plugins.core.issue.ignore.pattern; + +import org.sonar.api.config.Settings; +import org.sonar.plugins.core.issue.ignore.IgnoreIssuesConfiguration; + +public class InclusionPatternInitializer extends AbstractPatternInitializer { + + public InclusionPatternInitializer(Settings settings) { + super(settings); + } + + @Override + protected String getMulticriteriaConfigurationKey() { + return IgnoreIssuesConfiguration.PATTERNS_MULTICRITERIA_INCLUSION_KEY; + } + + @Override + protected boolean shouldAddPatternIfMatch(boolean match) { + return ! match; + } + +} diff --git a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/ignore/pattern/IssuePattern.java b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/ignore/pattern/IssuePattern.java index f4e80ac86cf..458292a6e80 100644 --- a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/ignore/pattern/IssuePattern.java +++ b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/ignore/pattern/IssuePattern.java @@ -143,7 +143,7 @@ public class IssuePattern { return false; } - public boolean matchRule(RuleKey rule) { + boolean matchRule(RuleKey rule) { if (rule == null) { return false; } @@ -152,7 +152,7 @@ public class IssuePattern { return rulePattern.match(key); } - public boolean matchResource(String resource) { + boolean matchResource(String resource) { return resource != null && resourcePattern.match(resource); } diff --git a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/ignore/pattern/PatternMatcher.java b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/ignore/pattern/PatternMatcher.java index 40b923d75e3..a01be7b19a2 100644 --- a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/ignore/pattern/PatternMatcher.java +++ b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/ignore/pattern/PatternMatcher.java @@ -19,17 +19,15 @@ */ package org.sonar.plugins.core.issue.ignore.pattern; -import com.google.common.annotations.VisibleForTesting; import com.google.common.collect.LinkedHashMultimap; import com.google.common.collect.Multimap; -import org.sonar.api.BatchExtension; import org.sonar.api.issue.Issue; import java.util.Collection; import java.util.Iterator; import java.util.Set; -public class PatternMatcher implements BatchExtension { +public class PatternMatcher { private Multimap<String, IssuePattern> patternByComponent = LinkedHashMultimap.create(); @@ -45,8 +43,7 @@ public class PatternMatcher implements BatchExtension { return matchingPattern; } - @VisibleForTesting - Collection<IssuePattern> getPatternsForComponent(String componentKey) { + public Collection<IssuePattern> getPatternsForComponent(String componentKey) { return patternByComponent.get(componentKey); } diff --git a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/ignore/scanner/RegexpScanner.java b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/ignore/scanner/RegexpScanner.java index 3001337abc8..b479000d013 100644 --- a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/ignore/scanner/RegexpScanner.java +++ b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/ignore/scanner/RegexpScanner.java @@ -20,18 +20,16 @@ package org.sonar.plugins.core.issue.ignore.scanner; -import org.sonar.plugins.core.issue.ignore.pattern.PatternMatcher; - -import org.apache.commons.lang.StringUtils; import com.google.common.collect.Lists; import com.google.common.collect.Sets; import org.apache.commons.io.FileUtils; +import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.sonar.api.BatchExtension; -import org.sonar.plugins.core.issue.ignore.pattern.LineRange; +import org.sonar.plugins.core.issue.ignore.pattern.ExclusionPatternInitializer; import org.sonar.plugins.core.issue.ignore.pattern.IssuePattern; -import org.sonar.plugins.core.issue.ignore.pattern.PatternsInitializer; +import org.sonar.plugins.core.issue.ignore.pattern.LineRange; import java.io.File; import java.io.IOException; @@ -43,7 +41,7 @@ public class RegexpScanner implements BatchExtension { private static final Logger LOG = LoggerFactory.getLogger(RegexpScanner.class); - private PatternMatcher patternMatcher; + private ExclusionPatternInitializer exclusionPatternInitializer; private List<java.util.regex.Pattern> allFilePatterns; private List<DoubleRegexpMatcher> blockMatchers; @@ -53,8 +51,8 @@ public class RegexpScanner implements BatchExtension { private List<LineExclusion> lineExclusions; private LineExclusion currentLineExclusion; - public RegexpScanner(PatternsInitializer patternsInitializer, PatternMatcher patternMatcher) { - this.patternMatcher = patternMatcher; + public RegexpScanner(ExclusionPatternInitializer patternsInitializer) { + this.exclusionPatternInitializer = patternsInitializer; lineExclusions = Lists.newArrayList(); allFilePatterns = Lists.newArrayList(); @@ -94,7 +92,7 @@ public class RegexpScanner implements BatchExtension { // 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()) { - patternMatcher.addPatternToExcludeResource(resource); + exclusionPatternInitializer.getPatternMatcher().addPatternToExcludeResource(resource); // nothing more to do on this file LOG.debug("- Exclusion pattern '{}': every violation in this file will be ignored.", pattern); return; @@ -115,7 +113,7 @@ public class RegexpScanner implements BatchExtension { if (!lineExclusions.isEmpty()) { Set<LineRange> lineRanges = convertLineExclusionsToLineRanges(); LOG.debug("- Line exclusions found: {}", lineRanges); - patternMatcher.addPatternToExcludeLines(resource, lineRanges); + exclusionPatternInitializer.getPatternMatcher().addPatternToExcludeLines(resource, lineRanges); } } diff --git a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/ignore/scanner/SourceScanner.java b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/ignore/scanner/SourceScanner.java index 8fc73aac95f..0f3f06e185b 100644 --- a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/ignore/scanner/SourceScanner.java +++ b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/ignore/scanner/SourceScanner.java @@ -20,9 +20,6 @@ package org.sonar.plugins.core.issue.ignore.scanner; -import org.sonar.plugins.core.issue.ignore.pattern.PatternMatcher; - -import org.sonar.plugins.core.issue.ignore.pattern.IssuePattern; import org.sonar.api.batch.Phase; import org.sonar.api.batch.Sensor; import org.sonar.api.batch.SensorContext; @@ -35,7 +32,8 @@ import org.sonar.api.scan.filesystem.ModuleFileSystem; import org.sonar.api.scan.filesystem.PathResolver; import org.sonar.api.utils.SonarException; import org.sonar.core.component.ComponentKeys; -import org.sonar.plugins.core.issue.ignore.pattern.PatternsInitializer; +import org.sonar.plugins.core.issue.ignore.pattern.ExclusionPatternInitializer; +import org.sonar.plugins.core.issue.ignore.pattern.InclusionPatternInitializer; import java.io.File; import java.nio.charset.Charset; @@ -45,21 +43,23 @@ import java.util.List; public final class SourceScanner implements Sensor { private final RegexpScanner regexpScanner; - private final PatternsInitializer patternsInitializer; - private final PatternMatcher patternMatcher; + private final ExclusionPatternInitializer exclusionPatternInitializer; + private final InclusionPatternInitializer inclusionPatternInitializer; private final ModuleFileSystem fileSystem; private final PathResolver pathResolver; - public SourceScanner(RegexpScanner regexpScanner, PatternsInitializer patternsInitializer, PatternMatcher patternMatcher, ModuleFileSystem fileSystem) { + public SourceScanner(RegexpScanner regexpScanner, ExclusionPatternInitializer exclusionPatternInitializer, InclusionPatternInitializer inclusionPatternInitializer, + ModuleFileSystem fileSystem) { this.regexpScanner = regexpScanner; - this.patternsInitializer = patternsInitializer; - this.patternMatcher = patternMatcher; + this.exclusionPatternInitializer = exclusionPatternInitializer; + this.inclusionPatternInitializer = inclusionPatternInitializer; this.fileSystem = fileSystem; this.pathResolver = new PathResolver(); } public boolean shouldExecuteOnProject(Project project) { - return patternsInitializer.hasConfiguredPatterns(); + return inclusionPatternInitializer.hasConfiguredPatterns() + || exclusionPatternInitializer.hasConfiguredPatterns(); } /** @@ -89,12 +89,9 @@ public final class SourceScanner implements Sensor { if (componentKey != null) { String relativePath = pathResolver.relativePath(dirs, inputFile).path(); - for (IssuePattern pattern: patternsInitializer.getMulticriteriaPatterns()) { - if (pattern.matchResource(relativePath)) { - patternMatcher.addPatternForComponent(componentKey, pattern); - } - } - if (patternsInitializer.hasFileContentPattern()) { + inclusionPatternInitializer.initializePatternsForPath(relativePath, componentKey); + exclusionPatternInitializer.initializePatternsForPath(relativePath, componentKey); + if (exclusionPatternInitializer.hasFileContentPattern()) { regexpScanner.scan(componentKey, inputFile, sourcesEncoding); } } diff --git a/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/issue/ignore/IgnoreIssuesPluginTest.java b/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/issue/ignore/IgnoreIssuesPluginTest.java index ca2b2dcf0b5..339ebee90f3 100644 --- a/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/issue/ignore/IgnoreIssuesPluginTest.java +++ b/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/issue/ignore/IgnoreIssuesPluginTest.java @@ -27,6 +27,6 @@ import static org.fest.assertions.Assertions.assertThat; public class IgnoreIssuesPluginTest { @Test public void justForCoverage() { - assertThat(IgnoreIssuesPlugin.getExtensions()).hasSize(3 /* properties */ + 5 /* extensions */); + assertThat(IgnoreIssuesPlugin.getExtensions()).hasSize(4 /* properties */ + 6 /* extensions */); } } diff --git a/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/issue/ignore/IssuesFilterTest.java b/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/issue/ignore/IssuesFilterTest.java new file mode 100644 index 00000000000..a04f02928a4 --- /dev/null +++ b/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/issue/ignore/IssuesFilterTest.java @@ -0,0 +1,76 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2013 SonarSource + * mailto:contact AT sonarsource DOT com + * + * SonarQube 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. + * + * SonarQube 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.plugins.core.issue.ignore; + +import org.junit.Before; +import org.junit.Test; +import org.sonar.api.issue.Issue; +import org.sonar.plugins.core.issue.ignore.pattern.ExclusionPatternInitializer; +import org.sonar.plugins.core.issue.ignore.pattern.InclusionPatternInitializer; +import org.sonar.plugins.core.issue.ignore.pattern.IssuePattern; +import org.sonar.plugins.core.issue.ignore.pattern.PatternMatcher; + +import static org.fest.assertions.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class IssuesFilterTest { + + private InclusionPatternInitializer inclusionPatternInitializer; + private ExclusionPatternInitializer exclusionPatternInitializer; + private PatternMatcher inclusionPatternMatcher; + private PatternMatcher exclusionPatternMatcher; + private IgnoreIssuesFilter ignoreFilter; + private EnforceIssuesFilter enforceFilter; + private Issue issue; + + @Before + public void init() { + exclusionPatternMatcher = mock(PatternMatcher.class); + exclusionPatternInitializer = mock(ExclusionPatternInitializer.class); + when(exclusionPatternInitializer.getPatternMatcher()).thenReturn(exclusionPatternMatcher); + inclusionPatternMatcher = mock(PatternMatcher.class); + inclusionPatternInitializer = mock(InclusionPatternInitializer.class); + when(inclusionPatternInitializer.getPatternMatcher()).thenReturn(inclusionPatternMatcher); + issue = mock(Issue.class); + + ignoreFilter = new IgnoreIssuesFilter(exclusionPatternInitializer); + enforceFilter = new EnforceIssuesFilter(inclusionPatternInitializer); + } + + @Test + public void shouldAcceptIfMatcherHasNoPatternForIssue() { + when(inclusionPatternMatcher.getMatchingPattern(issue)).thenReturn(null); + when(exclusionPatternMatcher.getMatchingPattern(issue)).thenReturn(null); + + assertThat(ignoreFilter.accept(issue)).isTrue(); + assertThat(enforceFilter.accept(issue)).isTrue(); + } + + @Test + public void shouldNotAcceptIfMatcherHasPatternForIssue() { + when(inclusionPatternMatcher.getMatchingPattern(issue)).thenReturn(mock(IssuePattern.class)); + when(exclusionPatternMatcher.getMatchingPattern(issue)).thenReturn(mock(IssuePattern.class)); + + assertThat(ignoreFilter.accept(issue)).isFalse(); + assertThat(enforceFilter.accept(issue)).isFalse(); + } +} diff --git a/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/issue/ignore/pattern/PatternsInitializerTest.java b/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/issue/ignore/pattern/ExclusionPatternInitializerTest.java index aec0ea0d1de..ecee38a4373 100644 --- a/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/issue/ignore/pattern/PatternsInitializerTest.java +++ b/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/issue/ignore/pattern/ExclusionPatternInitializerTest.java @@ -29,16 +29,16 @@ import org.sonar.plugins.core.issue.ignore.IgnoreIssuesConfiguration; import static org.fest.assertions.Assertions.assertThat; -public class PatternsInitializerTest { +public class ExclusionPatternInitializerTest { - private PatternsInitializer patternsInitializer; + private ExclusionPatternInitializer patternsInitializer; private Settings settings; @Before public void init() { settings = new Settings(new PropertyDefinitions(IgnoreIssuesConfiguration.getPropertyDefinitions())); - patternsInitializer = new PatternsInitializer(settings); + patternsInitializer = new ExclusionPatternInitializer(settings); } @Test @@ -49,14 +49,14 @@ public class PatternsInitializerTest { } @Test - public void shouldReturnMulticriteriaPattern() { - settings.setProperty(IgnoreIssuesConfiguration.PATTERNS_MULTICRITERIA_KEY, "1,2"); - settings.setProperty(IgnoreIssuesConfiguration.PATTERNS_MULTICRITERIA_KEY + ".1." + IgnoreIssuesConfiguration.RESOURCE_KEY, "org/foo/Bar.java"); - settings.setProperty(IgnoreIssuesConfiguration.PATTERNS_MULTICRITERIA_KEY + ".1." + IgnoreIssuesConfiguration.RULE_KEY, "*"); - settings.setProperty(IgnoreIssuesConfiguration.PATTERNS_MULTICRITERIA_KEY + ".1." + IgnoreIssuesConfiguration.LINE_RANGE_KEY, "*"); - settings.setProperty(IgnoreIssuesConfiguration.PATTERNS_MULTICRITERIA_KEY + ".2." + IgnoreIssuesConfiguration.RESOURCE_KEY, "org/foo/Hello.java"); - settings.setProperty(IgnoreIssuesConfiguration.PATTERNS_MULTICRITERIA_KEY + ".2." + IgnoreIssuesConfiguration.RULE_KEY, "checkstyle:MagicNumber"); - settings.setProperty(IgnoreIssuesConfiguration.PATTERNS_MULTICRITERIA_KEY + ".2." + IgnoreIssuesConfiguration.LINE_RANGE_KEY, "[15-200]"); + public void shouldHavePatternsBasedOnMulticriteriaPattern() { + settings.setProperty(IgnoreIssuesConfiguration.PATTERNS_MULTICRITERIA_EXCLUSION_KEY, "1,2"); + settings.setProperty(IgnoreIssuesConfiguration.PATTERNS_MULTICRITERIA_EXCLUSION_KEY + ".1." + IgnoreIssuesConfiguration.RESOURCE_KEY, "org/foo/Bar.java"); + settings.setProperty(IgnoreIssuesConfiguration.PATTERNS_MULTICRITERIA_EXCLUSION_KEY + ".1." + IgnoreIssuesConfiguration.RULE_KEY, "*"); + settings.setProperty(IgnoreIssuesConfiguration.PATTERNS_MULTICRITERIA_EXCLUSION_KEY + ".1." + IgnoreIssuesConfiguration.LINE_RANGE_KEY, "*"); + settings.setProperty(IgnoreIssuesConfiguration.PATTERNS_MULTICRITERIA_EXCLUSION_KEY + ".2." + IgnoreIssuesConfiguration.RESOURCE_KEY, "org/foo/Hello.java"); + settings.setProperty(IgnoreIssuesConfiguration.PATTERNS_MULTICRITERIA_EXCLUSION_KEY + ".2." + IgnoreIssuesConfiguration.RULE_KEY, "checkstyle:MagicNumber"); + settings.setProperty(IgnoreIssuesConfiguration.PATTERNS_MULTICRITERIA_EXCLUSION_KEY + ".2." + IgnoreIssuesConfiguration.LINE_RANGE_KEY, "[15-200]"); patternsInitializer.initPatterns(); assertThat(patternsInitializer.hasConfiguredPatterns()).isTrue(); @@ -65,32 +65,41 @@ public class PatternsInitializerTest { 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) public void shouldLogInvalidResourceKey() { - settings.setProperty(IgnoreIssuesConfiguration.PATTERNS_MULTICRITERIA_KEY, "1"); - settings.setProperty(IgnoreIssuesConfiguration.PATTERNS_MULTICRITERIA_KEY + ".1." + IgnoreIssuesConfiguration.RESOURCE_KEY, ""); - settings.setProperty(IgnoreIssuesConfiguration.PATTERNS_MULTICRITERIA_KEY + ".1." + IgnoreIssuesConfiguration.RULE_KEY, "*"); - settings.setProperty(IgnoreIssuesConfiguration.PATTERNS_MULTICRITERIA_KEY + ".1." + IgnoreIssuesConfiguration.LINE_RANGE_KEY, "*"); + settings.setProperty(IgnoreIssuesConfiguration.PATTERNS_MULTICRITERIA_EXCLUSION_KEY, "1"); + settings.setProperty(IgnoreIssuesConfiguration.PATTERNS_MULTICRITERIA_EXCLUSION_KEY + ".1." + IgnoreIssuesConfiguration.RESOURCE_KEY, ""); + settings.setProperty(IgnoreIssuesConfiguration.PATTERNS_MULTICRITERIA_EXCLUSION_KEY + ".1." + IgnoreIssuesConfiguration.RULE_KEY, "*"); + settings.setProperty(IgnoreIssuesConfiguration.PATTERNS_MULTICRITERIA_EXCLUSION_KEY + ".1." + IgnoreIssuesConfiguration.LINE_RANGE_KEY, "*"); patternsInitializer.initPatterns(); } @Test(expected = SonarException.class) public void shouldLogInvalidRuleKey() { - settings.setProperty(IgnoreIssuesConfiguration.PATTERNS_MULTICRITERIA_KEY, "1"); - settings.setProperty(IgnoreIssuesConfiguration.PATTERNS_MULTICRITERIA_KEY + ".1." + IgnoreIssuesConfiguration.RESOURCE_KEY, "*"); - settings.setProperty(IgnoreIssuesConfiguration.PATTERNS_MULTICRITERIA_KEY + ".1." + IgnoreIssuesConfiguration.RULE_KEY, ""); - settings.setProperty(IgnoreIssuesConfiguration.PATTERNS_MULTICRITERIA_KEY + ".1." + IgnoreIssuesConfiguration.LINE_RANGE_KEY, "*"); + settings.setProperty(IgnoreIssuesConfiguration.PATTERNS_MULTICRITERIA_EXCLUSION_KEY, "1"); + settings.setProperty(IgnoreIssuesConfiguration.PATTERNS_MULTICRITERIA_EXCLUSION_KEY + ".1." + IgnoreIssuesConfiguration.RESOURCE_KEY, "*"); + settings.setProperty(IgnoreIssuesConfiguration.PATTERNS_MULTICRITERIA_EXCLUSION_KEY + ".1." + IgnoreIssuesConfiguration.RULE_KEY, ""); + settings.setProperty(IgnoreIssuesConfiguration.PATTERNS_MULTICRITERIA_EXCLUSION_KEY + ".1." + IgnoreIssuesConfiguration.LINE_RANGE_KEY, "*"); patternsInitializer.initPatterns(); } @Test(expected = SonarException.class) public void shouldLogInvalidLineRange() { - settings.setProperty(IgnoreIssuesConfiguration.PATTERNS_MULTICRITERIA_KEY, "1"); - settings.setProperty(IgnoreIssuesConfiguration.PATTERNS_MULTICRITERIA_KEY + ".1." + IgnoreIssuesConfiguration.RESOURCE_KEY, "org/foo/Bar.java"); - settings.setProperty(IgnoreIssuesConfiguration.PATTERNS_MULTICRITERIA_KEY + ".1." + IgnoreIssuesConfiguration.RULE_KEY, "*"); - settings.setProperty(IgnoreIssuesConfiguration.PATTERNS_MULTICRITERIA_KEY + ".1." + IgnoreIssuesConfiguration.LINE_RANGE_KEY, "notALineRange"); + settings.setProperty(IgnoreIssuesConfiguration.PATTERNS_MULTICRITERIA_EXCLUSION_KEY, "1"); + settings.setProperty(IgnoreIssuesConfiguration.PATTERNS_MULTICRITERIA_EXCLUSION_KEY + ".1." + IgnoreIssuesConfiguration.RESOURCE_KEY, "org/foo/Bar.java"); + settings.setProperty(IgnoreIssuesConfiguration.PATTERNS_MULTICRITERIA_EXCLUSION_KEY + ".1." + IgnoreIssuesConfiguration.RULE_KEY, "*"); + settings.setProperty(IgnoreIssuesConfiguration.PATTERNS_MULTICRITERIA_EXCLUSION_KEY + ".1." + IgnoreIssuesConfiguration.LINE_RANGE_KEY, "notALineRange"); patternsInitializer.initPatterns(); } diff --git a/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/issue/ignore/pattern/InclusionPatternInitializerTest.java b/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/issue/ignore/pattern/InclusionPatternInitializerTest.java new file mode 100644 index 00000000000..a0ca422d793 --- /dev/null +++ b/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/issue/ignore/pattern/InclusionPatternInitializerTest.java @@ -0,0 +1,74 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2013 SonarSource + * mailto:contact AT sonarsource DOT com + * + * SonarQube 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. + * + * SonarQube 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.plugins.core.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.plugins.core.issue.ignore.IgnoreIssuesConfiguration; + +import static org.fest.assertions.Assertions.assertThat; + +public class InclusionPatternInitializerTest { + + private InclusionPatternInitializer patternsInitializer; + + private Settings settings; + + @Before + public void init() { + settings = new Settings(new PropertyDefinitions(IgnoreIssuesConfiguration.getPropertyDefinitions())); + patternsInitializer = new InclusionPatternInitializer(settings); + } + + @Test + public void testNoConfiguration() { + patternsInitializer.initPatterns(); + assertThat(patternsInitializer.hasConfiguredPatterns()).isFalse(); + assertThat(patternsInitializer.getMulticriteriaPatterns().size()).isEqualTo(0); + } + + @Test + public void shouldHavePatternsBasedOnMulticriteriaPattern() { + settings.setProperty(IgnoreIssuesConfiguration.PATTERNS_MULTICRITERIA_INCLUSION_KEY, "1,2"); + settings.setProperty(IgnoreIssuesConfiguration.PATTERNS_MULTICRITERIA_INCLUSION_KEY + ".1." + IgnoreIssuesConfiguration.RESOURCE_KEY, "org/foo/Bar.java"); + settings.setProperty(IgnoreIssuesConfiguration.PATTERNS_MULTICRITERIA_INCLUSION_KEY + ".1." + IgnoreIssuesConfiguration.RULE_KEY, "*"); + settings.setProperty(IgnoreIssuesConfiguration.PATTERNS_MULTICRITERIA_INCLUSION_KEY + ".1." + IgnoreIssuesConfiguration.LINE_RANGE_KEY, "*"); + settings.setProperty(IgnoreIssuesConfiguration.PATTERNS_MULTICRITERIA_INCLUSION_KEY + ".2." + IgnoreIssuesConfiguration.RESOURCE_KEY, "org/foo/Hello.java"); + settings.setProperty(IgnoreIssuesConfiguration.PATTERNS_MULTICRITERIA_INCLUSION_KEY + ".2." + IgnoreIssuesConfiguration.RULE_KEY, "checkstyle:MagicNumber"); + settings.setProperty(IgnoreIssuesConfiguration.PATTERNS_MULTICRITERIA_INCLUSION_KEY + ".2." + IgnoreIssuesConfiguration.LINE_RANGE_KEY, "[15-200]"); + patternsInitializer.initPatterns(); + + 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.getPatternMatcher().getPatternsForComponent("org.foo.Bar")).hasSize(1); + assertThat(patternsInitializer.getPatternMatcher().getPatternsForComponent("org.foo.Baz")).hasSize(2); + assertThat(patternsInitializer.getPatternMatcher().getPatternsForComponent("org.foo.Hello")).hasSize(1); + } + +} diff --git a/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/issue/ignore/scanner/RegexpScannerTest.java b/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/issue/ignore/scanner/RegexpScannerTest.java index fe7bc1973f9..3ab03f3e989 100644 --- a/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/issue/ignore/scanner/RegexpScannerTest.java +++ b/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/issue/ignore/scanner/RegexpScannerTest.java @@ -20,16 +20,15 @@ package org.sonar.plugins.core.issue.ignore.scanner; -import org.sonar.plugins.core.issue.ignore.pattern.PatternMatcher; - import com.google.common.collect.Sets; import org.junit.Before; import org.junit.Test; import org.mockito.Mock; import org.mockito.MockitoAnnotations; -import org.sonar.plugins.core.issue.ignore.pattern.LineRange; +import org.sonar.plugins.core.issue.ignore.pattern.ExclusionPatternInitializer; import org.sonar.plugins.core.issue.ignore.pattern.IssuePattern; -import org.sonar.plugins.core.issue.ignore.pattern.PatternsInitializer; +import org.sonar.plugins.core.issue.ignore.pattern.LineRange; +import org.sonar.plugins.core.issue.ignore.pattern.PatternMatcher; import org.sonar.test.TestUtils; import java.io.IOException; @@ -48,7 +47,7 @@ public class RegexpScannerTest { private String javaFile; @Mock - private PatternsInitializer patternsInitializer; + private ExclusionPatternInitializer patternsInitializer; @Mock private PatternMatcher patternMatcher; @Mock @@ -69,8 +68,9 @@ public class RegexpScannerTest { 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 RegexpScanner(patternsInitializer, patternMatcher); + regexpScanner = new RegexpScanner(patternsInitializer); verify(patternsInitializer, times(1)).getAllFilePatterns(); verify(patternsInitializer, times(1)).getBlockPatterns(); @@ -88,6 +88,7 @@ public class RegexpScannerTest { public void shouldAddPatternToExcludeFile() throws IOException { regexpScanner.scan(javaFile, TestUtils.getResource(getClass(), "file-with-single-regexp.txt"), UTF_8); + verify(patternsInitializer).getPatternMatcher(); verify(patternMatcher, times(1)).addPatternToExcludeResource(javaFile); verifyNoMoreInteractions(patternsInitializer); } @@ -96,6 +97,7 @@ public class RegexpScannerTest { public void shouldAddPatternToExcludeFileEvenIfAlsoDoubleRegexps() throws IOException { regexpScanner.scan(javaFile, TestUtils.getResource(getClass(), "file-with-single-regexp-and-double-regexp.txt"), UTF_8); + verify(patternsInitializer).getPatternMatcher(); verify(patternMatcher, times(1)).addPatternToExcludeResource(javaFile); verifyNoMoreInteractions(patternsInitializer); } @@ -106,6 +108,7 @@ public class RegexpScannerTest { Set<LineRange> lineRanges = Sets.newHashSet(); lineRanges.add(new LineRange(21, 25)); + verify(patternsInitializer).getPatternMatcher(); verify(patternMatcher, times(1)).addPatternToExcludeLines(javaFile, lineRanges); verifyNoMoreInteractions(patternsInitializer); } @@ -116,6 +119,7 @@ public class RegexpScannerTest { Set<LineRange> lineRanges = Sets.newHashSet(); lineRanges.add(new LineRange(21, 34)); + verify(patternsInitializer).getPatternMatcher(); verify(patternMatcher, times(1)).addPatternToExcludeLines(javaFile, lineRanges); verifyNoMoreInteractions(patternsInitializer); } @@ -127,6 +131,7 @@ public class RegexpScannerTest { Set<LineRange> lineRanges = Sets.newHashSet(); lineRanges.add(new LineRange(21, 25)); lineRanges.add(new LineRange(29, 33)); + verify(patternsInitializer).getPatternMatcher(); verify(patternMatcher, times(1)).addPatternToExcludeLines(javaFile, lineRanges); verifyNoMoreInteractions(patternsInitializer); } @@ -137,6 +142,7 @@ public class RegexpScannerTest { Set<LineRange> lineRanges = Sets.newHashSet(); lineRanges.add(new LineRange(25, 35)); + verify(patternsInitializer).getPatternMatcher(); verify(patternMatcher, times(1)).addPatternToExcludeLines(javaFile, lineRanges); verifyNoMoreInteractions(patternsInitializer); } @@ -147,6 +153,7 @@ public class RegexpScannerTest { Set<LineRange> lineRanges = Sets.newHashSet(); lineRanges.add(new LineRange(21, 29)); + verify(patternsInitializer).getPatternMatcher(); verify(patternMatcher, times(1)).addPatternToExcludeLines(javaFile, lineRanges); verifyNoMoreInteractions(patternsInitializer); } diff --git a/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/issue/ignore/scanner/SourceScannerTest.java b/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/issue/ignore/scanner/SourceScannerTest.java index 24860050ee3..10e62084d0c 100644 --- a/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/issue/ignore/scanner/SourceScannerTest.java +++ b/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/issue/ignore/scanner/SourceScannerTest.java @@ -32,9 +32,9 @@ import org.sonar.api.resources.Project; import org.sonar.api.scan.filesystem.FileQuery; import org.sonar.api.scan.filesystem.ModuleFileSystem; import org.sonar.api.utils.SonarException; -import org.sonar.plugins.core.issue.ignore.pattern.IssuePattern; +import org.sonar.plugins.core.issue.ignore.pattern.ExclusionPatternInitializer; +import org.sonar.plugins.core.issue.ignore.pattern.InclusionPatternInitializer; import org.sonar.plugins.core.issue.ignore.pattern.PatternMatcher; -import org.sonar.plugins.core.issue.ignore.pattern.PatternsInitializer; import java.io.File; import java.io.IOException; @@ -45,7 +45,6 @@ import java.util.List; import static com.google.common.base.Charsets.UTF_8; import static org.fest.assertions.Assertions.assertThat; import static org.mockito.Mockito.doThrow; -import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; @@ -59,7 +58,9 @@ public class SourceScannerTest { @Mock private RegexpScanner regexpScanner; @Mock - private PatternsInitializer patternsInitializer; + private InclusionPatternInitializer inclusionPatternInitializer; + @Mock + private ExclusionPatternInitializer exclusionPatternInitializer; @Mock private PatternMatcher patternMatcher; @Mock @@ -79,7 +80,7 @@ public class SourceScannerTest { Mockito.doReturn("java").when(project).getLanguageKey(); when(fileSystem.sourceCharset()).thenReturn(UTF_8); - scanner = new SourceScanner(regexpScanner, patternsInitializer, patternMatcher, fileSystem); + scanner = new SourceScanner(regexpScanner, exclusionPatternInitializer, inclusionPatternInitializer, fileSystem); } @Test @@ -89,11 +90,22 @@ public class SourceScannerTest { @Test public void shouldExecute() throws IOException { - when(patternsInitializer.hasConfiguredPatterns()).thenReturn(true); + when(exclusionPatternInitializer.hasConfiguredPatterns()).thenReturn(true); + when(inclusionPatternInitializer.hasConfiguredPatterns()).thenReturn(true); + assertThat(scanner.shouldExecuteOnProject(null)).isTrue(); + + when(exclusionPatternInitializer.hasConfiguredPatterns()).thenReturn(true); + when(inclusionPatternInitializer.hasConfiguredPatterns()).thenReturn(false); assertThat(scanner.shouldExecuteOnProject(null)).isTrue(); - when(patternsInitializer.hasConfiguredPatterns()).thenReturn(false); + when(exclusionPatternInitializer.hasConfiguredPatterns()).thenReturn(false); + when(inclusionPatternInitializer.hasConfiguredPatterns()).thenReturn(true); + assertThat(scanner.shouldExecuteOnProject(null)).isTrue(); + + when(exclusionPatternInitializer.hasConfiguredPatterns()).thenReturn(false); + when(inclusionPatternInitializer.hasConfiguredPatterns()).thenReturn(false); assertThat(scanner.shouldExecuteOnProject(null)).isFalse(); + } @Test @@ -107,10 +119,14 @@ public class SourceScannerTest { .thenReturn(Arrays.asList(testFile)); when(fileSystem.sourceDirs()).thenReturn(Arrays.asList(new File("src/main/java"))); when(fileSystem.testDirs()).thenReturn(Arrays.asList(new File("src/test/java"))); - when(patternsInitializer.hasFileContentPattern()).thenReturn(true); + when(exclusionPatternInitializer.hasFileContentPattern()).thenReturn(true); scanner.analyse(project, null); + verify(inclusionPatternInitializer).initializePatternsForPath("Foo.java", "polop:[default].Foo"); + verify(inclusionPatternInitializer).initializePatternsForPath("FooTest.java", "polop:[default].FooTest"); + verify(exclusionPatternInitializer).initializePatternsForPath("Foo.java", "polop:[default].Foo"); + verify(exclusionPatternInitializer).initializePatternsForPath("FooTest.java", "polop:[default].FooTest"); verify(regexpScanner).scan("polop:[default].Foo", sourceFile, UTF_8); verify(regexpScanner).scan("polop:[default].FooTest", testFile, UTF_8); } @@ -126,39 +142,14 @@ public class SourceScannerTest { .thenReturn(Arrays.asList(testFile)); when(fileSystem.sourceDirs()).thenReturn(Arrays.asList(new File("src/main/java"))); when(fileSystem.testDirs()).thenReturn(Arrays.asList(new File("src/test/java"))); - when(patternsInitializer.hasFileContentPattern()).thenReturn(false); + when(exclusionPatternInitializer.hasFileContentPattern()).thenReturn(false); scanner.analyse(project, null); - verifyNoMoreInteractions(regexpScanner); - } - - @Test - public void shouldAddExclusionsForMulticriteriaPatterns() throws IOException { - File sourceFile = new File("src/main/java/Foo.java"); - File testFile = new File("src/test/java/FooTest.java"); - - when(project.getLanguageKey()).thenReturn("java"); - when(fileSystem.files(Mockito.isA(FileQuery.class))) - .thenReturn(Arrays.asList(sourceFile)) - .thenReturn(Arrays.asList(testFile)); - when(fileSystem.sourceDirs()).thenReturn(Arrays.asList(new File("src/main/java"))); - when(fileSystem.testDirs()).thenReturn(Arrays.asList(new File("src/test/java"))); - - IssuePattern pattern1 = mock(IssuePattern.class); - when(pattern1.matchResource("Foo.java")).thenReturn(true); - when(pattern1.matchResource("FooTest.java")).thenReturn(false); - IssuePattern pattern2 = mock(IssuePattern.class); - when(pattern2.matchResource("Foo.java")).thenReturn(false); - when(pattern2.matchResource("FooTest.java")).thenReturn(true); - - Mockito.doReturn(ImmutableList.of(pattern1, pattern2)).when(patternsInitializer).getMulticriteriaPatterns(); - when(patternsInitializer.hasFileContentPattern()).thenReturn(false); - - scanner.analyse(project, null); - - verify(patternMatcher).addPatternForComponent("polop:[default].Foo", pattern1); - verify(patternMatcher).addPatternForComponent("polop:[default].FooTest", pattern2); + verify(inclusionPatternInitializer).initializePatternsForPath("Foo.java", "polop:[default].Foo"); + verify(inclusionPatternInitializer).initializePatternsForPath("FooTest.java", "polop:[default].FooTest"); + verify(exclusionPatternInitializer).initializePatternsForPath("Foo.java", "polop:[default].Foo"); + verify(exclusionPatternInitializer).initializePatternsForPath("FooTest.java", "polop:[default].FooTest"); verifyZeroInteractions(regexpScanner); } @@ -173,10 +164,14 @@ public class SourceScannerTest { .thenReturn(Arrays.asList(testFile)); when(fileSystem.sourceDirs()).thenReturn(ImmutableList.of(new File(""))); when(fileSystem.testDirs()).thenReturn(ImmutableList.of(new File(""))); - when(patternsInitializer.hasFileContentPattern()).thenReturn(true); + when(exclusionPatternInitializer.hasFileContentPattern()).thenReturn(true); scanner.analyse(project, null); + verify(inclusionPatternInitializer).initializePatternsForPath("Foo.php", "polop:Foo.php"); + verify(inclusionPatternInitializer).initializePatternsForPath("FooTest.php", "polop:FooTest.php"); + verify(exclusionPatternInitializer).initializePatternsForPath("Foo.php", "polop:Foo.php"); + verify(exclusionPatternInitializer).initializePatternsForPath("FooTest.php", "polop:FooTest.php"); verify(regexpScanner).scan("polop:Foo.php", sourceFile, UTF_8); verify(regexpScanner).scan("polop:FooTest.php", testFile, UTF_8); } @@ -193,11 +188,14 @@ public class SourceScannerTest { .thenReturn(empty); when(fileSystem.sourceDirs()).thenReturn(ImmutableList.of(new File("src/main/java"), new File(""))); when(fileSystem.testDirs()).thenReturn(ImmutableList.of(new File("src/test/java"))); - when(patternsInitializer.hasFileContentPattern()).thenReturn(true); + when(exclusionPatternInitializer.hasFileContentPattern()).thenReturn(true); scanner.analyse(project, null); - verify(regexpScanner, never()).scan("other.js", sourceFile, UTF_8); + verify(inclusionPatternInitializer).initializePatternsForPath("Foo.java", "polop:[default].Foo"); + verify(exclusionPatternInitializer).initializePatternsForPath("Foo.java", "polop:[default].Foo"); + verify(regexpScanner).scan("polop:[default].Foo", sourceFile, UTF_8); + verify(regexpScanner, never()).scan("other.js", otherFile, UTF_8); } @Test @@ -211,7 +209,7 @@ public class SourceScannerTest { .thenReturn(empty); when(fileSystem.sourceDirs()).thenReturn(Arrays.asList(new File("src/main/java"))); when(fileSystem.testDirs()).thenReturn(Arrays.asList(new File("src/test/java"))); - when(patternsInitializer.hasFileContentPattern()).thenReturn(true); + when(exclusionPatternInitializer.hasFileContentPattern()).thenReturn(true); scanner.analyse(project, null); @@ -224,7 +222,6 @@ public class SourceScannerTest { when(project.getLanguageKey()).thenReturn("php"); when(fileSystem.files(Mockito.isA(FileQuery.class))).thenReturn(Arrays.asList(sourceFile)); - List<IssuePattern> empty = ImmutableList.of(); doThrow(new IOException("BUG")).when(regexpScanner).scan("polop:Foo.php", sourceFile, UTF_8); thrown.expect(SonarException.class); |