void (String text, String expected, Consumer<? super PsiBuilder> parser) { PsiBuilder builder = createBuilder(text); PsiBuilder.Marker rootMarker = builder.mark(); parser.accept(builder); rootMarker.done(ROOT); // check light tree composition FlyweightCapableTreeStructure<LighterASTNode> lightTree = builder.getLightTree(); assertEquals(expected, DebugUtil.lightTreeToString(lightTree, true)); // verify that light tree can be taken multiple times FlyweightCapableTreeStructure<LighterASTNode> lightTree2 = builder.getLightTree(); assertEquals(expected, DebugUtil.lightTreeToString(lightTree2, true)); // check heavy tree composition ASTNode root = builder.getTreeBuilt(); assertEquals(expected, DebugUtil.nodeTreeToString(root, true)); // check heavy vs. light tree merging PsiBuilder builder2 = createBuilder(text); PsiBuilder.Marker rootMarker2 = builder2.mark(); parser.accept(builder2); rootMarker2.done(ROOT); DiffTree.diff( new ASTStructure(root), builder2.getLightTree(), new ShallowNodeComparator<>() { @NotNull @Override public ThreeState deepEqual(@NotNull ASTNode oldNode, @NotNull LighterASTNode newNode) { return ThreeState.UNSURE; } @Override public boolean typesEqual(@NotNull ASTNode oldNode, @NotNull LighterASTNode newNode) { return true; } @Override public boolean hashCodesEqual(@NotNull ASTNode oldNode, @NotNull LighterASTNode newNode) { return true; } }, new DiffTreeChangeBuilder<>() { @Override public void nodeReplaced(@NotNull ASTNode oldChild, @NotNull LighterASTNode newChild) { fail("replaced(" + oldChild + "," + newChild.getTokenType() + ")"); } @Override public void nodeDeleted(@NotNull ASTNode oldParent, @NotNull ASTNode oldNode) { fail("deleted(" + oldParent + "," + oldNode + ")"); } @Override public void nodeInserted(@NotNull ASTNode oldParent, @NotNull LighterASTNode newNode, int pos) { fail("inserted(" + oldParent + "," + newNode.getTokenType() + ")"); } }, root.getText()); }