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;
21
22 import static com.google.common.truth.Truth.assertWithMessage;
23 import static com.puppycrawl.tools.checkstyle.checks.naming.AbstractNameCheck.MSG_INVALID_PATTERN;
24 import static org.mockito.ArgumentMatchers.any;
25 import static org.mockito.Mockito.CALLS_REAL_METHODS;
26 import static org.mockito.Mockito.doThrow;
27 import static org.mockito.Mockito.mock;
28
29 import java.io.File;
30 import java.io.Writer;
31 import java.nio.charset.StandardCharsets;
32 import java.nio.file.Files;
33 import java.nio.file.StandardCopyOption;
34 import java.util.ArrayList;
35 import java.util.Arrays;
36 import java.util.Collection;
37 import java.util.Collections;
38 import java.util.HashMap;
39 import java.util.HashSet;
40 import java.util.List;
41 import java.util.Map;
42 import java.util.Set;
43 import java.util.UUID;
44 import java.util.regex.Matcher;
45 import java.util.regex.Pattern;
46
47 import org.junit.jupiter.api.Test;
48 import org.junit.jupiter.api.io.TempDir;
49 import org.mockito.MockedConstruction;
50 import org.mockito.MockedStatic;
51 import org.mockito.Mockito;
52 import org.mockito.internal.util.Checks;
53
54 import com.puppycrawl.tools.checkstyle.api.AbstractCheck;
55 import com.puppycrawl.tools.checkstyle.api.CheckstyleException;
56 import com.puppycrawl.tools.checkstyle.api.Configuration;
57 import com.puppycrawl.tools.checkstyle.api.Context;
58 import com.puppycrawl.tools.checkstyle.api.DetailAST;
59 import com.puppycrawl.tools.checkstyle.api.FileContents;
60 import com.puppycrawl.tools.checkstyle.api.FileText;
61 import com.puppycrawl.tools.checkstyle.api.TokenTypes;
62 import com.puppycrawl.tools.checkstyle.checks.NoCodeInFileCheck;
63 import com.puppycrawl.tools.checkstyle.checks.coding.EmptyStatementCheck;
64 import com.puppycrawl.tools.checkstyle.checks.coding.HiddenFieldCheck;
65 import com.puppycrawl.tools.checkstyle.checks.design.OneTopLevelClassCheck;
66 import com.puppycrawl.tools.checkstyle.checks.indentation.CommentsIndentationCheck;
67 import com.puppycrawl.tools.checkstyle.checks.javadoc.JavadocPackageCheck;
68 import com.puppycrawl.tools.checkstyle.checks.javadoc.JavadocParagraphCheck;
69 import com.puppycrawl.tools.checkstyle.checks.naming.ConstantNameCheck;
70 import com.puppycrawl.tools.checkstyle.checks.naming.MemberNameCheck;
71 import com.puppycrawl.tools.checkstyle.checks.naming.ParameterNameCheck;
72 import com.puppycrawl.tools.checkstyle.checks.naming.TypeNameCheck;
73 import com.puppycrawl.tools.checkstyle.checks.whitespace.WhitespaceAfterCheck;
74 import com.puppycrawl.tools.checkstyle.checks.whitespace.WhitespaceAroundCheck;
75 import com.puppycrawl.tools.checkstyle.filters.SuppressWithNearbyCommentFilter;
76 import com.puppycrawl.tools.checkstyle.filters.SuppressionXpathFilter;
77 import com.puppycrawl.tools.checkstyle.internal.utils.TestUtil;
78 import com.puppycrawl.tools.checkstyle.utils.CommonUtil;
79
80
81
82
83
84
85
86
87 public class TreeWalkerTest extends AbstractModuleTestSupport {
88
89 @TempDir
90 public File temporaryFolder;
91
92 @Override
93 protected String getPackageLocation() {
94 return "com/puppycrawl/tools/checkstyle/treewalker";
95 }
96
97 @Test
98 public void testProperFileExtension() throws Exception {
99 final String path = getPath("InputTreeWalkerProperFileExtension.java");
100 final String[] expected = {
101 "10:27: " + getCheckMessage(ConstantNameCheck.class,
102 MSG_INVALID_PATTERN, "k", "^[A-Z][A-Z0-9]*(_[A-Z0-9]+)*$"),
103 };
104 verifyWithInlineConfigParserTwice(path, expected);
105 }
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129 @Test
130 public void testNoAuditEventsWithoutFilters() throws Exception {
131 final String[] expected = {
132 "10:1: " + getCheckMessage(OneTopLevelClassCheck.class,
133 OneTopLevelClassCheck.MSG_KEY, "InputTreeWalkerInner"),
134 };
135 try (MockedConstruction<TreeWalkerAuditEvent> mocked =
136 Mockito.mockConstruction(TreeWalkerAuditEvent.class, (mock, context) -> {
137 throw new CheckstyleException("No audit events expected");
138 })) {
139 verifyWithInlineConfigParserTwice(getPath("InputTreeWalker.java"), expected);
140 }
141 }
142
143
144
145
146
147 @Test
148 public void testConditionRequiredWithoutOrdinaryChecks() throws Exception {
149 final String[] expected = {
150 "7:5: " + getCheckMessage(JavadocParagraphCheck.class,
151 JavadocParagraphCheck.MSG_REDUNDANT_PARAGRAPH),
152 };
153 final String path = getPath("InputTreeWalkerJavadoc.java");
154 final DetailAST mockAst = mock();
155 final DetailAST realAst = JavaParser.parseFile(new File(path),
156 JavaParser.Options.WITH_COMMENTS);
157
158 doThrow(IllegalStateException.class).when(mockAst).getFirstChild();
159 try (MockedStatic<JavaParser> parser = Mockito.mockStatic(JavaParser.class)) {
160 parser.when(() -> JavaParser.parse(any(FileContents.class))).thenReturn(mockAst);
161
162 parser.when(() -> JavaParser.appendHiddenCommentNodes(mockAst)).thenReturn(realAst);
163
164 verifyWithInlineConfigParserTwice(path, expected);
165 }
166 }
167
168
169
170
171
172 @Test
173 public void testConditionRequiredWithoutCommentChecks() throws Exception {
174 final String[] expected = {
175 "10:1: " + getCheckMessage(OneTopLevelClassCheck.class,
176 OneTopLevelClassCheck.MSG_KEY, "InputTreeWalkerInner"),
177 };
178 try (MockedStatic<JavaParser> parser =
179 Mockito.mockStatic(JavaParser.class, CALLS_REAL_METHODS)) {
180
181 parser.when(() -> JavaParser.appendHiddenCommentNodes(any(DetailAST.class)))
182 .thenThrow(IllegalStateException.class);
183
184 verifyWithInlineConfigParserTwice(getPath("InputTreeWalker.java"), expected);
185 }
186 }
187
188 @Test
189 public void testImproperFileExtension() throws Exception {
190 final String regularFilePath = getPath("InputTreeWalkerImproperFileExtension.java");
191 final File originalFile = new File(regularFilePath);
192 final File tempFile = new File(temporaryFolder, "file.pdf");
193 Files.copy(originalFile.toPath(), tempFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
194 final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
195 verifyWithInlineConfigParserTwice(tempFile.getPath(), expected);
196 }
197
198 @Test
199 public void testAcceptableTokens()
200 throws Exception {
201 final DefaultConfiguration checkConfig =
202 createModuleConfig(HiddenFieldCheck.class);
203 checkConfig.addProperty("tokens", "VARIABLE_DEF, ENUM_DEF, CLASS_DEF, METHOD_DEF,"
204 + "IMPORT");
205 try {
206 execute(checkConfig, getPath("InputTreeWalker.java"));
207 assertWithMessage("CheckstyleException is expected").fail();
208 }
209 catch (CheckstyleException exc) {
210 final String errorMsg = exc.getMessage();
211 final Pattern expected = Pattern.compile(Pattern.quote("cannot initialize module"
212 + " com.puppycrawl.tools.checkstyle.TreeWalker - Token ")
213 + "\"(ENUM_DEF|CLASS_DEF|METHOD_DEF|IMPORT)\""
214 + Pattern.quote(" was not found in Acceptable tokens list in check"
215 + " com.puppycrawl.tools.checkstyle.checks.coding.HiddenFieldCheck"));
216
217 final Matcher errorMsgMatcher = expected.matcher(errorMsg);
218 assertWithMessage("Failure for: " + errorMsg)
219 .that(errorMsgMatcher.matches())
220 .isTrue();
221 }
222 }
223
224 @Test
225 public void testOnEmptyFile() throws Exception {
226 final DefaultConfiguration checkConfig = createModuleConfig(HiddenFieldCheck.class);
227 final String uniqueFileName = "file_" + UUID.randomUUID() + ".java";
228 final File emptyFile = new File(temporaryFolder, uniqueFileName);
229 emptyFile.createNewFile();
230 execute(checkConfig, emptyFile.getPath());
231 final long fileSize = Files.size(emptyFile.toPath());
232 assertWithMessage("File should be empty")
233 .that(fileSize)
234 .isEqualTo(0);
235 }
236
237 @Test
238 public void testWithCheckNotHavingTreeWalkerAsParent() throws Exception {
239 final DefaultConfiguration checkConfig = createModuleConfig(JavadocPackageCheck.class);
240
241 try {
242 final String uniqueFileName = "junit_" + UUID.randomUUID() + ".java";
243 final File filePath = new File(temporaryFolder, uniqueFileName);
244 execute(createTreeWalkerConfig(checkConfig), filePath.toString());
245 assertWithMessage("CheckstyleException is expected").fail();
246 }
247 catch (CheckstyleException exception) {
248 assertWithMessage("Error message is unexpected")
249 .that(exception.getMessage())
250 .contains("TreeWalker is not allowed as a parent of");
251 }
252 }
253
254 @Test
255 public void testSetupChildExceptions() {
256 final TreeWalker treeWalker = new TreeWalker();
257 final PackageObjectFactory factory = new PackageObjectFactory(
258 new HashSet<>(), Thread.currentThread().getContextClassLoader());
259 treeWalker.setModuleFactory(factory);
260
261 final Configuration config = new DefaultConfiguration("java.lang.String");
262 try {
263 treeWalker.setupChild(config);
264 assertWithMessage("Exception is expected").fail();
265 }
266 catch (CheckstyleException exc) {
267 assertWithMessage("Error message is not expected")
268 .that(exc.getMessage())
269 .isEqualTo("TreeWalker is not allowed as a parent of java.lang.String "
270 + "Please review 'Parent Module' section for this Check in "
271 + "web documentation if Check is standard.");
272 }
273 }
274
275 @Test
276 public void testSettersForParameters() throws Exception {
277 final TreeWalker treeWalker = new TreeWalker();
278 final DefaultConfiguration config = new DefaultConfiguration("default config");
279 treeWalker.setTabWidth(1);
280 treeWalker.configure(config);
281
282 final int tabWidth = TestUtil.getInternalState(treeWalker, "tabWidth");
283 assertWithMessage("Invalid setter result")
284 .that(tabWidth)
285 .isEqualTo(1);
286 final Object configuration = TestUtil.getInternalState(treeWalker, "configuration");
287 assertWithMessage("Invalid configuration")
288 .that(configuration)
289 .isEqualTo(config);
290 }
291
292 @Test
293 public void testForInvalidCheckImplementation() throws Exception {
294 final DefaultConfiguration checkConfig = createModuleConfig(BadJavaDocCheck.class);
295 final String uniqueFileName = "file_" + UUID.randomUUID() + ".java";
296 final File pathToEmptyFile = new File(temporaryFolder, uniqueFileName);
297
298 try {
299 execute(checkConfig, pathToEmptyFile.toString());
300 assertWithMessage("Exception is expected").fail();
301 }
302 catch (CheckstyleException exc) {
303 assertWithMessage("Error message is unexpected")
304 .that(exc.getMessage())
305 .isEqualTo("cannot initialize module com.puppycrawl.tools.checkstyle."
306 + "TreeWalker - Check 'com.puppycrawl.tools.checkstyle."
307 + "TreeWalkerTest$BadJavaDocCheck' waits for comment type token "
308 + "('SINGLE_LINE_COMMENT') and should override "
309 + "'isCommentNodesRequired()' method to return 'true'");
310 assertWithMessage("Error message is unexpected")
311 .that(exc.getMessage())
312 .contains("isCommentNodesRequired");
313 }
314 }
315
316 @Test
317 public void testProcessNonJavaFiles() throws Exception {
318 final TreeWalker treeWalker = new TreeWalker();
319 final PackageObjectFactory factory = new PackageObjectFactory(
320 new HashSet<>(), Thread.currentThread().getContextClassLoader());
321 treeWalker.setModuleFactory(factory);
322 treeWalker.configure(new DefaultConfiguration("default config"));
323 final DefaultConfiguration childConfig = createModuleConfig(JavadocParagraphCheck.class);
324 treeWalker.setupChild(childConfig);
325 final File file = new File("input.java");
326 final List<String> lines =
327 new ArrayList<>(Arrays.asList("package com.puppycrawl.tools.checkstyle;", "",
328 "error public class InputTreeWalkerFileWithViolation {}"));
329 final FileText fileText = new FileText(file, lines);
330 treeWalker.setFileContents(new FileContents(fileText));
331 try {
332 treeWalker.processFiltered(file, fileText);
333 assertWithMessage("Exception expected").fail();
334 }
335 catch (CheckstyleException exc) {
336 assertWithMessage("Invalid exception message")
337 .that(exc.getMessage())
338 .isEqualTo("IllegalStateException occurred while parsing file input.java.");
339 }
340 }
341
342 @Test
343 public void testProcessNonJavaFilesWithoutException() throws Exception {
344 final TreeWalker treeWalker = new TreeWalker();
345 treeWalker.setTabWidth(1);
346 treeWalker.configure(new DefaultConfiguration("default config"));
347 final File file = new File(getPath("InputTreeWalkerNotJava.xml"));
348 final FileText fileText = new FileText(file, StandardCharsets.ISO_8859_1.name());
349 treeWalker.processFiltered(file, fileText);
350 final Collection<Checks> checks = TestUtil.getInternalState(treeWalker, "ordinaryChecks");
351 assertWithMessage("No checks -> No parsing")
352 .that(checks)
353 .isEmpty();
354 }
355
356 @Test
357 public void testWithCacheWithNoViolation() throws Exception {
358 final String path = getPath("InputTreeWalkerWithCacheWithNoViolation.java");
359 final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
360 verifyWithInlineConfigParserTwice(path, expected);
361 }
362
363 @Test
364 public void testProcessWithParserThrowable() throws Exception {
365 final TreeWalker treeWalker = new TreeWalker();
366 treeWalker.configure(createModuleConfig(TypeNameCheck.class));
367 final PackageObjectFactory factory = new PackageObjectFactory(
368 new HashSet<>(), Thread.currentThread().getContextClassLoader());
369 treeWalker.setModuleFactory(factory);
370 treeWalker.setupChild(createModuleConfig(TypeNameCheck.class));
371 final File file = new File(temporaryFolder, "file.java");
372 final List<String> lines = new ArrayList<>();
373 lines.add(" classD a {} ");
374 final FileText fileText = new FileText(file, lines);
375 treeWalker.setFileContents(new FileContents(fileText));
376 try {
377 treeWalker.processFiltered(file, fileText);
378 assertWithMessage("Exception is expected").fail();
379 }
380 catch (CheckstyleException exception) {
381 assertWithMessage("Error message is unexpected")
382 .that(exception.getMessage())
383 .contains("occurred while parsing file");
384 }
385 }
386
387 @Test
388 public void testProcessWithRecognitionException() throws Exception {
389 final TreeWalker treeWalker = new TreeWalker();
390 treeWalker.configure(createModuleConfig(TypeNameCheck.class));
391 final PackageObjectFactory factory = new PackageObjectFactory(
392 new HashSet<>(), Thread.currentThread().getContextClassLoader());
393 treeWalker.setModuleFactory(factory);
394 treeWalker.setupChild(createModuleConfig(TypeNameCheck.class));
395 final File file = new File(temporaryFolder, "file.java");
396 final List<String> lines = new ArrayList<>();
397 lines.add(" class a%$# {} ");
398 final FileText fileText = new FileText(file, lines);
399 treeWalker.setFileContents(new FileContents(fileText));
400 try {
401 treeWalker.processFiltered(file, fileText);
402 assertWithMessage("Exception is expected").fail();
403 }
404 catch (CheckstyleException exception) {
405 assertWithMessage("Error message is unexpected")
406 .that(exception.getMessage())
407 .contains("IllegalStateException occurred while parsing file");
408 }
409 }
410
411 @Test
412 public void testRequiredTokenIsEmptyIntArray() throws Exception {
413 final File file = new File(temporaryFolder, "file.java");
414 try (Writer writer = Files.newBufferedWriter(file.toPath(), StandardCharsets.UTF_8)) {
415 final String configComment = """
416
417
418
419
420
421 """;
422 writer.write(configComment);
423 }
424 final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
425 verifyWithInlineConfigParserTwice(file.getPath(), expected);
426 }
427
428 @Test
429 public void testBehaviourWithZeroChecks() throws Exception {
430 final TreeWalker treeWalker = new TreeWalker();
431 final PackageObjectFactory factory = new PackageObjectFactory(
432 new HashSet<>(), Thread.currentThread().getContextClassLoader());
433 treeWalker.setModuleFactory(factory);
434
435 final File file = new File(temporaryFolder, "file.java");
436 final FileText fileText = new FileText(file, new ArrayList<>());
437
438 treeWalker.processFiltered(file, fileText);
439 final Collection<Checks> checks = TestUtil.getInternalState(treeWalker, "ordinaryChecks");
440 assertWithMessage("No checks -> No parsing")
441 .that(checks)
442 .isEmpty();
443 }
444
445 @Test
446 public void testBehaviourWithOrdinaryAndCommentChecks() throws Exception {
447 final TreeWalker treeWalker = new TreeWalker();
448 treeWalker.configure(createModuleConfig(TypeNameCheck.class));
449 treeWalker.configure(createModuleConfig(CommentsIndentationCheck.class));
450 final PackageObjectFactory factory = new PackageObjectFactory(
451 new HashSet<>(), Thread.currentThread().getContextClassLoader());
452 treeWalker.setModuleFactory(factory);
453 treeWalker.setupChild(createModuleConfig(TypeNameCheck.class));
454 treeWalker.setupChild(createModuleConfig(CommentsIndentationCheck.class));
455 final File file = new File(temporaryFolder, "file.java");
456 final List<String> lines = new ArrayList<>();
457 lines.add(" class a%$# {} ");
458 final FileText fileText = new FileText(file, lines);
459 treeWalker.setFileContents(new FileContents(fileText));
460
461 try {
462 treeWalker.processFiltered(file, fileText);
463 assertWithMessage("file is not compilable, exception is expected").fail();
464 }
465 catch (CheckstyleException exception) {
466 final String message = "IllegalStateException occurred while parsing file";
467 assertWithMessage("Error message is unexpected")
468 .that(exception.getMessage())
469 .contains(message);
470 }
471 }
472
473 @Test
474 public void testSetupChild() throws Exception {
475 final TreeWalker treeWalker = new TreeWalker();
476 final PackageObjectFactory factory = new PackageObjectFactory(
477 new HashSet<>(), Thread.currentThread().getContextClassLoader());
478 treeWalker.setModuleFactory(factory);
479 treeWalker.setTabWidth(99);
480 treeWalker.finishLocalSetup();
481
482 final Configuration config = new DefaultConfiguration(
483 XpathFileGeneratorAstFilter.class.getName());
484
485 treeWalker.setupChild(config);
486
487 final Set<TreeWalkerFilter> filters = TestUtil.getInternalState(treeWalker, "filters");
488 final int tabWidth = TestUtil.getInternalState(filters.iterator().next(), "tabWidth");
489
490 assertWithMessage("expected tab width")
491 .that(tabWidth)
492 .isEqualTo(99);
493 }
494
495 @Test
496 public void testBehaviourWithChecksAndFilters() throws Exception {
497
498 final String[] expected = {
499 "17:17: " + getCheckMessage(MemberNameCheck.class, "name.invalidPattern", "P",
500 "^[a-z][a-zA-Z0-9]*$"),
501 "12:17: " + getCheckMessage(MemberNameCheck.class, "name.invalidPattern", "I",
502 "^[a-z][a-zA-Z0-9]*$"),
503 };
504
505 verifyWithInlineConfigParserTwice(
506 getPath("InputTreeWalkerSuppressionCommentFilter.java"),
507 expected);
508 }
509
510 @Test
511 public void testMultiCheckOrder() throws Exception {
512
513 final String[] expected = {
514 "13:9: " + getCheckMessage(WhitespaceAfterCheck.class, "ws.notFollowed", "if"),
515 "13:9: " + getCheckMessage(WhitespaceAroundCheck.class, "ws.notFollowed", "if"),
516 };
517
518 verifyWithInlineConfigParserTwice(
519 getPath("InputTreeWalkerMultiCheckOrder.java"),
520 expected);
521 }
522
523 @Test
524 public void testMultiCheckOfSameTypeNoIdResultsInOrderingByHash() throws Exception {
525
526 final String[] expected = {
527 "15:28: " + getCheckMessage(ParameterNameCheck.class,
528 "name.invalidPattern", "V2", "^[a-z]([a-z0-9][a-zA-Z0-9]*)?$"),
529 "17:25: " + getCheckMessage(ParameterNameCheck.class,
530 "name.invalidPattern", "b", "^[a-z][a-z0-9][a-zA-Z0-9]*$"),
531 };
532
533 verifyWithInlineConfigParserTwice(
534 getPath("InputTreeWalkerMultiCheckOrder2.java"),
535 expected);
536 }
537
538 @Test
539 public void testFinishLocalSetupFullyInitialized() {
540 final TreeWalker treeWalker = new TreeWalker();
541 treeWalker.setSeverity("error");
542 treeWalker.setTabWidth(100);
543 treeWalker.finishLocalSetup();
544
545 final Context context = TestUtil.getInternalState(treeWalker, "childContext");
546 assertWithMessage("Severity differs from expected")
547 .that(context.get("severity"))
548 .isEqualTo("error");
549 assertWithMessage("Tab width differs from expected")
550 .that(context.get("tabWidth"))
551 .isEqualTo(String.valueOf(100));
552 }
553
554 @Test
555 public void testCheckInitIsCalledInTreeWalker() throws Exception {
556 final DefaultConfiguration checkConfig =
557 createModuleConfig(VerifyInitCheck.class);
558 final String uniqueFileName = "file_" + UUID.randomUUID() + ".pdf";
559 final File file = new File(temporaryFolder, uniqueFileName);
560 execute(checkConfig, file.getPath());
561 assertWithMessage("Init was not called")
562 .that(VerifyInitCheck.isInitWasCalled())
563 .isTrue();
564 }
565
566 @Test
567 public void testCheckDestroyIsCalledInTreeWalker() throws Exception {
568 VerifyDestroyCheck.resetDestroyWasCalled();
569 final DefaultConfiguration checkConfig =
570 createModuleConfig(VerifyDestroyCheck.class);
571 final String uniqueFileName = "file_" + UUID.randomUUID() + ".pdf";
572 final File file = new File(temporaryFolder, uniqueFileName);
573 execute(checkConfig, file.getPath());
574 assertWithMessage("Destroy was not called")
575 .that(VerifyDestroyCheck.isDestroyWasCalled())
576 .isTrue();
577 }
578
579 @Test
580 public void testCommentCheckDestroyIsCalledInTreeWalker() throws Exception {
581 VerifyDestroyCheck.resetDestroyWasCalled();
582 final DefaultConfiguration checkConfig =
583 createModuleConfig(VerifyDestroyCommentCheck.class);
584 final String uniqueFileName = "file_" + UUID.randomUUID() + ".pdf";
585 final File file = new File(temporaryFolder, uniqueFileName);
586 execute(checkConfig, file.getPath());
587 assertWithMessage("Destroy was not called")
588 .that(VerifyDestroyCheck.isDestroyWasCalled())
589 .isTrue();
590 }
591
592 @Test
593 public void testCacheWhenFileExternalResourceContentDoesNotChange() throws Exception {
594 final DefaultConfiguration filterConfig = createModuleConfig(SuppressionXpathFilter.class);
595 filterConfig.addProperty("file", getPath("InputTreeWalkerSuppressionXpathFilter.xml"));
596 final DefaultConfiguration treeWalkerConfig = createModuleConfig(TreeWalker.class);
597 treeWalkerConfig.addChild(filterConfig);
598
599 final DefaultConfiguration checkerConfig = createRootConfig(treeWalkerConfig);
600 final String uniqueFileName1 = "junit_" + UUID.randomUUID() + ".java";
601 final File cacheFile = new File(temporaryFolder, uniqueFileName1);
602 checkerConfig.addProperty("cacheFile", cacheFile.getPath());
603
604 final String uniqueFileName2 = "file_" + UUID.randomUUID() + ".java";
605 final File filePath = new File(temporaryFolder, uniqueFileName2);
606
607 execute(checkerConfig, filePath.toString());
608
609 execute(checkerConfig, filePath.toString());
610
611 assertWithMessage("External resource is not present in cache")
612 .that(Files.readString(cacheFile.toPath()))
613 .contains("InputTreeWalkerSuppressionXpathFilter.xml");
614 }
615
616 @Test
617 public void testTreeWalkerFilterAbsolutePath() throws Exception {
618
619 final String filePath = "src/test/resources/" + getPackageLocation()
620 + "/InputTreeWalkerSuppressionXpathFilterAbsolute.java";
621
622 final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
623 verifyWithInlineConfigParserTwice(filePath, expected);
624 }
625
626 @Test
627 public void testExternalResourceFiltersWithNoExternalResource() throws Exception {
628 final DefaultConfiguration checkConfig = createModuleConfig(EmptyStatementCheck.class);
629 final DefaultConfiguration filterConfig =
630 createModuleConfig(SuppressWithNearbyCommentFilter.class);
631 final DefaultConfiguration treeWalkerConfig = createModuleConfig(TreeWalker.class);
632 treeWalkerConfig.addChild(checkConfig);
633 treeWalkerConfig.addChild(filterConfig);
634
635 final DefaultConfiguration checkerConfig = createRootConfig(treeWalkerConfig);
636 final String uniqueFileName1 = "junit_" + UUID.randomUUID() + ".java";
637 final File cacheFile = new File(temporaryFolder, uniqueFileName1);
638 checkerConfig.addProperty("cacheFile", cacheFile.getPath());
639 final String uniqueFileName2 = "junit_" + UUID.randomUUID() + ".java";
640 final File filePath = new File(temporaryFolder, uniqueFileName2);
641
642 execute(checkerConfig, filePath.toString());
643
644 final long cacheSize = Files.size(cacheFile.toPath());
645 assertWithMessage("cacheFile should not be empty")
646 .that(cacheSize)
647 .isNotEqualTo(0);
648 }
649
650
651
652
653
654
655 @Test
656 public void testOrderOfCheckExecution() throws Exception {
657
658 final DefaultConfiguration configuration1 = createModuleConfig(AaCheck.class);
659 configuration1.addProperty("id", "2");
660 final DefaultConfiguration configuration2 = createModuleConfig(BbCheck.class);
661 configuration2.addProperty("id", "1");
662
663 final DefaultConfiguration treeWalkerConfig = createModuleConfig(TreeWalker.class);
664 treeWalkerConfig.addChild(configuration2);
665 treeWalkerConfig.addChild(configuration1);
666
667 final List<File> files =
668 Collections.singletonList(new File(getPath("InputTreeWalker2.java")));
669 final Checker checker = createChecker(treeWalkerConfig);
670
671 try {
672 checker.process(files);
673 assertWithMessage("exception is expected").fail();
674 }
675 catch (CheckstyleException exception) {
676 assertWithMessage("wrong order of Check executions")
677 .that(exception.getCause().getMessage())
678 .isEqualTo(AaCheck.class.toString());
679 }
680 }
681
682 @Test
683 public void testSkipFileOnJavaParseExceptionTrue() throws Exception {
684 final DefaultConfiguration config = createModuleConfig(TreeWalker.class);
685 config.addProperty("skipFileOnJavaParseException", "true");
686 config.addProperty("javaParseExceptionSeverity", "ignore");
687 config.addChild(createModuleConfig(ConstantNameCheck.class));
688
689 final File[] files = {
690 new File(getNonCompilablePath("InputTreeWalkerSkipParsingException.java")),
691 new File(getPath("InputTreeWalkerProperFileExtension.java")),
692 new File(getNonCompilablePath("InputTreeWalkerSkipParsingException2.java")),
693 };
694
695 final Checker checker = createChecker(config);
696 final Map<String, List<String>> expectedViolation = new HashMap<>();
697 expectedViolation.put(getPath("InputTreeWalkerProperFileExtension.java"),
698 Collections.singletonList(
699 "10:27: " + getCheckMessage(ConstantNameCheck.class,
700 MSG_INVALID_PATTERN, "k", "^[A-Z][A-Z0-9]*(_[A-Z0-9]+)*$")));
701 verify(checker, files, expectedViolation);
702 }
703
704
705
706
707
708
709
710
711
712
713 @Test
714 public void testSkipFileOnJavaParseExceptionFalse() throws Exception {
715 final DefaultConfiguration config = createModuleConfig(TreeWalker.class);
716 config.addProperty("skipFileOnJavaParseException", "false");
717 config.addChild(createModuleConfig(ConstantNameCheck.class));
718
719 final String[] files = {
720 getNonCompilablePath("InputTreeWalkerSkipParsingException2.java"),
721 getPath("InputTreeWalkerProperFileExtension.java"),
722 getNonCompilablePath("InputTreeWalkerSkipParsingException.java"),
723 };
724 final Exception ex = TestUtil.getExpectedThrowable(CheckstyleException.class,
725 () -> execute(config, files),
726 "Exception is expected");
727 assertWithMessage("Error message is unexpected")
728 .that(ex.getMessage())
729 .contains("Exception was thrown while processing");
730 }
731
732 @Test
733 public void testSkipFileOnJavaParseExceptionConfigSeverityIgnore() throws Exception {
734 final String path =
735 getNonCompilablePath(
736 "InputTreeWalkerSkipParsingExceptionConfigSeverityIgnore.java");
737 final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
738 verifyWithInlineXmlConfig(path, expected);
739 }
740
741 @Test
742 public void testSkipFileOnJavaParseExceptionConfigSeverityDefault() throws Exception {
743 final String path =
744 getNonCompilablePath(
745 "InputTreeWalkerSkipParsingExceptionConfigSeverityDefault.java");
746 final String[] expected = {
747 "1: " + getCheckMessage(TreeWalker.PARSE_EXCEPTION_MSG, "IllegalStateException")
748 + " occurred while parsing file " + path + ".",
749 };
750 verifyWithInlineXmlConfig(path, expected);
751 }
752
753 @Test
754 public void testSkipFileOnJavaParseExceptionSkipChecks() throws Exception {
755 final DefaultConfiguration config = createModuleConfig(TreeWalker.class);
756 config.addProperty("skipFileOnJavaParseException", "true");
757 config.addProperty("javaParseExceptionSeverity", "ignore");
758 config.addChild(createModuleConfig(NoCodeInFileCheck.class));
759
760 final Checker checker = createChecker(config);
761
762 final File[] files = {
763 new File(getNonCompilablePath("InputTreeWalkerSkipParsingException.java")),
764 new File(getPath("InputTreeWalkerProperFileExtension.java")),
765 new File(getNonCompilablePath("InputTreeWalkerSkipParsingException2.java")),
766 };
767 final Map<String, List<String>> expectedViolation = new HashMap<>();
768 expectedViolation.put(getPath("InputTreeWalkerProperFileExtension.java"),
769 new ArrayList<>());
770
771 verify(checker, files, expectedViolation);
772 }
773
774 @Test
775 public void testJavaParseExceptionSeverityDefaultError() throws Exception {
776 final DefaultConfiguration config = createModuleConfig(TreeWalker.class);
777 config.addProperty("skipFileOnJavaParseException", "true");
778 config.addChild(createModuleConfig(NoCodeInFileCheck.class));
779
780 final Checker checker = createChecker(config);
781
782 final File[] files = {
783 new File(getNonCompilablePath("InputTreeWalkerSkipParsingException.java")),
784 new File(getPath("InputTreeWalkerProperFileExtension.java")),
785 };
786
787 final Map<String, List<String>> expectedViolation = new HashMap<>();
788
789 expectedViolation.put(getPath("InputTreeWalkerProperFileExtension.java"),
790 new ArrayList<>());
791 expectedViolation.put(getNonCompilablePath("InputTreeWalkerSkipParsingException.java"),
792 List.of("1: Java specific (TreeWalker-based) modules are skipped due to an "
793 + "exception during parsing - "
794 + "IllegalStateException occurred while parsing file "
795 + getNonCompilablePath("InputTreeWalkerSkipParsingException.java") + "."));
796
797 verify(checker, files, expectedViolation);
798 }
799
800 public static class BadJavaDocCheck extends AbstractCheck {
801
802 @Override
803 public int[] getDefaultTokens() {
804 return getAcceptableTokens();
805 }
806
807 @Override
808 public int[] getAcceptableTokens() {
809 return new int[] {TokenTypes.SINGLE_LINE_COMMENT};
810 }
811
812 @Override
813 public int[] getRequiredTokens() {
814 return getAcceptableTokens();
815 }
816
817 }
818
819 public static class VerifyInitCheck extends AbstractCheck {
820
821 private static boolean initWasCalled;
822
823 @Override
824 public int[] getDefaultTokens() {
825 return CommonUtil.EMPTY_INT_ARRAY;
826 }
827
828 @Override
829 public int[] getAcceptableTokens() {
830 return getDefaultTokens();
831 }
832
833 @Override
834 public int[] getRequiredTokens() {
835 return getDefaultTokens();
836 }
837
838 @Override
839 public void init() {
840 super.init();
841 initWasCalled = true;
842 }
843
844 public static boolean isInitWasCalled() {
845 return initWasCalled;
846 }
847
848 }
849
850 public static class VerifyDestroyCheck extends AbstractCheck {
851
852 private static boolean destroyWasCalled;
853
854 @Override
855 public int[] getDefaultTokens() {
856 return CommonUtil.EMPTY_INT_ARRAY;
857 }
858
859 @Override
860 public int[] getAcceptableTokens() {
861 return getDefaultTokens();
862 }
863
864 @Override
865 public int[] getRequiredTokens() {
866 return getDefaultTokens();
867 }
868
869 @Override
870 public void destroy() {
871 super.destroy();
872 destroyWasCalled = true;
873 }
874
875 public static void resetDestroyWasCalled() {
876 destroyWasCalled = false;
877 }
878
879 public static boolean isDestroyWasCalled() {
880 return destroyWasCalled;
881 }
882
883 }
884
885 public static class VerifyDestroyCommentCheck extends VerifyDestroyCheck {
886
887 @Override
888 public boolean isCommentNodesRequired() {
889 return true;
890 }
891
892 }
893
894 public static class AaCheck extends AbstractCheck {
895
896 @Override
897 public int[] getDefaultTokens() {
898 return new int[0];
899 }
900
901 @Override
902 public int[] getAcceptableTokens() {
903 return new int[0];
904 }
905
906 @Override
907 public int[] getRequiredTokens() {
908 return new int[0];
909 }
910
911 @Override
912 public void beginTree(DetailAST rootAST) {
913 throw new IllegalStateException(AaCheck.class.toString());
914 }
915
916 }
917
918 public static class BbCheck extends AbstractCheck {
919
920 @Override
921 public int[] getDefaultTokens() {
922 return new int[0];
923 }
924
925 @Override
926 public int[] getAcceptableTokens() {
927 return new int[0];
928 }
929
930 @Override
931 public int[] getRequiredTokens() {
932 return new int[0];
933 }
934
935 @Override
936 public void beginTree(DetailAST rootAST) {
937 throw new IllegalStateException(BbCheck.class.toString());
938 }
939
940 }
941
942 public static class RequiredTokenIsEmptyIntArray extends AbstractCheck {
943
944 @Override
945 public int[] getRequiredTokens() {
946 return CommonUtil.EMPTY_INT_ARRAY;
947 }
948
949 @Override
950 public int[] getDefaultTokens() {
951 return new int[] {TokenTypes.ANNOTATION};
952 }
953
954 @Override
955 public int[] getAcceptableTokens() {
956 return CommonUtil.EMPTY_INT_ARRAY;
957 }
958
959 }
960
961 }