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