600 lines
32 KiB
Java
600 lines
32 KiB
Java
////////////////////////////////////////////////////////////////////////////////
|
|
// 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.internal;
|
|
|
|
import java.lang.reflect.Field;
|
|
import java.lang.reflect.Modifier;
|
|
import java.util.ArrayList;
|
|
import java.util.Arrays;
|
|
import java.util.HashMap;
|
|
import java.util.HashSet;
|
|
import java.util.List;
|
|
import java.util.Locale;
|
|
import java.util.Map;
|
|
import java.util.Map.Entry;
|
|
import java.util.Properties;
|
|
import java.util.Set;
|
|
import java.util.TreeMap;
|
|
import java.util.stream.Collectors;
|
|
import java.util.stream.Stream;
|
|
|
|
import org.junit.Assert;
|
|
import org.junit.Test;
|
|
|
|
import com.puppycrawl.tools.checkstyle.BaseCheckTestSupport;
|
|
import com.puppycrawl.tools.checkstyle.Checker;
|
|
import com.puppycrawl.tools.checkstyle.DefaultConfiguration;
|
|
import com.puppycrawl.tools.checkstyle.ModuleFactory;
|
|
import com.puppycrawl.tools.checkstyle.api.AbstractCheck;
|
|
import com.puppycrawl.tools.checkstyle.api.CheckstyleException;
|
|
import com.puppycrawl.tools.checkstyle.api.Configuration;
|
|
import com.puppycrawl.tools.checkstyle.checks.imports.ImportControlCheck;
|
|
import com.puppycrawl.tools.checkstyle.utils.CommonUtils;
|
|
|
|
public class AllChecksTest extends BaseCheckTestSupport {
|
|
private static final Locale[] ALL_LOCALES = {
|
|
Locale.GERMAN,
|
|
new Locale("es"),
|
|
new Locale("fi"),
|
|
Locale.FRENCH,
|
|
Locale.JAPANESE,
|
|
new Locale("pt"),
|
|
new Locale("tr"),
|
|
Locale.CHINESE,
|
|
Locale.ENGLISH,
|
|
};
|
|
|
|
private static final Map<String, Set<String>> CHECKSTYLE_TOKENS_IN_CONFIG_TO_IGNORE =
|
|
new HashMap<>();
|
|
private static final Map<String, Set<String>> GOOGLE_TOKENS_IN_CONFIG_TO_IGNORE =
|
|
new HashMap<>();
|
|
|
|
static {
|
|
// checkstyle
|
|
|
|
CHECKSTYLE_TOKENS_IN_CONFIG_TO_IGNORE.put("NoWhitespaceBefore", Stream.of(
|
|
// we use GenericWhitespace for this behavior
|
|
"GENERIC_START", "GENERIC_END").collect(Collectors.toSet()));
|
|
CHECKSTYLE_TOKENS_IN_CONFIG_TO_IGNORE.put("AbbreviationAsWordInName", Stream.of(
|
|
// enum values should be uppercase, we use EnumValueNameCheck instead
|
|
"ENUM_CONSTANT_DEF").collect(Collectors.toSet()));
|
|
CHECKSTYLE_TOKENS_IN_CONFIG_TO_IGNORE.put("FinalLocalVariable", Stream.of(
|
|
// we prefer all parameters be effectively final as to not damage readability
|
|
// we use ParameterAssignmentCheck to enforce this
|
|
"PARAMETER_DEF").collect(Collectors.toSet()));
|
|
// we have no need to block these specific tokens
|
|
CHECKSTYLE_TOKENS_IN_CONFIG_TO_IGNORE.put("IllegalToken",
|
|
Stream.of("LITERAL_SUPER", "LITERAL_ASSERT", "ENUM_CONSTANT_DEF",
|
|
"TYPE_PARAMETERS", "TYPE_UPPER_BOUNDS", "NUM_DOUBLE", "LITERAL_SWITCH",
|
|
"ANNOTATIONS", "LITERAL_SHORT", "LITERAL_PROTECTED", "FOR_CONDITION",
|
|
"FOR_INIT", "LITERAL_LONG", "MINUS", "OBJBLOCK", "LITERAL_NULL",
|
|
"ANNOTATION", "LITERAL_TRUE", "COMMENT_CONTENT", "LITERAL_CHAR",
|
|
"PARAMETER_DEF", "POST_DEC", "ANNOTATION_FIELD_DEF", "BLOCK_COMMENT_END",
|
|
"TYPE", "LITERAL_INT", "BSR", "ENUM", "ANNOTATION_MEMBER_VALUE_PAIR",
|
|
"TYPECAST", "LITERAL_SYNCHRONIZED", "PLUS_ASSIGN", "DOT", "LPAREN",
|
|
"LITERAL_IF", "LITERAL_CATCH", "BAND", "INTERFACE_DEF", "LOR", "BNOT",
|
|
"METHOD_CALL", "AT", "ELLIPSIS", "ARRAY_INIT", "FOR_EACH_CLAUSE",
|
|
"LITERAL_THROWS", "CHAR_LITERAL", "CASE_GROUP", "POST_INC", "SEMI",
|
|
"LITERAL_FINALLY", "ASSIGN", "RESOURCE_SPECIFICATION", "STATIC_IMPORT",
|
|
"GENERIC_START", "IMPORT", "SL", "VARIABLE_DEF", "LITERAL_DOUBLE",
|
|
"RCURLY", "RESOURCE", "SR", "COMMA", "BAND_ASSIGN", "METHOD_DEF",
|
|
"LITERAL_VOID", "NUM_LONG", "LITERAL_TRANSIENT", "LITERAL_THIS", "LCURLY",
|
|
"MINUS_ASSIGN", "TYPE_LOWER_BOUNDS", "TYPE_ARGUMENT", "LITERAL_CLASS",
|
|
"INSTANCE_INIT", "DIV", "STAR", "UNARY_MINUS", "FOR_ITERATOR", "NOT_EQUAL",
|
|
"LE", "LITERAL_INTERFACE", "LITERAL_FLOAT", "LITERAL_INSTANCEOF",
|
|
"BOR_ASSIGN", "LT", "SL_ASSIGN", "ELIST", "ANNOTATION_ARRAY_INIT",
|
|
"MODIFIERS", "LITERAL_BREAK", "EXTENDS_CLAUSE", "TYPE_PARAMETER",
|
|
"LITERAL_DEFAULT", "STATIC_INIT", "BSR_ASSIGN", "TYPE_EXTENSION_AND",
|
|
"BOR", "LITERAL_PRIVATE", "LITERAL_THROW", "LITERAL_BYTE", "BXOR",
|
|
"WILDCARD_TYPE", "FINAL", "PARAMETERS", "RPAREN", "SR_ASSIGN",
|
|
"UNARY_PLUS", "EMPTY_STAT", "LITERAL_STATIC", "LITERAL_CONTINUE",
|
|
"STAR_ASSIGN", "LAMBDA", "RBRACK", "BXOR_ASSIGN", "CTOR_CALL",
|
|
"LITERAL_FALSE", "DO_WHILE", "LITERAL_PUBLIC", "LITERAL_WHILE", "PLUS",
|
|
"INC", "CTOR_DEF", "GENERIC_END", "DIV_ASSIGN", "SLIST", "LNOT", "LAND",
|
|
"LITERAL_ELSE", "ABSTRACT", "STRICTFP", "QUESTION", "LITERAL_NEW",
|
|
"LITERAL_RETURN", "SINGLE_LINE_COMMENT", "INDEX_OP", "EXPR",
|
|
"BLOCK_COMMENT_BEGIN", "PACKAGE_DEF", "IMPLEMENTS_CLAUSE", "NUM_FLOAT",
|
|
"LITERAL_DO", "EOF", "GE", "RESOURCES", "MOD", "DEC", "EQUAL",
|
|
"LITERAL_BOOLEAN", "CLASS_DEF", "COLON", "LITERAL_TRY", "ENUM_DEF", "GT",
|
|
"NUM_INT", "ANNOTATION_DEF", "METHOD_REF", "TYPE_ARGUMENTS",
|
|
"DOUBLE_COLON", "IDENT", "MOD_ASSIGN", "LITERAL_FOR", "SUPER_CTOR_CALL",
|
|
"STRING_LITERAL", "ARRAY_DECLARATOR", "LITERAL_CASE").collect(
|
|
Collectors.toSet()));
|
|
// we have no need to block specific token text
|
|
CHECKSTYLE_TOKENS_IN_CONFIG_TO_IGNORE.put("IllegalTokenText",
|
|
Stream.of("LITERAL_SUPER", "LITERAL_ASSERT", "ENUM_CONSTANT_DEF",
|
|
"TYPE_PARAMETERS", "TYPE_UPPER_BOUNDS", "NUM_DOUBLE", "LITERAL_SWITCH",
|
|
"ANNOTATIONS", "LITERAL_SHORT", "LITERAL_PROTECTED", "FOR_CONDITION",
|
|
"FOR_INIT", "LITERAL_LONG", "MINUS", "OBJBLOCK", "LITERAL_NULL",
|
|
"ANNOTATION", "LITERAL_TRUE", "COMMENT_CONTENT", "LITERAL_CHAR",
|
|
"PARAMETER_DEF", "POST_DEC", "ANNOTATION_FIELD_DEF", "BLOCK_COMMENT_END",
|
|
"TYPE", "LITERAL_INT", "BSR", "ENUM", "LABELED_STAT",
|
|
"ANNOTATION_MEMBER_VALUE_PAIR", "TYPECAST", "LITERAL_SYNCHRONIZED",
|
|
"PLUS_ASSIGN", "DOT", "LPAREN", "LITERAL_IF", "LITERAL_CATCH", "BAND",
|
|
"INTERFACE_DEF", "LOR", "BNOT", "METHOD_CALL", "AT", "ELLIPSIS",
|
|
"ARRAY_INIT", "FOR_EACH_CLAUSE", "LITERAL_THROWS", "CHAR_LITERAL",
|
|
"CASE_GROUP", "POST_INC", "SEMI", "LITERAL_FINALLY", "ASSIGN",
|
|
"RESOURCE_SPECIFICATION", "STATIC_IMPORT", "GENERIC_START", "IMPORT", "SL",
|
|
"VARIABLE_DEF", "LITERAL_DOUBLE", "RCURLY", "RESOURCE", "SR", "COMMA",
|
|
"BAND_ASSIGN", "METHOD_DEF", "LITERAL_VOID", "NUM_LONG",
|
|
"LITERAL_TRANSIENT", "LITERAL_THIS", "LCURLY", "MINUS_ASSIGN",
|
|
"TYPE_LOWER_BOUNDS", "TYPE_ARGUMENT", "LITERAL_CLASS", "INSTANCE_INIT",
|
|
"DIV", "LITERAL_VOLATILE", "STAR", "UNARY_MINUS", "FOR_ITERATOR",
|
|
"NOT_EQUAL", "LE", "LITERAL_INTERFACE", "LITERAL_FLOAT",
|
|
"LITERAL_INSTANCEOF", "BOR_ASSIGN", "LT", "SL_ASSIGN", "ELIST",
|
|
"ANNOTATION_ARRAY_INIT", "MODIFIERS", "LITERAL_BREAK", "EXTENDS_CLAUSE",
|
|
"TYPE_PARAMETER", "LITERAL_DEFAULT", "STATIC_INIT", "BSR_ASSIGN",
|
|
"TYPE_EXTENSION_AND", "BOR", "LITERAL_PRIVATE", "LITERAL_THROW",
|
|
"LITERAL_BYTE", "BXOR", "WILDCARD_TYPE", "FINAL", "PARAMETERS", "RPAREN",
|
|
"SR_ASSIGN", "UNARY_PLUS", "EMPTY_STAT", "LITERAL_STATIC",
|
|
"LITERAL_CONTINUE", "STAR_ASSIGN", "LAMBDA", "RBRACK", "BXOR_ASSIGN",
|
|
"CTOR_CALL", "LITERAL_FALSE", "DO_WHILE", "LITERAL_PUBLIC",
|
|
"LITERAL_WHILE", "PLUS", "INC", "CTOR_DEF", "GENERIC_END", "DIV_ASSIGN",
|
|
"SLIST", "LNOT", "LAND", "LITERAL_ELSE", "ABSTRACT", "STRICTFP",
|
|
"QUESTION", "LITERAL_NEW", "LITERAL_RETURN", "SINGLE_LINE_COMMENT",
|
|
"INDEX_OP", "EXPR", "BLOCK_COMMENT_BEGIN", "PACKAGE_DEF",
|
|
"IMPLEMENTS_CLAUSE", "NUM_FLOAT", "LITERAL_DO", "EOF", "GE", "RESOURCES",
|
|
"MOD", "DEC", "EQUAL", "LITERAL_BOOLEAN", "CLASS_DEF", "COLON",
|
|
"LITERAL_TRY", "ENUM_DEF", "GT", "NUM_INT", "ANNOTATION_DEF",
|
|
"LITERAL_NATIVE", "METHOD_REF", "TYPE_ARGUMENTS", "DOUBLE_COLON", "IDENT",
|
|
"MOD_ASSIGN", "LITERAL_FOR", "SUPER_CTOR_CALL", "STRING_LITERAL",
|
|
"ARRAY_DECLARATOR", "LITERAL_CASE").collect(Collectors.toSet()));
|
|
// we do not use this check as it is deprecated
|
|
CHECKSTYLE_TOKENS_IN_CONFIG_TO_IGNORE.put("WriteTag",
|
|
Stream.of("ENUM_CONSTANT_DEF", "METHOD_DEF", "CTOR_DEF", "ANNOTATION_FIELD_DEF")
|
|
.collect(Collectors.toSet()));
|
|
// state of the configuration when test was made until reason found in
|
|
// https://github.com/checkstyle/checkstyle/issues/3730
|
|
CHECKSTYLE_TOKENS_IN_CONFIG_TO_IGNORE.put("AnnotationLocation",
|
|
Stream.of("TYPECAST", "DOT", "TYPE_ARGUMENT", "LITERAL_NEW", "LITERAL_THROWS",
|
|
"IMPLEMENTS_CLAUSE").collect(Collectors.toSet()));
|
|
CHECKSTYLE_TOKENS_IN_CONFIG_TO_IGNORE.put("NoLineWrap", Stream.of(
|
|
// method declaration could be long due to "parameters/exceptions", it is ok to
|
|
// be not strict there
|
|
"METHOD_DEF", "CTOR_DEF",
|
|
// type declaration could be long due to "extends/implements", it is ok to
|
|
// be not strict there
|
|
"CLASS_DEF", "ENUM_DEF", "INTERFACE_DEF")
|
|
.collect(Collectors.toSet()));
|
|
CHECKSTYLE_TOKENS_IN_CONFIG_TO_IGNORE.put("NoWhitespaceAfter", Stream.of(
|
|
// whitespace after is preferred
|
|
"TYPECAST", "LITERAL_SYNCHRONIZED").collect(Collectors.toSet()));
|
|
CHECKSTYLE_TOKENS_IN_CONFIG_TO_IGNORE.put("SeparatorWrap", Stream.of(
|
|
// needs context to decide what type of parentheses should be separated or not
|
|
// which this check does not provide
|
|
"LPAREN", "RPAREN").collect(Collectors.toSet()));
|
|
CHECKSTYLE_TOKENS_IN_CONFIG_TO_IGNORE.put("NeedBraces", Stream.of(
|
|
// we prefer no braces here as it looks unusual even though they help avoid sharing
|
|
// scope of variables
|
|
"LITERAL_DEFAULT", "LITERAL_CASE").collect(Collectors.toSet()));
|
|
CHECKSTYLE_TOKENS_IN_CONFIG_TO_IGNORE.put("FinalParameters", Stream.of(
|
|
// we prefer these to be effectively final as to not damage readability
|
|
"FOR_EACH_CLAUSE", "LITERAL_CATCH").collect(Collectors.toSet()));
|
|
CHECKSTYLE_TOKENS_IN_CONFIG_TO_IGNORE.put("WhitespaceAround", Stream.of(
|
|
// we prefer no spaces on one side or both for these tokens
|
|
"ARRAY_INIT",
|
|
// these are covered by GenericWhitespaceCheck
|
|
"WILDCARD_TYPE", "GENERIC_END", "GENERIC_START").collect(Collectors.toSet()));
|
|
|
|
// google
|
|
GOOGLE_TOKENS_IN_CONFIG_TO_IGNORE.put("AnnotationLocation", Stream.of(
|
|
// state of the configuration when test was made until reason found in
|
|
// https://github.com/checkstyle/checkstyle/issues/3730
|
|
"TYPECAST", "DOT", "TYPE_ARGUMENT", "ANNOTATION_DEF", "LITERAL_NEW",
|
|
"LITERAL_THROWS", "PARAMETER_DEF", "IMPLEMENTS_CLAUSE", "ANNOTATION_FIELD_DEF")
|
|
.collect(Collectors.toSet()));
|
|
GOOGLE_TOKENS_IN_CONFIG_TO_IGNORE.put("AbbreviationAsWordInName", Stream.of(
|
|
// enum values should be uppercase
|
|
"ENUM_CONSTANT_DEF").collect(Collectors.toSet()));
|
|
GOOGLE_TOKENS_IN_CONFIG_TO_IGNORE.put("NoLineWrap", Stream.of(
|
|
// method declaration could be long due to "parameters/exceptions", it is ok to
|
|
// be not strict there
|
|
"METHOD_DEF", "CTOR_DEF", "CLASS_DEF", "ENUM_DEF", "INTERFACE_DEF")
|
|
.collect(Collectors.toSet()));
|
|
GOOGLE_TOKENS_IN_CONFIG_TO_IGNORE.put("SeparatorWrap", Stream.of(
|
|
// state of configuration until
|
|
// https://github.com/checkstyle/checkstyle/issues/3752
|
|
"RBRACK", "AT", "ELLIPSIS", "SEMI", "ARRAY_DECLARATOR",
|
|
// needs context to decide what type of parentheses should be separated or not
|
|
// which this check does not provide
|
|
"LPAREN", "RPAREN").collect(Collectors.toSet()));
|
|
GOOGLE_TOKENS_IN_CONFIG_TO_IGNORE.put("NeedBraces", Stream.of(
|
|
// google doesn't require or prevent braces on these
|
|
"LAMBDA", "LITERAL_DEFAULT", "LITERAL_CASE").collect(Collectors.toSet()));
|
|
GOOGLE_TOKENS_IN_CONFIG_TO_IGNORE.put("EmptyBlock", Stream.of(
|
|
// state of the configuration when test was made until
|
|
// https://github.com/checkstyle/checkstyle/issues/3748
|
|
"LITERAL_DEFAULT", "LITERAL_CASE",
|
|
// can be empty for special cases via '6.2 Caught exceptions: not ignored'
|
|
"LITERAL_CATCH",
|
|
// specifically allowed via '5.2.4 Constant names'
|
|
"ARRAY_INIT")
|
|
.collect(Collectors.toSet()));
|
|
GOOGLE_TOKENS_IN_CONFIG_TO_IGNORE.put("WhitespaceAround", Stream.of(
|
|
// allowed via '4.8.3 Arrays'
|
|
"ARRAY_INIT",
|
|
// google prefers no spaces on one side or both for these tokens
|
|
"GENERIC_START", "GENERIC_END", "WILDCARD_TYPE")
|
|
.collect(Collectors.toSet()));
|
|
GOOGLE_TOKENS_IN_CONFIG_TO_IGNORE.put("IllegalTokenText", Stream.of(
|
|
// all other java tokens and text are allowed
|
|
"LITERAL_SUPER", "LITERAL_ASSERT", "ENUM_CONSTANT_DEF", "TYPE_PARAMETERS",
|
|
"TYPE_UPPER_BOUNDS", "NUM_DOUBLE", "LITERAL_SWITCH", "ANNOTATIONS",
|
|
"LITERAL_SHORT", "LITERAL_PROTECTED", "FOR_CONDITION", "FOR_INIT", "LITERAL_LONG",
|
|
"MINUS", "OBJBLOCK", "LITERAL_NULL", "ANNOTATION", "LITERAL_TRUE",
|
|
"COMMENT_CONTENT", "LITERAL_CHAR", "PARAMETER_DEF", "POST_DEC",
|
|
"ANNOTATION_FIELD_DEF", "BLOCK_COMMENT_END", "TYPE", "LITERAL_INT", "BSR", "ENUM",
|
|
"LABELED_STAT", "ANNOTATION_MEMBER_VALUE_PAIR", "TYPECAST", "LITERAL_SYNCHRONIZED",
|
|
"PLUS_ASSIGN", "DOT", "LPAREN", "LITERAL_IF", "LITERAL_CATCH", "BAND",
|
|
"INTERFACE_DEF", "LOR", "BNOT", "METHOD_CALL", "AT", "ELLIPSIS", "ARRAY_INIT",
|
|
"FOR_EACH_CLAUSE", "LITERAL_THROWS", "CASE_GROUP", "POST_INC", "SEMI",
|
|
"LITERAL_FINALLY", "ASSIGN", "RESOURCE_SPECIFICATION", "STATIC_IMPORT",
|
|
"GENERIC_START", "IMPORT", "SL", "VARIABLE_DEF", "LITERAL_DOUBLE", "RCURLY",
|
|
"RESOURCE", "SR", "COMMA", "BAND_ASSIGN", "METHOD_DEF", "LITERAL_VOID",
|
|
"NUM_LONG", "LITERAL_TRANSIENT", "LITERAL_THIS", "LCURLY", "MINUS_ASSIGN",
|
|
"TYPE_LOWER_BOUNDS", "TYPE_ARGUMENT", "LITERAL_CLASS", "INSTANCE_INIT", "DIV",
|
|
"LITERAL_VOLATILE", "STAR", "UNARY_MINUS", "FOR_ITERATOR", "NOT_EQUAL", "LE",
|
|
"LITERAL_INTERFACE", "LITERAL_FLOAT", "LITERAL_INSTANCEOF", "BOR_ASSIGN", "LT",
|
|
"SL_ASSIGN", "ELIST", "ANNOTATION_ARRAY_INIT", "MODIFIERS", "LITERAL_BREAK",
|
|
"EXTENDS_CLAUSE", "TYPE_PARAMETER", "LITERAL_DEFAULT", "STATIC_INIT", "BSR_ASSIGN",
|
|
"TYPE_EXTENSION_AND", "BOR", "LITERAL_PRIVATE", "LITERAL_THROW", "LITERAL_BYTE",
|
|
"BXOR", "WILDCARD_TYPE", "FINAL", "PARAMETERS", "RPAREN", "SR_ASSIGN",
|
|
"UNARY_PLUS", "EMPTY_STAT", "LITERAL_STATIC", "LITERAL_CONTINUE", "STAR_ASSIGN",
|
|
"LAMBDA", "RBRACK", "BXOR_ASSIGN", "CTOR_CALL", "LITERAL_FALSE", "DO_WHILE",
|
|
"LITERAL_PUBLIC", "LITERAL_WHILE", "PLUS", "INC", "CTOR_DEF", "GENERIC_END",
|
|
"DIV_ASSIGN", "SLIST", "LNOT", "LAND", "LITERAL_ELSE", "ABSTRACT", "STRICTFP",
|
|
"QUESTION", "LITERAL_NEW", "LITERAL_RETURN", "SINGLE_LINE_COMMENT", "INDEX_OP",
|
|
"EXPR", "BLOCK_COMMENT_BEGIN", "PACKAGE_DEF", "IMPLEMENTS_CLAUSE", "NUM_FLOAT",
|
|
"LITERAL_DO", "EOF", "GE", "RESOURCES", "MOD", "DEC", "EQUAL", "LITERAL_BOOLEAN",
|
|
"CLASS_DEF", "COLON", "LITERAL_TRY", "ENUM_DEF", "GT", "NUM_INT", "ANNOTATION_DEF",
|
|
"LITERAL_NATIVE", "METHOD_REF", "TYPE_ARGUMENTS", "DOUBLE_COLON", "IDENT",
|
|
"MOD_ASSIGN", "LITERAL_FOR", "SUPER_CTOR_CALL", "ARRAY_DECLARATOR", "LITERAL_CASE")
|
|
.collect(Collectors.toSet()));
|
|
GOOGLE_TOKENS_IN_CONFIG_TO_IGNORE.put("OperatorWrap", Stream.of(
|
|
// specifically allowed via '4.5.1 Where to break' because the following are
|
|
// assignment operators and they are allowed to break before or after the symbol
|
|
"DIV_ASSIGN", "BOR_ASSIGN", "SL_ASSIGN", "ASSIGN", "BSR_ASSIGN", "BAND_ASSIGN",
|
|
"PLUS_ASSIGN", "MINUS_ASSIGN", "SR_ASSIGN", "STAR_ASSIGN", "BXOR_ASSIGN",
|
|
"MOD_ASSIGN").collect(Collectors.toSet()));
|
|
}
|
|
|
|
@Test
|
|
public void testAllChecksWithDefaultConfiguration() throws Exception {
|
|
final String inputFilePath = getPath("InputDefaultConfig.java");
|
|
final String[] expected = CommonUtils.EMPTY_STRING_ARRAY;
|
|
|
|
for (Class<?> check : CheckUtil.getCheckstyleChecks()) {
|
|
final DefaultConfiguration checkConfig = createCheckConfig(check);
|
|
final Checker checker;
|
|
if (AbstractCheck.class.isAssignableFrom(check)) {
|
|
// Checks which have Check as a parent.
|
|
if (check.equals(ImportControlCheck.class)) {
|
|
// ImportControlCheck must have the import control configuration file to avoid
|
|
// violation.
|
|
checkConfig.addAttribute("file", getPath("import-control_complete.xml"));
|
|
}
|
|
checker = createChecker(checkConfig);
|
|
}
|
|
else {
|
|
// Checks which have TreeWalker as a parent.
|
|
BaseCheckTestSupport testSupport = new BaseCheckTestSupport() {
|
|
@Override
|
|
protected DefaultConfiguration createCheckerConfig(Configuration config) {
|
|
final DefaultConfiguration dc = new DefaultConfiguration("root");
|
|
dc.addChild(checkConfig);
|
|
return dc;
|
|
}
|
|
};
|
|
checker = testSupport.createChecker(checkConfig);
|
|
}
|
|
verify(checker, inputFilePath, expected);
|
|
}
|
|
}
|
|
|
|
@Test
|
|
public void testDefaultTokensAreSubsetOfAcceptableTokens() throws Exception {
|
|
for (Class<?> check : CheckUtil.getCheckstyleChecks()) {
|
|
if (AbstractCheck.class.isAssignableFrom(check)) {
|
|
final AbstractCheck testedCheck = (AbstractCheck) check.getDeclaredConstructor()
|
|
.newInstance();
|
|
final int[] defaultTokens = testedCheck.getDefaultTokens();
|
|
final int[] acceptableTokens = testedCheck.getAcceptableTokens();
|
|
|
|
if (!isSubset(defaultTokens, acceptableTokens)) {
|
|
final String errorMessage = String.format(Locale.ROOT,
|
|
"%s's default tokens must be a subset"
|
|
+ " of acceptable tokens.", check.getName());
|
|
Assert.fail(errorMessage);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
@Test
|
|
public void testRequiredTokensAreSubsetOfAcceptableTokens() throws Exception {
|
|
for (Class<?> check : CheckUtil.getCheckstyleChecks()) {
|
|
if (AbstractCheck.class.isAssignableFrom(check)) {
|
|
final AbstractCheck testedCheck = (AbstractCheck) check.getDeclaredConstructor()
|
|
.newInstance();
|
|
final int[] requiredTokens = testedCheck.getRequiredTokens();
|
|
final int[] acceptableTokens = testedCheck.getAcceptableTokens();
|
|
|
|
if (!isSubset(requiredTokens, acceptableTokens)) {
|
|
final String errorMessage = String.format(Locale.ROOT,
|
|
"%s's required tokens must be a subset"
|
|
+ " of acceptable tokens.", check.getName());
|
|
Assert.fail(errorMessage);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
@Test
|
|
public void testRequiredTokensAreSubsetOfDefaultTokens() throws Exception {
|
|
for (Class<?> check : CheckUtil.getCheckstyleChecks()) {
|
|
if (AbstractCheck.class.isAssignableFrom(check)) {
|
|
final AbstractCheck testedCheck = (AbstractCheck) check.getDeclaredConstructor()
|
|
.newInstance();
|
|
final int[] defaultTokens = testedCheck.getDefaultTokens();
|
|
final int[] requiredTokens = testedCheck.getRequiredTokens();
|
|
|
|
if (!isSubset(requiredTokens, defaultTokens)) {
|
|
final String errorMessage = String.format(Locale.ROOT,
|
|
"%s's required tokens must be a subset"
|
|
+ " of default tokens.", check.getName());
|
|
Assert.fail(errorMessage);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
@Test
|
|
public void testAllModulesAreReferencedInConfigFile() throws Exception {
|
|
final Set<String> modulesReferencedInConfig = CheckUtil.getConfigCheckStyleModules();
|
|
final Set<String> moduleNames = CheckUtil.getSimpleNames(CheckUtil.getCheckstyleModules());
|
|
|
|
moduleNames.stream().filter(check -> !modulesReferencedInConfig.contains(check))
|
|
.forEach(check -> {
|
|
final String errorMessage = String.format(Locale.ROOT,
|
|
"%s is not referenced in checkstyle_checks.xml", check);
|
|
Assert.fail(errorMessage);
|
|
});
|
|
}
|
|
|
|
@Test
|
|
public void testAllCheckTokensAreReferencedInCheckstyleConfigFile() throws Exception {
|
|
final Configuration configuration = ConfigurationUtil
|
|
.loadConfiguration("config/checkstyle_checks.xml");
|
|
|
|
validateAllCheckTokensAreReferencedInConfigFile("checkstyle", configuration,
|
|
CHECKSTYLE_TOKENS_IN_CONFIG_TO_IGNORE);
|
|
}
|
|
|
|
@Test
|
|
public void testAllCheckTokensAreReferencedInGoogleConfigFile() throws Exception {
|
|
final Configuration configuration = ConfigurationUtil
|
|
.loadConfiguration("src/main/resources/google_checks.xml");
|
|
|
|
validateAllCheckTokensAreReferencedInConfigFile("google", configuration,
|
|
GOOGLE_TOKENS_IN_CONFIG_TO_IGNORE);
|
|
}
|
|
|
|
private static void validateAllCheckTokensAreReferencedInConfigFile(String configName,
|
|
Configuration configuration, Map<String, Set<String>> tokensToIgnore) throws Exception {
|
|
final ModuleFactory moduleFactory = TestUtils.getPackageObjectFactory();
|
|
final Set<Configuration> configChecks = ConfigurationUtil.getChecks(configuration);
|
|
|
|
final Map<String, Set<String>> configCheckTokens = new HashMap<>();
|
|
final Map<String, Set<String>> checkTokens = new HashMap<>();
|
|
|
|
for (Configuration checkConfig : configChecks) {
|
|
final String checkName = checkConfig.getName();
|
|
final Object instance;
|
|
|
|
try {
|
|
instance = moduleFactory.createModule(checkName);
|
|
}
|
|
catch (CheckstyleException ex) {
|
|
throw new CheckstyleException("Couldn't find check: " + checkName, ex);
|
|
}
|
|
|
|
if (instance instanceof AbstractCheck) {
|
|
final AbstractCheck check = (AbstractCheck) instance;
|
|
|
|
Set<String> configTokens = configCheckTokens.get(checkName);
|
|
|
|
if (configTokens == null) {
|
|
configTokens = new HashSet<>();
|
|
|
|
configCheckTokens.put(checkName, configTokens);
|
|
|
|
// add all overriden tokens
|
|
final Set<String> overrideTokens = tokensToIgnore.get(checkName);
|
|
|
|
if (overrideTokens != null) {
|
|
configTokens.addAll(overrideTokens);
|
|
}
|
|
|
|
configTokens.addAll(CheckUtil.getTokenNameSet(check.getDefaultTokens()));
|
|
checkTokens.put(checkName,
|
|
CheckUtil.getTokenNameSet(check.getAcceptableTokens()));
|
|
}
|
|
|
|
try {
|
|
configTokens.addAll(Arrays.asList(checkConfig.getAttribute("tokens").trim()
|
|
.split(",\\s*")));
|
|
}
|
|
catch (CheckstyleException ex) {
|
|
// no tokens defined, so it is using default
|
|
}
|
|
}
|
|
}
|
|
|
|
for (Entry<String, Set<String>> entry : checkTokens.entrySet()) {
|
|
Assert.assertEquals("'" + entry.getKey()
|
|
+ "' should have all acceptable tokens from check in " + configName
|
|
+ " config or specify an override to ignore the specific tokens",
|
|
entry.getValue(), configCheckTokens.get(entry.getKey()));
|
|
}
|
|
}
|
|
|
|
@Test
|
|
public void testAllCheckstyleModulesHaveXdocDocumentation() throws Exception {
|
|
final Set<String> checkstyleModulesNames = CheckUtil.getSimpleNames(CheckUtil
|
|
.getCheckstyleModules());
|
|
final Set<String> modulesNamesWhichHaveXdocs = XDocUtil.getModulesNamesWhichHaveXdoc();
|
|
|
|
// these are documented on non-'config_' pages
|
|
checkstyleModulesNames.remove("TreeWalker");
|
|
checkstyleModulesNames.remove("Checker");
|
|
|
|
checkstyleModulesNames.stream()
|
|
.filter(moduleName -> !modulesNamesWhichHaveXdocs.contains(moduleName))
|
|
.forEach(moduleName -> {
|
|
final String missingModuleMessage = String.format(Locale.ROOT,
|
|
"Module %s does not have xdoc documentation.",
|
|
moduleName);
|
|
Assert.fail(missingModuleMessage);
|
|
});
|
|
}
|
|
|
|
@Test
|
|
public void testAllCheckstyleModulesInCheckstyleConfig() throws Exception {
|
|
final Set<String> configChecks = CheckUtil.getConfigCheckStyleModules();
|
|
|
|
for (String moduleName : CheckUtil.getSimpleNames(CheckUtil.getCheckstyleModules())) {
|
|
Assert.assertTrue("checkstyle_checks.xml is missing module: " + moduleName,
|
|
configChecks.contains(moduleName));
|
|
}
|
|
}
|
|
|
|
@Test
|
|
public void testAllCheckstyleChecksHaveMessage() throws Exception {
|
|
for (Class<?> module : CheckUtil.getCheckstyleChecks()) {
|
|
final String name = module.getSimpleName();
|
|
|
|
if ("FileContentsHolder".equals(name)) {
|
|
Assert.assertTrue(name
|
|
+ " should not have any 'MSG_*' field for error messages", CheckUtil
|
|
.getCheckMessages(module).isEmpty());
|
|
}
|
|
else {
|
|
Assert.assertFalse(name
|
|
+ " should have atleast one 'MSG_*' field for error messages", CheckUtil
|
|
.getCheckMessages(module).isEmpty());
|
|
}
|
|
}
|
|
}
|
|
|
|
@Test
|
|
public void testAllCheckstyleMessages() throws Exception {
|
|
final Map<String, List<String>> usedMessages = new TreeMap<>();
|
|
|
|
// test validity of messages from modules
|
|
for (Class<?> module : CheckUtil.getCheckstyleModules()) {
|
|
for (Field message : CheckUtil.getCheckMessages(module)) {
|
|
Assert.assertEquals(module.getSimpleName() + "." + message.getName()
|
|
+ " should be 'public static final'", Modifier.PUBLIC | Modifier.STATIC
|
|
| Modifier.FINAL, message.getModifiers());
|
|
|
|
// below is required for package/private classes
|
|
if (!message.isAccessible()) {
|
|
message.setAccessible(true);
|
|
}
|
|
|
|
verifyCheckstyleMessage(usedMessages, module, message);
|
|
}
|
|
}
|
|
|
|
// test properties for messages not used by checks
|
|
for (Entry<String, List<String>> entry : usedMessages.entrySet()) {
|
|
final Properties pr = new Properties();
|
|
pr.load(AllChecksTest.class.getResourceAsStream(
|
|
"/" + entry.getKey().replace('.', '/') + "/messages.properties"));
|
|
|
|
for (Object key : pr.keySet()) {
|
|
// hidden exception messages
|
|
if ("translation.wrongLanguageCode".equals(key)) {
|
|
continue;
|
|
}
|
|
|
|
Assert.assertTrue("property '" + key + "' isn't used by any check in package '"
|
|
+ entry.getKey() + "'", entry.getValue().contains(key.toString()));
|
|
}
|
|
}
|
|
}
|
|
|
|
private static void verifyCheckstyleMessage(Map<String, List<String>> usedMessages,
|
|
Class<?> module, Field message) throws Exception {
|
|
final String messageString = message.get(null).toString();
|
|
final String packageName = module.getPackage().getName();
|
|
List<String> packageMessages = usedMessages.get(packageName);
|
|
|
|
if (packageMessages == null) {
|
|
packageMessages = new ArrayList<>();
|
|
usedMessages.put(packageName, packageMessages);
|
|
}
|
|
|
|
packageMessages.add(messageString);
|
|
|
|
for (Locale locale : ALL_LOCALES) {
|
|
String result = null;
|
|
|
|
try {
|
|
result = CheckUtil.getCheckMessage(module, locale, messageString);
|
|
}
|
|
catch (IllegalArgumentException ex) {
|
|
Assert.fail(module.getSimpleName() + " with the message '" + messageString
|
|
+ "' in locale '" + locale.getLanguage() + "' failed with: "
|
|
+ ex.getClass().getSimpleName() + " - " + ex.getMessage());
|
|
}
|
|
|
|
Assert.assertNotNull(
|
|
module.getSimpleName() + " should have text for the message '"
|
|
+ messageString + "' in locale " + locale.getLanguage() + "'",
|
|
result);
|
|
Assert.assertFalse(
|
|
module.getSimpleName() + " should have non-empty text for the message '"
|
|
+ messageString + "' in locale '" + locale.getLanguage() + "'",
|
|
result.trim().isEmpty());
|
|
Assert.assertFalse(
|
|
module.getSimpleName() + " should have non-TODO text for the message '"
|
|
+ messageString + "' in locale " + locale.getLanguage() + "'",
|
|
!"todo.match".equals(messageString)
|
|
&& result.trim().startsWith("TODO"));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Checks that an array is a subset of other array.
|
|
* @param array to check whether it is a subset.
|
|
* @param arrayToCheckIn array to check in.
|
|
*/
|
|
private static boolean isSubset(int[] array, int... arrayToCheckIn) {
|
|
Arrays.sort(arrayToCheckIn);
|
|
for (final int element : array) {
|
|
if (Arrays.binarySearch(arrayToCheckIn, element) < 0) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
}
|