blob: f1492d5271a8c620e978b4b86ed2d1240b11af2d [file] [log] [blame]
////////////////////////////////////////////////////////////////////////////////
// checkstyle: Checks Java source code for adherence to a set of rules.
// Copyright (C) 2001-2017 the original author or authors.
//
// This library 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 2.1 of the License, or (at your option) any later version.
//
// This library 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 library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
////////////////////////////////////////////////////////////////////////////////
package com.puppycrawl.tools.checkstyle.filters;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Locale;
import java.util.stream.Collectors;
import org.junit.Assert;
import org.junit.Test;
import org.powermock.reflect.Whitebox;
import com.puppycrawl.tools.checkstyle.AbstractModuleTestSupport;
import com.puppycrawl.tools.checkstyle.Checker;
import com.puppycrawl.tools.checkstyle.DefaultConfiguration;
import com.puppycrawl.tools.checkstyle.TreeWalker;
import com.puppycrawl.tools.checkstyle.TreeWalkerAuditEvent;
import com.puppycrawl.tools.checkstyle.api.CheckstyleException;
import com.puppycrawl.tools.checkstyle.api.Configuration;
import com.puppycrawl.tools.checkstyle.api.FileContents;
import com.puppycrawl.tools.checkstyle.api.LocalizedMessage;
import com.puppycrawl.tools.checkstyle.checks.coding.IllegalCatchCheck;
import com.puppycrawl.tools.checkstyle.checks.naming.ConstantNameCheck;
import com.puppycrawl.tools.checkstyle.checks.naming.MemberNameCheck;
import com.puppycrawl.tools.checkstyle.utils.CommonUtils;
import nl.jqno.equalsverifier.EqualsVerifier;
public class SuppressionCommentFilterTest
extends AbstractModuleTestSupport {
private static final String[] ALL_MESSAGES = {
"13:17: Name 'I' must match pattern '^[a-z][a-zA-Z0-9]*$'.",
"16:17: Name 'J' must match pattern '^[a-z][a-zA-Z0-9]*$'.",
"19:17: Name 'K' must match pattern '^[a-z][a-zA-Z0-9]*$'.",
"22:17: Name 'L' must match pattern '^[a-z][a-zA-Z0-9]*$'.",
"23:30: Name 'm' must match pattern '^[A-Z][A-Z0-9]*(_[A-Z0-9]+)*$'.",
"27:17: Name 'M2' must match pattern '^[a-z][a-zA-Z0-9]*$'.",
"28:30: Name 'n' must match pattern '^[A-Z][A-Z0-9]*(_[A-Z0-9]+)*$'.",
"32:17: Name 'P' must match pattern '^[a-z][a-zA-Z0-9]*$'.",
"35:17: Name 'Q' must match pattern '^[a-z][a-zA-Z0-9]*$'.",
"38:17: Name 'R' must match pattern '^[a-z][a-zA-Z0-9]*$'.",
"39:30: Name 's' must match pattern '^[A-Z][A-Z0-9]*(_[A-Z0-9]+)*$'.",
"43:17: Name 'T' must match pattern '^[a-z][a-zA-Z0-9]*$'.",
"64:23: Catching 'Exception' is not allowed.",
"71:11: Catching 'Exception' is not allowed.",
"77:11: Catching 'RuntimeException' is not allowed.",
"78:11: Catching 'Exception' is not allowed.",
"86:31: Catching 'Exception' is not allowed.",
};
@Override
protected String getPackageLocation() {
return "com/puppycrawl/tools/checkstyle/filters/suppressioncommentfilter";
}
@Test
public void testNone() throws Exception {
final DefaultConfiguration filterConfig = null;
final String[] suppressed = CommonUtils.EMPTY_STRING_ARRAY;
verifySuppressed(filterConfig, suppressed);
}
//Suppress all checks between default comments
@Test
public void testDefault() throws Exception {
final DefaultConfiguration filterConfig =
createModuleConfig(SuppressionCommentFilter.class);
final String[] suppressed = {
"16:17: Name 'J' must match pattern '^[a-z][a-zA-Z0-9]*$'.",
"43:17: Name 'T' must match pattern '^[a-z][a-zA-Z0-9]*$'.",
"64:23: Catching 'Exception' is not allowed.",
"71:11: Catching 'Exception' is not allowed.",
"86:31: Catching 'Exception' is not allowed.",
};
verifySuppressed(filterConfig, suppressed);
}
@Test
public void testCheckC() throws Exception {
final DefaultConfiguration filterConfig =
createModuleConfig(SuppressionCommentFilter.class);
filterConfig.addAttribute("checkC", "false");
final String[] suppressed = {
"43:17: Name 'T' must match pattern '^[a-z][a-zA-Z0-9]*$'.",
"64:23: Catching 'Exception' is not allowed.",
"71:11: Catching 'Exception' is not allowed.",
};
verifySuppressed(filterConfig, suppressed);
}
@Test
public void testCheckCpp() throws Exception {
final DefaultConfiguration filterConfig =
createModuleConfig(SuppressionCommentFilter.class);
filterConfig.addAttribute("checkCPP", "false");
final String[] suppressed = {
"16:17: Name 'J' must match pattern '^[a-z][a-zA-Z0-9]*$'.",
"86:31: Catching 'Exception' is not allowed.",
};
verifySuppressed(filterConfig, suppressed);
}
//Suppress all checks between CS_OFF and CS_ON
@Test
public void testOffFormat() throws Exception {
final DefaultConfiguration filterConfig =
createModuleConfig(SuppressionCommentFilter.class);
filterConfig.addAttribute("offCommentFormat", "CS_OFF");
filterConfig.addAttribute("onCommentFormat", "CS_ON");
final String[] suppressed = {
"32:17: Name 'P' must match pattern '^[a-z][a-zA-Z0-9]*$'.",
"38:17: Name 'R' must match pattern '^[a-z][a-zA-Z0-9]*$'.",
"39:30: Name 's' must match pattern '^[A-Z][A-Z0-9]*(_[A-Z0-9]+)*$'.",
"42:17: Name 'T' must match pattern '^[a-z][a-zA-Z0-9]*$'.",
};
verifySuppressed(filterConfig, suppressed);
}
//Test suppression of checks of only one type
//Suppress only ConstantNameCheck between CS_OFF and CS_ON
@Test
public void testOffFormatCheck() throws Exception {
final DefaultConfiguration filterConfig =
createModuleConfig(SuppressionCommentFilter.class);
filterConfig.addAttribute("offCommentFormat", "CS_OFF");
filterConfig.addAttribute("onCommentFormat", "CS_ON");
filterConfig.addAttribute("checkFormat", "ConstantNameCheck");
final String[] suppressed = {
"39:30: Name 's' must match pattern '^[A-Z][A-Z0-9]*(_[A-Z0-9]+)*$'.",
};
verifySuppressed(filterConfig, suppressed);
}
@Test
public void testArgumentSuppression() throws Exception {
final DefaultConfiguration filterConfig =
createModuleConfig(SuppressionCommentFilter.class);
filterConfig.addAttribute("offCommentFormat", "IllegalCatchCheck OFF\\: (\\w+)");
filterConfig.addAttribute("onCommentFormat", "IllegalCatchCheck ON\\: (\\w+)");
filterConfig.addAttribute("checkFormat", "IllegalCatchCheck");
filterConfig.addAttribute("messageFormat", "^Catching '$1' is not allowed.*$");
final String[] suppressed = {
"78:11: Catching 'Exception' is not allowed.",
};
verifySuppressed(filterConfig, suppressed);
}
@Test
public void testExpansion() throws Exception {
final DefaultConfiguration filterConfig =
createModuleConfig(SuppressionCommentFilter.class);
filterConfig.addAttribute("offCommentFormat", "CSOFF\\: ([\\w\\|]+)");
filterConfig.addAttribute("onCommentFormat", "CSON\\: ([\\w\\|]+)");
filterConfig.addAttribute("checkFormat", "$1");
final String[] suppressed = {
"22:17: Name 'L' must match pattern '^[a-z][a-zA-Z0-9]*$'.",
"23:30: Name 'm' must match pattern '^[A-Z][A-Z0-9]*(_[A-Z0-9]+)*$'.",
"28:30: Name 'n' must match pattern '^[A-Z][A-Z0-9]*(_[A-Z0-9]+)*$'.",
};
verifySuppressed(filterConfig, suppressed);
}
@Test
public void testMessage() throws Exception {
final DefaultConfiguration filterConfig =
createModuleConfig(SuppressionCommentFilter.class);
filterConfig.addAttribute("onCommentFormat", "UNUSED ON\\: (\\w+)");
filterConfig.addAttribute("offCommentFormat", "UNUSED OFF\\: (\\w+)");
filterConfig.addAttribute("checkFormat", "Unused");
filterConfig.addAttribute("messageFormat", "^Unused \\w+ '$1'.$");
final String[] suppressed = {
"47:34: Unused parameter 'aInt'.",
};
verifySuppressed(filterConfig, suppressed);
}
private void verifySuppressed(Configuration aFilterConfig,
String... aSuppressed)
throws Exception {
verify(createChecker(aFilterConfig),
getPath("InputSuppressionCommentFilter.java"),
removeSuppressed(ALL_MESSAGES, aSuppressed));
}
@Override
public Checker createChecker(Configuration moduleConfig)
throws CheckstyleException {
final DefaultConfiguration checkerConfig =
new DefaultConfiguration("configuration");
final DefaultConfiguration checksConfig = createModuleConfig(TreeWalker.class);
final DefaultConfiguration memberNameCheckConfig =
createModuleConfig(MemberNameCheck.class);
memberNameCheckConfig.addAttribute("id", "ignore");
checksConfig.addChild(memberNameCheckConfig);
final DefaultConfiguration constantNameCheckConfig =
createModuleConfig(ConstantNameCheck.class);
constantNameCheckConfig.addAttribute("id", null);
checksConfig.addChild(constantNameCheckConfig);
checksConfig.addChild(createModuleConfig(IllegalCatchCheck.class));
checkerConfig.addChild(checksConfig);
if (moduleConfig != null) {
checksConfig.addChild(moduleConfig);
}
final Checker checker = new Checker();
final Locale locale = Locale.ROOT;
checker.setLocaleCountry(locale.getCountry());
checker.setLocaleLanguage(locale.getLanguage());
checker.setModuleClassLoader(Thread.currentThread().getContextClassLoader());
checker.configure(checkerConfig);
checker.addListener(getBriefUtLogger());
return checker;
}
private static String[] removeSuppressed(String[] from, String... remove) {
final Collection<String> coll = Arrays.stream(from).collect(Collectors.toList());
coll.removeAll(Arrays.asList(remove));
return coll.toArray(new String[coll.size()]);
}
@Test
public void testEqualsAndHashCodeOfTagClass() {
EqualsVerifier.forClass(SuppressionCommentFilter.Tag.class).usingGetClass().verify();
}
@Test
public void testToStringOfTagClass() {
final SuppressionCommentFilter.Tag tag = new SuppressionCommentFilter.Tag(
0, 1, "text",
SuppressionCommentFilter.TagType.OFF, new SuppressionCommentFilter()
);
assertEquals("Invalid toString result",
"Tag[text='text', line=0, column=1, type=OFF,"
+ " tagCheckRegexp=.*, tagMessageRegexp=null]", tag.toString());
}
@Test
public void testInvalidCheckFormat() throws Exception {
final DefaultConfiguration filterConfig =
createModuleConfig(SuppressionCommentFilter.class);
filterConfig.addAttribute("checkFormat", "e[l");
try {
final String[] suppressed = CommonUtils.EMPTY_STRING_ARRAY;
verifySuppressed(filterConfig, suppressed);
}
catch (CheckstyleException ex) {
final IllegalArgumentException cause = (IllegalArgumentException) ex.getCause();
assertEquals("Invalid exception message",
"unable to parse expanded comment e[l", cause.getMessage());
}
}
@Test
public void testInvalidMessageFormat() throws Exception {
final DefaultConfiguration filterConfig =
createModuleConfig(SuppressionCommentFilter.class);
filterConfig.addAttribute("messageFormat", "e[l");
try {
final String[] suppressed = CommonUtils.EMPTY_STRING_ARRAY;
verifySuppressed(filterConfig, suppressed);
}
catch (CheckstyleException ex) {
final IllegalArgumentException cause = (IllegalArgumentException) ex.getCause();
assertEquals("Invalid exception message",
"unable to parse expanded comment e[l", cause.getMessage());
}
}
@Test
public void testAcceptNullLocalizedMessage() {
final SuppressionCommentFilter filter = new SuppressionCommentFilter();
final TreeWalkerAuditEvent auditEvent = new TreeWalkerAuditEvent(null, null, null, null);
Assert.assertTrue("Filter should accept audit event", filter.accept(auditEvent));
Assert.assertNull("File name should not be null", auditEvent.getFileName());
}
@Test
public void testSuppressById() throws Exception {
final DefaultConfiguration filterConfig =
createModuleConfig(SuppressionCommentFilter.class);
filterConfig.addAttribute("offCommentFormat", "CSOFF (\\w+) \\(\\w+\\)");
filterConfig.addAttribute("onCommentFormat", "CSON (\\w+)");
filterConfig.addAttribute("checkFormat", "$1");
final String[] suppressedViolationMessages = {
"6:17: Name 'A1' must match pattern '^[a-z][a-zA-Z0-9]*$'.",
"12:9: Name 'line_length' must match pattern '^[a-z][a-zA-Z0-9]*$'.",
};
final String[] expectedViolationMessages = {
"6:17: Name 'A1' must match pattern '^[a-z][a-zA-Z0-9]*$'.",
"9:30: Name 'abc' must match pattern '^[A-Z][A-Z0-9]*(_[A-Z0-9]+)*$'.",
"12:9: Name 'line_length' must match pattern '^[a-z][a-zA-Z0-9]*$'.",
"15:18: Name 'ID' must match pattern '^[a-z][a-zA-Z0-9]*$'.",
};
verify(createChecker(filterConfig),
getPath("InputSuppressionCommentFilterSuppressById.java"),
removeSuppressed(expectedViolationMessages, suppressedViolationMessages));
}
@Test
public void testFindNearestMatchDontAllowSameColumn() {
final SuppressionCommentFilter suppressionCommentFilter = new SuppressionCommentFilter();
final FileContents contents =
new FileContents("filename", "//CHECKSTYLE:OFF: ConstantNameCheck", "line2");
contents.reportSingleLineComment(1, 0);
final TreeWalkerAuditEvent dummyEvent = new TreeWalkerAuditEvent(contents, "filename",
new LocalizedMessage(1, null, null, null, null, Object.class, null), null);
final boolean result = suppressionCommentFilter.accept(dummyEvent);
assertFalse("Fileter should not accept event", result);
}
@Test
public void testTagsAreClearedEachRun() {
final SuppressionCommentFilter suppressionCommentFilter = new SuppressionCommentFilter();
final FileContents contents =
new FileContents("filename", "//CHECKSTYLE:OFF", "line2");
contents.reportSingleLineComment(1, 0);
final TreeWalkerAuditEvent dummyEvent = new TreeWalkerAuditEvent(contents, "filename",
new LocalizedMessage(1, null, null, null, null, Object.class, null), null);
suppressionCommentFilter.accept(dummyEvent);
final FileContents contents2 =
new FileContents("filename2", "some line", "//CHECKSTYLE:OFF");
contents2.reportSingleLineComment(2, 0);
final TreeWalkerAuditEvent dummyEvent2 = new TreeWalkerAuditEvent(contents2, "filename",
new LocalizedMessage(1, null, null, null, null, Object.class, null), null);
suppressionCommentFilter.accept(dummyEvent2);
final List<SuppressionCommentFilter.Tag> tags =
Whitebox.getInternalState(suppressionCommentFilter, "tags");
assertEquals("Invalid tags size", 1, tags.size());
}
}