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