diff --git a/config/import-control.xml b/config/import-control.xml
index fb22fab..a1065a3 100644
--- a/config/import-control.xml
+++ b/config/import-control.xml
@@ -9,6 +9,12 @@
+
+
+
+
+
+
diff --git a/pom.xml b/pom.xml
index d5afcf3..809ead1 100644
--- a/pom.xml
+++ b/pom.xml
@@ -285,6 +285,11 @@
0
0
+
+ com.github.checkstyle.regression.configuration.ConfigGenerator
+ 80
+ 91
+
com.github.checkstyle.regression.module.ModuleUtils
28
diff --git a/src/main/java/com/github/checkstyle/regression/configuration/ConfigGenerator.java b/src/main/java/com/github/checkstyle/regression/configuration/ConfigGenerator.java
new file mode 100644
index 0000000..5fd46d5
--- /dev/null
+++ b/src/main/java/com/github/checkstyle/regression/configuration/ConfigGenerator.java
@@ -0,0 +1,187 @@
+////////////////////////////////////////////////////////////////////////////////
+// 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.configuration;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.StringWriter;
+import java.util.List;
+
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.transform.OutputKeys;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerConfigurationException;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.xml.sax.SAXException;
+
+import com.github.checkstyle.regression.data.ModuleInfo;
+
+/**
+ * Generates the config XML and output it to a specific file.
+ * @author LuoLiangchen
+ */
+public final class ConfigGenerator {
+ /** The parent name "Checker". */
+ private static final String PARENT_CHECKER = "Checker";
+
+ /** The parent name "TreeWalker". */
+ private static final String PARENT_TREE_WALKER = "TreeWalker";
+
+ /** The name of a module element. */
+ private static final String ELEMENT_MODULE = "module";
+
+ /** The attribute name "name". */
+ private static final String ATTR_NAME = "name";
+
+ /** The "doctype-public" value of the config. */
+ private static final String DOCTYPE_PUBLIC =
+ "-//Puppy Crawl//DTD Check Configuration 1.3//EN";
+
+ /** The "doctype-system" value of the config. */
+ private static final String DOCTYPE_SYSTEM =
+ "http://www.puppycrawl.com/dtds/configuration_1_3.dtd";
+
+ /** Prevents instantiation. */
+ private ConfigGenerator() {
+ }
+
+ /**
+ * Creates a new {@link Document} instance from the {@code BASE_CONFIG}.
+ * @return a new {@link Document} instance
+ */
+ private static Document createXmlDocument() {
+ final Document document;
+
+ try {
+ final File baseConfig = new File("src/main/resources/com/github/checkstyle/regression/"
+ + "configuration/base_config.xml");
+ document = DocumentBuilderFactory.newInstance().newDocumentBuilder()
+ .parse(baseConfig);
+ }
+ catch (ParserConfigurationException | SAXException | IOException ex) {
+ throw new IllegalStateException("cannot instantiate Document instance", ex);
+ }
+
+ return document;
+ }
+
+ /**
+ * Creates a new {@link Transformer} instance and do initialization.
+ * @return a new {@link Transformer} instance
+ */
+ private static Transformer createXmlTransformer() {
+ final Transformer transformer;
+
+ try {
+ transformer = TransformerFactory.newInstance().newTransformer();
+ transformer.setOutputProperty(OutputKeys.INDENT, "yes");
+ transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");
+ transformer.setOutputProperty(OutputKeys.DOCTYPE_PUBLIC, DOCTYPE_PUBLIC);
+ transformer.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM, DOCTYPE_SYSTEM);
+ }
+ catch (TransformerConfigurationException ex) {
+ throw new IllegalStateException("cannot instantiate Transformer instance", ex);
+ }
+
+ return transformer;
+ }
+
+ /**
+ * Generates the plain text of the config XML from the given module infos.
+ * @param moduleInfos the given module infos
+ * @return the generated plain text of the config
+ * @throws TransformerException failure of transforming the XML document
+ */
+ public static String generateConfigText(List moduleInfos)
+ throws TransformerException {
+ final Document document = createXmlDocument();
+
+ final Node checkerNode = getCheckerModuleNode(document);
+ final Node treeWalkerNode = getTreeWalkerModuleNode(document);
+ for (ModuleInfo moduleInfo : moduleInfos) {
+ final Node moduleNode = createModuleNode(document, moduleInfo);
+ final String parent = moduleInfo.moduleExtractInfo().parent();
+ if (PARENT_CHECKER.equals(parent)) {
+ checkerNode.appendChild(moduleNode);
+ }
+ else if (PARENT_TREE_WALKER.equals(parent)) {
+ treeWalkerNode.appendChild(moduleNode);
+ }
+ }
+
+ final Transformer transformer = createXmlTransformer();
+ final StringWriter writer = new StringWriter();
+ transformer.transform(new DOMSource(document), new StreamResult(writer));
+ return writer.getBuffer().toString().replaceAll("\r\n", "\n");
+ }
+
+ /**
+ * Creates a XML element node which represents the settings of a checkstyle module.
+ * The information to create the node is grabbed from the given module info.
+ * @param document the XML document to create element
+ * @param moduleInfo the given module info
+ * @return a checkstyle module node
+ */
+ private static Node createModuleNode(Document document, ModuleInfo moduleInfo) {
+ final Element moduleNode = document.createElement(ELEMENT_MODULE);
+ moduleNode.setAttribute(ATTR_NAME, moduleInfo.name());
+ return moduleNode;
+ }
+
+ /**
+ * Gets the "TreeWalker" element node of the config document.
+ * @param document the XML document to search
+ * @return the "TreeWalker" element node
+ */
+ private static Node getTreeWalkerModuleNode(Document document) {
+ Node returnValue = null;
+ final NodeList nodeList = document.getDocumentElement()
+ .getElementsByTagName(ELEMENT_MODULE);
+
+ for (int i = 0; i < nodeList.getLength(); ++i) {
+ final Node node = nodeList.item(i);
+ final Node nameAttr = node.getAttributes().getNamedItem(ATTR_NAME);
+ if (PARENT_TREE_WALKER.equals(nameAttr.getNodeValue())) {
+ returnValue = node;
+ break;
+ }
+ }
+
+ return returnValue;
+ }
+
+ /**
+ * Gets the "Checker" element node of the config document.
+ * @param document the XML document to search
+ * @return the "Checker" element node
+ */
+ private static Node getCheckerModuleNode(Document document) {
+ return document.getDocumentElement();
+ }
+}
diff --git a/src/main/java/com/github/checkstyle/regression/configuration/package-info.java b/src/main/java/com/github/checkstyle/regression/configuration/package-info.java
new file mode 100644
index 0000000..a30ef4e
--- /dev/null
+++ b/src/main/java/com/github/checkstyle/regression/configuration/package-info.java
@@ -0,0 +1,24 @@
+////////////////////////////////////////////////////////////////////////////////
+// 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 the config XML generation classes.
+ * @author LuoLiangchen
+ */
+package com.github.checkstyle.regression.configuration;
diff --git a/src/main/resources/com/github/checkstyle/regression/configuration/base_config.xml b/src/main/resources/com/github/checkstyle/regression/configuration/base_config.xml
new file mode 100644
index 0000000..f7c3219
--- /dev/null
+++ b/src/main/resources/com/github/checkstyle/regression/configuration/base_config.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/test/java/com/github/checkstyle/regression/configuration/ConfigGeneratorTest.java b/src/test/java/com/github/checkstyle/regression/configuration/ConfigGeneratorTest.java
new file mode 100644
index 0000000..9425cef
--- /dev/null
+++ b/src/test/java/com/github/checkstyle/regression/configuration/ConfigGeneratorTest.java
@@ -0,0 +1,131 @@
+////////////////////////////////////////////////////////////////////////////////
+// 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.configuration;
+
+import static com.github.checkstyle.regression.internal.TestUtils.assertUtilsClassHasPrivateConstructor;
+import static org.junit.Assert.assertEquals;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.StringWriter;
+import java.util.Arrays;
+import java.util.Collections;
+
+import org.apache.commons.io.IOUtils;
+import org.junit.Test;
+
+import com.github.checkstyle.regression.data.ImmutableModuleExtractInfo;
+import com.github.checkstyle.regression.data.ImmutableModuleInfo;
+import com.github.checkstyle.regression.data.ModuleExtractInfo;
+import com.github.checkstyle.regression.data.ModuleInfo;
+
+public class ConfigGeneratorTest {
+ private static final String BASE_PACKAGE = "com.puppycrawl.tools.checkstyle";
+
+ @Test
+ public void testIsProperUtilsClass() throws Exception {
+ assertUtilsClassHasPrivateConstructor(ConfigGenerator.class);
+ }
+
+ @Test
+ public void testDtdVersion() throws Exception {
+ }
+
+ @Test
+ public void testGenerateConfigTextWithEmptyModuleInfos() throws Exception {
+ final String excepted = getExpectedXml("expected_empty_module_infos.xml");
+
+ final String actual = ConfigGenerator.generateConfigText(Collections.emptyList());
+ assertEquals("Config is not as expected", excepted, actual);
+ }
+
+ @Test
+ public void testGenerateConfigTextWithCheckerParentModule() throws Exception {
+ final String excepted = getExpectedXml("expected_checker_parent_module.xml");
+
+ final ModuleExtractInfo extractInfo = ImmutableModuleExtractInfo.builder()
+ .name("FileLengthCheck")
+ .packageName(BASE_PACKAGE + ".checks.sizes")
+ .parent("Checker")
+ .build();
+ final ModuleInfo moduleInfo = ImmutableModuleInfo.builder()
+ .moduleExtractInfo(extractInfo)
+ .build();
+
+ final String actual = ConfigGenerator.generateConfigText(
+ Collections.singletonList(moduleInfo));
+ assertEquals("Config is not as expected", excepted, actual);
+ }
+
+ @Test
+ public void testGenerateConfigTextWithTreeWalkerParentModule() throws Exception {
+ final String excepted = getExpectedXml("expected_tree_walker_parent_module.xml");
+
+ final ModuleExtractInfo extractInfo = ImmutableModuleExtractInfo.builder()
+ .name("HiddenFieldCheck")
+ .packageName(BASE_PACKAGE + ".checks.coding")
+ .parent("TreeWalker")
+ .build();
+ final ModuleInfo moduleInfo = ImmutableModuleInfo.builder()
+ .moduleExtractInfo(extractInfo)
+ .build();
+
+ final String actual = ConfigGenerator.generateConfigText(
+ Collections.singletonList(moduleInfo));
+ assertEquals("Config is not as expected", excepted, actual);
+ }
+
+ @Test
+ public void testGenerateConfigTextWithMiscModuleInfos() throws Exception {
+ final String excepted =
+ getExpectedXml("expected_misc_module_infos.xml");
+
+ final ModuleExtractInfo extractInfo1 = ImmutableModuleExtractInfo.builder()
+ .name("NewlineAtEndOfFileCheck")
+ .packageName(BASE_PACKAGE + ".checks")
+ .parent("Checker")
+ .build();
+ final ModuleInfo moduleInfo1 = ImmutableModuleInfo.builder()
+ .moduleExtractInfo(extractInfo1)
+ .build();
+
+ final ModuleExtractInfo extractInfo2 = ImmutableModuleExtractInfo.builder()
+ .name("EmptyStatementCheck")
+ .packageName(BASE_PACKAGE + ".checks.coding")
+ .parent("TreeWalker")
+ .build();
+ final ModuleInfo moduleInfo2 = ImmutableModuleInfo.builder()
+ .moduleExtractInfo(extractInfo2)
+ .build();
+
+ final String actual = ConfigGenerator.generateConfigText(
+ Arrays.asList(moduleInfo1, moduleInfo2));
+ assertEquals("Config is not as expected", excepted, actual);
+ }
+
+ private static String getExpectedXml(String fileName) throws IOException {
+ try (InputStream stream = ConfigGeneratorTest.class.getClassLoader().getResourceAsStream(
+ "com/github/checkstyle/regression/configuration/" + fileName)) {
+ final StringWriter writer = new StringWriter();
+ IOUtils.copy(stream, writer, "UTF-8");
+ return writer.toString();
+ }
+ }
+}
diff --git a/src/test/resources/com/github/checkstyle/regression/configuration/expected_checker_parent_module.xml b/src/test/resources/com/github/checkstyle/regression/configuration/expected_checker_parent_module.xml
new file mode 100644
index 0000000..043a8ed
--- /dev/null
+++ b/src/test/resources/com/github/checkstyle/regression/configuration/expected_checker_parent_module.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/test/resources/com/github/checkstyle/regression/configuration/expected_empty_module_infos.xml b/src/test/resources/com/github/checkstyle/regression/configuration/expected_empty_module_infos.xml
new file mode 100644
index 0000000..82c1889
--- /dev/null
+++ b/src/test/resources/com/github/checkstyle/regression/configuration/expected_empty_module_infos.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/test/resources/com/github/checkstyle/regression/configuration/expected_misc_module_infos.xml b/src/test/resources/com/github/checkstyle/regression/configuration/expected_misc_module_infos.xml
new file mode 100644
index 0000000..4bafc78
--- /dev/null
+++ b/src/test/resources/com/github/checkstyle/regression/configuration/expected_misc_module_infos.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/test/resources/com/github/checkstyle/regression/configuration/expected_tree_walker_parent_module.xml b/src/test/resources/com/github/checkstyle/regression/configuration/expected_tree_walker_parent_module.xml
new file mode 100644
index 0000000..6e41959
--- /dev/null
+++ b/src/test/resources/com/github/checkstyle/regression/configuration/expected_tree_walker_parent_module.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+