-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Issue #79: Processing UT changes to get possible property values
- Loading branch information
Showing
9 changed files
with
594 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
86 changes: 86 additions & 0 deletions
86
src/main/java/com/github/checkstyle/regression/customcheck/CustomCheckProcessor.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
//////////////////////////////////////////////////////////////////////////////// | ||
// 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.github.checkstyle.regression.customcheck; | ||
|
||
import java.io.File; | ||
import java.util.Collections; | ||
import java.util.List; | ||
|
||
import com.puppycrawl.tools.checkstyle.Checker; | ||
import com.puppycrawl.tools.checkstyle.DefaultConfiguration; | ||
import com.puppycrawl.tools.checkstyle.TreeWalker; | ||
import com.puppycrawl.tools.checkstyle.api.CheckstyleException; | ||
import com.puppycrawl.tools.checkstyle.api.Configuration; | ||
|
||
/** | ||
* Processes the specific file using our custom check. | ||
* | ||
* <p>This utility class would run a custom check on the file with the given path and return | ||
* the collected property info.</p> | ||
* @author LuoLiangchen | ||
*/ | ||
public final class CustomCheckProcessor { | ||
/** Prevents instantiation. */ | ||
private CustomCheckProcessor() { | ||
} | ||
|
||
/** | ||
* Processes the file with the given path using the given custom check. | ||
* @param path the path of the file | ||
* @param checkClass the class of the custom check | ||
* @throws CheckstyleException failure when running the check | ||
*/ | ||
public static void process(String path, Class<?> checkClass) throws CheckstyleException { | ||
final DefaultConfiguration moduleConfig = createModuleConfig(checkClass); | ||
final Configuration dc = createTreeWalkerConfig(moduleConfig); | ||
final Checker checker = new Checker(); | ||
checker.setModuleClassLoader(Thread.currentThread().getContextClassLoader()); | ||
checker.configure(dc); | ||
final List<File> processedFiles = Collections.singletonList(new File(path)); | ||
checker.process(processedFiles); | ||
} | ||
|
||
/** | ||
* Creates {@link DefaultConfiguration} for the {@link TreeWalker} | ||
* based on the given {@link Configuration} instance. | ||
* @param config {@link Configuration} instance. | ||
* @return {@link DefaultConfiguration} for the {@link TreeWalker} | ||
* based on the given {@link Configuration} instance. | ||
*/ | ||
private static DefaultConfiguration createTreeWalkerConfig(Configuration config) { | ||
final DefaultConfiguration dc = | ||
new DefaultConfiguration("configuration"); | ||
final DefaultConfiguration twConf = createModuleConfig(TreeWalker.class); | ||
// make sure that the tests always run with this charset | ||
dc.addAttribute("charset", "UTF-8"); | ||
dc.addChild(twConf); | ||
twConf.addChild(config); | ||
return dc; | ||
} | ||
|
||
/** | ||
* Creates {@link DefaultConfiguration} for the given class. | ||
* @param clazz the class of module | ||
* @return the {@link DefaultConfiguration} of the module class | ||
*/ | ||
private static DefaultConfiguration createModuleConfig(Class<?> clazz) { | ||
return new DefaultConfiguration(clazz.getName()); | ||
} | ||
} |
220 changes: 220 additions & 0 deletions
220
src/main/java/com/github/checkstyle/regression/customcheck/UnitTestProcessorCheck.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,220 @@ | ||
//////////////////////////////////////////////////////////////////////////////// | ||
// 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.github.checkstyle.regression.customcheck; | ||
|
||
import java.util.Collections; | ||
import java.util.LinkedHashMap; | ||
import java.util.LinkedHashSet; | ||
import java.util.LinkedList; | ||
import java.util.List; | ||
import java.util.Map; | ||
import java.util.Optional; | ||
import java.util.Set; | ||
|
||
import com.github.checkstyle.regression.data.ImmutableProperty; | ||
import com.github.checkstyle.regression.data.ModuleInfo; | ||
import com.puppycrawl.tools.checkstyle.DefaultConfiguration; | ||
import com.puppycrawl.tools.checkstyle.api.AbstractCheck; | ||
import com.puppycrawl.tools.checkstyle.api.DetailAST; | ||
import com.puppycrawl.tools.checkstyle.api.TokenTypes; | ||
|
||
/** | ||
* The custom check which processes the unit test class of a checkstyle module and grab the | ||
* possible properties that could be used for generating config. | ||
* | ||
* <p>This check would walk through the {@code @Test} annotation, find variable definition | ||
* like {@code final DefaultConfiguration checkConfig = createModuleConfig(FooCheck.class)} | ||
* and grab the property info from {@link DefaultConfiguration#addAttribute(String, String)} | ||
* method call.</p> | ||
* @author LuoLiangchen | ||
*/ | ||
public class UnitTestProcessorCheck extends AbstractCheck { | ||
/** The map of unit test method name to properties. */ | ||
private static final Map<String, Set<ModuleInfo.Property>> UNIT_TEST_TO_PROPERTIES = | ||
new LinkedHashMap<>(); | ||
|
||
@Override | ||
public int[] getDefaultTokens() { | ||
return new int[] { | ||
TokenTypes.ANNOTATION, | ||
}; | ||
} | ||
|
||
@Override | ||
public int[] getRequiredTokens() { | ||
return new int[] { | ||
TokenTypes.ANNOTATION, | ||
}; | ||
} | ||
|
||
@Override | ||
public int[] getAcceptableTokens() { | ||
return new int[] { | ||
TokenTypes.ANNOTATION, | ||
}; | ||
} | ||
|
||
@Override | ||
public void visitToken(DetailAST ast) { | ||
if ("Test".equals(ast.findFirstToken(TokenTypes.IDENT).getText())) { | ||
final DetailAST methodDef = ast.getParent().getParent(); | ||
final DetailAST methodBlock = methodDef.findFirstToken(TokenTypes.SLIST); | ||
final Optional<String> configVariableName = | ||
getModuleConfigVariableName(methodBlock); | ||
if (configVariableName.isPresent()) { | ||
final Set<ModuleInfo.Property> properties = new LinkedHashSet<>(); | ||
|
||
for (DetailAST expr : getAllChildrenWithToken(methodBlock, TokenTypes.EXPR)) { | ||
if (isAddAttributeMethodCall(expr.getFirstChild(), configVariableName.get())) { | ||
final DetailAST elist = | ||
expr.getFirstChild().findFirstToken(TokenTypes.ELIST); | ||
final String key = convertExprToText(elist.getFirstChild()); | ||
final String value = convertExprToText(elist.getLastChild()); | ||
properties.add(ImmutableProperty.builder().name(key).value(value).build()); | ||
} | ||
} | ||
|
||
if (!UNIT_TEST_TO_PROPERTIES.containsValue(properties)) { | ||
final String methodName = methodDef.findFirstToken(TokenTypes.IDENT).getText(); | ||
UNIT_TEST_TO_PROPERTIES.put(methodName, properties); | ||
} | ||
} | ||
} | ||
} | ||
|
||
/** | ||
* Clears the map of unit test method name to properties. | ||
*/ | ||
public static void clearUnitTestToPropertiesMap() { | ||
UNIT_TEST_TO_PROPERTIES.clear(); | ||
} | ||
|
||
/** | ||
* Gets the map of unit test method name to properties. | ||
* @return the map of unit test method name to properties | ||
*/ | ||
public static Map<String, Set<ModuleInfo.Property>> getUnitTestToPropertiesMap() { | ||
return Collections.unmodifiableMap(UNIT_TEST_TO_PROPERTIES); | ||
} | ||
|
||
/** | ||
* Gets the module config variable name, if it exists. | ||
* @param methodBlock the UT method block ast, which should have a type {@link TokenTypes#SLIST} | ||
* @return the optional variable name, if it exists | ||
*/ | ||
private static Optional<String> getModuleConfigVariableName(DetailAST methodBlock) { | ||
Optional<String> returnValue = Optional.empty(); | ||
|
||
for (DetailAST ast = methodBlock.getFirstChild(); ast != null; ast = ast.getNextSibling()) { | ||
if (ast.getType() == TokenTypes.VARIABLE_DEF) { | ||
final DetailAST type = ast.findFirstToken(TokenTypes.TYPE); | ||
final DetailAST assign = ast.findFirstToken(TokenTypes.ASSIGN); | ||
if (isDefaultConfigurationType(type) && isCreateModuleConfigAssign(assign)) { | ||
returnValue = Optional.of(type.getNextSibling().getText()); | ||
break; | ||
} | ||
} | ||
} | ||
|
||
return returnValue; | ||
} | ||
|
||
/** | ||
* Checks whether this {@link TokenTypes#TYPE} ast is {@link DefaultConfiguration}. | ||
* @param ast the {@link TokenTypes#TYPE} ast | ||
* @return true if the type is {@link DefaultConfiguration} | ||
*/ | ||
private static boolean isDefaultConfigurationType(DetailAST ast) { | ||
return "DefaultConfiguration".equals(ast.getFirstChild().getText()); | ||
} | ||
|
||
/** | ||
* Checks whether this {@link TokenTypes#ASSIGN} ast contains | ||
* a {@code createModuleConfig} method call. | ||
* @param ast the {@link TokenTypes#ASSIGN} ast | ||
* @return true if the assignment contains a {@code createModuleConfig} method call | ||
*/ | ||
private static boolean isCreateModuleConfigAssign(DetailAST ast) { | ||
final boolean result; | ||
|
||
if (ast == null) { | ||
result = false; | ||
} | ||
else { | ||
final DetailAST exprChild = ast.getFirstChild().getFirstChild(); | ||
result = exprChild.getType() == TokenTypes.METHOD_CALL | ||
&& exprChild.getFirstChild().getType() == TokenTypes.IDENT | ||
&& "createModuleConfig".equals(exprChild.getFirstChild().getText()); | ||
} | ||
|
||
return result; | ||
} | ||
|
||
/** | ||
* Gets all children of a ast with the given tokens type. | ||
* @param parent the parent ast | ||
* @param type the given tokens type | ||
* @return the children with the given tokens type | ||
*/ | ||
private static List<DetailAST> getAllChildrenWithToken(DetailAST parent, int type) { | ||
final List<DetailAST> returnValue = new LinkedList<>(); | ||
|
||
for (DetailAST ast = parent.getFirstChild(); ast != null; ast = ast.getNextSibling()) { | ||
if (ast.getType() == type) { | ||
returnValue.add(ast); | ||
} | ||
} | ||
|
||
return returnValue; | ||
} | ||
|
||
/** | ||
* Checks whether this expression is an {@code addAttribute} method call on an instance with | ||
* the given variable name. | ||
* @param ast the ast to check | ||
* @param variableName the given variable name of the module config instance | ||
* @return true if the expression is a valid {@code addAttribute} method call | ||
*/ | ||
private static boolean isAddAttributeMethodCall(DetailAST ast, String variableName) { | ||
final boolean result; | ||
|
||
if (ast.getType() == TokenTypes.METHOD_CALL | ||
&& ast.getFirstChild().getType() == TokenTypes.DOT) { | ||
final DetailAST dot = ast.getFirstChild(); | ||
result = variableName.equals(dot.getFirstChild().getText()) | ||
&& "addAttribute".equals(dot.getLastChild().getText()); | ||
} | ||
else { | ||
result = false; | ||
} | ||
|
||
return result; | ||
} | ||
|
||
/** | ||
* Converts an expression to raw text. | ||
* @param ast the expression ast to convert | ||
* @return the converted raw text | ||
*/ | ||
private static String convertExprToText(DetailAST ast) { | ||
final String original = ast.getFirstChild().getText(); | ||
return original.substring(1, original.length() - 1); | ||
} | ||
} |
23 changes: 23 additions & 0 deletions
23
src/main/java/com/github/checkstyle/regression/customcheck/package-info.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
//////////////////////////////////////////////////////////////////////////////// | ||
// 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 | ||
//////////////////////////////////////////////////////////////////////////////// | ||
|
||
/** | ||
* Contains custom checks and utility classes to process files in checkstyle repository. | ||
*/ | ||
package com.github.checkstyle.regression.customcheck; |
31 changes: 31 additions & 0 deletions
31
src/test/java/com/github/checkstyle/regression/customcheck/CustomCheckProcessorTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
//////////////////////////////////////////////////////////////////////////////// | ||
// 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.github.checkstyle.regression.customcheck; | ||
|
||
import static com.github.checkstyle.regression.internal.TestUtils.assertUtilsClassHasPrivateConstructor; | ||
|
||
import org.junit.Test; | ||
|
||
public class CustomCheckProcessorTest { | ||
@Test | ||
public void testIsProperUtilsClass() throws Exception { | ||
assertUtilsClassHasPrivateConstructor(CustomCheckProcessor.class); | ||
} | ||
} |
Oops, something went wrong.