Skip to content

Commit

Permalink
Issue #10745: Add inline config support for tests with multiple modules
Browse files Browse the repository at this point in the history
  • Loading branch information
shashwatj07 authored and romani committed Aug 30, 2021
1 parent 71f7ced commit c74d3bb
Show file tree
Hide file tree
Showing 201 changed files with 1,889 additions and 1,859 deletions.
Expand Up @@ -33,18 +33,15 @@
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.ResourceBundle;

import com.google.common.collect.Maps;
import com.puppycrawl.tools.checkstyle.api.CheckstyleException;
import com.puppycrawl.tools.checkstyle.api.Configuration;
import com.puppycrawl.tools.checkstyle.api.Violation;
import com.puppycrawl.tools.checkstyle.bdd.InlineConfigParser;
import com.puppycrawl.tools.checkstyle.bdd.ModuleInputConfiguration;
import com.puppycrawl.tools.checkstyle.bdd.TestInputConfiguration;
import com.puppycrawl.tools.checkstyle.bdd.TestInputViolation;
import com.puppycrawl.tools.checkstyle.internal.utils.BriefUtLogger;
Expand Down Expand Up @@ -218,49 +215,42 @@ protected final String getUriString(String filename) {
}

protected final void verifyFilterWithInlineConfigParser(Configuration aConfig,
Configuration filterConfig,
String filePath, String[] expectedUnfiltered,
String... expectedFiltered)
String filePath,
String[] expectedUnfiltered,
String... expectedFiltered)
throws Exception {
final TestInputConfiguration checkTestInputConfiguration =
final TestInputConfiguration testInputConfiguration =
InlineConfigParser.parseWithFilteredViolations(filePath);
final DefaultConfiguration parsedCheckConfig =
checkTestInputConfiguration.createConfiguration();
final ModuleInputConfiguration checkModule =
checkTestInputConfiguration.getChildrenModules().get(0);
verifyConfig(aConfig, checkModule.createConfiguration(), checkModule);
verifyViolations(parsedCheckConfig, filePath, checkTestInputConfiguration);
verify(parsedCheckConfig, filePath, expectedUnfiltered);
final TestInputConfiguration filterTestInputConfiguration =
InlineConfigParser.parseFilter(filePath);
final ModuleInputConfiguration filterModule =
filterTestInputConfiguration.getChildrenModules().get(0);
verifyConfig(filterConfig, filterModule.createConfiguration(), filterModule);
parsedCheckConfig.addChild(filterModule.createConfiguration());
verifyViolations(parsedCheckConfig, filePath, filterTestInputConfiguration);
verify(parsedCheckConfig, filePath, expectedFiltered);
final DefaultConfiguration configWithoutFilters =
testInputConfiguration.createConfigurationWithoutFilters();
final List<TestInputViolation> violationsWithoutFilters =
new ArrayList<>(testInputConfiguration.getViolations());
violationsWithoutFilters.addAll(testInputConfiguration.getFilteredViolations());
Collections.sort(violationsWithoutFilters);
verifyViolations(configWithoutFilters, filePath, violationsWithoutFilters);
verify(configWithoutFilters, filePath, expectedUnfiltered);
final DefaultConfiguration configWithFilters =
testInputConfiguration.createConfiguration();
verifyViolations(configWithFilters, filePath, testInputConfiguration.getViolations());
verify(configWithFilters, filePath, expectedFiltered);
}

/**
* Performs verification of the file with the given file path using specified configuration
* and the array expected messages. Also performs verification of the config specified in
* input file.
*
* @param aConfig configuration.
* @param filePath file path to verify.
* @param expected an array of expected messages.
* @throws Exception if exception occurs during verification process.
*/
protected final void verifyWithInlineConfigParser(Configuration aConfig,
String filePath, String... expected)
protected final void verifyWithInlineConfigParser(String filePath, String... expected)
throws Exception {
final TestInputConfiguration testInputConfiguration =
InlineConfigParser.parse(filePath);
final Configuration parsedConfig = testInputConfiguration.createConfiguration();
final ModuleInputConfiguration checkModule =
testInputConfiguration.getChildrenModules().get(0);
verifyConfig(aConfig, checkModule.createConfiguration(), checkModule);
verifyViolations(parsedConfig, filePath, testInputConfiguration);
final DefaultConfiguration parsedConfig =
testInputConfiguration.createConfiguration();
verifyViolations(parsedConfig, filePath, testInputConfiguration.getViolations());
verify(parsedConfig, filePath, expected);
}

Expand Down Expand Up @@ -389,59 +379,27 @@ protected final void verifyWithLimitedResources(Configuration aConfig,
throws Exception {
// We return null here, which gives us a result to make an assertion about
final Void result = TestUtil.getResultWithLimitedResources(() -> {
verifyWithInlineConfigParser(aConfig, fileName, expected);
verifyWithInlineConfigParser(fileName, expected);
return null;
});
assertWithMessage("Verify should complete successfully.")
.that(result)
.isNull();
}

/**
* Performs verification of the config read from input file.
*
* @param testConfig hardcoded test config.
* @param parsedConfig parsed config from input file.
* @param moduleInputConfiguration ModuleInputConfiguration object.
* @throws CheckstyleException if property keys not found.
*/
private static void verifyConfig(Configuration testConfig,
Configuration parsedConfig,
ModuleInputConfiguration moduleInputConfiguration)
throws CheckstyleException {
assertWithMessage("Check name differs from expected.")
.that(testConfig.getName())
.isEqualTo(parsedConfig.getName());
for (String property : parsedConfig.getPropertyNames()) {
assertWithMessage("Property value for key %s differs from expected.", property)
.that(testConfig.getProperty(property))
.isEqualTo(parsedConfig.getProperty(property));
}
final List<String> testProperties =
new LinkedList<>(Arrays.asList(testConfig.getPropertyNames()));
testProperties.removeAll(Arrays.asList(parsedConfig.getPropertyNames()));
for (String property : testProperties) {
assertWithMessage("Property value for key %s differs from expected.", property)
.that(moduleInputConfiguration.getDefaultPropertyValue(property))
.isEqualTo(testConfig.getProperty(property));
}
}

/**
* Performs verification of violation lines.
*
* @param config parsed config.
* @param file file path.
* @param testInputConfiguration TestInputConfiguration object.
* @param testInputViolations List of TestInputViolation objects.
* @throws Exception if exception occurs during verification process.
*/
private void verifyViolations(Configuration config,
String file,
TestInputConfiguration testInputConfiguration)
List<TestInputViolation> testInputViolations)
throws Exception {
final List<String> actualViolations = getActualViolationsForFile(config, file);
final List<TestInputViolation> testInputViolations =
testInputConfiguration.getViolations();
assertWithMessage("Number of actual and expected violations differ.")
.that(actualViolations)
.hasSize(testInputViolations.size());
Expand Down
Expand Up @@ -101,12 +101,8 @@ private static TestInputConfiguration parse(String inputFilePath,
final List<String> lines = readFile(filePath);
final TestInputConfiguration.Builder testInputConfigBuilder =
new TestInputConfiguration.Builder();
final ModuleInputConfiguration.Builder moduleInputConfigBuilder =
new ModuleInputConfiguration.Builder();
setModuleName(moduleInputConfigBuilder, inputFilePath, lines);
setProperties(moduleInputConfigBuilder, inputFilePath, lines, 2);
setModules(testInputConfigBuilder, inputFilePath, lines);
setViolations(testInputConfigBuilder, lines, setFilteredViolations);
testInputConfigBuilder.addChildModule(moduleInputConfigBuilder.build());
return testInputConfigBuilder.build();
}

Expand All @@ -115,26 +111,20 @@ public static TestInputConfiguration parseWithFilteredViolations(String inputFil
return parse(inputFilePath, true);
}

/**
* Parses the filter input file provided.
*
* @param inputFilePath the input file path.
* @throws Exception if unable to read file or file not formatted properly.
*/
public static TestInputConfiguration parseFilter(String inputFilePath)
private static void setModules(TestInputConfiguration.Builder testInputConfigBuilder,
String inputFilePath, List<String> lines)
throws Exception {
final Path filePath = Paths.get(inputFilePath);
final List<String> lines = readFile(filePath);
final TestInputConfiguration.Builder testInputConfigBuilder =
new TestInputConfiguration.Builder();
final ModuleInputConfiguration.Builder moduleInputConfigBuilder =
new ModuleInputConfiguration.Builder();
final int lineNo = getFilterConfigLineNo(lines);
setFilterName(moduleInputConfigBuilder, inputFilePath, lines, lineNo);
setProperties(moduleInputConfigBuilder, inputFilePath, lines, lineNo + 1);
setViolations(testInputConfigBuilder, lines, false);
testInputConfigBuilder.addChildModule(moduleInputConfigBuilder.build());
return testInputConfigBuilder.build();
int lineNo = 1;
do {
final ModuleInputConfiguration.Builder moduleInputConfigBuilder =
new ModuleInputConfiguration.Builder();
setModuleName(moduleInputConfigBuilder, inputFilePath, lines.get(lineNo));
setProperties(moduleInputConfigBuilder, inputFilePath, lines, lineNo + 1);
testInputConfigBuilder.addChildModule(moduleInputConfigBuilder.build());
do {
lineNo++;
} while (lines.get(lineNo).isEmpty() || !lines.get(lineNo - 1).isEmpty());
} while (!lines.get(lineNo).startsWith("*/"));
}

private static String getFullyQualifiedClassName(String filePath, String moduleName) {
Expand Down Expand Up @@ -199,34 +189,10 @@ private static List<String> readFile(Path filePath) throws CheckstyleException {
}
}

private static void setModuleName(ModuleInputConfiguration.Builder inputConfigBuilder,
String filePath, List<String> lines)
throws CheckstyleException {
if (lines.size() < 2) {
throw new CheckstyleException("Config not specified in " + filePath);
}
final String moduleName = lines.get(1);
private static void setModuleName(ModuleInputConfiguration.Builder moduleInputConfigBuilder,
String filePath, String moduleName) {
final String fullyQualifiedClassName = getFullyQualifiedClassName(filePath, moduleName);
inputConfigBuilder.setModuleName(fullyQualifiedClassName);
}

private static int getFilterConfigLineNo(List<String> lines) {
int lineNo = 1;
while (!lines.get(lineNo - 1).isEmpty() || lines.get(lineNo).isEmpty()) {
lineNo++;
}
return lineNo;
}

private static void setFilterName(ModuleInputConfiguration.Builder inputConfigBuilder,
String filePath, List<String> lines, int lineNo)
throws CheckstyleException {
final String filterName = lines.get(lineNo);
if (!filterName.endsWith("Filter")) {
throw new CheckstyleException("Filter not specified in " + filePath);
}
final String fullyQualifiedClassName = getFullyQualifiedClassName(filePath, filterName);
inputConfigBuilder.setModuleName(fullyQualifiedClassName);
moduleInputConfigBuilder.setModuleName(fullyQualifiedClassName);
}

private static void setProperties(ModuleInputConfiguration.Builder inputConfigBuilder,
Expand Down Expand Up @@ -336,13 +302,13 @@ private static void setFilteredViolation(TestInputConfiguration.Builder inputCon
final Matcher violationBelowMatcher =
FILTERED_VIOLATION_BELOW_PATTERN.matcher(line);
if (violationMatcher.matches()) {
inputConfigBuilder.addViolation(lineNo, violationMatcher.group(1));
inputConfigBuilder.addFilteredViolation(lineNo, violationMatcher.group(1));
}
else if (violationAboveMatcher.matches()) {
inputConfigBuilder.addViolation(lineNo - 1, violationAboveMatcher.group(1));
inputConfigBuilder.addFilteredViolation(lineNo - 1, violationAboveMatcher.group(1));
}
else if (violationBelowMatcher.matches()) {
inputConfigBuilder.addViolation(lineNo + 1, violationBelowMatcher.group(1));
inputConfigBuilder.addFilteredViolation(lineNo + 1, violationBelowMatcher.group(1));
}
}
}
Expand Up @@ -59,18 +59,26 @@ public final class TestInputConfiguration {

private final List<TestInputViolation> violations;

private final List<TestInputViolation> filteredViolations;

private TestInputConfiguration(List<ModuleInputConfiguration> childrenModules,
List<TestInputViolation> violations) {
List<TestInputViolation> violations,
List<TestInputViolation> filteredViolations) {
this.childrenModules = childrenModules;
this.violations = violations;
this.filteredViolations = filteredViolations;
}

public List<ModuleInputConfiguration> getChildrenModules() {
return Collections.unmodifiableList(childrenModules);
}

public List<TestInputViolation> getViolations() {
return Collections.unmodifiableList(violations);
}

public List<ModuleInputConfiguration> getChildrenModules() {
return Collections.unmodifiableList(childrenModules);
public List<TestInputViolation> getFilteredViolations() {
return Collections.unmodifiableList(filteredViolations);
}

public DefaultConfiguration createConfiguration() {
Expand All @@ -93,24 +101,52 @@ public DefaultConfiguration createConfiguration() {
return root;
}

public DefaultConfiguration createConfigurationWithoutFilters() {
final DefaultConfiguration root = new DefaultConfiguration(ROOT_MODULE_NAME);
final DefaultConfiguration treeWalker =
new DefaultConfiguration(TreeWalker.class.getName());
root.addProperty("charset", StandardCharsets.UTF_8.name());
childrenModules
.stream()
.map(ModuleInputConfiguration::createConfiguration)
.filter(moduleConfig -> !moduleConfig.getName().endsWith("Filter"))
.forEach(moduleConfig -> {
if (CHECKER_CHILDREN.contains(moduleConfig.getName())) {
root.addChild(moduleConfig);
}
else {
treeWalker.addChild(moduleConfig);
}
});
root.addChild(treeWalker);
return root;
}

public static final class Builder {

private final List<ModuleInputConfiguration> childrenModules = new ArrayList<>();

private final List<TestInputViolation> violations = new ArrayList<>();

private final List<TestInputViolation> filteredViolations = new ArrayList<>();

public void addChildModule(ModuleInputConfiguration childModule) {
childrenModules.add(childModule);
}

public void addViolation(int violationLine, String violationMessage) {
violations.add(new TestInputViolation(violationLine, violationMessage));
}

public void addChildModule(ModuleInputConfiguration childModule) {
childrenModules.add(childModule);
public void addFilteredViolation(int violationLine, String violationMessage) {
filteredViolations.add(new TestInputViolation(violationLine, violationMessage));
}

public TestInputConfiguration build() {
return new TestInputConfiguration(
childrenModules,
violations
violations,
filteredViolations
);
}
}
Expand Down
Expand Up @@ -21,7 +21,7 @@

import java.util.regex.Pattern;

public final class TestInputViolation {
public final class TestInputViolation implements Comparable<TestInputViolation> {

/** Pattern to match the symbol: "{". */
private static final Pattern OPEN_CURLY_PATTERN = Pattern.compile("\\{");
Expand Down Expand Up @@ -83,4 +83,9 @@ public String toRegex() {
}
return regex;
}

@Override
public int compareTo(TestInputViolation testInputViolation) {
return lineNo - testInputViolation.lineNo;
}
}
Expand Up @@ -60,7 +60,7 @@ public void testJavaStyleOn()
"55:27: " + getCheckMessage(MSG_KEY),
"55:29: " + getCheckMessage(MSG_KEY),
};
verifyWithInlineConfigParser(checkConfig,
verifyWithInlineConfigParser(
getPath("InputArrayTypeStyle.java"), expected);
}

Expand All @@ -81,7 +81,7 @@ public void testJavaStyleOff()
"55:27: " + getCheckMessage(MSG_KEY),
"55:29: " + getCheckMessage(MSG_KEY),
};
verifyWithInlineConfigParser(checkConfig,
verifyWithInlineConfigParser(
getPath("InputArrayTypeStyleOff.java"), expected);
}

Expand All @@ -96,7 +96,7 @@ public void testNestedGenerics()
"24:76: " + getCheckMessage(MSG_KEY),
"31:16: " + getCheckMessage(MSG_KEY),
};
verifyWithInlineConfigParser(checkConfig,
verifyWithInlineConfigParser(
getPath("InputArrayTypeStyleNestedGenerics.java"), expected);
}

Expand Down

0 comments on commit c74d3bb

Please sign in to comment.