Copy resources from Switch Off Violations plugin to core Remove references to deprecated APIstags/4.0
@@ -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(); | |||
} | |||
} |
@@ -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"; | |||
} |
@@ -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()); | |||
} | |||
} |
@@ -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); | |||
} | |||
} |
@@ -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(); | |||
} | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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); | |||
} | |||
} |
@@ -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); | |||
} | |||
} |
@@ -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)); | |||
} | |||
} |
@@ -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(); | |||
} | |||
} | |||
} |
@@ -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"; | |||
} | |||
} |
@@ -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); | |||
} | |||
} |
@@ -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 */); | |||
} | |||
} |
@@ -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()); | |||
} | |||
} |
@@ -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;"); | |||
} | |||
} |
@@ -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]"); | |||
} | |||
} |
@@ -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); | |||
} | |||
} |
@@ -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); | |||
} | |||
} |
@@ -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); | |||
} | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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; | |||
} | |||
} |