////////////////////////////////////////////////////////////////////////////////
// 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 java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collection;
import java.util.Locale;
import java.util.stream.Collectors;
import org.junit.Assert;
import org.junit.Test;
import com.puppycrawl.tools.checkstyle.BaseCheckTestSupport;
import com.puppycrawl.tools.checkstyle.BriefUtLogger;
import com.puppycrawl.tools.checkstyle.Checker;
import com.puppycrawl.tools.checkstyle.DefaultConfiguration;
import com.puppycrawl.tools.checkstyle.TreeWalker;
import com.puppycrawl.tools.checkstyle.api.AuditEvent;
import com.puppycrawl.tools.checkstyle.api.CheckstyleException;
import com.puppycrawl.tools.checkstyle.api.Configuration;
import com.puppycrawl.tools.checkstyle.checks.FileContentsHolder;
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 SuppressWithNearbyCommentFilterTest
extends BaseCheckTestSupport {
private static final String[] ALL_MESSAGES = {
"14:17: Name 'A1' must match pattern '^[a-z][a-zA-Z0-9]*$'.",
"15:17: Name 'A2' must match pattern '^[a-z][a-zA-Z0-9]*$'.",
"16:59: Name 'A3' must match pattern '^[a-z][a-zA-Z0-9]*$'.",
"18:17: Name 'B1' must match pattern '^[a-z][a-zA-Z0-9]*$'.",
"19:17: Name 'B2' must match pattern '^[a-z][a-zA-Z0-9]*$'.",
"20:59: Name 'B3' must match pattern '^[a-z][a-zA-Z0-9]*$'.",
"22:17: Name 'C1' must match pattern '^[a-z][a-zA-Z0-9]*$'.",
"24:17: Name 'C2' must match pattern '^[a-z][a-zA-Z0-9]*$'.",
"25:17: Name 'C3' must match pattern '^[a-z][a-zA-Z0-9]*$'.",
"27:17: Name 'D1' must match pattern '^[a-z][a-zA-Z0-9]*$'.",
"28:17: Name 'D2' must match pattern '^[a-z][a-zA-Z0-9]*$'.",
"30:17: Name 'D3' must match pattern '^[a-z][a-zA-Z0-9]*$'.",
"32:30: Name 'e1' must match pattern '^[A-Z][A-Z0-9]*(_[A-Z0-9]+)*$'.",
"33:17: Name 'E2' must match pattern '^[a-z][a-zA-Z0-9]*$'.",
"34:17: Name 'E3' must match pattern '^[a-z][a-zA-Z0-9]*$'.",
"35:30: Name 'e4' must match pattern '^[A-Z][A-Z0-9]*(_[A-Z0-9]+)*$'.",
"36:17: Name 'E5' must match pattern '^[a-z][a-zA-Z0-9]*$'.",
"37:30: Name 'e6' must match pattern '^[A-Z][A-Z0-9]*(_[A-Z0-9]+)*$'.",
"38:17: Name 'E7' must match pattern '^[a-z][a-zA-Z0-9]*$'.",
"39:17: Name 'E8' must match pattern '^[a-z][a-zA-Z0-9]*$'.",
"40:30: Name 'e9' must match pattern '^[A-Z][A-Z0-9]*(_[A-Z0-9]+)*$'.",
"64:23: Catching 'Exception' is not allowed.",
"66:23: Catching 'Throwable' is not allowed.",
"73:11: Catching 'Exception' is not allowed.",
"80:59: Name 'A2' must match pattern '^[a-z][a-zA-Z0-9]*$'.",
"81:17: Name 'A1' must match pattern '^[a-z][a-zA-Z0-9]*$'.",
};
@Override
protected String getPath(String filename) throws IOException {
return super.getPath("filters" + File.separator + filename);
}
@Test
public void testNone() throws Exception {
final DefaultConfiguration filterConfig = null;
final String[] suppressed = CommonUtils.EMPTY_STRING_ARRAY;
verifySuppressed(filterConfig, suppressed);
}
@Test
public void testDefault() throws Exception {
final DefaultConfiguration filterConfig =
createFilterConfig(SuppressWithNearbyCommentFilter.class);
final String[] suppressed = {
"14:17: Name 'A1' must match pattern '^[a-z][a-zA-Z0-9]*$'.",
"15:17: Name 'A2' must match pattern '^[a-z][a-zA-Z0-9]*$'.",
"16:59: Name 'A3' must match pattern '^[a-z][a-zA-Z0-9]*$'.",
"18:17: Name 'B1' must match pattern '^[a-z][a-zA-Z0-9]*$'.",
"19:17: Name 'B2' must match pattern '^[a-z][a-zA-Z0-9]*$'.",
"20:59: Name 'B3' must match pattern '^[a-z][a-zA-Z0-9]*$'.",
"80:59: Name 'A2' must match pattern '^[a-z][a-zA-Z0-9]*$'.",
};
verifySuppressed(filterConfig, suppressed);
}
@Test
public void testCheckC() throws Exception {
final DefaultConfiguration filterConfig =
createFilterConfig(SuppressWithNearbyCommentFilter.class);
filterConfig.addAttribute("checkC", "false");
final String[] suppressed = {
"14:17: Name 'A1' must match pattern '^[a-z][a-zA-Z0-9]*$'.",
"18:17: Name 'B1' must match pattern '^[a-z][a-zA-Z0-9]*$'.",
};
verifySuppressed(filterConfig, suppressed);
}
@Test
public void testCheckCpp() throws Exception {
final DefaultConfiguration filterConfig =
createFilterConfig(SuppressWithNearbyCommentFilter.class);
filterConfig.addAttribute("checkCPP", "false");
final String[] suppressed = {
"15:17: Name 'A2' must match pattern '^[a-z][a-zA-Z0-9]*$'.",
"16:59: Name 'A3' must match pattern '^[a-z][a-zA-Z0-9]*$'.",
"19:17: Name 'B2' must match pattern '^[a-z][a-zA-Z0-9]*$'.",
"20:59: Name 'B3' must match pattern '^[a-z][a-zA-Z0-9]*$'.",
"80:59: Name 'A2' must match pattern '^[a-z][a-zA-Z0-9]*$'.",
};
verifySuppressed(filterConfig, suppressed);
}
@Test
public void testUsingVariableMessage() throws Exception {
final DefaultConfiguration filterConfig =
createFilterConfig(SuppressWithNearbyCommentFilter.class);
filterConfig.addAttribute("commentFormat", "ALLOW CATCH (\\w+) BECAUSE");
filterConfig.addAttribute("checkFormat", "IllegalCatchCheck");
filterConfig.addAttribute("messageFormat", "$1");
filterConfig.addAttribute("influenceFormat", "-1");
final String[] suppressed = {
"66:23: Catching 'Throwable' is not allowed.",
"73:11: Catching 'Exception' is not allowed.",
};
verifySuppressed(filterConfig, suppressed);
}
@Test
public void testUsingVariableCheckOnNextLine() throws Exception {
final DefaultConfiguration filterConfig =
createFilterConfig(SuppressWithNearbyCommentFilter.class);
filterConfig.addAttribute("commentFormat", "ALLOW (\\w+) ON NEXT LINE");
filterConfig.addAttribute("checkFormat", "$1");
filterConfig.addAttribute("influenceFormat", "1");
final String[] suppressed = {
"24:17: Name 'C2' must match pattern '^[a-z][a-zA-Z0-9]*$'.",
};
verifySuppressed(filterConfig, suppressed);
}
@Test
public void testUsingVariableCheckOnPreviousLine() throws Exception {
final DefaultConfiguration filterConfig =
createFilterConfig(SuppressWithNearbyCommentFilter.class);
filterConfig.addAttribute("commentFormat", "ALLOW (\\w+) ON PREVIOUS LINE");
filterConfig.addAttribute("checkFormat", "$1");
filterConfig.addAttribute("influenceFormat", "-1");
final String[] suppressed = {
"28:17: Name 'D2' must match pattern '^[a-z][a-zA-Z0-9]*$'.",
};
verifySuppressed(filterConfig, suppressed);
}
@Test
public void testVariableCheckOnVariableNumberOfLines() throws Exception {
final DefaultConfiguration filterConfig =
createFilterConfig(SuppressWithNearbyCommentFilter.class);
filterConfig.addAttribute("commentFormat", "ALLOW (\\w+) UNTIL THIS LINE([+-]\\d+)");
filterConfig.addAttribute("checkFormat", "$1");
filterConfig.addAttribute("influenceFormat", "$2");
final String[] suppressed = {
"35:30: Name 'e4' must match pattern '^[A-Z][A-Z0-9]*(_[A-Z0-9]+)*$'.",
"36:17: Name 'E5' must match pattern '^[a-z][a-zA-Z0-9]*$'.",
"38:17: Name 'E7' must match pattern '^[a-z][a-zA-Z0-9]*$'.",
"39:17: Name 'E8' must match pattern '^[a-z][a-zA-Z0-9]*$'.",
};
verifySuppressed(filterConfig, suppressed);
}
@Test
public void testEqualsAndHashCodeOfTagClass() {
EqualsVerifier.forClass(SuppressWithNearbyCommentFilter.Tag.class).usingGetClass().verify();
}
private static DefaultConfiguration createFilterConfig(Class<?> classObj) {
return new DefaultConfiguration(classObj.getName());
}
private void verifySuppressed(Configuration filterConfig,
String... suppressed)
throws Exception {
verify(createChecker(filterConfig),
getPath("InputSuppressWithNearbyCommentFilter.java"),
removeSuppressed(ALL_MESSAGES, suppressed));
}
@Override
public Checker createChecker(Configuration checkConfig)
throws CheckstyleException {
final DefaultConfiguration checkerConfig =
new DefaultConfiguration("configuration");
final DefaultConfiguration checksConfig = createCheckConfig(TreeWalker.class);
checksConfig.addChild(createCheckConfig(FileContentsHolder.class));
final DefaultConfiguration memberNameCheckConfig = createCheckConfig(MemberNameCheck.class);
memberNameCheckConfig.addAttribute("id", "ignore");
checksConfig.addChild(memberNameCheckConfig);
final DefaultConfiguration constantNameCheckConfig =
createCheckConfig(ConstantNameCheck.class);
constantNameCheckConfig.addAttribute("id", null);
checksConfig.addChild(constantNameCheckConfig);
checksConfig.addChild(createCheckConfig(IllegalCatchCheck.class));
checkerConfig.addChild(checksConfig);
if (checkConfig != null) {
checkerConfig.addChild(checkConfig);
}
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(new BriefUtLogger(stream));
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 testInvalidInfluenceFormat() throws Exception {
final DefaultConfiguration filterConfig =
createFilterConfig(SuppressWithNearbyCommentFilter.class);
filterConfig.addAttribute("influenceFormat", "a");
try {
final String[] suppressed = CommonUtils.EMPTY_STRING_ARRAY;
verifySuppressed(filterConfig, suppressed);
}
catch (CheckstyleException ex) {
final IllegalArgumentException cause = (IllegalArgumentException) ex.getCause();
assertEquals("unable to parse influence"
+ " from 'SUPPRESS CHECKSTYLE MemberNameCheck' using a",
cause.getMessage());
}
}
@Test
public void testInvalidCheckFormat() throws Exception {
final DefaultConfiguration filterConfig =
createFilterConfig(SuppressWithNearbyCommentFilter.class);
filterConfig.addAttribute("checkFormat", "a[l");
try {
final String[] suppressed = CommonUtils.EMPTY_STRING_ARRAY;
verifySuppressed(filterConfig, suppressed);
}
catch (CheckstyleException ex) {
final IllegalArgumentException cause = (IllegalArgumentException) ex.getCause();
assertEquals("unable to parse expanded comment a[l",
cause.getMessage());
}
}
@Test
public void testAcceptNullLocalizedMessage() {
final SuppressWithNearbyCommentFilter filter = new SuppressWithNearbyCommentFilter();
final AuditEvent auditEvent = new AuditEvent(this);
Assert.assertTrue(filter.accept(auditEvent));
}
@Test
public void testToStringOfTagClass() {
final SuppressWithNearbyCommentFilter.Tag tag = new SuppressWithNearbyCommentFilter.Tag(
"text", 7, new SuppressWithNearbyCommentFilter()
);
assertEquals("Tag[lines=[7 to 7]; text='text']", tag.toString());
}
@Test
public void testUsingTagMessageRegexp() throws Exception {
final DefaultConfiguration filterConfig =
createFilterConfig(SuppressWithNearbyCommentFilter.class);
filterConfig.addAttribute("commentFormat", "SUPPRESS CHECKSTYLE (\\w+)");
filterConfig.addAttribute("checkFormat", "IllegalCatchCheck");
filterConfig.addAttribute("messageFormat", "^$1 ololo*$");
final String[] suppressed = CommonUtils.EMPTY_STRING_ARRAY;
verifySuppressed(filterConfig, suppressed);
}
@Test
public void testSuppressById() throws Exception {
final DefaultConfiguration filterConfig =
createFilterConfig(SuppressWithNearbyCommentFilter.class);
filterConfig.addAttribute("commentFormat", "@cs-: (\\w+) \\(\\w+\\)");
filterConfig.addAttribute("checkFormat", "$1");
filterConfig.addAttribute("influenceFormat", "0");
final String[] suppressedViolationMessages = {
"5:17: Name 'A1' must match pattern '^[a-z][a-zA-Z0-9]*$'.",
"9:9: Name 'line_length' must match pattern '^[a-z][a-zA-Z0-9]*$'.",
};
final String[] expectedViolationMessages = {
"5:17: Name 'A1' must match pattern '^[a-z][a-zA-Z0-9]*$'.",
"7:30: Name 'abc' must match pattern '^[A-Z][A-Z0-9]*(_[A-Z0-9]+)*$'.",
"9:9: Name 'line_length' must match pattern '^[a-z][a-zA-Z0-9]*$'.",
"11:18: Name 'ID' must match pattern '^[a-z][a-zA-Z0-9]*$'.",
};
verify(createChecker(filterConfig),
getPath("InputSuppressByIdWithNearbyCommentFilter.java"),
removeSuppressed(expectedViolationMessages, suppressedViolationMessages));
}
}