1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package com.puppycrawl.tools.checkstyle.internal;
21
22 import static com.google.common.truth.Truth.assertWithMessage;
23
24 import java.io.IOException;
25 import java.io.InputStream;
26 import java.nio.file.Files;
27 import java.nio.file.Path;
28 import java.nio.file.Paths;
29 import java.util.ArrayList;
30 import java.util.HashMap;
31 import java.util.List;
32 import java.util.Locale;
33 import java.util.Map;
34 import java.util.Set;
35 import java.util.stream.Collectors;
36
37 import javax.xml.parsers.SAXParser;
38 import javax.xml.parsers.SAXParserFactory;
39
40 import org.junit.jupiter.api.Test;
41 import org.xml.sax.Attributes;
42 import org.xml.sax.helpers.DefaultHandler;
43
44 import com.puppycrawl.tools.checkstyle.api.AbstractCheck;
45 import com.puppycrawl.tools.checkstyle.api.AbstractFileSetCheck;
46 import com.puppycrawl.tools.checkstyle.internal.utils.CheckUtil;
47
48 public class XdocsUrlTest {
49
50 private static final String PACKAGE_NAME =
51 "src/main/java/com/puppycrawl/tools/checkstyle/checks";
52
53 private static final String TREE_WORKER = "TreeWalker";
54
55 private static final String SUFFIX_CHECK = "Check";
56
57 private static final String CHECKS = "checks";
58
59 private static final String MISC = "misc";
60
61 private static final String ANNOTATION = "annotation";
62
63 private static final String COMMENTS_INDENTATION = "CommentsIndentation";
64
65 private static final String INDENTATION = "Indentation";
66
67 private static final String SUPPRESS_WARNINGS_HOLDER = "SuppressWarningsHolder";
68
69 private static final Path AVAILABLE_CHECKS_PATH = Paths.get("src/xdocs/checks.xml");
70
71 private static Map<String, List<String>> getXdocsMap() throws IOException {
72 final Map<String, List<String>> checksNamesMap = new HashMap<>();
73 final Set<Class<?>> checkSet = CheckUtil.getCheckstyleModules();
74 final Set<Class<?>> treeWalkerOrFileSetCheckSet = checkSet.stream()
75 .filter(clazz -> {
76 return AbstractCheck.class.isAssignableFrom(clazz)
77 || AbstractFileSetCheck.class.isAssignableFrom(clazz);
78 })
79 .collect(Collectors.toUnmodifiableSet());
80 for (Class<?> check : treeWalkerOrFileSetCheckSet) {
81 final String checkName = check.getSimpleName();
82 if (!TREE_WORKER.equals(checkName)) {
83 String packageName = check.getPackage().getName();
84 packageName = packageName.substring(packageName.lastIndexOf('.') + 1);
85 if (CHECKS.equals(packageName)) {
86 packageName = MISC;
87 }
88 if (checksNamesMap.get(packageName) == null) {
89 final List<String> arrayList = new ArrayList<>();
90 arrayList.add(checkName);
91 checksNamesMap.put(packageName, arrayList);
92 }
93 else {
94 checksNamesMap.get(packageName).add(checkName);
95 }
96 }
97 }
98 return checksNamesMap;
99 }
100
101 @Test
102 public void testXdocsUrl() throws Exception {
103 final SAXParserFactory parserFactory = SAXParserFactory.newInstance();
104 final SAXParser parser = parserFactory.newSAXParser();
105 final DummyHandler checkHandler = new DummyHandler();
106 try (InputStream input = Files.newInputStream(AVAILABLE_CHECKS_PATH)) {
107 parser.parse(input, checkHandler);
108 }
109 final Map<String, List<String>> checksNamesMap = getXdocsMap();
110 for (List<String> sub : checkHandler.checkNamesList) {
111 final String moduleName = sub.get(0);
112 final String checkNameInAttribute = sub.get(1);
113 final String checkNameInText = sub.get(2);
114 final String checkNameInconsistentErrorMsg = String.format(Locale.ROOT,
115 "Check with name '%s' in attribute "
116 + "is not consistent with check name in text in file '%s'",
117 checkNameInAttribute, AVAILABLE_CHECKS_PATH);
118 assertWithMessage(checkNameInconsistentErrorMsg)
119 .that(checkNameInText)
120 .matches(checkNameInAttribute);
121 final String checkNameModuleErrorMsg = String.format(Locale.ROOT,
122 "Check with name '%s' is not in '%s' module",
123 checkNameInAttribute, moduleName);
124 if (COMMENTS_INDENTATION.equals(checkNameInAttribute)
125 || INDENTATION.equals(checkNameInAttribute)) {
126 assertWithMessage(checkNameModuleErrorMsg)
127 .that(moduleName)
128 .matches(MISC);
129 }
130 else if (SUPPRESS_WARNINGS_HOLDER.equals(checkNameInAttribute)) {
131 assertWithMessage(checkNameModuleErrorMsg)
132 .that(moduleName)
133 .matches(ANNOTATION);
134 }
135 else {
136 final List<String> moduleFileNames = checksNamesMap.get(moduleName);
137 final String moduleNameErrorMsg = String.format(Locale.ROOT,
138 "module name: '%s' does not exist in '%s'", moduleName, PACKAGE_NAME);
139 assertWithMessage(moduleNameErrorMsg)
140 .that(moduleFileNames)
141 .isNotNull();
142 final String checkNameWithSuffix = checkNameInAttribute + SUFFIX_CHECK;
143 assertWithMessage(checkNameModuleErrorMsg)
144 .that(moduleFileNames)
145 .contains(checkNameWithSuffix);
146 }
147 }
148 }
149
150 public static final class DummyHandler extends DefaultHandler {
151
152 private static final String SPLIT_CHECK_NAME_IN_ATTRIBUTE = "#";
153
154 private static final String PREFIX_CONFIG = "config_";
155
156 private static final String NODE_NAME = "a";
157
158 private final List<List<String>> checkNamesList = new ArrayList<>();
159
160 private List<String> singleCheckNameList;
161
162 private String currentTag;
163
164 @Override
165 public void startElement(String uri, String localName, String qName,
166 Attributes attributes) {
167 if (NODE_NAME.equals(qName)) {
168 final String[] moduleAndCheckName =
169 attributes.getValue(0).split(SPLIT_CHECK_NAME_IN_ATTRIBUTE);
170 if (moduleAndCheckName[0].startsWith(PREFIX_CONFIG)) {
171 singleCheckNameList = new ArrayList<>();
172 final String moduleName =
173 moduleAndCheckName[0].replaceAll("(.*config_)|(\\.html.*)", "");
174 singleCheckNameList.add(moduleName);
175 singleCheckNameList.add(moduleAndCheckName[1]);
176 }
177 }
178 currentTag = qName;
179 }
180
181 @Override
182 public void characters(char[] ch, int start, int length) {
183 if (currentTag != null && singleCheckNameList != null && currentTag.equals(NODE_NAME)) {
184 final String currentValue = new String(ch, start, length).trim();
185 if (!currentValue.isEmpty() && !"\n".equals(currentValue)) {
186 singleCheckNameList.add(currentValue);
187 }
188 currentTag = null;
189 }
190 }
191
192 @Override
193 public void endElement(String uri, String localName, String qName) {
194 if (singleCheckNameList != null && qName.equals(NODE_NAME)) {
195 checkNamesList.add(singleCheckNameList);
196 singleCheckNameList = null;
197 }
198 }
199 }
200 }