1 package com
.intellij
.ide
.util
.treeView
;
3 import com
.intellij
.openapi
.util
.Disposer
;
4 import com
.intellij
.openapi
.util
.Ref
;
5 import com
.intellij
.util
.Time
;
6 import com
.intellij
.util
.WaitFor
;
7 import com
.intellij
.util
.ui
.UIUtil
;
8 import junit
.framework
.TestSuite
;
11 import javax
.swing
.tree
.DefaultMutableTreeNode
;
12 import javax
.swing
.tree
.TreePath
;
14 public class TreeUiTest
extends AbstractTreeBuilderTest
{
16 public TreeUiTest(boolean passthrougth
) {
20 public TreeUiTest(boolean yieldingUiBuild
, boolean bgStructureBuilding
) {
21 super(yieldingUiBuild
, bgStructureBuilding
);
24 public void testEmptyInvisibleRoot() throws Exception
{
25 myTree
.setRootVisible(false);
33 buildNode("/", false);
36 myTree
.setRootVisible(true);
37 buildNode("/", false);
41 public void testVisibleRoot() throws Exception
{
42 myTree
.setRootVisible(true);
43 buildStructure(myRoot
);
50 public void testInvisibleRoot() throws Exception
{
51 myTree
.setRootVisible(false);
52 buildStructure(myRoot
);
59 collapsePath(new TreePath(myTreeModel
.getRoot()));
69 buildNode("com", true);
83 public void testAutoExpand() throws Exception
{
84 buildStructure(myRoot
);
87 myAutoExpand
.add(new NodeElement("/"));
88 buildStructure(myRoot
);
97 myAutoExpand
.add(new NodeElement("jetbrains"));
107 collapsePath(getPath("jetbrains"));
114 updateFrom(new NodeElement("org"));
121 updateFrom(new NodeElement("jetbrains"));
130 public void testAutoExpandDeep() throws Exception
{
131 myTree
.setRootVisible(false);
132 //myAutoExpand.add(new NodeElement("jetbrains"));
133 myAutoExpand
.add(new NodeElement("fabrique"));
136 buildStructure(myRoot
);
137 //assertTree("+/\n");
139 expand(getPath("/"));
140 expand(getPath("jetbrains"));
149 collapsePath(getPath("/"));
152 expand(getPath("/"));
153 expand(getPath("jetbrains"));
163 collapsePath(getPath("jetbrains"));
170 expand(getPath("jetbrains"));
182 public void testAutoExpandInNonVisibleNode() throws Exception
{
183 myAutoExpand
.add(new NodeElement("fabrique"));
184 buildStructure(myRoot
);
186 expand(getPath("/"));
194 public void testSmartExpand() throws Exception
{
195 mySmartExpand
= true;
196 buildStructure(myRoot
);
199 expand(getPath("/"));
206 expand(getPath("jetbrains"));
215 collapsePath(getPath("jetbrains"));
229 mySmartExpand
= false;
230 collapsePath(getPath("jetbrains"));
237 expand(getPath("jetbrains"));
247 public void testClear() throws Exception
{
248 getBuilder().getUi().setClearOnHideDelay(10 * Time
.SECOND
);
250 buildStructure(myRoot
);
254 final DefaultMutableTreeNode openApiNode
= findNode("openapi", false);
255 final DefaultMutableTreeNode ideNode
= findNode("ide", false);
256 final DefaultMutableTreeNode runnerNode
= findNode("runner", false);
257 final DefaultMutableTreeNode rcpNode
= findNode("rcp", false);
259 assertNull(openApiNode
);
261 assertNull(runnerNode
);
264 buildNode(myOpenApi
, true);
265 buildNode(myIde
, true);
266 buildNode(myRunner
, false);
270 assertNull(findNode("openapi", true));
271 assertNull(findNode("ide", true));
272 assertNull(findNode("runner", false));
273 assertNull(findNode("rcp", false));
289 getMyBuilder().myWasCleanedUp
= false;
305 buildNode(myFabrique
.myElement
, true, false);
318 public void testUpdateRestoresState() throws Exception
{
319 buildStructure(myRoot
);
321 buildNode(myOpenApi
, true);
322 buildNode(myIde
, true);
323 buildNode(myRunner
, false);
341 final AbstractTreeBuilderTest
.Node newRoot
= myRoot
.addChild("newRoot");
343 buildStructure(newRoot
);
360 public void testSelect() throws Exception
{
361 buildStructure(myRoot
);
366 buildNode(myOpenApi
, true);
376 buildNode("fabrique", true);
389 public void testCallbackOnceOnSelect() throws Exception
{
390 buildStructure(myRoot
);
392 assertCallbackOnce(new TreeAction() {
393 public void run(Runnable onDone
) {
394 getMyBuilder().select(new Object
[] {new NodeElement("intellij"), new NodeElement("fabrique")}, onDone
);
409 public void testCallbackOnceOnExpand() throws Exception
{
410 buildStructure(myRoot
);
412 assertCallbackOnce(new TreeAction() {
413 public void run(Runnable onDone
) {
414 getMyBuilder().expand(new Object
[] {new NodeElement("intellij"), new NodeElement("fabrique")}, onDone
);
432 public void testNoInfiniteAutoExpand() throws Exception
{
433 mySmartExpand
= false;
435 assertNoInfiniteAutoExpand(new Runnable() {
437 myAutoExpand
.add(new NodeElement("level2"));
438 myAutoExpand
.add(new NodeElement("level3"));
439 myAutoExpand
.add(new NodeElement("level4"));
440 myAutoExpand
.add(new NodeElement("level5"));
441 myAutoExpand
.add(new NodeElement("level6"));
442 myAutoExpand
.add(new NodeElement("level7"));
443 myAutoExpand
.add(new NodeElement("level8"));
444 myAutoExpand
.add(new NodeElement("level9"));
445 myAutoExpand
.add(new NodeElement("level10"));
446 myAutoExpand
.add(new NodeElement("level11"));
447 myAutoExpand
.add(new NodeElement("level12"));
448 myAutoExpand
.add(new NodeElement("level13"));
449 myAutoExpand
.add(new NodeElement("level14"));
450 myAutoExpand
.add(new NodeElement("level15"));
455 public void testNoInfiniteSmartExpand() throws Exception
{
456 mySmartExpand
= false;
458 assertNoInfiniteAutoExpand(new Runnable() {
460 mySmartExpand
= true;
465 private void assertNoInfiniteAutoExpand(final Runnable enableExpand
) throws Exception
{
466 class Level
extends Node
{
470 Level(Node parent
, int level
) {
471 super(parent
, "level" + level
);
476 public Object
[] getChildElements() {
477 if (super.getChildElements().length
== 0) {
478 addChild(new Level(this, myLevel
+ 1));
481 return super.getChildElements();
485 myRoot
.addChild(new Level(myRoot
, 0));
488 buildNode("level0", false);
496 expand(getPath("level1"));
507 expand(getPath("level6"));
523 private void assertCallbackOnce(final TreeAction action
) {
524 final int[] notifyCount
= new int[1];
525 final boolean[] done
= new boolean[1];
526 invokeLaterIfNeeded(new Runnable() {
528 action
.run(new Runnable() {
539 protected boolean condition() {
540 return done
[0] && getMyBuilder().getUi().isReady();
545 assertEquals(1, notifyCount
[0]);
548 public void testSelectMultiple() throws Exception
{
549 buildStructure(myRoot
);
553 select(new Object
[] {new NodeElement("openapi"), new NodeElement("fabrique")}, false);
565 public void testUnsuccessfulSelect() throws Exception
{
566 buildStructure(myRoot
);
567 select(new Object
[] {new NodeElement("openapi"), new NodeElement("fabrique")}, false);
579 select(new Object
[] {new NodeElement("whatever1"), new NodeElement("whatever2")}, false);
593 public void testSelectionWhenChildMoved() throws Exception
{
594 buildStructure(myRoot
);
597 final Node refactoring
= myCom
.getChildNode("intellij").addChild("refactoring");
599 buildNode("refactoring", true);
611 refactoring
.delete();
612 myCom
.getChildNode("intellij").getChildNode("openapi").addChild("refactoring");
628 public void testSelectionGoesToParentWhenOnlyChildRemove() throws Exception
{
629 buildStructure(myRoot
);
630 buildNode("openapi", true);
641 myCom
.getChildNode("intellij").getChildNode("openapi").delete();
654 public void testSelectionGoesToParentWhenOnlyChildMoved() throws Exception
{
655 buildStructure(myRoot
);
656 buildNode("openapi", true);
667 myCom
.getChildNode("intellij").getChildNode("openapi").delete();
668 myRoot
.getChildNode("xunit").addChild("openapi");
683 public void testSelectionGoesToParentWhenOnlyChildMoved2() throws Exception
{
684 buildStructure(myRoot
);
685 buildNode("openapi", true);
696 myCom
.getChildNode("intellij").getChildNode("openapi").delete();
697 myRoot
.getChildNode("xunit").addChild("openapi");
699 getBuilder().addSubtreeToUpdateByElement(new NodeElement("intellij"));
700 getBuilder().addSubtreeToUpdateByElement(new NodeElement("xunit"));
703 doAndWaitForBuilder(new Runnable() {
705 getBuilder().getUpdater().performUpdate();
720 public void testSelectionGoesToParentWhenChildrenFold() throws Exception
{
721 buildStructure(myRoot
);
722 buildNode("openapi", true);
734 final DefaultMutableTreeNode node
= findNode("intellij", false);
735 collapsePath(new TreePath(node
.getPath()));
747 public void testQueryStructure() throws Exception
{
748 buildStructure(myRoot
);
751 assertUpdates("/: update");
753 expand(getPath("/"));
759 assertUpdates("/: update getChildren\n" +
760 "com: update getChildren\n" +
761 "eclipse: update\n" +
762 "fabrique: update\n" +
763 "intellij: update\n" +
764 "jetbrains: update getChildren\n" +
765 "org: update getChildren\n" +
767 "xunit: update getChildren");
769 collapsePath(getPath("/"));
773 expand(getPath("/"));
779 assertUpdates("/: update getChildren\n" +
780 "com: update getChildren\n" +
781 "eclipse: update\n" +
782 "fabrique: update\n" +
783 "intellij: update\n" +
784 "jetbrains: update getChildren\n" +
785 "org: update getChildren\n" +
787 "xunit: update getChildren");
796 assertUpdates("/: update getChildren\n" +
797 "com: update getChildren\n" +
798 "eclipse: update\n" +
799 "fabrique: update\n" +
800 "intellij: update\n" +
801 "jetbrains: update getChildren\n" +
802 "org: update getChildren\n" +
804 "xunit: update getChildren");
808 public void testQueryStructureWhenExpand() throws Exception
{
809 buildStructure(myRoot
);
812 assertUpdates("/: update");
814 buildNode("ide", false);
823 assertUpdates("/: update getChildren\n" +
824 "com: update getChildren\n" +
825 "eclipse: update\n" +
826 "fabrique: update (2) getChildren\n" +
827 "ide: update getChildren\n" +
828 "intellij: update\n" +
829 "jetbrains: update getChildren\n" +
830 "org: update getChildren\n" +
832 "xunit: update getChildren");
836 public void testQueryStructureIsAlwaysLeaf() throws Exception
{
837 buildStructure(myRoot
);
838 myStructure
.addLeaf(new NodeElement("openapi"));
840 buildNode("jetbrains", false);
848 assertUpdates("/: update (2) getChildren\n" +
849 "com: update getChildren\n" +
850 "eclipse: update\n" +
851 "fabrique: update (2) getChildren\n" +
853 "intellij: update\n" +
854 "jetbrains: update getChildren\n" +
855 "org: update getChildren\n" +
857 "xunit: update getChildren");
859 expand(getPath("fabrique"));
867 assertUpdates("ide: update getChildren");
870 buildNode("com", false);
880 myElementUpdate
.clear();
882 expand(getPath("intellij"));
896 public void testToggleIsAlwaysLeaf() throws Exception
{
897 buildStructure(myRoot
);
899 buildNode("openapi", true);
909 myStructure
.addLeaf(new NodeElement("intellij"));
911 updateFrom(new NodeElement("com"));
920 myStructure
.removeLeaf(new NodeElement("intellij"));
921 updateFrom(new NodeElement("com"));
930 expand(getPath("intellij"));
943 public void testSorting() throws Exception
{
944 buildStructure(myRoot
);
947 buildNode("/", false);
972 updateFrom(new NodeElement("/"), false);
981 expand(getPath("com"));
988 assertSorted("intellij");
991 public void testResorting() throws Exception
{
992 final boolean invert
[] = new boolean[] {false};
993 NodeDescriptor
.NodeComparator
<NodeDescriptor
> c
= new NodeDescriptor
.NodeComparator
<NodeDescriptor
>() {
994 public int compare(NodeDescriptor o1
, NodeDescriptor o2
) {
995 return invert
[0] ? AlphaComparator
.INSTANCE
.compare(o2
, o1
) : AlphaComparator
.INSTANCE
.compare(o1
, o2
);
999 myComparator
.setDelegate(c
);
1001 buildStructure(myRoot
);
1003 buildNode("/", false);
1014 assertTrue(getMyBuilder().getUi().myOwnComparatorStamp
> c
.getStamp());
1018 updateFrom(new NodeElement("/"), false);
1026 public void testRestoreSelectionOfRemovedElement() throws Exception
{
1027 buildStructure(myRoot
);
1028 buildNode("openapi", true);
1038 removeFromParentButKeepRef(new NodeElement("openapi"));
1050 public void testElementMove1() throws Exception
{
1051 assertMove(new Runnable() {
1053 getBuilder().getUpdater().addSubtreeToUpdateByElement(new NodeElement("com"));
1054 getBuilder().getUpdater().addSubtreeToUpdateByElement(new NodeElement("jetbrains"));
1059 public void testElementMove2() throws Exception
{
1060 assertMove(new Runnable() {
1062 getBuilder().getUpdater().addSubtreeToUpdateByElement(new NodeElement("jetbrains"));
1063 getBuilder().getUpdater().addSubtreeToUpdateByElement(new NodeElement("com"));
1068 public void testSelectionOnDelete() throws Exception
{
1069 doTestSelectionOnDelete(false);
1072 public void testSelectionOnDeleteButKeepRef() throws Exception
{
1073 doTestSelectionOnDelete(true);
1076 private void doTestSelectionOnDelete(boolean keepRef
) throws Exception
{
1077 myComparator
.setDelegate(new NodeDescriptor
.NodeComparator
<NodeDescriptor
>() {
1078 public int compare(NodeDescriptor o1
, NodeDescriptor o2
) {
1079 boolean isParent1
= myStructure
._getChildElements(o1
.getElement(), false).length
> 0;
1080 boolean isParent2
= myStructure
._getChildElements(o2
.getElement(), false).length
> 0;
1082 int result
= AlphaComparator
.INSTANCE
.compare(o1
, o2
);
1096 buildStructure(myRoot
);
1097 myRoot
.addChild("toDelete");
1099 select(new NodeElement("toDelete"), false);
1108 removeFromParentButKeepRef(new NodeElement("toDelete"));
1110 myStructure
.getNodeFor(new NodeElement("toDelete")).delete();
1113 getMyBuilder().addSubtreeToUpdateByElement(new NodeElement("/"));
1122 public void testSelectWhenUpdatesArePending() throws Exception
{
1123 getBuilder().getUpdater().setDelay(1000);
1125 buildStructure(myRoot
);
1127 buildNode("intellij", false);
1128 select(new Object
[] {new NodeElement("intellij")}, false);
1138 myIntellij
.addChild("ui");
1140 DefaultMutableTreeNode intellijNode
= findNode("intellij", false);
1141 assertTrue(myTree
.isExpanded(new TreePath(intellijNode
.getPath())));
1142 getMyBuilder().addSubtreeToUpdate(intellijNode
);
1143 assertFalse(getMyBuilder().getUi().isReady());
1145 select(new Object
[] {new NodeElement("ui")}, false);
1156 public void testAddNewElementToLeafElementAlwaysShowPlus() throws Exception
{
1157 myAlwaysShowPlus
.add(new NodeElement("openapi"));
1159 buildStructure(myRoot
);
1160 select(new Object
[] {new NodeElement("openapi")}, false);
1170 expand(getPath("openapi"));
1180 myOpenApi
.addChild("ui");
1182 getMyBuilder().addSubtreeToUpdate(findNode("openapi", false));
1193 public void testAddNewElementToLeafElement() throws Exception
{
1194 buildStructure(myRoot
);
1195 select(new Object
[] {new NodeElement("openapi")}, false);
1205 expand(getPath("openapi"));
1215 myOpenApi
.addChild("ui");
1217 getMyBuilder().addSubtreeToUpdate(findNode("openapi", false));
1229 private void assertMove(Runnable updateRoutine
) throws Exception
{
1230 buildStructure(myRoot
);
1232 buildNode("intellij", true);
1240 AbstractTreeBuilderTest
.Node intellij
= removeFromParentButKeepRef(new NodeElement("intellij"));
1241 myRoot
.getChildNode("jetbrains").addChild(intellij
);
1243 updateRoutine
.run();
1256 public void testChangeRootElement() throws Exception
{
1257 buildStructure(myRoot
);
1259 select(new NodeElement("com"), false);
1267 myRoot
= new Node(null, "root");
1268 myStructure
.reinitRoot(myRoot
);
1270 myRoot
.addChild("com");
1273 assertTree("+root\n");
1276 public void testReleaseBuilderDuringUpdate() throws Exception
{
1277 assertReleaseDuringBuilding("update", "fabrique", new Runnable() {
1280 select(new NodeElement("ide"), false);
1282 catch (Exception e
) {
1283 myCancelRequest
= e
;
1289 public void testReleaseBuilderDuringGetChildren() throws Exception
{
1290 assertReleaseDuringBuilding("getChildren", "fabrique", new Runnable() {
1293 select(new NodeElement("ide"), false);
1295 catch (Exception e
) {
1296 myCancelRequest
= e
;
1302 private void assertReleaseDuringBuilding(final String actionAction
, final Object actionElement
, Runnable buildAction
) throws Exception
{
1303 buildStructure(myRoot
);
1305 myElementUpdateHook
= new ElementUpdateHook() {
1306 public void onElementAction(String action
, Object element
) {
1307 if (!element
.toString().equals(actionElement
.toString())) return;
1309 if (actionAction
.equals(action
)) {
1310 SwingUtilities
.invokeLater(new Runnable() {
1312 myReadyRequest
= true;
1313 Disposer
.dispose(getBuilder());
1322 boolean released
= new WaitFor(5000) {
1324 protected boolean condition() {
1325 return getBuilder().getUi() == null;
1327 }.isConditionRealized();
1329 assertTrue(released
);
1332 public static class SyncUpdate
extends TreeUiTest
{
1333 public SyncUpdate() {
1334 super(false, false);
1338 public static class Passthrough
extends TreeUiTest
{
1339 public Passthrough() {
1343 public void testSelectionGoesToParentWhenOnlyChildMoved2() throws Exception
{
1347 public void testQueryStructureWhenExpand() throws Exception
{
1352 public void testElementMove1() throws Exception
{
1357 public void testClear() throws Exception
{
1362 public void testSelectWhenUpdatesArePending() throws Exception
{
1363 // doesn't make sense in pass-through mode
1367 public static class YieldingUpdate
extends TreeUiTest
{
1368 public YieldingUpdate() {
1373 public static class BgLoadingSyncUpdate
extends TreeUiTest
{
1374 public BgLoadingSyncUpdate() {
1379 protected int getChildrenLoadingDelay() {
1384 protected int getNodeDescriptorUpdateDelay() {
1389 public void testNoInfiniteSmartExpand() throws Exception
{
1394 public static class QuickBgLoadingSyncUpdate
extends TreeUiTest
{
1395 public QuickBgLoadingSyncUpdate() {
1401 protected int getNodeDescriptorUpdateDelay() {
1406 public void testNoInfiniteSmartExpand() throws Exception
{
1412 public static TestSuite
suite() {
1413 TestSuite suite
= new TestSuite();
1414 suite
.addTestSuite(Passthrough
.class);
1415 suite
.addTestSuite(SyncUpdate
.class);
1416 suite
.addTestSuite(YieldingUpdate
.class);
1417 suite
.addTestSuite(BgLoadingSyncUpdate
.class);
1418 suite
.addTestSuite(QuickBgLoadingSyncUpdate
.class);