1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.checkstyle.suppressionxpathfilter;
21
22 import static com.google.common.truth.Truth.assertWithMessage;
23
24 import java.io.File;
25 import java.io.Writer;
26 import java.nio.charset.StandardCharsets;
27 import java.nio.file.Files;
28 import java.util.List;
29 import java.util.Locale;
30 import java.util.UUID;
31 import java.util.regex.Matcher;
32 import java.util.regex.Pattern;
33
34 import org.checkstyle.base.AbstractCheckstyleModuleTestSupport;
35 import org.junit.jupiter.api.io.TempDir;
36
37 import com.puppycrawl.tools.checkstyle.DefaultConfiguration;
38 import com.puppycrawl.tools.checkstyle.JavaParser;
39 import com.puppycrawl.tools.checkstyle.TreeWalker;
40 import com.puppycrawl.tools.checkstyle.api.DetailAST;
41 import com.puppycrawl.tools.checkstyle.api.FileText;
42 import com.puppycrawl.tools.checkstyle.filters.SuppressionXpathFilter;
43 import com.puppycrawl.tools.checkstyle.utils.CommonUtil;
44 import com.puppycrawl.tools.checkstyle.xpath.XpathQueryGenerator;
45
46 public abstract class AbstractXpathTestSupport extends AbstractCheckstyleModuleTestSupport {
47
48 private static final int DEFAULT_TAB_WIDTH = 4;
49
50 private static final String DELIMITER = " | \n";
51
52 private static final Pattern LINE_COLUMN_NUMBER_REGEX =
53 Pattern.compile("(\\d+):(\\d+):");
54
55
56
57
58 @TempDir
59 public File temporaryFolder;
60
61
62
63
64
65
66 protected abstract String getCheckName();
67
68 @Override
69 public String getPackageLocation() {
70 final String subpackage = getCheckName().toLowerCase(Locale.ENGLISH)
71 .replace("check", "");
72 return "org/checkstyle/suppressionxpathfilter/" + subpackage;
73 }
74
75
76
77
78
79
80
81
82
83 private static List<String> generateXpathQueries(File fileToProcess,
84 ViolationPosition position)
85 throws Exception {
86 final FileText fileText = new FileText(fileToProcess,
87 StandardCharsets.UTF_8.name());
88 final DetailAST rootAst = JavaParser.parseFile(fileToProcess,
89 JavaParser.Options.WITH_COMMENTS);
90 final XpathQueryGenerator queryGenerator = new XpathQueryGenerator(rootAst,
91 position.violationLineNumber, position.violationColumnNumber,
92 fileText, DEFAULT_TAB_WIDTH);
93
94 return queryGenerator.generate();
95 }
96
97
98
99
100
101
102
103 private static void verifyXpathQueries(List<String> generatedXpathQueries,
104 List<String> expectedXpathQueries) {
105 assertWithMessage("Generated queries do not match expected ones")
106 .that(generatedXpathQueries)
107 .isEqualTo(expectedXpathQueries);
108 }
109
110
111
112
113
114
115
116
117
118
119
120 private String createSuppressionsXpathConfigFile(String checkName,
121 List<String> xpathQueries)
122 throws Exception {
123 final String uniqueFileName =
124 "suppressions_xpath_config_" + UUID.randomUUID() + ".xml";
125 final File suppressionsXpathConfigPath = new File(temporaryFolder, uniqueFileName);
126 try (Writer bw = Files.newBufferedWriter(suppressionsXpathConfigPath.toPath())) {
127 bw.write("<?xml version=\"1.0\"?>\n");
128 bw.write("<!DOCTYPE suppressions PUBLIC\n");
129 bw.write(" \"-//Checkstyle//DTD SuppressionXpathFilter ");
130 bw.write("Configuration 1.2//EN\"\n");
131 bw.write(" \"https://checkstyle.org/dtds/");
132 bw.write("suppressions_1_2_xpath.dtd\">\n");
133 bw.write("<suppressions>\n");
134 bw.write(" <suppress-xpath\n");
135 bw.write(" checks=\"");
136 bw.write(checkName);
137 bw.write("\"\n");
138 bw.write(" query=\"");
139 bw.write(String.join(DELIMITER, xpathQueries));
140 bw.write("\"/>\n");
141 bw.write("</suppressions>");
142 }
143
144 return suppressionsXpathConfigPath.toString();
145 }
146
147
148
149
150
151
152
153
154
155 private DefaultConfiguration createSuppressionXpathFilter(String checkName,
156 List<String> xpathQueries) throws Exception {
157 final DefaultConfiguration suppressionXpathFilterConfig =
158 createModuleConfig(SuppressionXpathFilter.class);
159 suppressionXpathFilterConfig.addProperty("file",
160 createSuppressionsXpathConfigFile(checkName, xpathQueries));
161
162 return suppressionXpathFilterConfig;
163 }
164
165
166
167
168
169
170
171 private static ViolationPosition extractLineAndColumnNumber(String... expectedViolations) {
172 ViolationPosition violation = null;
173 final Matcher matcher =
174 LINE_COLUMN_NUMBER_REGEX.matcher(expectedViolations[0]);
175 if (matcher.find()) {
176 final int violationLineNumber = Integer.parseInt(matcher.group(1));
177 final int violationColumnNumber = Integer.parseInt(matcher.group(2));
178 violation = new ViolationPosition(violationLineNumber, violationColumnNumber);
179 }
180 return violation;
181 }
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199 protected void runVerifications(DefaultConfiguration moduleConfig,
200 File fileToProcess,
201 String[] expectedViolation,
202 List<String> expectedXpathQueries) throws Exception {
203 if (expectedViolation.length != 1) {
204 throw new IllegalArgumentException(
205 "Expected violations should contain exactly one element."
206 + " Multiple violations are not supported."
207 );
208 }
209
210 final ViolationPosition position =
211 extractLineAndColumnNumber(expectedViolation);
212 final List<String> generatedXpathQueries =
213 generateXpathQueries(fileToProcess, position);
214
215 final DefaultConfiguration treeWalkerConfigWithXpath =
216 createModuleConfig(TreeWalker.class);
217 treeWalkerConfigWithXpath.addChild(moduleConfig);
218 treeWalkerConfigWithXpath.addChild(createSuppressionXpathFilter(moduleConfig.getName(),
219 generatedXpathQueries));
220
221 final Integer[] warnList = getLinesWithWarn(fileToProcess.getPath());
222 verify(moduleConfig, fileToProcess.getPath(), expectedViolation, warnList);
223 verifyXpathQueries(generatedXpathQueries, expectedXpathQueries);
224 verify(treeWalkerConfigWithXpath, fileToProcess.getPath(), CommonUtil.EMPTY_STRING_ARRAY);
225 }
226
227 private record ViolationPosition(int violationLineNumber, int violationColumnNumber) {
228
229
230
231
232
233
234 private ViolationPosition {
235 }
236 }
237
238 }