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.invokeVoidMethod(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.invokeVoidMethod(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,
397 "getBranchTokenTypes", BitSet.class);
398 method.accept(null);
399 final BitSet branchTokenTypes2 = TestUtil.invokeMethod(parent,
400 "getBranchTokenTypes", BitSet.class);
401 assertWithMessage("Branch token types are not equal")
402 .that(branchTokenTypes)
403 .isEqualTo(branchTokenTypes2);
404 assertWithMessage("Branch token types should not be the same")
405 .that(branchTokenTypes)
406 .isNotSameInstanceAs(branchTokenTypes2);
407 }
408 }
409
410 @Test
411 public void testCacheBranchTokenTypes() {
412 final DetailAST root = new DetailAstImpl();
413 final BitSet bitSet = new BitSet();
414 bitSet.set(999);
415
416 TestUtil.setInternalState(root, "branchTokenTypes", bitSet);
417 assertWithMessage("Branch tokens has changed")
418 .that(root.branchContains(999))
419 .isTrue();
420 }
421
422 @Test
423 public void testClearChildCountCache() {
424 final DetailAstImpl parent = new DetailAstImpl();
425 final DetailAstImpl child = new DetailAstImpl();
426 parent.setFirstChild(child);
427
428 final List<Consumer<DetailAstImpl>> clearChildCountCacheMethods = Arrays.asList(
429 child::setNextSibling,
430 child::addPreviousSibling,
431 child::addNextSibling
432 );
433
434 for (Consumer<DetailAstImpl> method : clearChildCountCacheMethods) {
435 final int startCount = parent.getChildCount();
436 method.accept(null);
437 final int intermediateCount = TestUtil.getInternalState(parent, "childCount",
438 Integer.class);
439 final int finishCount = parent.getChildCount();
440 assertWithMessage("Child count has changed")
441 .that(finishCount)
442 .isEqualTo(startCount);
443 assertWithMessage("Invalid child count")
444 .that(intermediateCount)
445 .isEqualTo(Integer.MIN_VALUE);
446 }
447
448 final int startCount = child.getChildCount();
449 child.addChild(null);
450 final int intermediateCount = TestUtil.getInternalState(child, "childCount", Integer.class);
451 final int finishCount = child.getChildCount();
452 assertWithMessage("Child count has changed")
453 .that(finishCount)
454 .isEqualTo(startCount);
455 assertWithMessage("Invalid child count")
456 .that(intermediateCount)
457 .isEqualTo(Integer.MIN_VALUE);
458 }
459
460 @Test
461 public void testCacheGetChildCount() {
462 final DetailAST root = new DetailAstImpl();
463
464 TestUtil.setInternalState(root, "childCount", 999);
465 assertWithMessage("Child count has changed")
466 .that(root.getChildCount())
467 .isEqualTo(999);
468 }
469
470 @Test
471 public void testAddNextSibling() {
472 final DetailAstImpl parent = new DetailAstImpl();
473 final DetailAstImpl child = new DetailAstImpl();
474 final DetailAstImpl sibling = new DetailAstImpl();
475 final DetailAstImpl newSibling = new DetailAstImpl();
476 final DetailAST newNextSibling = new DetailAstImpl();
477
478 parent.setFirstChild(child);
479 child.setNextSibling(sibling);
480 child.addNextSibling(newSibling);
481 newSibling.addNextSibling(newNextSibling);
482
483 assertWithMessage("Invalid previous sibling")
484 .that(newNextSibling.getPreviousSibling())
485 .isEqualTo(newSibling);
486 assertWithMessage("Invalid next sibling")
487 .that(newNextSibling.getNextSibling())
488 .isEqualTo(sibling);
489 assertWithMessage("Invalid next sibling")
490 .that(sibling.getNextSibling())
491 .isNull();
492 assertWithMessage("Invalid node")
493 .that(sibling.getPreviousSibling().getPreviousSibling())
494 .isEqualTo(newSibling);
495 assertWithMessage("Invalid node")
496 .that(newNextSibling.getPreviousSibling().getPreviousSibling())
497 .isEqualTo(child);
498 assertWithMessage("Invalid parent")
499 .that(newSibling.getParent())
500 .isEqualTo(parent);
501 assertWithMessage("Invalid next sibling")
502 .that(newSibling.getNextSibling())
503 .isEqualTo(newNextSibling);
504 assertWithMessage("Invalid child")
505 .that(child.getNextSibling())
506 .isEqualTo(newSibling);
507 }
508
509 @Test
510 public void testAddNextSibling2() {
511 final DetailAstImpl parent = new DetailAstImpl();
512 final DetailAstImpl child = new DetailAstImpl();
513 parent.setFirstChild(child);
514 final DetailAstImpl siblingOfChild = new DetailAstImpl();
515 child.addNextSibling(siblingOfChild);
516
517 assertWithMessage("Previous Sibling should be child")
518 .that(siblingOfChild.getPreviousSibling())
519 .isEqualTo(child);
520
521 final DetailAST nullChild = null;
522 siblingOfChild.addNextSibling(nullChild);
523 assertWithMessage("Expected to be null")
524 .that(siblingOfChild.getNextSibling())
525 .isNull();
526 assertWithMessage("Child count should be 2")
527 .that(parent.getChildCount())
528 .isEqualTo(2);
529 }
530
531 @Test
532 public void testAddNextSibling3() {
533 final DetailAstImpl parent = new DetailAstImpl();
534 final DetailAstImpl child = new DetailAstImpl();
535 final DetailAstImpl sibling = new DetailAstImpl();
536
537 parent.setFirstChild(child);
538 child.setNextSibling(sibling);
539 child.addNextSibling(null);
540
541 assertWithMessage("Invalid next sibling")
542 .that(child.getNextSibling())
543 .isEqualTo(sibling);
544 }
545
546 @Test
547 public void testAddNextSibling4() {
548 final DetailAstImpl parent = new DetailAstImpl();
549 parent.setText("Parent");
550 final DetailAstImpl child = new DetailAstImpl();
551 child.setText("Child");
552 final DetailAstImpl sibling = new DetailAstImpl();
553 sibling.setText("Sibling");
554 parent.setFirstChild(child);
555 child.addNextSibling(sibling);
556
557 assertWithMessage("Invalid next sibling")
558 .that(child.getNextSibling())
559 .isEqualTo(sibling);
560 }
561
562 @Test
563 public void testAddNextSiblingNullParent() {
564 final DetailAstImpl child = new DetailAstImpl();
565 final DetailAstImpl newSibling = new DetailAstImpl();
566 final DetailAstImpl oldParent = new DetailAstImpl();
567 oldParent.addChild(newSibling);
568 child.addNextSibling(newSibling);
569
570 assertWithMessage("Invalid parent")
571 .that(newSibling.getParent())
572 .isEqualTo(oldParent);
573 assertWithMessage("Invalid next sibling")
574 .that(newSibling.getNextSibling())
575 .isNull();
576 assertWithMessage("Invalid parent")
577 .that(child.getNextSibling())
578 .isSameInstanceAs(newSibling);
579 }
580
581 @Test
582 public void testGetLineNo() {
583 final DetailAstImpl root1 = new DetailAstImpl();
584 root1.setLineNo(1);
585 assertWithMessage("Invalid line number")
586 .that(root1.getLineNo())
587 .isEqualTo(1);
588
589 final DetailAstImpl root2 = new DetailAstImpl();
590 final DetailAstImpl firstChild = new DetailAstImpl();
591 firstChild.setLineNo(2);
592 root2.setFirstChild(firstChild);
593 assertWithMessage("Invalid line number")
594 .that(root2.getLineNo())
595 .isEqualTo(2);
596
597 final DetailAstImpl root3 = new DetailAstImpl();
598 final DetailAstImpl nextSibling = new DetailAstImpl();
599 nextSibling.setLineNo(3);
600 root3.setNextSibling(nextSibling);
601 assertWithMessage("Invalid line number")
602 .that(root3.getLineNo())
603 .isEqualTo(3);
604
605 final DetailAstImpl root4 = new DetailAstImpl();
606 final DetailAstImpl comment = new DetailAstImpl();
607 comment.setType(TokenTypes.SINGLE_LINE_COMMENT);
608 comment.setLineNo(3);
609 root4.setFirstChild(comment);
610 assertWithMessage("Invalid line number")
611 .that(root4.getLineNo())
612 .isEqualTo(Integer.MIN_VALUE);
613 }
614
615 @Test
616 public void testGetColumnNo() {
617 final DetailAstImpl root1 = new DetailAstImpl();
618 root1.setColumnNo(1);
619 assertWithMessage("Invalid column number")
620 .that(root1.getColumnNo())
621 .isEqualTo(1);
622
623 final DetailAstImpl root2 = new DetailAstImpl();
624 final DetailAstImpl firstChild = new DetailAstImpl();
625 firstChild.setColumnNo(2);
626 root2.setFirstChild(firstChild);
627 assertWithMessage("Invalid column number")
628 .that(root2.getColumnNo())
629 .isEqualTo(2);
630
631 final DetailAstImpl root3 = new DetailAstImpl();
632 final DetailAstImpl nextSibling = new DetailAstImpl();
633 nextSibling.setColumnNo(3);
634 root3.setNextSibling(nextSibling);
635 assertWithMessage("Invalid column number")
636 .that(root3.getColumnNo())
637 .isEqualTo(3);
638
639 final DetailAstImpl root4 = new DetailAstImpl();
640 final DetailAstImpl comment = new DetailAstImpl();
641 comment.setType(TokenTypes.SINGLE_LINE_COMMENT);
642 comment.setColumnNo(3);
643 root4.setFirstChild(comment);
644 assertWithMessage("Invalid column number")
645 .that(root4.getColumnNo())
646 .isEqualTo(Integer.MIN_VALUE);
647 }
648
649 @Test
650 public void testFindFirstToken() {
651 final DetailAstImpl root = new DetailAstImpl();
652 final DetailAstImpl firstChild = new DetailAstImpl();
653 firstChild.setType(TokenTypes.IDENT);
654 final DetailAstImpl secondChild = new DetailAstImpl();
655 secondChild.setType(TokenTypes.EXPR);
656 final DetailAstImpl thirdChild = new DetailAstImpl();
657 thirdChild.setType(TokenTypes.IDENT);
658
659 root.addChild(firstChild);
660 root.addChild(secondChild);
661 root.addChild(thirdChild);
662
663 assertWithMessage("Invalid result")
664 .that(firstChild.findFirstToken(TokenTypes.IDENT))
665 .isNull();
666 final DetailAST ident = root.findFirstToken(TokenTypes.IDENT);
667 assertWithMessage("Invalid result")
668 .that(ident)
669 .isEqualTo(firstChild);
670 final DetailAST expr = root.findFirstToken(TokenTypes.EXPR);
671 assertWithMessage("Invalid result")
672 .that(expr)
673 .isEqualTo(secondChild);
674 assertWithMessage("Invalid result")
675 .that(root.findFirstToken(0))
676 .isNull();
677 }
678
679 @Test
680 public void testManyComments() throws Exception {
681 final File file = new File(temporaryFolder, "InputDetailASTManyComments.java");
682
683 try (Writer bw = Files.newBufferedWriter(file.toPath(), StandardCharsets.UTF_8)) {
684 bw.write(
685 """
686
687
688
689
690
691 """);
692 bw.write("class C {\n");
693 for (int i = 0; i <= 30000; i++) {
694 bw.write("// " + i + "\n");
695 }
696 bw.write("}\n");
697 }
698
699 final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
700 verifyWithInlineConfigParser(file.getAbsolutePath(), expected);
701 }
702
703 @Test
704 public void testTreeStructure() throws Exception {
705 final List<File> files = getAllFiles(
706 new File("src/test/resources/com/puppycrawl/tools/checkstyle"));
707
708 for (File file : files) {
709 final String fileName = file.getCanonicalPath();
710 final DetailAST rootAST = JavaParser.parseFile(new File(fileName),
711 JavaParser.Options.WITHOUT_COMMENTS);
712
713 assertWithMessage("file must return a root node: " + fileName)
714 .that(rootAST)
715 .isNotNull();
716
717 assertWithMessage("tree is valid")
718 .that(checkTree(fileName, rootAST))
719 .isTrue();
720 }
721 }
722
723 @Test
724 public void testToString() {
725 final DetailAstImpl ast = new DetailAstImpl();
726 ast.setText("text");
727 ast.setColumnNo(1);
728 ast.setLineNo(1);
729 assertWithMessage("Invalid text")
730 .that(ast.toString())
731 .isEqualTo("text[1x1]");
732 }
733
734 @Test
735 public void testRemoveChildren() {
736 final DetailAstImpl parent = new DetailAstImpl();
737 final DetailAstImpl child1 = new DetailAstImpl();
738 parent.setFirstChild(child1);
739 final DetailAstImpl child2 = new DetailAstImpl();
740 child1.setNextSibling(child2);
741
742 parent.removeChildren();
743
744 assertWithMessage("")
745 .that(parent.getChildCount())
746 .isEqualTo(0);
747 }
748
749 @Test
750 public void testAddChild() {
751 final DetailAstImpl grandParent = new DetailAstImpl();
752 grandParent.setText("grandparent");
753 final DetailAstImpl parent = new DetailAstImpl();
754 parent.setText("parent");
755 grandParent.setFirstChild(parent);
756
757 final DetailAstImpl child = new DetailAstImpl();
758 child.setText("child");
759 parent.setFirstChild(child);
760
761 final DetailAstImpl secondChild = new DetailAstImpl();
762 secondChild.setText("SecondChild");
763 parent.addChild(secondChild);
764
765 assertWithMessage("Invalid previous sibling")
766 .that(secondChild.getPreviousSibling())
767 .isEqualTo(child);
768 }
769
770 private static List<File> getAllFiles(File dir) {
771 final List<File> result = new ArrayList<>();
772
773 dir.listFiles(file -> {
774 if (file.isDirectory()) {
775 result.addAll(getAllFiles(file));
776 }
777 else if (file.getName().endsWith(".java")
778 && !NO_ROOT_FILES.contains(file.getName())) {
779 result.add(file);
780 }
781 return false;
782 });
783
784 return result;
785 }
786
787 private static boolean checkTree(final String filename, final DetailAST root) {
788 DetailAST curNode = root;
789 DetailAST parent = null;
790 DetailAST prev = null;
791 while (curNode != null) {
792 checkNode(curNode, parent, prev, filename, root);
793 DetailAST toVisit = curNode.getFirstChild();
794 if (toVisit == null) {
795 while (curNode != null && toVisit == null) {
796 toVisit = curNode.getNextSibling();
797 if (toVisit == null) {
798 curNode = curNode.getParent();
799 if (curNode != null) {
800 parent = curNode.getParent();
801 }
802 }
803 else {
804 prev = curNode;
805 curNode = toVisit;
806 }
807 }
808 }
809 else {
810 parent = curNode;
811 curNode = toVisit;
812 prev = null;
813 }
814 }
815
816 return true;
817 }
818
819 private static void checkNode(final DetailAST node,
820 final DetailAST parent,
821 final DetailAST prev,
822 final String filename,
823 final DetailAST root) {
824 final Object[] params = {
825 node, parent, prev, filename, root,
826 };
827 final MessageFormat badParentFormatter = new MessageFormat(
828 "Bad parent node={0} parent={1} filename={3} root={4}", Locale.ROOT);
829 final String badParentMsg = badParentFormatter.format(params);
830 assertWithMessage(badParentMsg)
831 .that(node.getParent())
832 .isEqualTo(parent);
833 final MessageFormat badPrevFormatter = new MessageFormat(
834 "Bad prev node={0} prev={2} parent={1} filename={3} root={4}", Locale.ROOT);
835 final String badPrevMsg = badPrevFormatter.format(params);
836 assertWithMessage(badPrevMsg)
837 .that(node.getPreviousSibling())
838 .isEqualTo(prev);
839 }
840
841 }