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", Integer.class);
283 assertWithMessage("Invalid setter result")
284 .that(tabWidth)
285 .isEqualTo(1);
286 final Object configuration = TestUtil.getInternalState(treeWalker, "configuration",
287 Object.class);
288 assertWithMessage("Invalid configuration")
289 .that(configuration)
290 .isEqualTo(config);
291 }
292
293 @Test
294 public void testForInvalidCheckImplementation() throws Exception {
295 final DefaultConfiguration checkConfig = createModuleConfig(BadJavaDocCheck.class);
296 final String uniqueFileName = "file_" + UUID.randomUUID() + ".java";
297 final File pathToEmptyFile = new File(temporaryFolder, uniqueFileName);
298
299 try {
300 execute(checkConfig, pathToEmptyFile.toString());
301 assertWithMessage("Exception is expected").fail();
302 }
303 catch (CheckstyleException exc) {
304 assertWithMessage("Error message is unexpected")
305 .that(exc.getMessage())
306 .isEqualTo("cannot initialize module com.puppycrawl.tools.checkstyle."
307 + "TreeWalker - Check 'com.puppycrawl.tools.checkstyle."
308 + "TreeWalkerTest$BadJavaDocCheck' waits for comment type token "
309 + "('SINGLE_LINE_COMMENT') and should override "
310 + "'isCommentNodesRequired()' method to return 'true'");
311 assertWithMessage("Error message is unexpected")
312 .that(exc.getMessage())
313 .contains("isCommentNodesRequired");
314 }
315 }
316
317 @Test
318 public void testProcessNonJavaFiles() throws Exception {
319 final TreeWalker treeWalker = new TreeWalker();
320 final PackageObjectFactory factory = new PackageObjectFactory(
321 new HashSet<>(), Thread.currentThread().getContextClassLoader());
322 treeWalker.setModuleFactory(factory);
323 treeWalker.configure(new DefaultConfiguration("default config"));
324 final DefaultConfiguration childConfig = createModuleConfig(JavadocParagraphCheck.class);
325 treeWalker.setupChild(childConfig);
326 final File file = new File("input.java");
327 final List<String> lines =
328 new ArrayList<>(Arrays.asList("package com.puppycrawl.tools.checkstyle;", "",
329 "error public class InputTreeWalkerFileWithViolation {}"));
330 final FileText fileText = new FileText(file, lines);
331 treeWalker.setFileContents(new FileContents(fileText));
332 try {
333 treeWalker.processFiltered(file, fileText);
334 assertWithMessage("Exception expected").fail();
335 }
336 catch (CheckstyleException exc) {
337 assertWithMessage("Invalid exception message")
338 .that(exc.getMessage())
339 .isEqualTo("IllegalStateException occurred while parsing file input.java.");
340 }
341 }
342
343 @Test
344 public void testProcessNonJavaFilesWithoutException() throws Exception {
345 final TreeWalker treeWalker = new TreeWalker();
346 treeWalker.setTabWidth(1);
347 treeWalker.configure(new DefaultConfiguration("default config"));
348 final File file = new File(getPath("InputTreeWalkerNotJava.xml"));
349 final FileText fileText = new FileText(file, StandardCharsets.ISO_8859_1.name());
350 treeWalker.processFiltered(file, fileText);
351 final Collection<Checks> checks =
352 TestUtil.getInternalStateCollectionChecks(treeWalker, "ordinaryChecks");
353 assertWithMessage("No checks -> No parsing")
354 .that(checks)
355 .isEmpty();
356 }
357
358 @Test
359 public void testWithCacheWithNoViolation() throws Exception {
360 final String path = getPath("InputTreeWalkerWithCacheWithNoViolation.java");
361 final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
362 verifyWithInlineConfigParserTwice(path, expected);
363 }
364
365 @Test
366 public void testProcessWithParserThrowable() throws Exception {
367 final TreeWalker treeWalker = new TreeWalker();
368 treeWalker.configure(createModuleConfig(TypeNameCheck.class));
369 final PackageObjectFactory factory = new PackageObjectFactory(
370 new HashSet<>(), Thread.currentThread().getContextClassLoader());
371 treeWalker.setModuleFactory(factory);
372 treeWalker.setupChild(createModuleConfig(TypeNameCheck.class));
373 final File file = new File(temporaryFolder, "file.java");
374 final List<String> lines = new ArrayList<>();
375 lines.add(" classD a {} ");
376 final FileText fileText = new FileText(file, lines);
377 treeWalker.setFileContents(new FileContents(fileText));
378 try {
379 treeWalker.processFiltered(file, fileText);
380 assertWithMessage("Exception is expected").fail();
381 }
382 catch (CheckstyleException exception) {
383 assertWithMessage("Error message is unexpected")
384 .that(exception.getMessage())
385 .contains("occurred while parsing file");
386 }
387 }
388
389 @Test
390 public void testProcessWithRecognitionException() throws Exception {
391 final TreeWalker treeWalker = new TreeWalker();
392 treeWalker.configure(createModuleConfig(TypeNameCheck.class));
393 final PackageObjectFactory factory = new PackageObjectFactory(
394 new HashSet<>(), Thread.currentThread().getContextClassLoader());
395 treeWalker.setModuleFactory(factory);
396 treeWalker.setupChild(createModuleConfig(TypeNameCheck.class));
397 final File file = new File(temporaryFolder, "file.java");
398 final List<String> lines = new ArrayList<>();
399 lines.add(" class a%$# {} ");
400 final FileText fileText = new FileText(file, lines);
401 treeWalker.setFileContents(new FileContents(fileText));
402 try {
403 treeWalker.processFiltered(file, fileText);
404 assertWithMessage("Exception is expected").fail();
405 }
406 catch (CheckstyleException exception) {
407 assertWithMessage("Error message is unexpected")
408 .that(exception.getMessage())
409 .contains("IllegalStateException occurred while parsing file");
410 }
411 }
412
413 @Test
414 public void testRequiredTokenIsEmptyIntArray() throws Exception {
415 final File file = new File(temporaryFolder, "file.java");
416 try (Writer writer = Files.newBufferedWriter(file.toPath(), StandardCharsets.UTF_8)) {
417 final String configComment = """
418
419
420
421
422
423 """;
424 writer.write(configComment);
425 }
426 final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
427 verifyWithInlineConfigParserTwice(file.getPath(), expected);
428 }
429
430 @Test
431 public void testBehaviourWithZeroChecks() throws Exception {
432 final TreeWalker treeWalker = new TreeWalker();
433 final PackageObjectFactory factory = new PackageObjectFactory(
434 new HashSet<>(), Thread.currentThread().getContextClassLoader());
435 treeWalker.setModuleFactory(factory);
436
437 final File file = new File(temporaryFolder, "file.java");
438 final FileText fileText = new FileText(file, new ArrayList<>());
439
440 treeWalker.processFiltered(file, fileText);
441 final Collection<Checks> checks =
442 TestUtil.getInternalStateCollectionChecks(treeWalker, "ordinaryChecks");
443 assertWithMessage("No checks -> No parsing")
444 .that(checks)
445 .isEmpty();
446 }
447
448 @Test
449 public void testBehaviourWithOrdinaryAndCommentChecks() throws Exception {
450 final TreeWalker treeWalker = new TreeWalker();
451 treeWalker.configure(createModuleConfig(TypeNameCheck.class));
452 treeWalker.configure(createModuleConfig(CommentsIndentationCheck.class));
453 final PackageObjectFactory factory = new PackageObjectFactory(
454 new HashSet<>(), Thread.currentThread().getContextClassLoader());
455 treeWalker.setModuleFactory(factory);
456 treeWalker.setupChild(createModuleConfig(TypeNameCheck.class));
457 treeWalker.setupChild(createModuleConfig(CommentsIndentationCheck.class));
458 final File file = new File(temporaryFolder, "file.java");
459 final List<String> lines = new ArrayList<>();
460 lines.add(" class a%$# {} ");
461 final FileText fileText = new FileText(file, lines);
462 treeWalker.setFileContents(new FileContents(fileText));
463
464 try {
465 treeWalker.processFiltered(file, fileText);
466 assertWithMessage("file is not compilable, exception is expected").fail();
467 }
468 catch (CheckstyleException exception) {
469 final String message = "IllegalStateException occurred while parsing file";
470 assertWithMessage("Error message is unexpected")
471 .that(exception.getMessage())
472 .contains(message);
473 }
474 }
475
476 @Test
477 public void testSetupChild() throws Exception {
478 final TreeWalker treeWalker = new TreeWalker();
479 final PackageObjectFactory factory = new PackageObjectFactory(
480 new HashSet<>(), Thread.currentThread().getContextClassLoader());
481 treeWalker.setModuleFactory(factory);
482 treeWalker.setTabWidth(99);
483 treeWalker.finishLocalSetup();
484
485 final Configuration config = new DefaultConfiguration(
486 XpathFileGeneratorAstFilter.class.getName());
487
488 treeWalker.setupChild(config);
489
490 final Set<TreeWalkerFilter> filters =
491 TestUtil.getInternalStateSetTreeWalkerFilter(treeWalker, "filters");
492 final int tabWidth = TestUtil.getInternalState(filters.iterator().next(),
493 "tabWidth", Integer.class);
494
495 assertWithMessage("expected tab width")
496 .that(tabWidth)
497 .isEqualTo(99);
498 }
499
500 @Test
501 public void testBehaviourWithChecksAndFilters() throws Exception {
502
503 final String[] expected = {
504 "17:17: " + getCheckMessage(MemberNameCheck.class, "name.invalidPattern", "P",
505 "^[a-z][a-zA-Z0-9]*$"),
506 "12:17: " + getCheckMessage(MemberNameCheck.class, "name.invalidPattern", "I",
507 "^[a-z][a-zA-Z0-9]*$"),
508 };
509
510 verifyWithInlineConfigParserTwice(
511 getPath("InputTreeWalkerSuppressionCommentFilter.java"),
512 expected);
513 }
514
515 @Test
516 public void testMultiCheckOrder() throws Exception {
517
518 final String[] expected = {
519 "13:9: " + getCheckMessage(WhitespaceAfterCheck.class, "ws.notFollowed", "if"),
520 "13:9: " + getCheckMessage(WhitespaceAroundCheck.class, "ws.notFollowed", "if"),
521 };
522
523 verifyWithInlineConfigParserTwice(
524 getPath("InputTreeWalkerMultiCheckOrder.java"),
525 expected);
526 }
527
528 @Test
529 public void testMultiCheckOfSameTypeNoIdResultsInOrderingByHash() throws Exception {
530
531 final String[] expected = {
532 "15:28: " + getCheckMessage(ParameterNameCheck.class,
533 "name.invalidPattern", "V2", "^[a-z]([a-z0-9][a-zA-Z0-9]*)?$"),
534 "17:25: " + getCheckMessage(ParameterNameCheck.class,
535 "name.invalidPattern", "b", "^[a-z][a-z0-9][a-zA-Z0-9]*$"),
536 };
537
538 verifyWithInlineConfigParserTwice(
539 getPath("InputTreeWalkerMultiCheckOrder2.java"),
540 expected);
541 }
542
543 @Test
544 public void testFinishLocalSetupFullyInitialized() {
545 final TreeWalker treeWalker = new TreeWalker();
546 treeWalker.setSeverity("error");
547 treeWalker.setTabWidth(100);
548 treeWalker.finishLocalSetup();
549
550 final Context context = TestUtil.getInternalState(treeWalker, "childContext",
551 Context.class);
552 assertWithMessage("Severity differs from expected")
553 .that(context.get("severity"))
554 .isEqualTo("error");
555 assertWithMessage("Tab width differs from expected")
556 .that(context.get("tabWidth"))
557 .isEqualTo(String.valueOf(100));
558 }
559
560 @Test
561 public void testCheckInitIsCalledInTreeWalker() throws Exception {
562 final DefaultConfiguration checkConfig =
563 createModuleConfig(VerifyInitCheck.class);
564 final String uniqueFileName = "file_" + UUID.randomUUID() + ".pdf";
565 final File file = new File(temporaryFolder, uniqueFileName);
566 execute(checkConfig, file.getPath());
567 assertWithMessage("Init was not called")
568 .that(VerifyInitCheck.isInitWasCalled())
569 .isTrue();
570 }
571
572 @Test
573 public void testCheckDestroyIsCalledInTreeWalker() throws Exception {
574 VerifyDestroyCheck.resetDestroyWasCalled();
575 final DefaultConfiguration checkConfig =
576 createModuleConfig(VerifyDestroyCheck.class);
577 final String uniqueFileName = "file_" + UUID.randomUUID() + ".pdf";
578 final File file = new File(temporaryFolder, uniqueFileName);
579 execute(checkConfig, file.getPath());
580 assertWithMessage("Destroy was not called")
581 .that(VerifyDestroyCheck.isDestroyWasCalled())
582 .isTrue();
583 }
584
585 @Test
586 public void testCommentCheckDestroyIsCalledInTreeWalker() throws Exception {
587 VerifyDestroyCheck.resetDestroyWasCalled();
588 final DefaultConfiguration checkConfig =
589 createModuleConfig(VerifyDestroyCommentCheck.class);
590 final String uniqueFileName = "file_" + UUID.randomUUID() + ".pdf";
591 final File file = new File(temporaryFolder, uniqueFileName);
592 execute(checkConfig, file.getPath());
593 assertWithMessage("Destroy was not called")
594 .that(VerifyDestroyCheck.isDestroyWasCalled())
595 .isTrue();
596 }
597
598 @Test
599 public void testCacheWhenFileExternalResourceContentDoesNotChange() throws Exception {
600 final DefaultConfiguration filterConfig = createModuleConfig(SuppressionXpathFilter.class);
601 filterConfig.addProperty("file", getPath("InputTreeWalkerSuppressionXpathFilter.xml"));
602 final DefaultConfiguration treeWalkerConfig = createModuleConfig(TreeWalker.class);
603 treeWalkerConfig.addChild(filterConfig);
604
605 final DefaultConfiguration checkerConfig = createRootConfig(treeWalkerConfig);
606 final String uniqueFileName1 = "junit_" + UUID.randomUUID() + ".java";
607 final File cacheFile = new File(temporaryFolder, uniqueFileName1);
608 checkerConfig.addProperty("cacheFile", cacheFile.getPath());
609
610 final String uniqueFileName2 = "file_" + UUID.randomUUID() + ".java";
611 final File filePath = new File(temporaryFolder, uniqueFileName2);
612
613 execute(checkerConfig, filePath.toString());
614
615 execute(checkerConfig, filePath.toString());
616
617 assertWithMessage("External resource is not present in cache")
618 .that(Files.readString(cacheFile.toPath()))
619 .contains("InputTreeWalkerSuppressionXpathFilter.xml");
620 }
621
622 @Test
623 public void testTreeWalkerFilterAbsolutePath() throws Exception {
624
625 final String filePath = "src/test/resources/" + getPackageLocation()
626 + "/InputTreeWalkerSuppressionXpathFilterAbsolute.java";
627
628 final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
629 verifyWithInlineConfigParserTwice(filePath, expected);
630 }
631
632 @Test
633 public void testExternalResourceFiltersWithNoExternalResource() throws Exception {
634 final DefaultConfiguration checkConfig = createModuleConfig(EmptyStatementCheck.class);
635 final DefaultConfiguration filterConfig =
636 createModuleConfig(SuppressWithNearbyCommentFilter.class);
637 final DefaultConfiguration treeWalkerConfig = createModuleConfig(TreeWalker.class);
638 treeWalkerConfig.addChild(checkConfig);
639 treeWalkerConfig.addChild(filterConfig);
640
641 final DefaultConfiguration checkerConfig = createRootConfig(treeWalkerConfig);
642 final String uniqueFileName1 = "junit_" + UUID.randomUUID() + ".java";
643 final File cacheFile = new File(temporaryFolder, uniqueFileName1);
644 checkerConfig.addProperty("cacheFile", cacheFile.getPath());
645 final String uniqueFileName2 = "junit_" + UUID.randomUUID() + ".java";
646 final File filePath = new File(temporaryFolder, uniqueFileName2);
647
648 execute(checkerConfig, filePath.toString());
649
650 final long cacheSize = Files.size(cacheFile.toPath());
651 assertWithMessage("cacheFile should not be empty")
652 .that(cacheSize)
653 .isNotEqualTo(0);
654 }
655
656
657
658
659
660
661 @Test
662 public void testOrderOfCheckExecution() throws Exception {
663
664 final DefaultConfiguration configuration1 = createModuleConfig(AaCheck.class);
665 configuration1.addProperty("id", "2");
666 final DefaultConfiguration configuration2 = createModuleConfig(BbCheck.class);
667 configuration2.addProperty("id", "1");
668
669 final DefaultConfiguration treeWalkerConfig = createModuleConfig(TreeWalker.class);
670 treeWalkerConfig.addChild(configuration2);
671 treeWalkerConfig.addChild(configuration1);
672
673 final List<File> files =
674 Collections.singletonList(new File(getPath("InputTreeWalker2.java")));
675 final Checker checker = createChecker(treeWalkerConfig);
676
677 try {
678 checker.process(files);
679 assertWithMessage("exception is expected").fail();
680 }
681 catch (CheckstyleException exception) {
682 assertWithMessage("wrong order of Check executions")
683 .that(exception.getCause().getMessage())
684 .isEqualTo(AaCheck.class.toString());
685 }
686 }
687
688 @Test
689 public void testSkipFileOnJavaParseExceptionTrue() throws Exception {
690 final DefaultConfiguration config = createModuleConfig(TreeWalker.class);
691 config.addProperty("skipFileOnJavaParseException", "true");
692 config.addProperty("javaParseExceptionSeverity", "ignore");
693 config.addChild(createModuleConfig(ConstantNameCheck.class));
694
695 final File[] files = {
696 new File(getNonCompilablePath("InputTreeWalkerSkipParsingException.java")),
697 new File(getPath("InputTreeWalkerProperFileExtension.java")),
698 new File(getNonCompilablePath("InputTreeWalkerSkipParsingException2.java")),
699 };
700
701 final Checker checker = createChecker(config);
702 final Map<String, List<String>> expectedViolation = new HashMap<>();
703 expectedViolation.put(getPath("InputTreeWalkerProperFileExtension.java"),
704 Collections.singletonList(
705 "10:27: " + getCheckMessage(ConstantNameCheck.class,
706 MSG_INVALID_PATTERN, "k", "^[A-Z][A-Z0-9]*(_[A-Z0-9]+)*$")));
707 verify(checker, files, expectedViolation);
708 }
709
710
711
712
713
714
715
716
717
718
719 @Test
720 public void testSkipFileOnJavaParseExceptionFalse() throws Exception {
721 final DefaultConfiguration config = createModuleConfig(TreeWalker.class);
722 config.addProperty("skipFileOnJavaParseException", "false");
723 config.addChild(createModuleConfig(ConstantNameCheck.class));
724
725 final String[] files = {
726 getNonCompilablePath("InputTreeWalkerSkipParsingException2.java"),
727 getPath("InputTreeWalkerProperFileExtension.java"),
728 getNonCompilablePath("InputTreeWalkerSkipParsingException.java"),
729 };
730 final Exception ex = TestUtil.getExpectedThrowable(CheckstyleException.class,
731 () -> execute(config, files),
732 "Exception is expected");
733 assertWithMessage("Error message is unexpected")
734 .that(ex.getMessage())
735 .contains("Exception was thrown while processing");
736 }
737
738 @Test
739 public void testSkipFileOnJavaParseExceptionConfigSeverityIgnore() throws Exception {
740 final String path =
741 getNonCompilablePath(
742 "InputTreeWalkerSkipParsingExceptionConfigSeverityIgnore.java");
743 final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
744 verifyWithInlineXmlConfig(path, expected);
745 }
746
747 @Test
748 public void testSkipFileOnJavaParseExceptionConfigSeverityDefault() throws Exception {
749 final String path =
750 getNonCompilablePath(
751 "InputTreeWalkerSkipParsingExceptionConfigSeverityDefault.java");
752 final String[] expected = {
753 "1: " + getCheckMessage(TreeWalker.PARSE_EXCEPTION_MSG, "IllegalStateException")
754 + " occurred while parsing file " + path + ".",
755 };
756 verifyWithInlineXmlConfig(path, expected);
757 }
758
759 @Test
760 public void testSkipFileOnJavaParseExceptionSkipChecks() throws Exception {
761 final DefaultConfiguration config = createModuleConfig(TreeWalker.class);
762 config.addProperty("skipFileOnJavaParseException", "true");
763 config.addProperty("javaParseExceptionSeverity", "ignore");
764 config.addChild(createModuleConfig(NoCodeInFileCheck.class));
765
766 final Checker checker = createChecker(config);
767
768 final File[] files = {
769 new File(getNonCompilablePath("InputTreeWalkerSkipParsingException.java")),
770 new File(getPath("InputTreeWalkerProperFileExtension.java")),
771 new File(getNonCompilablePath("InputTreeWalkerSkipParsingException2.java")),
772 };
773 final Map<String, List<String>> expectedViolation = new HashMap<>();
774 expectedViolation.put(getPath("InputTreeWalkerProperFileExtension.java"),
775 new ArrayList<>());
776
777 verify(checker, files, expectedViolation);
778 }
779
780 @Test
781 public void testJavaParseExceptionSeverityDefaultError() throws Exception {
782 final DefaultConfiguration config = createModuleConfig(TreeWalker.class);
783 config.addProperty("skipFileOnJavaParseException", "true");
784 config.addChild(createModuleConfig(NoCodeInFileCheck.class));
785
786 final Checker checker = createChecker(config);
787
788 final File[] files = {
789 new File(getNonCompilablePath("InputTreeWalkerSkipParsingException.java")),
790 new File(getPath("InputTreeWalkerProperFileExtension.java")),
791 };
792
793 final Map<String, List<String>> expectedViolation = new HashMap<>();
794
795 expectedViolation.put(getPath("InputTreeWalkerProperFileExtension.java"),
796 new ArrayList<>());
797 expectedViolation.put(getNonCompilablePath("InputTreeWalkerSkipParsingException.java"),
798 List.of("1: Java specific (TreeWalker-based) modules are skipped due to an "
799 + "exception during parsing - "
800 + "IllegalStateException occurred while parsing file "
801 + getNonCompilablePath("InputTreeWalkerSkipParsingException.java") + "."));
802
803 verify(checker, files, expectedViolation);
804 }
805
806 public static class BadJavaDocCheck extends AbstractCheck {
807
808 @Override
809 public int[] getDefaultTokens() {
810 return getAcceptableTokens();
811 }
812
813 @Override
814 public int[] getAcceptableTokens() {
815 return new int[] {TokenTypes.SINGLE_LINE_COMMENT};
816 }
817
818 @Override
819 public int[] getRequiredTokens() {
820 return getAcceptableTokens();
821 }
822
823 }
824
825 public static class VerifyInitCheck extends AbstractCheck {
826
827 private static boolean initWasCalled;
828
829 @Override
830 public int[] getDefaultTokens() {
831 return CommonUtil.EMPTY_INT_ARRAY;
832 }
833
834 @Override
835 public int[] getAcceptableTokens() {
836 return getDefaultTokens();
837 }
838
839 @Override
840 public int[] getRequiredTokens() {
841 return getDefaultTokens();
842 }
843
844 @Override
845 public void init() {
846 super.init();
847 initWasCalled = true;
848 }
849
850 public static boolean isInitWasCalled() {
851 return initWasCalled;
852 }
853
854 }
855
856 public static class VerifyDestroyCheck extends AbstractCheck {
857
858 private static boolean destroyWasCalled;
859
860 @Override
861 public int[] getDefaultTokens() {
862 return CommonUtil.EMPTY_INT_ARRAY;
863 }
864
865 @Override
866 public int[] getAcceptableTokens() {
867 return getDefaultTokens();
868 }
869
870 @Override
871 public int[] getRequiredTokens() {
872 return getDefaultTokens();
873 }
874
875 @Override
876 public void destroy() {
877 super.destroy();
878 destroyWasCalled = true;
879 }
880
881 public static void resetDestroyWasCalled() {
882 destroyWasCalled = false;
883 }
884
885 public static boolean isDestroyWasCalled() {
886 return destroyWasCalled;
887 }
888
889 }
890
891 public static class VerifyDestroyCommentCheck extends VerifyDestroyCheck {
892
893 @Override
894 public boolean isCommentNodesRequired() {
895 return true;
896 }
897
898 }
899
900 public static class AaCheck extends AbstractCheck {
901
902 @Override
903 public int[] getDefaultTokens() {
904 return new int[0];
905 }
906
907 @Override
908 public int[] getAcceptableTokens() {
909 return new int[0];
910 }
911
912 @Override
913 public int[] getRequiredTokens() {
914 return new int[0];
915 }
916
917 @Override
918 public void beginTree(DetailAST rootAST) {
919 throw new IllegalStateException(AaCheck.class.toString());
920 }
921
922 }
923
924 public static class BbCheck extends AbstractCheck {
925
926 @Override
927 public int[] getDefaultTokens() {
928 return new int[0];
929 }
930
931 @Override
932 public int[] getAcceptableTokens() {
933 return new int[0];
934 }
935
936 @Override
937 public int[] getRequiredTokens() {
938 return new int[0];
939 }
940
941 @Override
942 public void beginTree(DetailAST rootAST) {
943 throw new IllegalStateException(BbCheck.class.toString());
944 }
945
946 }
947
948 public static class RequiredTokenIsEmptyIntArray extends AbstractCheck {
949
950 @Override
951 public int[] getRequiredTokens() {
952 return CommonUtil.EMPTY_INT_ARRAY;
953 }
954
955 @Override
956 public int[] getDefaultTokens() {
957 return new int[] {TokenTypes.ANNOTATION};
958 }
959
960 @Override
961 public int[] getAcceptableTokens() {
962 return CommonUtil.EMPTY_INT_ARRAY;
963 }
964
965 }
966
967 }