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
24 import java.io.File;
25 import java.io.Writer;
26 import java.nio.charset.StandardCharsets;
27 import java.nio.file.Files;
28 import java.text.MessageFormat;
29 import java.util.ArrayList;
30 import java.util.Arrays;
31 import java.util.BitSet;
32 import java.util.List;
33 import java.util.Locale;
34 import java.util.Set;
35 import java.util.function.Consumer;
36
37 import org.antlr.v4.runtime.CommonToken;
38 import org.junit.jupiter.api.Test;
39 import org.junit.jupiter.api.io.TempDir;
40
41 import com.puppycrawl.tools.checkstyle.api.DetailAST;
42 import com.puppycrawl.tools.checkstyle.api.TokenTypes;
43 import com.puppycrawl.tools.checkstyle.internal.utils.TestUtil;
44 import com.puppycrawl.tools.checkstyle.utils.CommonUtil;
45
46
47
48
49 public class DetailAstImplTest extends AbstractModuleTestSupport {
50
51
52 public static final Set<String> NO_ROOT_FILES = Set.of(
53
54 "InputGrammar.java",
55
56 "InputPackageDeclarationWithCommentOnly.java",
57 "InputSingleSpaceSeparatorEmpty.java",
58 "InputNoCodeInFile1.java",
59 "InputNoCodeInFile2.java",
60 "InputNoCodeInFile3.java",
61 "InputNoCodeInFile5.java"
62 );
63
64 @TempDir
65 public File temporaryFolder;
66
67 @Override
68 protected String getPackageLocation() {
69 return "com/puppycrawl/tools/checkstyle/api/detailast";
70 }
71
72 private static void invokeSetParentMethod(DetailAST instance, DetailAstImpl parent)
73 throws Exception {
74 TestUtil.invokeMethod(instance, "setParent", parent);
75 }
76
77 @Test
78 public void testInitialize() {
79 final DetailAstImpl ast = new DetailAstImpl();
80 ast.setText("test");
81 ast.setType(1);
82 ast.setLineNo(2);
83 ast.setColumnNo(3);
84
85 final DetailAstImpl copy = new DetailAstImpl();
86 copy.setText(ast.getText());
87 copy.setType(ast.getType());
88 copy.setLineNo(ast.getLineNo());
89 copy.setColumnNo(ast.getColumnNo());
90
91 assertWithMessage("Invalid text")
92 .that(copy.getText())
93 .isEqualTo("test");
94 assertWithMessage("Invalid type")
95 .that(copy.getType())
96 .isEqualTo(1);
97 assertWithMessage("Invalid line number")
98 .that(copy.getLineNo())
99 .isEqualTo(2);
100 assertWithMessage("Invalid column number")
101 .that(copy.getColumnNo())
102 .isEqualTo(3);
103 }
104
105 @Test
106 public void testInitializeToken() {
107 final CommonToken token = new CommonToken(1);
108 token.setText("test");
109 token.setLine(2);
110 token.setCharPositionInLine(3);
111
112 final DetailAstImpl ast = new DetailAstImpl();
113 ast.initialize(token);
114
115 assertWithMessage("Invalid text")
116 .that(ast.getText())
117 .isEqualTo("test");
118 assertWithMessage("Invalid type")
119 .that(ast.getType())
120 .isEqualTo(1);
121 assertWithMessage("Invalid line number")
122 .that(ast.getLineNo())
123 .isEqualTo(2);
124 assertWithMessage("Invalid column number")
125 .that(ast.getColumnNo())
126 .isEqualTo(3);
127 }
128
129 @Test
130 public void testGetChildCount() throws Exception {
131 final DetailAstImpl root = new DetailAstImpl();
132 final DetailAstImpl firstLevelA = new DetailAstImpl();
133 final DetailAstImpl firstLevelB = new DetailAstImpl();
134 final DetailAstImpl secondLevelA = new DetailAstImpl();
135
136 root.setFirstChild(firstLevelA);
137
138 invokeSetParentMethod(firstLevelA, root);
139 firstLevelA.setFirstChild(secondLevelA);
140 firstLevelA.setNextSibling(firstLevelB);
141
142 invokeSetParentMethod(firstLevelB, root);
143
144 invokeSetParentMethod(secondLevelA, root);
145
146 assertWithMessage("Invalid child count")
147 .that(secondLevelA.getChildCount())
148 .isEqualTo(0);
149 assertWithMessage("Invalid child count")
150 .that(firstLevelB.getChildCount())
151 .isEqualTo(0);
152 assertWithMessage("Invalid child count")
153 .that(firstLevelA.getChildCount())
154 .isEqualTo(1);
155 assertWithMessage("Invalid child count")
156 .that(root.getChildCount())
157 .isEqualTo(2);
158 assertWithMessage("Invalid child count")
159 .that(root.getNumberOfChildren())
160 .isEqualTo(2);
161
162 assertWithMessage("Previous sibling should be null")
163 .that(root.getPreviousSibling())
164 .isNull();
165 assertWithMessage("Previous sibling should be null")
166 .that(firstLevelA.getPreviousSibling())
167 .isNull();
168 assertWithMessage("Previous sibling should be null")
169 .that(secondLevelA.getPreviousSibling())
170 .isNull();
171 assertWithMessage("Invalid previous sibling")
172 .that(firstLevelB.getPreviousSibling())
173 .isEqualTo(firstLevelA);
174 }
175
176 @Test
177 public void testHasChildren() {
178 final DetailAstImpl root = new DetailAstImpl();
179 final DetailAstImpl child = new DetailAstImpl();
180 root.setFirstChild(child);
181
182 assertWithMessage("Root node should have children")
183 .that(root.hasChildren())
184 .isTrue();
185 assertWithMessage("Child node should have no children")
186 .that(child.hasChildren())
187 .isFalse();
188 }
189
190 @Test
191 public void testGetChildCountType() throws Exception {
192 final DetailAstImpl root = new DetailAstImpl();
193 final DetailAstImpl firstLevelA = new DetailAstImpl();
194 final DetailAstImpl firstLevelB = new DetailAstImpl();
195
196 root.setFirstChild(firstLevelA);
197
198 invokeSetParentMethod(firstLevelA, root);
199 firstLevelA.setNextSibling(firstLevelB);
200
201 firstLevelA.setType(TokenTypes.IDENT);
202 firstLevelB.setType(TokenTypes.EXPR);
203
204 invokeSetParentMethod(firstLevelB, root);
205
206 final int childCountLevelB = firstLevelB.getChildCount(0);
207 assertWithMessage("Invalid child count")
208 .that(childCountLevelB)
209 .isEqualTo(0);
210 final int childCountLevelA = firstLevelA.getChildCount(TokenTypes.EXPR);
211 assertWithMessage("Invalid child count")
212 .that(childCountLevelA)
213 .isEqualTo(0);
214 final int identTypeCount = root.getChildCount(TokenTypes.IDENT);
215 assertWithMessage("Invalid child count")
216 .that(identTypeCount)
217 .isEqualTo(1);
218 final int exprTypeCount = root.getChildCount(TokenTypes.EXPR);
219 assertWithMessage("Invalid child count")
220 .that(exprTypeCount)
221 .isEqualTo(1);
222 final int invalidTypeCount = root.getChildCount(0);
223 assertWithMessage("Invalid child count")
224 .that(invalidTypeCount)
225 .isEqualTo(0);
226 }
227
228 @Test
229 public void testSetSiblingNull() throws Exception {
230 final DetailAstImpl root = new DetailAstImpl();
231 final DetailAstImpl firstLevelA = new DetailAstImpl();
232
233 root.setFirstChild(firstLevelA);
234
235 assertWithMessage("Invalid child count")
236 .that(root.getChildCount())
237 .isEqualTo(1);
238
239 invokeSetParentMethod(firstLevelA, root);
240 firstLevelA.addPreviousSibling(null);
241 firstLevelA.addNextSibling(null);
242
243 assertWithMessage("Invalid child count")
244 .that(root.getChildCount())
245 .isEqualTo(1);
246 }
247
248 @Test
249 public void testAddPreviousSibling() {
250 final DetailAST previousSibling = new DetailAstImpl();
251 final DetailAstImpl instance = new DetailAstImpl();
252 final DetailAstImpl parent = new DetailAstImpl();
253
254 parent.setFirstChild(instance);
255
256 instance.addPreviousSibling(previousSibling);
257
258 assertWithMessage("unexpected result")
259 .that(instance.getPreviousSibling())
260 .isEqualTo(previousSibling);
261 assertWithMessage("unexpected result")
262 .that(parent.getFirstChild())
263 .isEqualTo(previousSibling);
264
265 final DetailAST newPreviousSibling = new DetailAstImpl();
266
267 instance.addPreviousSibling(newPreviousSibling);
268
269 assertWithMessage("unexpected result")
270 .that(instance.getPreviousSibling())
271 .isEqualTo(newPreviousSibling);
272 assertWithMessage("unexpected result")
273 .that(newPreviousSibling.getPreviousSibling())
274 .isEqualTo(previousSibling);
275 assertWithMessage("unexpected result")
276 .that(previousSibling.getNextSibling())
277 .isEqualTo(newPreviousSibling);
278 assertWithMessage("unexpected result")
279 .that(parent.getFirstChild())
280 .isEqualTo(previousSibling);
281
282 final DetailAstImpl secondNewPreviousSibling = new DetailAstImpl();
283 instance.addPreviousSibling(secondNewPreviousSibling);
284 assertWithMessage("unexpected result")
285 .that(secondNewPreviousSibling.getPreviousSibling())
286 .isEqualTo(newPreviousSibling);
287 assertWithMessage("unexpected result")
288 .that(secondNewPreviousSibling.getNextSibling())
289 .isEqualTo(instance);
290 assertWithMessage("unexpected result")
291 .that(newPreviousSibling.getNextSibling())
292 .isEqualTo(secondNewPreviousSibling);
293 assertWithMessage("unexpected result")
294 .that(secondNewPreviousSibling.getPreviousSibling().getPreviousSibling())
295 .isEqualTo(previousSibling);
296 assertWithMessage("unexpected result")
297 .that(instance.getPreviousSibling().getPreviousSibling().getPreviousSibling())
298 .isEqualTo(previousSibling);
299 }
300
301 @Test
302 public void testAddPreviousSiblingNullParent() {
303 final DetailAstImpl child = new DetailAstImpl();
304 final DetailAST newSibling = new DetailAstImpl();
305
306 child.addPreviousSibling(newSibling);
307
308 assertWithMessage("Invalid child token")
309 .that(newSibling.getNextSibling())
310 .isEqualTo(child);
311 assertWithMessage("Invalid child token")
312 .that(child.getPreviousSibling())
313 .isEqualTo(newSibling);
314 }
315
316 @Test
317 public void testInsertSiblingBetween() throws Exception {
318 final DetailAstImpl root = new DetailAstImpl();
319 final DetailAstImpl firstLevelA = new DetailAstImpl();
320 final DetailAST firstLevelB = new DetailAstImpl();
321 final DetailAST firstLevelC = new DetailAstImpl();
322
323 assertWithMessage("Invalid child count")
324 .that(root.getChildCount())
325 .isEqualTo(0);
326
327 root.setFirstChild(firstLevelA);
328 invokeSetParentMethod(firstLevelA, root);
329
330 assertWithMessage("Invalid child count")
331 .that(root.getChildCount())
332 .isEqualTo(1);
333
334 firstLevelA.addNextSibling(firstLevelB);
335 invokeSetParentMethod(firstLevelB, root);
336
337 assertWithMessage("Invalid next sibling")
338 .that(firstLevelA.getNextSibling())
339 .isEqualTo(firstLevelB);
340
341 firstLevelA.addNextSibling(firstLevelC);
342 invokeSetParentMethod(firstLevelC, root);
343
344 assertWithMessage("Invalid next sibling")
345 .that(firstLevelA.getNextSibling())
346 .isEqualTo(firstLevelC);
347 }
348
349 @Test
350 public void testBranchContains() {
351 final DetailAstImpl root = createToken(null, TokenTypes.CLASS_DEF);
352 final DetailAstImpl modifiers = createToken(root, TokenTypes.MODIFIERS);
353 createToken(modifiers, TokenTypes.LITERAL_PUBLIC);
354
355 assertWithMessage("invalid result")
356 .that(root.branchContains(TokenTypes.LITERAL_PUBLIC))
357 .isTrue();
358 assertWithMessage("invalid result")
359 .that(root.branchContains(TokenTypes.OBJBLOCK))
360 .isFalse();
361 }
362
363 private static DetailAstImpl createToken(DetailAstImpl root, int type) {
364 final DetailAstImpl result = new DetailAstImpl();
365 result.setType(type);
366 if (root != null) {
367 root.addChild(result);
368 }
369 return result;
370 }
371
372 @Test
373 public void testClearBranchTokenTypes() throws Exception {
374 final DetailAstImpl parent = new DetailAstImpl();
375 final DetailAstImpl child = new DetailAstImpl();
376 parent.setFirstChild(child);
377
378 final List<Consumer<DetailAstImpl>> clearBranchTokenTypesMethods = Arrays.asList(
379 child::setFirstChild,
380 child::setNextSibling,
381 child::addPreviousSibling,
382 child::addNextSibling,
383 child::addChild,
384 ast -> {
385 try {
386 TestUtil.invokeMethod(child, "setParent", ast);
387 }
388
389 catch (Exception exception) {
390 throw new IllegalStateException(exception);
391 }
392 }
393 );
394
395 for (Consumer<DetailAstImpl> method : clearBranchTokenTypesMethods) {
396 final BitSet branchTokenTypes = TestUtil.invokeMethod(parent, "getBranchTokenTypes");
397 method.accept(null);
398 final BitSet branchTokenTypes2 = TestUtil.invokeMethod(parent, "getBranchTokenTypes");
399 assertWithMessage("Branch token types are not equal")
400 .that(branchTokenTypes)
401 .isEqualTo(branchTokenTypes2);
402 assertWithMessage("Branch token types should not be the same")
403 .that(branchTokenTypes)
404 .isNotSameInstanceAs(branchTokenTypes2);
405 }
406 }
407
408 @Test
409 public void testCacheBranchTokenTypes() {
410 final DetailAST root = new DetailAstImpl();
411 final BitSet bitSet = new BitSet();
412 bitSet.set(999);
413
414 TestUtil.setInternalState(root, "branchTokenTypes", bitSet);
415 assertWithMessage("Branch tokens has changed")
416 .that(root.branchContains(999))
417 .isTrue();
418 }
419
420 @Test
421 public void testClearChildCountCache() {
422 final DetailAstImpl parent = new DetailAstImpl();
423 final DetailAstImpl child = new DetailAstImpl();
424 parent.setFirstChild(child);
425
426 final List<Consumer<DetailAstImpl>> clearChildCountCacheMethods = Arrays.asList(
427 child::setNextSibling,
428 child::addPreviousSibling,
429 child::addNextSibling
430 );
431
432 for (Consumer<DetailAstImpl> method : clearChildCountCacheMethods) {
433 final int startCount = parent.getChildCount();
434 method.accept(null);
435 final int intermediateCount = TestUtil.getInternalState(parent, "childCount",
436 Integer.class);
437 final int finishCount = parent.getChildCount();
438 assertWithMessage("Child count has changed")
439 .that(finishCount)
440 .isEqualTo(startCount);
441 assertWithMessage("Invalid child count")
442 .that(intermediateCount)
443 .isEqualTo(Integer.MIN_VALUE);
444 }
445
446 final int startCount = child.getChildCount();
447 child.addChild(null);
448 final int intermediateCount = TestUtil.getInternalState(child, "childCount", Integer.class);
449 final int finishCount = child.getChildCount();
450 assertWithMessage("Child count has changed")
451 .that(finishCount)
452 .isEqualTo(startCount);
453 assertWithMessage("Invalid child count")
454 .that(intermediateCount)
455 .isEqualTo(Integer.MIN_VALUE);
456 }
457
458 @Test
459 public void testCacheGetChildCount() {
460 final DetailAST root = new DetailAstImpl();
461
462 TestUtil.setInternalState(root, "childCount", 999);
463 assertWithMessage("Child count has changed")
464 .that(root.getChildCount())
465 .isEqualTo(999);
466 }
467
468 @Test
469 public void testAddNextSibling() {
470 final DetailAstImpl parent = new DetailAstImpl();
471 final DetailAstImpl child = new DetailAstImpl();
472 final DetailAstImpl sibling = new DetailAstImpl();
473 final DetailAstImpl newSibling = new DetailAstImpl();
474 final DetailAST newNextSibling = new DetailAstImpl();
475
476 parent.setFirstChild(child);
477 child.setNextSibling(sibling);
478 child.addNextSibling(newSibling);
479 newSibling.addNextSibling(newNextSibling);
480
481 assertWithMessage("Invalid previous sibling")
482 .that(newNextSibling.getPreviousSibling())
483 .isEqualTo(newSibling);
484 assertWithMessage("Invalid next sibling")
485 .that(newNextSibling.getNextSibling())
486 .isEqualTo(sibling);
487 assertWithMessage("Invalid next sibling")
488 .that(sibling.getNextSibling())
489 .isNull();
490 assertWithMessage("Invalid node")
491 .that(sibling.getPreviousSibling().getPreviousSibling())
492 .isEqualTo(newSibling);
493 assertWithMessage("Invalid node")
494 .that(newNextSibling.getPreviousSibling().getPreviousSibling())
495 .isEqualTo(child);
496 assertWithMessage("Invalid parent")
497 .that(newSibling.getParent())
498 .isEqualTo(parent);
499 assertWithMessage("Invalid next sibling")
500 .that(newSibling.getNextSibling())
501 .isEqualTo(newNextSibling);
502 assertWithMessage("Invalid child")
503 .that(child.getNextSibling())
504 .isEqualTo(newSibling);
505 }
506
507 @Test
508 public void testAddNextSibling2() {
509 final DetailAstImpl parent = new DetailAstImpl();
510 final DetailAstImpl child = new DetailAstImpl();
511 parent.setFirstChild(child);
512 final DetailAstImpl siblingOfChild = new DetailAstImpl();
513 child.addNextSibling(siblingOfChild);
514
515 assertWithMessage("Previous Sibling should be child")
516 .that(siblingOfChild.getPreviousSibling())
517 .isEqualTo(child);
518
519 final DetailAST nullChild = null;
520 siblingOfChild.addNextSibling(nullChild);
521 assertWithMessage("Expected to be null")
522 .that(siblingOfChild.getNextSibling())
523 .isNull();
524 assertWithMessage("Child count should be 2")
525 .that(parent.getChildCount())
526 .isEqualTo(2);
527 }
528
529 @Test
530 public void testAddNextSibling3() {
531 final DetailAstImpl parent = new DetailAstImpl();
532 final DetailAstImpl child = new DetailAstImpl();
533 final DetailAstImpl sibling = new DetailAstImpl();
534
535 parent.setFirstChild(child);
536 child.setNextSibling(sibling);
537 child.addNextSibling(null);
538
539 assertWithMessage("Invalid next sibling")
540 .that(child.getNextSibling())
541 .isEqualTo(sibling);
542 }
543
544 @Test
545 public void testAddNextSibling4() {
546 final DetailAstImpl parent = new DetailAstImpl();
547 parent.setText("Parent");
548 final DetailAstImpl child = new DetailAstImpl();
549 child.setText("Child");
550 final DetailAstImpl sibling = new DetailAstImpl();
551 sibling.setText("Sibling");
552 parent.setFirstChild(child);
553 child.addNextSibling(sibling);
554
555 assertWithMessage("Invalid next sibling")
556 .that(child.getNextSibling())
557 .isEqualTo(sibling);
558 }
559
560 @Test
561 public void testAddNextSiblingNullParent() {
562 final DetailAstImpl child = new DetailAstImpl();
563 final DetailAstImpl newSibling = new DetailAstImpl();
564 final DetailAstImpl oldParent = new DetailAstImpl();
565 oldParent.addChild(newSibling);
566 child.addNextSibling(newSibling);
567
568 assertWithMessage("Invalid parent")
569 .that(newSibling.getParent())
570 .isEqualTo(oldParent);
571 assertWithMessage("Invalid next sibling")
572 .that(newSibling.getNextSibling())
573 .isNull();
574 assertWithMessage("Invalid parent")
575 .that(child.getNextSibling())
576 .isSameInstanceAs(newSibling);
577 }
578
579 @Test
580 public void testGetLineNo() {
581 final DetailAstImpl root1 = new DetailAstImpl();
582 root1.setLineNo(1);
583 assertWithMessage("Invalid line number")
584 .that(root1.getLineNo())
585 .isEqualTo(1);
586
587 final DetailAstImpl root2 = new DetailAstImpl();
588 final DetailAstImpl firstChild = new DetailAstImpl();
589 firstChild.setLineNo(2);
590 root2.setFirstChild(firstChild);
591 assertWithMessage("Invalid line number")
592 .that(root2.getLineNo())
593 .isEqualTo(2);
594
595 final DetailAstImpl root3 = new DetailAstImpl();
596 final DetailAstImpl nextSibling = new DetailAstImpl();
597 nextSibling.setLineNo(3);
598 root3.setNextSibling(nextSibling);
599 assertWithMessage("Invalid line number")
600 .that(root3.getLineNo())
601 .isEqualTo(3);
602
603 final DetailAstImpl root4 = new DetailAstImpl();
604 final DetailAstImpl comment = new DetailAstImpl();
605 comment.setType(TokenTypes.SINGLE_LINE_COMMENT);
606 comment.setLineNo(3);
607 root4.setFirstChild(comment);
608 assertWithMessage("Invalid line number")
609 .that(root4.getLineNo())
610 .isEqualTo(Integer.MIN_VALUE);
611 }
612
613 @Test
614 public void testGetColumnNo() {
615 final DetailAstImpl root1 = new DetailAstImpl();
616 root1.setColumnNo(1);
617 assertWithMessage("Invalid column number")
618 .that(root1.getColumnNo())
619 .isEqualTo(1);
620
621 final DetailAstImpl root2 = new DetailAstImpl();
622 final DetailAstImpl firstChild = new DetailAstImpl();
623 firstChild.setColumnNo(2);
624 root2.setFirstChild(firstChild);
625 assertWithMessage("Invalid column number")
626 .that(root2.getColumnNo())
627 .isEqualTo(2);
628
629 final DetailAstImpl root3 = new DetailAstImpl();
630 final DetailAstImpl nextSibling = new DetailAstImpl();
631 nextSibling.setColumnNo(3);
632 root3.setNextSibling(nextSibling);
633 assertWithMessage("Invalid column number")
634 .that(root3.getColumnNo())
635 .isEqualTo(3);
636
637 final DetailAstImpl root4 = new DetailAstImpl();
638 final DetailAstImpl comment = new DetailAstImpl();
639 comment.setType(TokenTypes.SINGLE_LINE_COMMENT);
640 comment.setColumnNo(3);
641 root4.setFirstChild(comment);
642 assertWithMessage("Invalid column number")
643 .that(root4.getColumnNo())
644 .isEqualTo(Integer.MIN_VALUE);
645 }
646
647 @Test
648 public void testFindFirstToken() {
649 final DetailAstImpl root = new DetailAstImpl();
650 final DetailAstImpl firstChild = new DetailAstImpl();
651 firstChild.setType(TokenTypes.IDENT);
652 final DetailAstImpl secondChild = new DetailAstImpl();
653 secondChild.setType(TokenTypes.EXPR);
654 final DetailAstImpl thirdChild = new DetailAstImpl();
655 thirdChild.setType(TokenTypes.IDENT);
656
657 root.addChild(firstChild);
658 root.addChild(secondChild);
659 root.addChild(thirdChild);
660
661 assertWithMessage("Invalid result")
662 .that(firstChild.findFirstToken(TokenTypes.IDENT))
663 .isNull();
664 final DetailAST ident = root.findFirstToken(TokenTypes.IDENT);
665 assertWithMessage("Invalid result")
666 .that(ident)
667 .isEqualTo(firstChild);
668 final DetailAST expr = root.findFirstToken(TokenTypes.EXPR);
669 assertWithMessage("Invalid result")
670 .that(expr)
671 .isEqualTo(secondChild);
672 assertWithMessage("Invalid result")
673 .that(root.findFirstToken(0))
674 .isNull();
675 }
676
677 @Test
678 public void testManyComments() throws Exception {
679 final File file = new File(temporaryFolder, "InputDetailASTManyComments.java");
680
681 try (Writer bw = Files.newBufferedWriter(file.toPath(), StandardCharsets.UTF_8)) {
682 bw.write("/*\ncom.puppycrawl.tools.checkstyle.checks.TodoCommentCheck\n\n\n\n*/\n");
683 bw.write("class C {\n");
684 for (int i = 0; i <= 30000; i++) {
685 bw.write("// " + i + "\n");
686 }
687 bw.write("}\n");
688 }
689
690 final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
691 verifyWithInlineConfigParser(file.getAbsolutePath(), expected);
692 }
693
694 @Test
695 public void testTreeStructure() throws Exception {
696 final List<File> files = getAllFiles(
697 new File("src/test/resources/com/puppycrawl/tools/checkstyle"));
698
699 for (File file : files) {
700 final String fileName = file.getCanonicalPath();
701 final DetailAST rootAST = JavaParser.parseFile(new File(fileName),
702 JavaParser.Options.WITHOUT_COMMENTS);
703
704 assertWithMessage("file must return a root node: " + fileName)
705 .that(rootAST)
706 .isNotNull();
707
708 assertWithMessage("tree is valid")
709 .that(checkTree(fileName, rootAST))
710 .isTrue();
711 }
712 }
713
714 @Test
715 public void testToString() {
716 final DetailAstImpl ast = new DetailAstImpl();
717 ast.setText("text");
718 ast.setColumnNo(1);
719 ast.setLineNo(1);
720 assertWithMessage("Invalid text")
721 .that(ast.toString())
722 .isEqualTo("text[1x1]");
723 }
724
725 @Test
726 public void testRemoveChildren() {
727 final DetailAstImpl parent = new DetailAstImpl();
728 final DetailAstImpl child1 = new DetailAstImpl();
729 parent.setFirstChild(child1);
730 final DetailAstImpl child2 = new DetailAstImpl();
731 child1.setNextSibling(child2);
732
733 parent.removeChildren();
734
735 assertWithMessage("")
736 .that(parent.getChildCount())
737 .isEqualTo(0);
738 }
739
740 @Test
741 public void testAddChild() {
742 final DetailAstImpl grandParent = new DetailAstImpl();
743 grandParent.setText("grandparent");
744 final DetailAstImpl parent = new DetailAstImpl();
745 parent.setText("parent");
746 grandParent.setFirstChild(parent);
747
748 final DetailAstImpl child = new DetailAstImpl();
749 child.setText("child");
750 parent.setFirstChild(child);
751
752 final DetailAstImpl secondChild = new DetailAstImpl();
753 secondChild.setText("SecondChild");
754 parent.addChild(secondChild);
755
756 assertWithMessage("Invalid previous sibling")
757 .that(secondChild.getPreviousSibling())
758 .isEqualTo(child);
759 }
760
761 private static List<File> getAllFiles(File dir) {
762 final List<File> result = new ArrayList<>();
763
764 dir.listFiles(file -> {
765 if (file.isDirectory()) {
766 result.addAll(getAllFiles(file));
767 }
768 else if (file.getName().endsWith(".java")
769 && !NO_ROOT_FILES.contains(file.getName())) {
770 result.add(file);
771 }
772 return false;
773 });
774
775 return result;
776 }
777
778 private static boolean checkTree(final String filename, final DetailAST root) {
779 DetailAST curNode = root;
780 DetailAST parent = null;
781 DetailAST prev = null;
782 while (curNode != null) {
783 checkNode(curNode, parent, prev, filename, root);
784 DetailAST toVisit = curNode.getFirstChild();
785 if (toVisit == null) {
786 while (curNode != null && toVisit == null) {
787 toVisit = curNode.getNextSibling();
788 if (toVisit == null) {
789 curNode = curNode.getParent();
790 if (curNode != null) {
791 parent = curNode.getParent();
792 }
793 }
794 else {
795 prev = curNode;
796 curNode = toVisit;
797 }
798 }
799 }
800 else {
801 parent = curNode;
802 curNode = toVisit;
803 prev = null;
804 }
805 }
806
807 return true;
808 }
809
810 private static void checkNode(final DetailAST node,
811 final DetailAST parent,
812 final DetailAST prev,
813 final String filename,
814 final DetailAST root) {
815 final Object[] params = {
816 node, parent, prev, filename, root,
817 };
818 final MessageFormat badParentFormatter = new MessageFormat(
819 "Bad parent node={0} parent={1} filename={3} root={4}", Locale.ROOT);
820 final String badParentMsg = badParentFormatter.format(params);
821 assertWithMessage(badParentMsg)
822 .that(node.getParent())
823 .isEqualTo(parent);
824 final MessageFormat badPrevFormatter = new MessageFormat(
825 "Bad prev node={0} prev={2} parent={1} filename={3} root={4}", Locale.ROOT);
826 final String badPrevMsg = badPrevFormatter.format(params);
827 assertWithMessage(badPrevMsg)
828 .that(node.getPreviousSibling())
829 .isEqualTo(prev);
830 }
831
832 }