Browse Source

SONAR-3644 Save changes to new API before revert

Copy resources from Switch Off Violations plugin to core
Remove references to deprecated APIs
tags/4.0
Jean-Baptiste Lievremont 10 years ago
parent
commit
c6999241df
27 changed files with 2344 additions and 2 deletions
  1. 9
    2
      plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/CorePlugin.java
  2. 47
    0
      plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/ignore/Constants.java
  3. 109
    0
      plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/ignore/IgnoreIssuesConfiguration.java
  4. 64
    0
      plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/ignore/IgnoreIssuesFilter.java
  5. 45
    0
      plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/ignore/IgnoreIssuesPlugin.java
  6. 91
    0
      plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/ignore/pattern/LineRange.java
  7. 159
    0
      plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/ignore/pattern/Pattern.java
  8. 158
    0
      plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/ignore/pattern/PatternDecoder.java
  9. 118
    0
      plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/ignore/pattern/PatternsInitializer.java
  10. 189
    0
      plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/ignore/scanner/RegexpScanner.java
  11. 112
    0
      plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/ignore/scanner/SourceScanner.java
  12. 104
    0
      plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/issue/ignore/IgnoreIssuesFilterTest.java
  13. 32
    0
      plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/issue/ignore/IgnoreIssuesPluginTest.java
  14. 73
    0
      plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/issue/ignore/pattern/LineRangeTest.java
  15. 196
    0
      plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/issue/ignore/pattern/PatternDecoderTest.java
  16. 114
    0
      plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/issue/ignore/pattern/PatternTest.java
  17. 116
    0
      plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/issue/ignore/pattern/PatternsInitializerTest.java
  18. 150
    0
      plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/issue/ignore/scanner/RegexpScannerTest.java
  19. 178
    0
      plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/issue/ignore/scanner/SourceScannerTest.java
  20. 37
    0
      plugins/sonar-core-plugin/src/test/resources/org/sonar/plugins/core/issue/ignore/scanner/RegexpScannerTest/file-with-double-regexp-mess.txt
  21. 37
    0
      plugins/sonar-core-plugin/src/test/resources/org/sonar/plugins/core/issue/ignore/scanner/RegexpScannerTest/file-with-double-regexp-twice.txt
  22. 34
    0
      plugins/sonar-core-plugin/src/test/resources/org/sonar/plugins/core/issue/ignore/scanner/RegexpScannerTest/file-with-double-regexp-unfinished.txt
  23. 35
    0
      plugins/sonar-core-plugin/src/test/resources/org/sonar/plugins/core/issue/ignore/scanner/RegexpScannerTest/file-with-double-regexp-wrong-order.txt
  24. 35
    0
      plugins/sonar-core-plugin/src/test/resources/org/sonar/plugins/core/issue/ignore/scanner/RegexpScannerTest/file-with-double-regexp.txt
  25. 33
    0
      plugins/sonar-core-plugin/src/test/resources/org/sonar/plugins/core/issue/ignore/scanner/RegexpScannerTest/file-with-no-regexp.txt
  26. 36
    0
      plugins/sonar-core-plugin/src/test/resources/org/sonar/plugins/core/issue/ignore/scanner/RegexpScannerTest/file-with-single-regexp-and-double-regexp.txt
  27. 33
    0
      plugins/sonar-core-plugin/src/test/resources/org/sonar/plugins/core/issue/ignore/scanner/RegexpScannerTest/file-with-single-regexp.txt

+ 9
- 2
plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/CorePlugin.java View File

@@ -47,6 +47,7 @@ import org.sonar.plugins.core.issue.IssueTracking;
import org.sonar.plugins.core.issue.IssueTrackingDecorator;
import org.sonar.plugins.core.issue.IssuesDensityDecorator;
import org.sonar.plugins.core.issue.WeightedIssuesDecorator;
import org.sonar.plugins.core.issue.ignore.IgnoreIssuesPlugin;
import org.sonar.plugins.core.issue.notification.ChangesOnMyIssueNotificationDispatcher;
import org.sonar.plugins.core.issue.notification.IssueChangesEmailTemplate;
import org.sonar.plugins.core.issue.notification.NewFalsePositiveNotificationDispatcher;
@@ -406,9 +407,11 @@ import java.util.List;
})
public final class CorePlugin extends SonarPlugin {

@SuppressWarnings("unchecked")
@SuppressWarnings("rawtypes")
public List getExtensions() {
return ImmutableList.of(
ImmutableList.Builder<Object> extensions = ImmutableList.builder();

extensions.add(
DefaultResourceTypes.class,
UserManagedMetrics.class,
Periods.class,
@@ -524,5 +527,9 @@ public final class CorePlugin extends SonarPlugin {
// Notify alerts on my favourite projects
NewAlerts.class,
NewAlerts.newMetadata());

extensions.addAll(IgnoreIssuesPlugin.getExtensions());

return extensions.build();
}
}

+ 47
- 0
plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/ignore/Constants.java View File

@@ -0,0 +1,47 @@
/*
* 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;

public interface Constants {
// New Properties
String SUB_CATEGORY_IGNORE_ISSUES = "Ignore Issues";

String CORE_KEY_PREFIX = "sonar.issue.ignore";
String DEPRECATED_PLUGIN_KEY_PREFIX = "sonar.switchoffviolations";

String MULTICRITERIA_SUFFIX = ".multicriteria";
String PATTERNS_MULTICRITERIA_KEY = CORE_KEY_PREFIX + MULTICRITERIA_SUFFIX;
String DEPRECATED_MULTICRITERIA_KEY = DEPRECATED_PLUGIN_KEY_PREFIX + MULTICRITERIA_SUFFIX;
String RESOURCE_KEY = "resourceKey";
String RULE_KEY = "ruleKey";
String LINE_RANGE_KEY = "lineRange";

String BLOCK_SUFFIX = ".block";
String PATTERNS_BLOCK_KEY = CORE_KEY_PREFIX + BLOCK_SUFFIX;
String DEPRECATED_BLOCK_KEY = DEPRECATED_PLUGIN_KEY_PREFIX + BLOCK_SUFFIX;
String BEGIN_BLOCK_REGEXP = "beginBlockRegexp";
String END_BLOCK_REGEXP = "endBlockRegexp";

String ALLFILE_SUFFIX = ".allfile";
String PATTERNS_ALLFILE_KEY = CORE_KEY_PREFIX + ALLFILE_SUFFIX;
String DEPRECATED_ALLFILE_KEY = DEPRECATED_PLUGIN_KEY_PREFIX + ALLFILE_SUFFIX;
String FILE_REGEXP = "fileRegexp";
}

+ 109
- 0
plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/ignore/IgnoreIssuesConfiguration.java View File

@@ -0,0 +1,109 @@
// POLOP_IS_GREAT
/*
* 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.sonar.api.PropertyType;

import org.sonar.api.config.PropertyFieldDefinition;
import org.sonar.api.resources.Qualifiers;
import org.sonar.api.CoreProperties;
import com.google.common.collect.ImmutableList;
import org.sonar.api.config.PropertyDefinition;

import java.util.List;

public class IgnoreIssuesConfiguration {


static final int LARGE_SIZE = 20;
static final int SMALL_SIZE = 10;

public static List<PropertyDefinition> getPropertyDefinitions() {
return ImmutableList.of(
PropertyDefinition.builder(Constants.PATTERNS_MULTICRITERIA_KEY)
.category(CoreProperties.CATEGORY_EXCLUSIONS)
.subCategory(Constants.SUB_CATEGORY_IGNORE_ISSUES)
.deprecatedKey(Constants.DEPRECATED_MULTICRITERIA_KEY)
.name("Resource Key Pattern")
.description("Patterns used to identify which violations to switch off.<br/>" +
"More information on the <a href=\"http://docs.codehaus.org/display/SONAR/Project+Administration#ProjectAdministration-IgnoringIssues\">Project Administration page</a>.<br/>")
.onQualifiers(Qualifiers.PROJECT)
.fields(
PropertyFieldDefinition.build(Constants.RESOURCE_KEY)
.name("Resource Key Pattern")
.description("Pattern used to match resources which should be ignored")
.type(PropertyType.STRING)
.indicativeSize(LARGE_SIZE)
.build(),
PropertyFieldDefinition.build(Constants.RULE_KEY)
.name("Rule Key Pattern")
.description("Pattern used to match rules which should be ignored")
.type(PropertyType.STRING)
.indicativeSize(LARGE_SIZE)
.build(),
PropertyFieldDefinition.build(Constants.LINE_RANGE_KEY)
.name("Line Range")
.description("Range of lines that should be ignored.")
.type(PropertyType.STRING)
.indicativeSize(SMALL_SIZE)
.build())
.build(),
PropertyDefinition.builder(Constants.PATTERNS_BLOCK_KEY)
.category(CoreProperties.CATEGORY_EXCLUSIONS)
.subCategory(Constants.SUB_CATEGORY_IGNORE_ISSUES)
.deprecatedKey(Constants.DEPRECATED_BLOCK_KEY)
.name("Block exclusion patterns")
.description("Patterns used to identify blocks in which violations are switched off.<br/>" +
"More information on the <a href=\"http://docs.codehaus.org/display/SONAR/Project+Administration#ProjectAdministration-IgnoringIssues\">Project Administration page</a>.<br/>")
.onQualifiers(Qualifiers.PROJECT)
.fields(
PropertyFieldDefinition.build(Constants.BEGIN_BLOCK_REGEXP)
.name("Regular expression for start of block")
.description("If this regular expression is found in a resource, then following lines are ignored until end of block.")
.type(PropertyType.STRING)
.indicativeSize(LARGE_SIZE)
.build(),
PropertyFieldDefinition.build(Constants.END_BLOCK_REGEXP)
.name("Regular expression for end of block")
.description("If specified, this regular expression is used to determine the end of code blocks to ignore. If not, then block ends at the end of file.")
.type(PropertyType.STRING)
.indicativeSize(LARGE_SIZE)
.build())
.build(),
PropertyDefinition.builder(Constants.PATTERNS_ALLFILE_KEY)
.category(CoreProperties.CATEGORY_EXCLUSIONS)
.subCategory(Constants.SUB_CATEGORY_IGNORE_ISSUES)
.deprecatedKey(Constants.DEPRECATED_ALLFILE_KEY)
.name("File exclusion patterns")
.description("Patterns used to identify files in which violations are switched off.<br/>" +
"More information on the <a href=\"http://docs.codehaus.org/display/SONAR/Project+Administration#ProjectAdministration-IgnoringIssues\">Project Administration page</a>.<br/>")
.onQualifiers(Qualifiers.PROJECT)
.fields(
PropertyFieldDefinition.build(Constants.FILE_REGEXP)
.name("Regular expression")
.description("If this regular expression is found in a resource, then following lines are ignored.")
.type(PropertyType.STRING)
.indicativeSize(LARGE_SIZE)
.build())
.build());
}
}

+ 64
- 0
plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/ignore/IgnoreIssuesFilter.java View File

@@ -0,0 +1,64 @@
/*
* 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.api.issue.IssueFilter;
import org.sonar.plugins.core.issue.ignore.pattern.Pattern;
import org.sonar.plugins.core.issue.ignore.pattern.PatternsInitializer;

import java.util.List;

public final class IgnoreIssuesFilter implements IssueFilter {

private static final Logger LOG = LoggerFactory.getLogger(IgnoreIssuesFilter.class);

private PatternsInitializer patternsInitializer;

public IgnoreIssuesFilter(PatternsInitializer patternsInitializer) {
this.patternsInitializer = patternsInitializer;
}

public boolean accept(Issue issue) {
Pattern extraPattern = patternsInitializer.getExtraPattern(issue.componentKey());
LOG.debug("Extra pattern for resource {}: {}", issue.componentKey(), extraPattern);
if (extraPattern != null && extraPattern.match(issue)) {
logExclusion(issue, extraPattern);
return false;
}

List<Pattern> patterns = patternsInitializer.getMulticriteriaPatterns();
for (Pattern pattern : patterns) {
if (pattern.match(issue)) {
logExclusion(issue, pattern);
return false;
}
}
return true;
}

private void logExclusion(Issue issue, Pattern pattern) {
LOG.debug("Issue {} ignored by {}", issue, pattern);
}

}

+ 45
- 0
plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/ignore/IgnoreIssuesPlugin.java View File

@@ -0,0 +1,45 @@
/*
* 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 com.google.common.collect.ImmutableList;
import org.sonar.plugins.core.issue.ignore.pattern.PatternsInitializer;
import org.sonar.plugins.core.issue.ignore.scanner.RegexpScanner;
import org.sonar.plugins.core.issue.ignore.scanner.SourceScanner;

import java.util.List;

public final class IgnoreIssuesPlugin {

public static List<?> getExtensions() {
ImmutableList.Builder<Object> extensions = ImmutableList.builder();

extensions.addAll(IgnoreIssuesConfiguration.getPropertyDefinitions());
extensions.add(
PatternsInitializer.class,
RegexpScanner.class,
SourceScanner.class,
IgnoreIssuesFilter.class);

return extensions.build();
}

}

+ 91
- 0
plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/ignore/pattern/LineRange.java View File

@@ -0,0 +1,91 @@
/*
* 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.base.Preconditions;
import com.google.common.collect.Sets;

import java.util.Set;

public class LineRange {
private int from;
private int to;

public LineRange(int from, int to) {
Preconditions.checkArgument(from <= to, "Line range is not valid: %s must be greater than %s", from, to);

this.from = from;
this.to = to;
}

public boolean in(int lineId) {
return from <= lineId && lineId <= to;
}

public Set<Integer> toLines() {
Set<Integer> lines = Sets.newLinkedHashSet();
for (int index = from; index <= to; index++) {
lines.add(index);
}
return lines;
}

@Override
public String toString() {
return "[" + from + "-" + to + "]";
}

@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + from;
result = prime * result + to;
return result;
}

@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
if (fieldsDiffer((LineRange) obj)) {
return false;
}
return true;
}

private boolean fieldsDiffer(LineRange other) {
if (from != other.from) {
return true;
}
if (to != other.to) {
return true;
}
return false;
}
}

+ 159
- 0
plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/ignore/pattern/Pattern.java View File

@@ -0,0 +1,159 @@
/*
* 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.Sets;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.apache.commons.lang.builder.ToStringStyle;
import org.sonar.api.issue.Issue;
import org.sonar.api.rule.RuleKey;
import org.sonar.api.utils.WildcardPattern;

import java.util.Set;

public class Pattern {

private WildcardPattern resourcePattern;
private WildcardPattern rulePattern;
private Set<Integer> lines = Sets.newLinkedHashSet();
private Set<LineRange> lineRanges = Sets.newLinkedHashSet();
private String beginBlockRegexp;
private String endBlockRegexp;
private String allFileRegexp;
private boolean checkLines = true;

public Pattern() {
}

public Pattern(String resourcePattern, String rulePattern) {
this.resourcePattern = WildcardPattern.create(resourcePattern);
this.rulePattern = WildcardPattern.create(rulePattern);
}

public Pattern(String resourcePattern, String rulePattern, Set<LineRange> lineRanges) {
this(resourcePattern, rulePattern);
this.lineRanges = lineRanges;
}

public WildcardPattern getResourcePattern() {
return resourcePattern;
}

public WildcardPattern getRulePattern() {
return rulePattern;
}

public String getBeginBlockRegexp() {
return beginBlockRegexp;
}

public String getEndBlockRegexp() {
return endBlockRegexp;
}

public String getAllFileRegexp() {
return allFileRegexp;
}

Pattern addLineRange(int fromLineId, int toLineId) {
lineRanges.add(new LineRange(fromLineId, toLineId));
return this;
}

Pattern addLine(int lineId) {
lines.add(lineId);
return this;
}

boolean isCheckLines() {
return checkLines;
}

Pattern setCheckLines(boolean b) {
this.checkLines = b;
return this;
}

Pattern setBeginBlockRegexp(String beginBlockRegexp) {
this.beginBlockRegexp = beginBlockRegexp;
return this;
}

Pattern setEndBlockRegexp(String endBlockRegexp) {
this.endBlockRegexp = endBlockRegexp;
return this;
}

Pattern setAllFileRegexp(String allFileRegexp) {
this.allFileRegexp = allFileRegexp;
return this;
}

Set<Integer> getAllLines() {
Set<Integer> allLines = Sets.newLinkedHashSet(lines);
for (LineRange lineRange : lineRanges) {
allLines.addAll(lineRange.toLines());
}
return allLines;
}

public boolean match(Issue violation) {
boolean match = matchResource(violation.componentKey()) && matchRule(violation.ruleKey());
if (checkLines && violation.line() != null) {
match = match && matchLine(violation.line());
}
return match;
}

boolean matchLine(int lineId) {
if (lines.contains(lineId)) {
return true;
}

for (LineRange range : lineRanges) {
if (range.in(lineId)) {
return true;
}
}

return false;
}

boolean matchRule(RuleKey rule) {
System.out.printf("Matching rule {} against pattern {}", rule, rulePattern);
if (rule == null) {
return false;
}

String key = new StringBuilder().append(rule.repository()).append(':').append(rule.rule()).toString();
return rulePattern.match(key);
}

boolean matchResource(String resource) {
System.out.printf("Matching resource {} against pattern {}", resource, resourcePattern);
return resource != null && resourcePattern.match(resource);
}

@Override
public String toString() {
return ToStringBuilder.reflectionToString(this, ToStringStyle.SHORT_PREFIX_STYLE);
}
}

+ 158
- 0
plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/ignore/pattern/PatternDecoder.java View File

@@ -0,0 +1,158 @@
/*
* 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.annotations.VisibleForTesting;
import com.google.common.collect.Lists;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.StringUtils;
import org.sonar.api.utils.SonarException;

import java.io.File;
import java.io.IOException;
import java.util.List;

public class PatternDecoder {

private static final int THREE_FIELDS_PER_LINE = 3;
private static final String LINE_RANGE_REGEXP = "\\[((\\d+|\\d+-\\d+),?)*\\]";

public List<Pattern> decode(String patternsList) {
List<Pattern> patterns = Lists.newLinkedList();
String[] patternsLines = StringUtils.split(patternsList, "\n");
for (String patternLine : patternsLines) {
Pattern pattern = decodeLine(patternLine.trim());
if (pattern != null) {
patterns.add(pattern);
}
}
return patterns;
}

public List<Pattern> decode(File file) {
try {
List<String> lines = FileUtils.readLines(file);
List<Pattern> patterns = Lists.newLinkedList();
for (String line : lines) {
Pattern pattern = decodeLine(line);
if (pattern != null) {
patterns.add(pattern);
}
}
return patterns;

} catch (IOException e) {
throw new SonarException("Fail to load the file: " + file.getAbsolutePath(), e);
}
}

/**
* Main method that decodes a line which defines a pattern
*/
public Pattern decodeLine(String line) {
if (isBlankOrComment(line)) {
return null;
}

String[] fields = StringUtils.splitPreserveAllTokens(line, ';');
if (fields.length > THREE_FIELDS_PER_LINE) {
throw new SonarException("Invalid format. The following line has more than 3 fields separated by comma: " + line);
}

Pattern pattern;
if (fields.length == THREE_FIELDS_PER_LINE) {
checkRegularLineConstraints(line, fields);
pattern = new Pattern(StringUtils.trim(fields[0]), StringUtils.trim(fields[1]));
decodeRangeOfLines(pattern, fields[2]);
} else if (fields.length == 2) {
checkDoubleRegexpLineConstraints(line, fields);
pattern = new Pattern().setBeginBlockRegexp(fields[0]).setEndBlockRegexp(fields[1]);
} else {
pattern = new Pattern().setAllFileRegexp(fields[0]);
}

return pattern;
}

private void checkRegularLineConstraints(String line, String[] fields) {
if (!isResource(fields[0])) {
throw new SonarException("Invalid format. The first field does not define a resource pattern: " + line);
}
if (!isRule(fields[1])) {
throw new SonarException("Invalid format. The second field does not define a rule pattern: " + line);
}
if (!isLinesRange(fields[2])) {
throw new SonarException("Invalid format. The third field does not define a range of lines: " + line);
}
}

private void checkDoubleRegexpLineConstraints(String line, String[] fields) {
if (!isRegexp(fields[0])) {
throw new SonarException("Invalid format. The first field does not define a regular expression: " + line);
}
if (!isRegexp(fields[1])) {
throw new SonarException("Invalid format. The second field does not define a regular expression: " + line);
}
}

public static void decodeRangeOfLines(Pattern pattern, String field) {
if (StringUtils.equals(field, "*")) {
pattern.setCheckLines(false);
} else {
pattern.setCheckLines(true);
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]));
} else {
pattern.addLine(Integer.valueOf(part));
}
}
}
}

@VisibleForTesting
boolean isLinesRange(String field) {
return StringUtils.equals(field, "*") || java.util.regex.Pattern.matches(LINE_RANGE_REGEXP, field);
}

@VisibleForTesting
boolean isBlankOrComment(String line) {
return StringUtils.isBlank(line) || StringUtils.startsWith(line, "#");
}

@VisibleForTesting
boolean isResource(String field) {
return StringUtils.isNotBlank(field);
}

@VisibleForTesting
boolean isRule(String field) {
return StringUtils.isNotBlank(field);
}

@VisibleForTesting
boolean isRegexp(String field) {
return StringUtils.isNotBlank(field);
}
}

+ 118
- 0
plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/ignore/pattern/PatternsInitializer.java View File

@@ -0,0 +1,118 @@
/*
* 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.annotations.VisibleForTesting;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.apache.commons.lang.StringUtils;
import org.sonar.api.BatchExtension;
import org.sonar.api.config.Settings;
import org.sonar.plugins.core.issue.ignore.Constants;

import java.util.List;
import java.util.Map;
import java.util.Set;

import static com.google.common.base.Objects.firstNonNull;
import static com.google.common.base.Strings.nullToEmpty;

public class PatternsInitializer implements BatchExtension {

private final Settings settings;

private List<Pattern> multicriteriaPatterns;
private List<Pattern> blockPatterns;
private List<Pattern> allFilePatterns;
private Map<String, Pattern> extraPatternByResource = Maps.newHashMap();

public PatternsInitializer(Settings settings) {
this.settings = settings;
initPatterns();
}

public List<Pattern> getMulticriteriaPatterns() {
return multicriteriaPatterns;
}

public List<Pattern> getBlockPatterns() {
return blockPatterns;
}

public List<Pattern> getAllFilePatterns() {
return allFilePatterns;
}

public Pattern getExtraPattern(String resource) {
return extraPatternByResource.get(resource.substring(resource.lastIndexOf(":") + 1));
}

@VisibleForTesting
protected final void initPatterns() {
multicriteriaPatterns = Lists.newArrayList();
blockPatterns = Lists.newArrayList();
allFilePatterns = Lists.newArrayList();

loadPatternsFromNewProperties();
}

private void loadPatternsFromNewProperties() {
// Patterns Multicriteria
String patternConf = StringUtils.defaultIfBlank(settings.getString(Constants.PATTERNS_MULTICRITERIA_KEY), "");
for (String id : StringUtils.split(patternConf, ',')) {
String propPrefix = Constants.PATTERNS_MULTICRITERIA_KEY + "." + id + ".";
String resourceKeyPattern = settings.getString(propPrefix + Constants.RESOURCE_KEY);
String ruleKeyPattern = settings.getString(propPrefix + Constants.RULE_KEY);
Pattern pattern = new Pattern(firstNonNull(resourceKeyPattern, "*"), firstNonNull(ruleKeyPattern, "*"));
String lineRange = settings.getString(propPrefix + Constants.LINE_RANGE_KEY);
PatternDecoder.decodeRangeOfLines(pattern, firstNonNull(lineRange, "*"));
multicriteriaPatterns.add(pattern);
}

// Patterns Block
patternConf = StringUtils.defaultIfBlank(settings.getString(Constants.PATTERNS_BLOCK_KEY), "");
for (String id : StringUtils.split(patternConf, ',')) {
String propPrefix = Constants.PATTERNS_BLOCK_KEY + "." + id + ".";
String beginBlockRegexp = settings.getString(propPrefix + Constants.BEGIN_BLOCK_REGEXP);
String endBlockRegexp = settings.getString(propPrefix + Constants.END_BLOCK_REGEXP);
Pattern pattern = new Pattern().setBeginBlockRegexp(nullToEmpty(beginBlockRegexp)).setEndBlockRegexp(nullToEmpty(endBlockRegexp));
blockPatterns.add(pattern);
}

// Patterns All File
patternConf = StringUtils.defaultIfBlank(settings.getString(Constants.PATTERNS_ALLFILE_KEY), "");
for (String id : StringUtils.split(patternConf, ',')) {
String propPrefix = Constants.PATTERNS_ALLFILE_KEY + "." + id + ".";
String allFileRegexp = settings.getString(propPrefix + Constants.FILE_REGEXP);
Pattern pattern = new Pattern().setAllFileRegexp(nullToEmpty(allFileRegexp));
allFilePatterns.add(pattern);
}
}

public void addPatternToExcludeResource(String resource) {
extraPatternByResource.put(resource, new Pattern(resource, "*").setCheckLines(false));
}

public void addPatternToExcludeLines(String resource, Set<LineRange> lineRanges) {
extraPatternByResource.put(resource, new Pattern(resource, "*", lineRanges));
}

}

+ 189
- 0
plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/ignore/scanner/RegexpScanner.java View File

@@ -0,0 +1,189 @@
/*
* 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.scanner;

import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import org.apache.commons.io.FileUtils;
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.Pattern;
import org.sonar.plugins.core.issue.ignore.pattern.PatternsInitializer;

import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.List;
import java.util.Set;

public class RegexpScanner implements BatchExtension {

private static final Logger LOG = LoggerFactory.getLogger(RegexpScanner.class);

private PatternsInitializer patternsInitializer;
private List<java.util.regex.Pattern> allFilePatterns;
private List<DoubleRegexpMatcher> blockMatchers;

// fields to be reset at every new scan
private DoubleRegexpMatcher currentMatcher;
private int fileLength;
private List<LineExclusion> lineExclusions;
private LineExclusion currentLineExclusion;

public RegexpScanner(PatternsInitializer patternsInitializer) {
this.patternsInitializer = patternsInitializer;

lineExclusions = Lists.newArrayList();
allFilePatterns = Lists.newArrayList();
blockMatchers = Lists.newArrayList();

for (Pattern pattern : this.patternsInitializer.getAllFilePatterns()) {
allFilePatterns.add(java.util.regex.Pattern.compile(pattern.getAllFileRegexp()));
}
for (Pattern pattern : this.patternsInitializer.getBlockPatterns()) {
blockMatchers.add(new DoubleRegexpMatcher(
java.util.regex.Pattern.compile(pattern.getBeginBlockRegexp()),
java.util.regex.Pattern.compile(pattern.getEndBlockRegexp())));
}

init();
}

private void init() {
currentMatcher = null;
fileLength = 0;
lineExclusions.clear();
currentLineExclusion = null;
}

public void scan(String resource, File file, Charset sourcesEncoding) throws IOException {
LOG.debug("Scanning {}", resource);
init();

List<String> lines = FileUtils.readLines(file, sourcesEncoding.name());
int lineIndex = 0;
for (String line : lines) {
lineIndex++;
if (line.trim().length() == 0) {
continue;
}

// 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()) {
patternsInitializer.addPatternToExcludeResource(resource);
// nothing more to do on this file
LOG.debug("- Exclusion pattern '{}': every violation in this file will be ignored.", pattern);
return;
}
}

// then check the double regexps if we're still here
checkDoubleRegexps(line, lineIndex);
}

// now create the new line-based pattern for this file if there are exclusions
fileLength = lineIndex;
if (!lineExclusions.isEmpty()) {
Set<LineRange> lineRanges = convertLineExclusionsToLineRanges();
LOG.debug("- Line exclusions found: {}", lineRanges);
patternsInitializer.addPatternToExcludeLines(resource, lineRanges);
}
}

private Set<LineRange> convertLineExclusionsToLineRanges() {
Set<LineRange> lineRanges = Sets.newHashSet();
for (LineExclusion lineExclusion : lineExclusions) {
lineRanges.add(lineExclusion.toLineRange());
}
return lineRanges;
}

private void checkDoubleRegexps(String line, int lineIndex) {
if (currentMatcher == null) {
for (DoubleRegexpMatcher matcher : blockMatchers) {
if (matcher.matchesFirstPattern(line)) {
startExclusion(lineIndex);
currentMatcher = matcher;
break;
}
}
} else {
if (currentMatcher.matchesSecondPattern(line)) {
endExclusion(lineIndex);
currentMatcher = null;
}
}
}

private void startExclusion(int lineIndex) {
currentLineExclusion = new LineExclusion(lineIndex);
lineExclusions.add(currentLineExclusion);
}

private void endExclusion(int lineIndex) {
currentLineExclusion.setEnd(lineIndex);
currentLineExclusion = null;
}

private class LineExclusion {

private int start;
private int end;

LineExclusion(int start) {
this.start = start;
this.end = -1;
}

void setEnd(int end) {
this.end = end;
}

public LineRange toLineRange() {
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 secondPattern.matcher(line).find();
}

}

}

+ 112
- 0
plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/ignore/scanner/SourceScanner.java View File

@@ -0,0 +1,112 @@
/*
* 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.scanner;

import org.sonar.api.batch.Phase;
import org.sonar.api.batch.Sensor;
import org.sonar.api.batch.SensorContext;
import org.sonar.api.resources.Java;
import org.sonar.api.resources.JavaFile;
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.PatternsInitializer;

import java.io.File;
import java.nio.charset.Charset;
import java.util.List;

@Phase(name = Phase.Name.PRE)
public final class SourceScanner implements Sensor {

private final RegexpScanner regexpScanner;
private final PatternsInitializer patternsInitializer;
private final ModuleFileSystem fileSystem;

public SourceScanner(RegexpScanner regexpScanner, PatternsInitializer patternsInitializer, ModuleFileSystem fileSystem) {
this.regexpScanner = regexpScanner;
this.patternsInitializer = patternsInitializer;
this.fileSystem = fileSystem;
}

public boolean shouldExecuteOnProject(Project project) {
return patternsInitializer.getAllFilePatterns().size() > 0 || patternsInitializer.getBlockPatterns().size() > 0;
}

/**
* {@inheritDoc}
*/
public void analyse(Project project, SensorContext context) {
parseDirs(project, false);
parseDirs(project, true);
}

protected void parseDirs(Project project, boolean isTest) {
Charset sourcesEncoding = fileSystem.sourceCharset();

List<File> files;
if (isTest) {
files = fileSystem.files(FileQuery.onTest().onLanguage(project.getLanguageKey()));
} else {
files = fileSystem.files(FileQuery.onSource().onLanguage(project.getLanguageKey()));
}

for (File inputFile : files) {
try {
String resource = defineResource(inputFile, fileSystem, project, isTest);
if (resource != null) {
regexpScanner.scan(resource, inputFile, sourcesEncoding);
}
} catch (Exception e) {
throw new SonarException("Unable to read the source file : '" + inputFile.getAbsolutePath() + "' with the charset : '"
+ sourcesEncoding.name() + "'.", e);
}
}
}

/*
* This method is necessary because Java resources are not treated as every other resource...
*/
private String defineResource(File inputFile, ModuleFileSystem fileSystem, Project project, boolean isTest) {
if (Java.KEY.equals(project.getLanguageKey()) && Java.isJavaFile(inputFile)) {
List<File> sourceDirs = null;
if (isTest) {
sourceDirs = fileSystem.testDirs();
} else {
sourceDirs = fileSystem.sourceDirs();
}
JavaFile file = JavaFile.fromIOFile(inputFile, sourceDirs, isTest);
if (file == null) {
return null;
} else {
return file.getKey();
}
}
return inputFile.getPath();
}

@Override
public String toString() {
return "Ignore Issues - Source Scanner";
}

}

+ 104
- 0
plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/issue/ignore/IgnoreIssuesFilterTest.java View File

@@ -0,0 +1,104 @@
/*
* 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.api.rule.RuleKey;
import org.sonar.api.rules.Rule;
import org.sonar.plugins.core.issue.ignore.pattern.Pattern;
import org.sonar.plugins.core.issue.ignore.pattern.PatternDecoder;
import org.sonar.plugins.core.issue.ignore.pattern.PatternsInitializer;

import java.io.IOException;
import java.util.Collections;
import java.util.List;

import static org.fest.assertions.Assertions.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

public class IgnoreIssuesFilterTest {

public static final Rule CHECKSTYLE_RULE = Rule.create("checkstyle", "MagicNumber", "");
public static final String JAVA_FILE = "org.foo.Hello";

private PatternsInitializer patternsInitializer;
private IgnoreIssuesFilter filter;

@Before
public void init() {
patternsInitializer = mock(PatternsInitializer.class);
when(patternsInitializer.getMulticriteriaPatterns()).thenReturn(Collections.<Pattern> emptyList());

filter = new IgnoreIssuesFilter(patternsInitializer);
}

@Test
public void shouldBeDeactivatedWhenPropertyIsMissing() {
assertThat(filter.accept(create(CHECKSTYLE_RULE, JAVA_FILE, null))).isTrue();
}

@Test
public void shouldBeIgnoredWithStandardPatterns() throws IOException {
when(patternsInitializer.getMulticriteriaPatterns()).thenReturn(createPatterns("org.foo.Bar;*;*\norg.foo.Hello;checkstyle:MagicNumber;[15-200]"));

assertThat(filter.accept(create(CHECKSTYLE_RULE, JAVA_FILE, 150))).isFalse();
}

@Test
public void shouldNotBeIgnoredWithStandardPatterns() throws IOException {
when(patternsInitializer.getMulticriteriaPatterns()).thenReturn(createPatterns("org.foo.Bar;*;*\norg.foo.Hello;checkstyle:MagicNumber;[15-200]"));

assertThat(filter.accept(create(CHECKSTYLE_RULE, JAVA_FILE, 5))).isTrue();
}

@Test
public void shouldBeIgnoredWithExtraPattern() throws IOException {
when(patternsInitializer.getExtraPattern(JAVA_FILE)).thenReturn(createPatterns("org.foo.Hello;*;[15-200]").get(0));

assertThat(filter.accept(create(CHECKSTYLE_RULE, JAVA_FILE, 150))).isFalse();
}

@Test
public void shouldNotBeIgnoredWithExtraPattern() throws IOException {
when(patternsInitializer.getExtraPattern(JAVA_FILE)).thenReturn(createPatterns("org.foo.Hello;*;[15-200]").get(0));

assertThat(filter.accept(create(CHECKSTYLE_RULE, JAVA_FILE, 5))).isTrue();
}

private Issue create(Rule rule, String component, Integer line) {
Issue mockIssue = mock(Issue.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;
}

private List<Pattern> createPatterns(String line) {
return new PatternDecoder().decode(line);
}
}

+ 32
- 0
plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/issue/ignore/IgnoreIssuesPluginTest.java View File

@@ -0,0 +1,32 @@
/*
* 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.Test;

import static org.fest.assertions.Assertions.assertThat;

public class IgnoreIssuesPluginTest {
@Test
public void justForCoverage() {
assertThat(new IgnoreIssuesPlugin().getExtensions()).hasSize(3 /* properties */ + 4 /* extensions */);
}
}

+ 73
- 0
plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/issue/ignore/pattern/LineRangeTest.java View File

@@ -0,0 +1,73 @@
/*
* 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.Test;

import static org.fest.assertions.Assertions.assertThat;

public class LineRangeTest {

@Test(expected = IllegalArgumentException.class)
public void lineRangeShouldBeOrdered() {
new LineRange(25, 12);
}

@Test
public void shouldConvertLineRangeToLines() {
LineRange range = new LineRange(12, 15);

assertThat(range.toLines()).containsOnly(12, 13, 14, 15);
}

@Test
public void shouldTestInclusionInRangeOfLines() {
LineRange range = new LineRange(12, 15);

assertThat(range.in(3)).isFalse();
assertThat(range.in(12)).isTrue();
assertThat(range.in(13)).isTrue();
assertThat(range.in(14)).isTrue();
assertThat(range.in(15)).isTrue();
assertThat(range.in(16)).isFalse();
}

@Test
public void testToString() throws Exception {
assertThat(new LineRange(12, 15).toString()).isEqualTo("[12-15]");
}

@Test
public void testEquals() throws Exception {
LineRange range = new LineRange(12, 15);
assertThat(range).isEqualTo(range);
assertThat(range).isEqualTo(new LineRange(12, 15));
assertThat(range).isNotEqualTo(new LineRange(12, 2000));
assertThat(range).isNotEqualTo(new LineRange(1000, 2000));
assertThat(range).isNotEqualTo(null);
assertThat(range).isNotEqualTo(new StringBuffer());
}

@Test
public void testHashCode() throws Exception {
assertThat(new LineRange(12, 15).hashCode()).isEqualTo(new LineRange(12, 15).hashCode());
}
}

+ 196
- 0
plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/issue/ignore/pattern/PatternDecoderTest.java View File

@@ -0,0 +1,196 @@
/*
* 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.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.sonar.api.utils.SonarException;

import java.io.File;
import java.util.List;

import static org.fest.assertions.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<Pattern> patterns = decoder.decode(patternsList);

assertThat(patterns).hasSize(5);
}

@Test
public void shouldCheckFormatOfResource() {
assertThat(decoder.isResource("")).isFalse();
assertThat(decoder.isResource("*")).isTrue();
assertThat(decoder.isResource("com.foo.*")).isTrue();
}

@Test
public void shouldCheckFormatOfRule() {
assertThat(decoder.isRule("")).isFalse();
assertThat(decoder.isRule("*")).isTrue();
assertThat(decoder.isRule("com.foo.*")).isTrue();
}

@Test
public void shouldCheckFormatOfLinesRange() {
assertThat(decoder.isLinesRange("")).isFalse();
assertThat(decoder.isLinesRange(" ")).isFalse();
assertThat(decoder.isLinesRange("12")).isFalse();
assertThat(decoder.isLinesRange("12,212")).isFalse();

assertThat(decoder.isLinesRange("*")).isTrue();
assertThat(decoder.isLinesRange("[]")).isTrue();
assertThat(decoder.isLinesRange("[13]")).isTrue();
assertThat(decoder.isLinesRange("[13,24]")).isTrue();
assertThat(decoder.isLinesRange("[13,24,25-500]")).isTrue();
assertThat(decoder.isLinesRange("[24-65]")).isTrue();
assertThat(decoder.isLinesRange("[13,24-65,84-89,122]")).isTrue();
}

@Test
public void shouldReadStarPatterns() {
Pattern pattern = decoder.decodeLine("*;*;*");

assertThat(pattern.getResourcePattern().toString()).isEqualTo("*");
assertThat(pattern.getRulePattern().toString()).isEqualTo("*");
assertThat(pattern.isCheckLines()).isFalse();
}

@Test
public void shouldReadLineIds() {
Pattern pattern = decoder.decodeLine("*;*;[10,25,98]");

assertThat(pattern.isCheckLines()).isTrue();
assertThat(pattern.getAllLines()).containsOnly(10, 25, 98);
}

@Test
public void shouldReadRangeOfLineIds() {
Pattern 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 []
Pattern pattern = decoder.decodeLine("*;*;[]");

assertThat(pattern.isCheckLines()).isTrue();
assertThat(pattern.getAllLines()).isEmpty();
}

@Test
public void shouldReadBlockPattern() {
Pattern 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() {
Pattern pattern = decoder.decodeLine("SONAR-ALL-OFF");

assertThat(pattern.getResourcePattern()).isNull();
assertThat(pattern.getAllFileRegexp()).isEqualTo("SONAR-ALL-OFF");
}

@Test
public void shouldFailIfUnexistingFile() {
thrown.expect(SonarException.class);
thrown.expectMessage("Fail to load the file");

decoder.decode(new File("foo"));
}

@Test
public void shouldFailToReadUncorrectLine1() {
thrown.expect(SonarException.class);
thrown.expectMessage("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("Invalid format. The first field does not define a resource pattern");

decoder.decode(";*;*");
}

@Test
public void shouldFailToReadUncorrectLine4() {
thrown.expect(SonarException.class);
thrown.expectMessage("Invalid format. The second field does not define a rule pattern");

decoder.decode("*;;*");
}

@Test
public void shouldFailToReadUncorrectLine5() {
thrown.expect(SonarException.class);
thrown.expectMessage("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("Invalid format. The first field does not define a regular expression");

decoder.decode(";ON");
}

@Test
public void shouldFailToReadUncorrectLine7() {
thrown.expect(SonarException.class);
thrown.expectMessage("Invalid format. The second field does not define a regular expression");

decoder.decode("OFF;");
}
}

+ 114
- 0
plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/issue/ignore/pattern/PatternTest.java View File

@@ -0,0 +1,114 @@
/*
* 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.Test;
import org.sonar.api.issue.Issue;
import org.sonar.api.rule.RuleKey;
import org.sonar.api.rules.Rule;

import static org.fest.assertions.Assertions.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

public class PatternTest {

@Test
public void shouldMatchLines() {
Pattern pattern = new Pattern("*", "*");
pattern.addLine(12).addLine(15).addLineRange(20, 25);

assertThat(pattern.matchLine(3)).isFalse();
assertThat(pattern.matchLine(12)).isTrue();
assertThat(pattern.matchLine(14)).isFalse();
assertThat(pattern.matchLine(21)).isTrue();
assertThat(pattern.matchLine(6599)).isFalse();
}

@Test
public void shouldMatchJavaFile() {
String javaFile = "org.foo.Bar";
assertThat(new Pattern("org.foo.Bar", "*").matchResource(javaFile)).isTrue();
assertThat(new Pattern("org.foo.*", "*").matchResource(javaFile)).isTrue();
assertThat(new Pattern("*Bar", "*").matchResource(javaFile)).isTrue();
assertThat(new Pattern("*", "*").matchResource(javaFile)).isTrue();
assertThat(new Pattern("org.*.?ar", "*").matchResource(javaFile)).isTrue();

assertThat(new Pattern("org.other.Hello", "*").matchResource(javaFile)).isFalse();
assertThat(new Pattern("org.foo.Hello", "*").matchResource(javaFile)).isFalse();
assertThat(new Pattern("org.*.??ar", "*").matchResource(javaFile)).isFalse();
assertThat(new Pattern("org.*.??ar", "*").matchResource(null)).isFalse();
assertThat(new Pattern("org.*.??ar", "*").matchResource("plop")).isFalse();
}

@Test
public void shouldMatchRule() {
RuleKey rule = Rule.create("checkstyle", "IllegalRegexp", "").ruleKey();
assertThat(new Pattern("*", "*").matchRule(rule)).isTrue();
assertThat(new Pattern("*", "checkstyle:*").matchRule(rule)).isTrue();
assertThat(new Pattern("*", "checkstyle:IllegalRegexp").matchRule(rule)).isTrue();
assertThat(new Pattern("*", "checkstyle:Illegal*").matchRule(rule)).isTrue();
assertThat(new Pattern("*", "*:*Illegal*").matchRule(rule)).isTrue();

assertThat(new Pattern("*", "pmd:IllegalRegexp").matchRule(rule)).isFalse();
assertThat(new Pattern("*", "pmd:*").matchRule(rule)).isFalse();
assertThat(new Pattern("*", "*:Foo*IllegalRegexp").matchRule(rule)).isFalse();
}

@Test
public void shouldMatchViolation() {
Rule rule = Rule.create("checkstyle", "IllegalRegexp", "");
String javaFile = "org.foo.Bar";

Pattern pattern = new Pattern("*", "*");
pattern.addLine(12);

assertThat(pattern.match(create(rule, javaFile, null))).isTrue();
assertThat(pattern.match(create(rule, javaFile, 12))).isTrue();
assertThat(pattern.match(create((Rule) null, javaFile, 5))).isFalse();
assertThat(pattern.match(create(rule, null, null))).isFalse();
assertThat(pattern.match(create((Rule) null, null, null))).isFalse();
}

private Issue create(Rule rule, String component, Integer line) {
Issue mockIssue = mock(Issue.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;
}

@Test
public void shouldNotMatchNullRule() {
assertThat(new Pattern("*", "*").matchRule(null)).isFalse();
}

@Test
public void shouldPrintPatternToString() {
Pattern pattern = new Pattern("*", "checkstyle:*");

assertThat(pattern.toString()).isEqualTo("Pattern[resourcePattern=*,rulePattern=checkstyle:*,lines=[],lineRanges=[],beginBlockRegexp=<null>,endBlockRegexp=<null>,allFileRegexp=<null>,checkLines=true]");
}
}

+ 116
- 0
plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/issue/ignore/pattern/PatternsInitializerTest.java View File

@@ -0,0 +1,116 @@
/*
* 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.Sets;
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.Constants;
import org.sonar.plugins.core.issue.ignore.IgnoreIssuesPlugin;

import java.util.Set;

import static org.fest.assertions.Assertions.assertThat;

public class PatternsInitializerTest {

private PatternsInitializer patternsInitializer;

private Settings settings;

@Before
public void init() {
settings = new Settings(new PropertyDefinitions(new IgnoreIssuesPlugin()));
patternsInitializer = new PatternsInitializer(settings);
}

@Test
public void testNoConfiguration() {
patternsInitializer.initPatterns();
assertThat(patternsInitializer.getMulticriteriaPatterns().size()).isEqualTo(0);
}

@Test
public void shouldReturnExtraPatternForResource() {
String file = "foo";
patternsInitializer.addPatternToExcludeResource(file);

Pattern extraPattern = patternsInitializer.getExtraPattern(file);
assertThat(extraPattern.matchResource(file)).isTrue();
assertThat(extraPattern.isCheckLines()).isFalse();
}

@Test
public void shouldReturnExtraPatternForLinesOfResource() {
String file = "foo";
Set<LineRange> lineRanges = Sets.newHashSet();
lineRanges.add(new LineRange(25, 28));
patternsInitializer.addPatternToExcludeLines(file, lineRanges);

Pattern extraPattern = patternsInitializer.getExtraPattern(file);
assertThat(extraPattern.matchResource(file)).isTrue();
assertThat(extraPattern.getAllLines()).isEqualTo(Sets.newHashSet(25, 26, 27, 28));
}

@Test
public void shouldReturnMulticriteriaPattern() {
settings.setProperty(Constants.PATTERNS_MULTICRITERIA_KEY, "1,2");
settings.setProperty(Constants.PATTERNS_MULTICRITERIA_KEY + ".1." + Constants.RESOURCE_KEY, "org.foo.Bar");
settings.setProperty(Constants.PATTERNS_MULTICRITERIA_KEY + ".1." + Constants.RULE_KEY, "*");
settings.setProperty(Constants.PATTERNS_MULTICRITERIA_KEY + ".1." + Constants.RESOURCE_KEY, "*");
settings.setProperty(Constants.PATTERNS_MULTICRITERIA_KEY + ".2." + Constants.LINE_RANGE_KEY, "org.foo.Hello");
settings.setProperty(Constants.PATTERNS_MULTICRITERIA_KEY + ".2." + Constants.RULE_KEY, "checkstyle:MagicNumber");
settings.setProperty(Constants.PATTERNS_MULTICRITERIA_KEY + ".2." + Constants.LINE_RANGE_KEY, "[15-200]");
patternsInitializer.initPatterns();

assertThat(patternsInitializer.getMulticriteriaPatterns().size()).isEqualTo(2);
assertThat(patternsInitializer.getBlockPatterns().size()).isEqualTo(0);
assertThat(patternsInitializer.getAllFilePatterns().size()).isEqualTo(0);
}

@Test
public void shouldReturnBlockPattern() {
settings.setProperty(Constants.PATTERNS_BLOCK_KEY, "1,2");
settings.setProperty(Constants.PATTERNS_BLOCK_KEY + ".1." + Constants.BEGIN_BLOCK_REGEXP, "// SONAR-OFF");
settings.setProperty(Constants.PATTERNS_BLOCK_KEY + ".1." + Constants.END_BLOCK_REGEXP, "// SONAR-ON");
settings.setProperty(Constants.PATTERNS_BLOCK_KEY + ".2." + Constants.BEGIN_BLOCK_REGEXP, "// FOO-OFF");
settings.setProperty(Constants.PATTERNS_BLOCK_KEY + ".2." + Constants.END_BLOCK_REGEXP, "// FOO-ON");
patternsInitializer.initPatterns();

assertThat(patternsInitializer.getMulticriteriaPatterns().size()).isEqualTo(0);
assertThat(patternsInitializer.getBlockPatterns().size()).isEqualTo(2);
assertThat(patternsInitializer.getAllFilePatterns().size()).isEqualTo(0);
}

@Test
public void shouldReturnAllFilePattern() {
settings.setProperty(Constants.PATTERNS_ALLFILE_KEY, "1,2");
settings.setProperty(Constants.PATTERNS_ALLFILE_KEY + ".1." + Constants.FILE_REGEXP, "@SONAR-IGNORE-ALL");
settings.setProperty(Constants.PATTERNS_ALLFILE_KEY + ".2." + Constants.FILE_REGEXP, "//FOO-IGNORE-ALL");
patternsInitializer.initPatterns();

assertThat(patternsInitializer.getMulticriteriaPatterns().size()).isEqualTo(0);
assertThat(patternsInitializer.getBlockPatterns().size()).isEqualTo(0);
assertThat(patternsInitializer.getAllFilePatterns().size()).isEqualTo(2);
}
}

+ 150
- 0
plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/issue/ignore/scanner/RegexpScannerTest.java View File

@@ -0,0 +1,150 @@
/*
* 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.scanner;

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.Pattern;
import org.sonar.plugins.core.issue.ignore.pattern.PatternsInitializer;
import org.sonar.test.TestUtils;

import java.io.IOException;
import java.util.Arrays;
import java.util.Set;

import static com.google.common.base.Charsets.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 RegexpScannerTest {

private RegexpScanner regexpScanner;

private String javaFile;
@Mock
private PatternsInitializer patternsInitializer;
@Mock
private Pattern allFilePattern;
@Mock
private Pattern blockPattern1;
@Mock
private Pattern blockPattern2;

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

regexpScanner = new RegexpScanner(patternsInitializer);
verify(patternsInitializer, times(1)).getAllFilePatterns();
verify(patternsInitializer, times(1)).getBlockPatterns();

javaFile = "org.sonar.test.MyFile";
}

@Test
public void shouldDoNothing() throws IOException {
regexpScanner.scan(javaFile, TestUtils.getResource(getClass(), "file-with-no-regexp.txt"), UTF_8);

verifyNoMoreInteractions(patternsInitializer);
}

@Test
public void shouldAddPatternToExcludeFile() throws IOException {
regexpScanner.scan(javaFile, TestUtils.getResource(getClass(), "file-with-single-regexp.txt"), UTF_8);

verify(patternsInitializer, times(1)).addPatternToExcludeResource(javaFile);
verifyNoMoreInteractions(patternsInitializer);
}

@Test
public void shouldAddPatternToExcludeFileEvenIfAlsoDoubleRegexps() throws IOException {
regexpScanner.scan(javaFile, TestUtils.getResource(getClass(), "file-with-single-regexp-and-double-regexp.txt"), UTF_8);

verify(patternsInitializer, times(1)).addPatternToExcludeResource(javaFile);
verifyNoMoreInteractions(patternsInitializer);
}

@Test
public void shouldAddPatternToExcludeLines() throws IOException {
regexpScanner.scan(javaFile, TestUtils.getResource(getClass(), "file-with-double-regexp.txt"), UTF_8);

Set<LineRange> lineRanges = Sets.newHashSet();
lineRanges.add(new LineRange(21, 25));
verify(patternsInitializer, times(1)).addPatternToExcludeLines(javaFile, lineRanges);
verifyNoMoreInteractions(patternsInitializer);
}

@Test
public void shouldAddPatternToExcludeLinesTillTheEnd() throws IOException {
regexpScanner.scan(javaFile, TestUtils.getResource(getClass(), "file-with-double-regexp-unfinished.txt"), UTF_8);

Set<LineRange> lineRanges = Sets.newHashSet();
lineRanges.add(new LineRange(21, 34));
verify(patternsInitializer, times(1)).addPatternToExcludeLines(javaFile, lineRanges);
verifyNoMoreInteractions(patternsInitializer);
}

@Test
public void shouldAddPatternToExcludeSeveralLineRanges() throws IOException {
regexpScanner.scan(javaFile, TestUtils.getResource(getClass(), "file-with-double-regexp-twice.txt"), UTF_8);

Set<LineRange> lineRanges = Sets.newHashSet();
lineRanges.add(new LineRange(21, 25));
lineRanges.add(new LineRange(29, 33));
verify(patternsInitializer, times(1)).addPatternToExcludeLines(javaFile, lineRanges);
verifyNoMoreInteractions(patternsInitializer);
}

@Test
public void shouldAddPatternToExcludeLinesWithWrongOrder() throws IOException {
regexpScanner.scan(javaFile, TestUtils.getResource(getClass(), "file-with-double-regexp-wrong-order.txt"), UTF_8);

Set<LineRange> lineRanges = Sets.newHashSet();
lineRanges.add(new LineRange(25, 35));
verify(patternsInitializer, times(1)).addPatternToExcludeLines(javaFile, lineRanges);
verifyNoMoreInteractions(patternsInitializer);
}

@Test
public void shouldAddPatternToExcludeLinesWithMess() throws IOException {
regexpScanner.scan(javaFile, TestUtils.getResource(getClass(), "file-with-double-regexp-mess.txt"), UTF_8);

Set<LineRange> lineRanges = Sets.newHashSet();
lineRanges.add(new LineRange(21, 29));
verify(patternsInitializer, times(1)).addPatternToExcludeLines(javaFile, lineRanges);
verifyNoMoreInteractions(patternsInitializer);
}

}

+ 178
- 0
plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/issue/ignore/scanner/SourceScannerTest.java View File

@@ -0,0 +1,178 @@
/*
* 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.scanner;

import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
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.Pattern;
import org.sonar.plugins.core.issue.ignore.pattern.PatternsInitializer;

import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

import static org.mockito.Mockito.verifyNoMoreInteractions;

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.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

public class SourceScannerTest {

private SourceScanner scanner;

@Mock
private RegexpScanner regexpScanner;
@Mock
private PatternsInitializer patternsInitializer;
@Mock
private Project project;
@Mock
private ModuleFileSystem fileSystem;

@Rule
public ExpectedException thrown = ExpectedException.none();

@Before
public void init() {
MockitoAnnotations.initMocks(this);

when(fileSystem.sourceCharset()).thenReturn(UTF_8);

scanner = new SourceScanner(regexpScanner, patternsInitializer, fileSystem);
}

@Test
public void testToString() throws Exception {
assertThat(scanner.toString()).isEqualTo("Ignore Issues - Source Scanner");
}

@Test
public void shouldExecute() throws IOException {
when(patternsInitializer.getAllFilePatterns()).thenReturn(Arrays.asList(new Pattern(), new Pattern()));
assertThat(scanner.shouldExecuteOnProject(null)).isTrue();

when(patternsInitializer.getAllFilePatterns()).thenReturn(Collections.<Pattern>emptyList());
when(patternsInitializer.getBlockPatterns()).thenReturn(Arrays.asList(new Pattern(), new Pattern()));
assertThat(scanner.shouldExecuteOnProject(null)).isTrue();

when(patternsInitializer.getAllFilePatterns()).thenReturn(Collections.<Pattern>emptyList());
when(patternsInitializer.getBlockPatterns()).thenReturn(Collections.<Pattern>emptyList());
assertThat(scanner.shouldExecuteOnProject(null)).isFalse();
}

@Test
public void shouldAnalyseJavaProject() 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")));

scanner.analyse(project, null);

verify(regexpScanner).scan("[default].Foo", sourceFile, UTF_8);
verify(regexpScanner).scan("[default].FooTest", testFile, UTF_8);
}

@Test
public void shouldAnalyseOtherProject() throws IOException {
File sourceFile = new File("Foo.php");
File testFile = new File("FooTest.php");

when(project.getLanguageKey()).thenReturn("php");
when(fileSystem.files(Mockito.isA(FileQuery.class)))
.thenReturn(Arrays.asList(sourceFile))
.thenReturn(Arrays.asList(testFile));

scanner.analyse(project, null);

verify(regexpScanner).scan("Foo.php", sourceFile, UTF_8);
verify(regexpScanner).scan("FooTest.php", testFile, UTF_8);
}

@Test
public void shouldAnalyseJavaProjectWithNonJavaFile() throws IOException {
File sourceFile = new File("src/main/java/Foo.java");
File otherFile = new File("other.js");

when(project.getLanguageKey()).thenReturn("java");
List<File> empty = Collections.emptyList();
when(fileSystem.files(Mockito.isA(FileQuery.class)))
.thenReturn(Arrays.asList(sourceFile, otherFile))
.thenReturn(empty);
when(fileSystem.sourceDirs()).thenReturn(Arrays.asList(new File("src/main/java")));
when(fileSystem.testDirs()).thenReturn(Arrays.asList(new File("src/test/java")));

scanner.analyse(project, null);

verify(regexpScanner, never()).scan("other.js", sourceFile, UTF_8);
}

@Test
public void shouldIgnoreInvalidFile() throws IOException {
File sourceFile = new File("invalid.java");

when(project.getLanguageKey()).thenReturn("java");
List<File> empty = Collections.emptyList();
when(fileSystem.files(Mockito.isA(FileQuery.class)))
.thenReturn(Arrays.asList(sourceFile))
.thenReturn(empty);
when(fileSystem.sourceDirs()).thenReturn(Arrays.asList(new File("src/main/java")));
when(fileSystem.testDirs()).thenReturn(Arrays.asList(new File("src/test/java")));

scanner.analyse(project, null);

verifyNoMoreInteractions(regexpScanner);
}

@Test
public void shouldReportFailure() throws IOException {
File sourceFile = new File("Foo.php");

when(project.getLanguageKey()).thenReturn("php");
when(fileSystem.files(Mockito.isA(FileQuery.class))).thenReturn(Arrays.asList(sourceFile));
doThrow(new IOException("BUG")).when(regexpScanner).scan("Foo.php", sourceFile, UTF_8);

thrown.expect(SonarException.class);
thrown.expectMessage("Unable to read the source file");

scanner.analyse(project, null);
}
}

+ 37
- 0
plugins/sonar-core-plugin/src/test/resources/org/sonar/plugins/core/issue/ignore/scanner/RegexpScannerTest/file-with-double-regexp-mess.txt View File

@@ -0,0 +1,37 @@
package org.sonar.plugins.switchoffviolations.pattern;

import com.google.common.collect.Sets;

import java.util.Set;

/**
*
*/
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;
}

// SONAR-OFF
public boolean in(int lineId) {
return from <= lineId && lineId <= to;
}
// FOO-OFF

public Set<Integer> toLines() {
Set<Integer> lines = Sets.newLinkedHashSet();
// SONAR-ON
for (int index = from; index <= to; index++) {
lines.add(index);
}
// FOO-ON
return lines;
}

}

+ 37
- 0
plugins/sonar-core-plugin/src/test/resources/org/sonar/plugins/core/issue/ignore/scanner/RegexpScannerTest/file-with-double-regexp-twice.txt View File

@@ -0,0 +1,37 @@
package org.sonar.plugins.switchoffviolations.pattern;

import com.google.common.collect.Sets;

import java.util.Set;

/**
*
*/
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;
}

// SONAR-OFF
public boolean in(int lineId) {
return from <= lineId && lineId <= to;
}
// SONAR-ON

public Set<Integer> toLines() {
Set<Integer> lines = Sets.newLinkedHashSet();
// FOO-OFF
for (int index = from; index <= to; index++) {
lines.add(index);
}
// FOO-ON
return lines;
}

}

+ 34
- 0
plugins/sonar-core-plugin/src/test/resources/org/sonar/plugins/core/issue/ignore/scanner/RegexpScannerTest/file-with-double-regexp-unfinished.txt View File

@@ -0,0 +1,34 @@
package org.sonar.plugins.switchoffviolations.pattern;

import com.google.common.collect.Sets;

import java.util.Set;

/**
*
*/
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;
}

// SONAR-OFF
public boolean in(int lineId) {
return from <= lineId && lineId <= to;
}

public Set<Integer> toLines() {
Set<Integer> lines = Sets.newLinkedHashSet();
for (int index = from; index <= to; index++) {
lines.add(index);
}
return lines;
}

}

+ 35
- 0
plugins/sonar-core-plugin/src/test/resources/org/sonar/plugins/core/issue/ignore/scanner/RegexpScannerTest/file-with-double-regexp-wrong-order.txt View File

@@ -0,0 +1,35 @@
package org.sonar.plugins.switchoffviolations.pattern;

import com.google.common.collect.Sets;

import java.util.Set;

/**
*
*/
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;
}

// SONAR-ON
public boolean in(int lineId) {
return from <= lineId && lineId <= to;
}
// SONAR-OFF

public Set<Integer> toLines() {
Set<Integer> lines = Sets.newLinkedHashSet();
for (int index = from; index <= to; index++) {
lines.add(index);
}
return lines;
}

}

+ 35
- 0
plugins/sonar-core-plugin/src/test/resources/org/sonar/plugins/core/issue/ignore/scanner/RegexpScannerTest/file-with-double-regexp.txt View File

@@ -0,0 +1,35 @@
package org.sonar.plugins.switchoffviolations.pattern;

import com.google.common.collect.Sets;

import java.util.Set;

/**
*
*/
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;
}

// SONAR-OFF
public boolean in(int lineId) {
return from <= lineId && lineId <= to;
}
// SONAR-ON

public Set<Integer> toLines() {
Set<Integer> lines = Sets.newLinkedHashSet();
for (int index = from; index <= to; index++) {
lines.add(index);
}
return lines;
}

}

+ 33
- 0
plugins/sonar-core-plugin/src/test/resources/org/sonar/plugins/core/issue/ignore/scanner/RegexpScannerTest/file-with-no-regexp.txt View File

@@ -0,0 +1,33 @@
package org.sonar.plugins.switchoffviolations.pattern;

import com.google.common.collect.Sets;

import java.util.Set;

/**
*
*/
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<Integer> toLines() {
Set<Integer> lines = Sets.newLinkedHashSet();
for (int index = from; index <= to; index++) {
lines.add(index);
}
return lines;
}

}

+ 36
- 0
plugins/sonar-core-plugin/src/test/resources/org/sonar/plugins/core/issue/ignore/scanner/RegexpScannerTest/file-with-single-regexp-and-double-regexp.txt View File

@@ -0,0 +1,36 @@
package org.sonar.plugins.switchoffviolations.pattern;

import com.google.common.collect.Sets;

// SONAR-OFF

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;
}
// SONAR-ON

public Set<Integer> toLines() {
Set<Integer> lines = Sets.newLinkedHashSet();
for (int index = from; index <= to; index++) {
lines.add(index);
}
return lines;
}

}

+ 33
- 0
plugins/sonar-core-plugin/src/test/resources/org/sonar/plugins/core/issue/ignore/scanner/RegexpScannerTest/file-with-single-regexp.txt View File

@@ -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<Integer> toLines() {
Set<Integer> lines = Sets.newLinkedHashSet();
for (int index = from; index <= to; index++) {
lines.add(index);
}
return lines;
}

}

Loading…
Cancel
Save