| /* |
| * Copyright 2000-2014 JetBrains s.r.o. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package com.intellij.ide.util.treeView; |
| |
| import com.intellij.openapi.progress.ProcessCanceledException; |
| import com.intellij.openapi.progress.ProgressIndicator; |
| import com.intellij.openapi.progress.Progressive; |
| import com.intellij.openapi.util.*; |
| import com.intellij.ui.LoadingNode; |
| import com.intellij.util.Time; |
| import com.intellij.util.WaitFor; |
| import com.intellij.util.ui.UIUtil; |
| import junit.framework.AssertionFailedError; |
| import junit.framework.TestSuite; |
| import org.jetbrains.annotations.NotNull; |
| import org.jetbrains.annotations.Nullable; |
| |
| import javax.swing.*; |
| import javax.swing.event.TreeModelEvent; |
| import javax.swing.event.TreeModelListener; |
| import javax.swing.tree.DefaultMutableTreeNode; |
| import javax.swing.tree.TreePath; |
| import java.lang.reflect.InvocationTargetException; |
| import java.util.Arrays; |
| import java.util.HashSet; |
| import java.util.Set; |
| |
| import static com.intellij.testFramework.PlatformTestUtil.notNull; |
| |
| @SuppressWarnings("JUnitTestClassNamingConvention") |
| public class TreeUiTest extends AbstractTreeBuilderTest { |
| public TreeUiTest(boolean passThrough) { |
| super(passThrough); |
| } |
| |
| public TreeUiTest(boolean yieldingUiBuild, boolean bgStructureBuilding) { |
| super(yieldingUiBuild, bgStructureBuilding); |
| } |
| |
| public void testEmptyInvisibleRoot() throws Exception { |
| myTree.setRootVisible(false); |
| showTree(); |
| assertTree("+/\n"); |
| |
| updateFromRoot(); |
| assertTree("+/\n"); |
| |
| buildNode("/", false); |
| assertTree("+/\n"); |
| |
| myTree.setRootVisible(true); |
| buildNode("/", false); |
| assertTree("/\n"); |
| } |
| |
| public void testVisibleRoot() throws Exception { |
| myTree.setRootVisible(true); |
| buildStructure(myRoot); |
| assertTree("+/\n"); |
| |
| updateFromRoot(); |
| assertTree("+/\n"); |
| } |
| |
| public void testThrowingProcessCancelledInterruptsUpdate() throws Exception { |
| assertInterruption(Interruption.throwProcessCancelled); |
| } |
| |
| public void testCancelUpdate() throws Exception { |
| assertInterruption(Interruption.invokeCancel); |
| } |
| |
| public void testDoubleCancelUpdate() throws Exception { |
| buildStructure(myRoot); |
| |
| runAndInterrupt(new Runnable() { |
| @Override |
| public void run() { |
| try { |
| select(new Object[] {new NodeElement("openapi")}, false, true); |
| } |
| catch (Exception e) { |
| fail(); |
| } |
| } |
| }, "getChildren", new NodeElement("intellij"), Interruption.invokeCancel); |
| |
| select(new NodeElement("fabrique"), false); |
| |
| assertTree("-/\n" |
| + " -com\n" |
| + " intellij\n" |
| + " -jetbrains\n" |
| + " +[fabrique]\n" |
| + " +org\n" |
| + " +xUnit\n"); |
| |
| updateFromRoot(); |
| |
| assertTree("-/\n" |
| + " -com\n" |
| + " +intellij\n" |
| + " -jetbrains\n" |
| + " +[fabrique]\n" |
| + " +org\n" |
| + " +xUnit\n"); |
| } |
| |
| public void testBatchUpdate() throws Exception { |
| buildStructure(myRoot); |
| |
| myElementUpdate.clear(); |
| |
| final NodeElement[] toExpand = new NodeElement[] { |
| new NodeElement("com"), |
| new NodeElement("jetbrains"), |
| new NodeElement("org"), |
| new NodeElement("xUnit") |
| }; |
| |
| final ActionCallback done = new ActionCallback(); |
| final Ref<ProgressIndicator> indicatorRef = new Ref<ProgressIndicator>(); |
| final Ref<ActionCallback> ready = new Ref<ActionCallback>(); |
| |
| myElementUpdateHook = new ElementUpdateHook() { |
| @Override |
| public void onElementAction(String action, Object element) { |
| if (new NodeElement("jetbrains").equals(element) && ready.get() == null) { |
| ActionCallback readyCallback = new ActionCallback(); |
| assertFalse(getBuilder().getUi().isReady()); |
| getBuilder().getReady(this).notify(readyCallback); |
| ready.set(readyCallback); |
| } |
| } |
| }; |
| |
| invokeLaterIfNeeded(new Runnable() { |
| @Override |
| public void run() { |
| getBuilder().batch(new Progressive() { |
| @Override |
| public void run(@NotNull ProgressIndicator indicator) { |
| indicatorRef.set(indicator); |
| expandNext(toExpand, 0, indicator, done); |
| } |
| }).notify(done); |
| } |
| }); |
| |
| waitBuilderToCome(new Condition<Object>() { |
| @Override |
| public boolean value(Object o) { |
| return done.isProcessed(); |
| } |
| }); |
| |
| assertTrue(done.isDone()); |
| assertNotNull(ready.get()); |
| assertTrue(ready.get().isDone()); |
| |
| assertTree("-/\n" + |
| " -com\n" + |
| " +intellij\n" + |
| " -jetbrains\n" + |
| " +fabrique\n" + |
| " -org\n" + |
| " +eclipse\n" + |
| " -xUnit\n" + |
| " runner\n"); |
| |
| assertFalse(indicatorRef.get().isCanceled()); |
| } |
| |
| public void testRenameCollapsedParentAlwaysShowsPlus() throws Exception { |
| buildStructure(myRoot); |
| myAlwaysShowPlus.add(myCom.getElement()); |
| |
| buildNode("com", false); |
| |
| assertTree("-/\n" + |
| " -com\n" + |
| " +intellij\n" + |
| " +jetbrains\n" + |
| " +org\n" + |
| " +xUnit\n"); |
| |
| collapsePath(getPath("com")); |
| assertTree("-/\n" + |
| " +com\n" + |
| " +jetbrains\n" + |
| " +org\n" + |
| " +xUnit\n"); |
| |
| myCom.getElement().setPresentableName("com1"); |
| updateFrom(myCom.getElement()); |
| |
| assertTree("-/\n" + |
| " +com1\n" + |
| " +jetbrains\n" + |
| " +org\n" + |
| " +xUnit\n"); |
| } |
| |
| public void testMoveElementToAdjacentEmptyParentWithSmartExpandAndSerialUpdateSubtrees() throws Exception { |
| Node com = myRoot.addChild("com"); |
| Node folder1 = com.addChild("folder1"); |
| Node folder2 = com.addChild("folder2"); |
| |
| Node file21 = folder2.addChild("file21"); |
| folder2.addChild("file22"); |
| |
| mySmartExpand = true; |
| activate(); |
| |
| buildNode(file21, true); |
| |
| assertTree("-/\n" + |
| " -com\n" + |
| " folder1\n" + |
| " -folder2\n" + |
| " [file21]\n" + |
| " file22\n"); |
| |
| folder2.myChildElements.remove(file21); |
| folder1.addChild(file21); |
| |
| getBuilder().queueUpdateFrom(folder2.getElement(), false); |
| getBuilder().queueUpdateFrom(folder1.getElement(), false); |
| |
| assertTree("-/\n" + |
| " -com\n" + |
| " -folder1\n" + |
| " [file21]\n" + |
| " -folder2\n" + |
| " file22\n"); |
| } |
| |
| public void testReadyCallbackWhenReleased() throws Exception { |
| buildStructure(myRoot); |
| |
| final Ref<Boolean> done = new Ref<Boolean>(false); |
| final Ref<Boolean> rejected = new Ref<Boolean>(false); |
| final Ref<Boolean> processed = new Ref<Boolean>(false); |
| final Ref<Boolean> wasUiNull = new Ref<Boolean>(true); |
| |
| final Ref<Runnable> addReadyCallbacks = new Ref<Runnable>(new Runnable() { |
| public void run() { |
| getBuilder().getReady(this).doWhenDone(new NamedRunnable("on done") { |
| @Override |
| public void run() { |
| wasUiNull.set(getBuilder().getUi() == null); |
| done.set(true); |
| } |
| }).doWhenRejected(new NamedRunnable("on rejected") { |
| @Override |
| public void run() { |
| wasUiNull.set(getBuilder().getUi() == null); |
| rejected.set(true); |
| } |
| }).doWhenProcessed(new NamedRunnable("on processed") { |
| @Override |
| public void run() { |
| processed.set(true); |
| } |
| }); |
| } |
| }); |
| |
| final Ref<Boolean> disposeRequested = new Ref<Boolean>(false); |
| myElementUpdateHook = new ElementUpdateHook() { |
| @Override |
| public void onElementAction(String action, Object element) { |
| if (addReadyCallbacks.get() != null) { |
| addReadyCallbacks.get().run(); |
| addReadyCallbacks.set(null); |
| } |
| |
| if (element.equals(new NodeElement("ide"))) { |
| disposeRequested.set(true); |
| //noinspection SSBasedInspection |
| getBuilder().dispose(); |
| } |
| } |
| }; |
| |
| invokeLaterIfNeeded(new Runnable() { |
| @Override |
| public void run() { |
| getBuilder().expand(new NodeElement("fabrique"), null); |
| } |
| }); |
| |
| waitBuilderToCome(new Condition<Object>() { |
| @Override |
| public boolean value(Object o) { |
| return disposeRequested.get(); |
| } |
| }); |
| assertTrue(wasUiNull.get()); |
| assertFalse(done.get()); |
| assertTrue(rejected.get()); |
| assertTrue(processed.get()); |
| } |
| |
| public void testNoExtraJTreeModelUpdate() throws Exception { |
| buildStructure(myRoot); |
| expand(getPath("/")); |
| |
| assertTree("-/\n" + |
| " +com\n" + |
| " +jetbrains\n" + |
| " +org\n" + |
| " +xUnit\n"); |
| |
| final Ref<StringBuffer> updates = new Ref<StringBuffer>(new StringBuffer()); |
| notNull(getMyBuilder().getTreeModel()).addTreeModelListener(new TreeModelListener() { |
| @Override |
| public void treeNodesChanged(TreeModelEvent e) { |
| updates.get().append("changed parent").append(e.getTreePath()).append(" children=").append(Arrays.asList(e.getChildren())) |
| .append("\n"); |
| } |
| |
| @Override |
| public void treeNodesInserted(TreeModelEvent e) { |
| updates.get().append("inserted=").append(e.getTreePath()).append("\n"); |
| } |
| |
| @Override |
| public void treeNodesRemoved(TreeModelEvent e) { |
| updates.get().append("removed=").append(e.getTreePath()).append("\n"); |
| } |
| |
| @Override |
| public void treeStructureChanged(TreeModelEvent e) { |
| updates.get().append("structureChanged=").append(e.getTreePath()).append("\n"); |
| } |
| }); |
| |
| assertEquals("", updates.get().toString()); |
| |
| updateFromRoot(); |
| assertEquals("", updates.get().toString()); |
| |
| myChanges.add(new NodeElement("com")); |
| updateFromRoot(); |
| assertEquals("changed parent[/] children=[com]\n", updates.get().toString()); |
| assertTree("-/\n" + |
| " +com\n" + |
| " +jetbrains\n" + |
| " +org\n" + |
| " +xUnit\n"); |
| updates.set(new StringBuffer()); |
| |
| updateFrom(new NodeElement("org")); |
| assertEquals("", updates.get().toString()); |
| |
| myChanges.add(new NodeElement("org")); |
| updateFrom(new NodeElement("org")); |
| assertEquals("changed parent[/] children=[org]\n", updates.get().toString()); |
| updates.set(new StringBuffer()); |
| |
| myChanges.add(new NodeElement("intellij")); |
| updateFromRoot(); |
| assertEquals("", updates.get().toString()); |
| } |
| |
| public void testCancelUpdateBatch() throws Exception { |
| buildStructure(myRoot); |
| |
| myAlwaysShowPlus.add(new NodeElement("com")); |
| myAlwaysShowPlus.add(new NodeElement("jetbrains")); |
| myAlwaysShowPlus.add(new NodeElement("org")); |
| myAlwaysShowPlus.add(new NodeElement("xUnit")); |
| |
| final Ref<Boolean> cancelled = new Ref<Boolean>(false); |
| myElementUpdateHook = new ElementUpdateHook() { |
| @Override |
| public void onElementAction(String action, Object element) { |
| NodeElement stopElement = new NodeElement("com"); |
| |
| if (cancelled.get()) { |
| myCancelRequest = new AssertionError("Not supposed to update after element=" + stopElement); |
| return; |
| } |
| |
| if (element.equals(stopElement) && action.equals("getChildren")) { |
| cancelled.set(true); |
| getBuilder().cancelUpdate(); |
| } |
| } |
| }; |
| |
| final NodeElement[] toExpand = new NodeElement[] { |
| new NodeElement("com"), |
| new NodeElement("jetbrains"), |
| new NodeElement("org"), |
| new NodeElement("xUnit") |
| }; |
| |
| final ActionCallback done = new ActionCallback(); |
| final Ref<ProgressIndicator> indicatorRef = new Ref<ProgressIndicator>(); |
| |
| invokeLaterIfNeeded(new Runnable() { |
| @Override |
| public void run() { |
| getBuilder().batch(new Progressive() { |
| @Override |
| public void run(@NotNull ProgressIndicator indicator) { |
| indicatorRef.set(indicator); |
| expandNext(toExpand, 0, indicator, done); |
| } |
| }).notify(done); |
| } |
| }); |
| |
| waitBuilderToCome(new Condition<Object>() { |
| @Override |
| public boolean value(Object o) { |
| return done.isProcessed() || myCancelRequest != null; |
| } |
| }); |
| |
| assertNull(myCancelRequest); |
| assertTrue(done.isRejected()); |
| assertTrue(indicatorRef.get().isCanceled()); |
| |
| assertFalse(getBuilder().getUi().isCancelProcessed()); |
| } |
| |
| |
| public void testExpandAll() throws Exception { |
| buildStructure(myRoot); |
| assertTree("+/\n"); |
| |
| final Ref<Boolean> done = new Ref<Boolean>(); |
| doAndWaitForBuilder(new Runnable() { |
| @Override |
| public void run() { |
| getBuilder().expandAll(new Runnable() { |
| @Override |
| public void run() { |
| done.set(true); |
| } |
| }); |
| } |
| }); |
| |
| assertTree("-/\n" |
| + " -com\n" |
| + " -intellij\n" |
| + " openapi\n" |
| + " -jetbrains\n" |
| + " -fabrique\n" |
| + " ide\n" |
| + " -org\n" |
| + " -eclipse\n" |
| + " rcp\n" |
| + " -xUnit\n" |
| + " runner\n"); |
| } |
| |
| public void testInvisibleRoot() throws Exception { |
| myTree.setRootVisible(false); |
| buildStructure(myRoot); |
| assertTree("-/\n" |
| + " +com\n" |
| + " +jetbrains\n" |
| + " +org\n" |
| + " +xUnit\n"); |
| |
| collapsePath(new TreePath(myTreeModel.getRoot())); |
| assertTree("+/\n"); |
| |
| updateFromRoot(); |
| assertTree("-/\n" |
| + " +com\n" |
| + " +jetbrains\n" |
| + " +org\n" |
| + " +xUnit\n"); |
| |
| buildNode("com", true); |
| assertTree("-/\n" |
| + " +[com]\n" |
| + " +jetbrains\n" |
| + " +org\n" |
| + " +xUnit\n"); |
| |
| myRoot.removeAll(); |
| updateFromRoot(); |
| |
| assertTree("+/\n"); |
| } |
| |
| public void testAutoExpand() throws Exception { |
| buildStructure(myRoot); |
| assertTree("+/\n"); |
| |
| myAutoExpand.add(new NodeElement("/")); |
| buildStructure(myRoot); |
| |
| assertTree("-/\n" |
| + " +com\n" |
| + " +jetbrains\n" |
| + " +org\n" |
| + " +xUnit\n"); |
| |
| myAutoExpand.add(new NodeElement("jetbrains")); |
| updateFromRoot(); |
| |
| assertTree("-/\n" |
| + " +com\n" |
| + " -jetbrains\n" |
| + " +fabrique\n" |
| + " +org\n" |
| + " +xUnit\n"); |
| |
| collapsePath(getPath("jetbrains")); |
| assertTree("-/\n" |
| + " +com\n" |
| + " +jetbrains\n" |
| + " +org\n" |
| + " +xUnit\n"); |
| |
| updateFrom(new NodeElement("org")); |
| assertTree("-/\n" |
| + " +com\n" |
| + " +jetbrains\n" |
| + " +org\n" |
| + " +xUnit\n"); |
| |
| updateFrom(new NodeElement("jetbrains")); |
| assertTree("-/\n" |
| + " +com\n" |
| + " -jetbrains\n" |
| + " +fabrique\n" |
| + " +org\n" |
| + " +xUnit\n"); |
| } |
| |
| public void testAutoExpandDeep() throws Exception { |
| myTree.setRootVisible(false); |
| //myAutoExpand.add(new NodeElement("jetbrains")); |
| myAutoExpand.add(new NodeElement("fabrique")); |
| |
| buildStructure(myRoot); |
| //assertTree("+/\n"); |
| |
| expand(getPath("/")); |
| expand(getPath("jetbrains")); |
| assertTree("-/\n" |
| + " +com\n" |
| + " -jetbrains\n" |
| + " -fabrique\n" |
| + " ide\n" |
| + " +org\n" |
| + " +xUnit\n"); |
| |
| collapsePath(getPath("/")); |
| assertTree("+/\n"); |
| |
| expand(getPath("/")); |
| expand(getPath("jetbrains")); |
| |
| assertTree("-/\n" |
| + " +com\n" |
| + " -jetbrains\n" |
| + " -fabrique\n" |
| + " ide\n" |
| + " +org\n" |
| + " +xUnit\n"); |
| |
| collapsePath(getPath("jetbrains")); |
| assertTree("-/\n" |
| + " +com\n" |
| + " +jetbrains\n" |
| + " +org\n" |
| + " +xUnit\n"); |
| |
| expand(getPath("jetbrains")); |
| assertTree("-/\n" |
| + " +com\n" |
| + " -jetbrains\n" |
| + " -fabrique\n" |
| + " ide\n" |
| + " +org\n" |
| + " +xUnit\n"); |
| } |
| |
| public void testExpandEqualElements() throws Exception { |
| buildStructure(myRoot, false); |
| notNull(myRoot.getChildNode("org")).addChild("jetbrains").addChild("community").addChild("ide"); |
| |
| activate(); |
| expand(getPath("/")); |
| |
| doAndWaitForBuilder(new Runnable() { |
| @Override |
| public void run() { |
| myTree.expandPath(getPath("org")); |
| myTree.setSelectionPath(myTree.getPathForRow(5)); |
| } |
| }); |
| |
| assertTree("-/\n" |
| + " +com\n" |
| + " +jetbrains\n" |
| + " -org\n" |
| + " +eclipse\n" |
| + " +[jetbrains]\n" |
| + " +xUnit\n"); |
| |
| doAndWaitForBuilder(new Runnable() { |
| @Override |
| public void run() { |
| myTree.expandPath(myTree.getPathForRow(5)); |
| } |
| }); |
| |
| assertTree("-/\n" |
| + " +com\n" |
| + " +jetbrains\n" |
| + " -org\n" |
| + " +eclipse\n" |
| + " -[jetbrains]\n" |
| + " +community\n" |
| + " +xUnit\n"); |
| |
| doAndWaitForBuilder(new Runnable() { |
| @Override |
| public void run() { |
| myTree.expandPath(myTree.getPathForRow(6)); |
| } |
| }); |
| |
| assertTree("-/\n" |
| + " +com\n" |
| + " +jetbrains\n" |
| + " -org\n" |
| + " +eclipse\n" |
| + " -[jetbrains]\n" |
| + " -community\n" |
| + " ide\n" |
| + " +xUnit\n"); |
| |
| doAndWaitForBuilder(new Runnable() { |
| @Override |
| public void run() { |
| myTree.collapsePath(myTree.getPathForRow(5)); |
| } |
| }); |
| |
| assertTree("-/\n" |
| + " +com\n" |
| + " +jetbrains\n" |
| + " -org\n" |
| + " +eclipse\n" |
| + " +[jetbrains]\n" |
| + " +xUnit\n"); |
| |
| doAndWaitForBuilder(new Runnable() { |
| @Override |
| public void run() { |
| myTree.expandPath(myTree.getPathForRow(5)); |
| } |
| }); |
| |
| assertTree("-/\n" |
| + " +com\n" |
| + " +jetbrains\n" |
| + " -org\n" |
| + " +eclipse\n" |
| + " -[jetbrains]\n" |
| + " +community\n" |
| + " +xUnit\n"); |
| } |
| |
| public void testAutoExpandInNonVisibleNode() throws Exception { |
| myAutoExpand.add(new NodeElement("fabrique")); |
| buildStructure(myRoot); |
| |
| expand(getPath("/")); |
| assertTree("-/\n" |
| + " +com\n" |
| + " +jetbrains\n" |
| + " +org\n" |
| + " +xUnit\n"); |
| } |
| |
| public void testSmartExpand() throws Exception { |
| mySmartExpand = true; |
| buildStructure(myRoot); |
| assertTree("+/\n"); |
| |
| expand(getPath("/")); |
| assertTree("-/\n" |
| + " +com\n" |
| + " +jetbrains\n" |
| + " +org\n" |
| + " +xUnit\n"); |
| |
| expand(getPath("jetbrains")); |
| assertTree("-/\n" |
| + " +com\n" |
| + " -jetbrains\n" |
| + " -fabrique\n" |
| + " ide\n" |
| + " +org\n" |
| + " +xUnit\n"); |
| |
| collapsePath(getPath("jetbrains")); |
| assertTree("-/\n" |
| + " +com\n" |
| + " +jetbrains\n" |
| + " +org\n" |
| + " +xUnit\n"); |
| |
| updateFromRoot(); |
| assertTree("-/\n" |
| + " +com\n" |
| + " +jetbrains\n" |
| + " +org\n" |
| + " +xUnit\n"); |
| |
| mySmartExpand = false; |
| collapsePath(getPath("jetbrains")); |
| assertTree("-/\n" |
| + " +com\n" |
| + " +jetbrains\n" |
| + " +org\n" |
| + " +xUnit\n"); |
| |
| expand(getPath("jetbrains")); |
| assertTree("-/\n" |
| + " +com\n" |
| + " -jetbrains\n" |
| + " +fabrique\n" |
| + " +org\n" |
| + " +xUnit\n"); |
| } |
| |
| public void testClear() throws Exception { |
| getBuilder().getUi().setClearOnHideDelay(Time.SECOND); |
| |
| buildStructure(myRoot); |
| |
| assertTree("+/\n"); |
| |
| final DefaultMutableTreeNode openApiNode = findNode("openapi", false); |
| final DefaultMutableTreeNode ideNode = findNode("ide", false); |
| final DefaultMutableTreeNode runnerNode = findNode("runner", false); |
| final DefaultMutableTreeNode rcpNode = findNode("rcp", false); |
| |
| assertNull(openApiNode); |
| assertNull(ideNode); |
| assertNull(runnerNode); |
| assertNull(rcpNode); |
| |
| buildNode(myOpenApi, true); |
| buildNode(myIde, true); |
| buildNode(myRunner, false); |
| |
| hideTree(); |
| |
| assertNull(findNode("openapi", true)); |
| assertNull(findNode("ide", true)); |
| assertNull(findNode("runner", false)); |
| assertNull(findNode("rcp", false)); |
| |
| showTree(); |
| |
| assertTree("-/\n" + |
| " -com\n" + |
| " -intellij\n" + |
| " [openapi]\n" + |
| " -jetbrains\n" + |
| " -fabrique\n" + |
| " [ide]\n" + |
| " +org\n" + |
| " -xUnit\n" + |
| " runner\n"); |
| |
| getMyBuilder().myWasCleanedUp = false; |
| hideTree(); |
| showTree(); |
| |
| assertTree("-/\n" + |
| " -com\n" + |
| " -intellij\n" + |
| " [openapi]\n" + |
| " -jetbrains\n" + |
| " -fabrique\n" + |
| " [ide]\n" + |
| " +org\n" + |
| " -xUnit\n" + |
| " runner\n"); |
| |
| buildNode(myFabrique.myElement, true, false); |
| assertTree("-/\n" + |
| " -com\n" + |
| " -intellij\n" + |
| " openapi\n" + |
| " -jetbrains\n" + |
| " -[fabrique]\n" + |
| " ide\n" + |
| " +org\n" + |
| " -xUnit\n" + |
| " runner\n"); |
| } |
| |
| public void testUpdateRestoresState() throws Exception { |
| buildStructure(myRoot); |
| |
| buildNode(myOpenApi, true); |
| buildNode(myIde, true); |
| buildNode(myRunner, false); |
| |
| waitBuilderToCome(); |
| |
| assertTree("-/\n" + |
| " -com\n" + |
| " -intellij\n" + |
| " [openapi]\n" + |
| " -jetbrains\n" + |
| " -fabrique\n" + |
| " [ide]\n" + |
| " +org\n" + |
| " -xUnit\n" + |
| " runner\n"); |
| |
| myRoot.removeAll(); |
| myStructure.clear(); |
| |
| final AbstractTreeBuilderTest.Node newRoot = myRoot.addChild("newRoot"); |
| |
| buildStructure(newRoot); |
| |
| updateFromRoot(); |
| assertTree("-/\n" + |
| " -newRoot\n" + |
| " -com\n" + |
| " -intellij\n" + |
| " [openapi]\n" + |
| " -jetbrains\n" + |
| " -fabrique\n" + |
| " [ide]\n" + |
| " +org\n" + |
| " -xUnit\n" + |
| " runner\n"); |
| } |
| |
| public void testSelect() throws Exception { |
| buildStructure(myRoot); |
| assertTree( |
| "+/\n"); |
| |
| buildNode(myOpenApi, true); |
| assertTree( |
| "-/\n" + |
| " -com\n" + |
| " -intellij\n" + |
| " [openapi]\n" + |
| " +jetbrains\n" + |
| " +org\n" + |
| " +xUnit\n"); |
| |
| buildNode("fabrique", true); |
| |
| assertTree( |
| "-/\n" + |
| " -com\n" + |
| " -intellij\n" + |
| " [openapi]\n" + |
| " -jetbrains\n" + |
| " +[fabrique]\n" + |
| " +org\n" + |
| " +xUnit\n"); |
| } |
| |
| public void testSelectWhileUpdating() throws Exception { |
| buildStructure(myRoot, false); |
| myForegroundLoadingNodes.add(myRoot.getElement()); |
| |
| myAutoExpand.add(myRoot.getElement()); |
| |
| invokeAndWaitIfNeeded(new Runnable() { |
| @Override |
| public void run() { |
| getBuilder().getUi().activate(true); |
| getBuilder().select(new NodeElement("com")); |
| } |
| }); |
| |
| waitBuilderToCome(); |
| |
| assertTree( |
| "-/\n" + |
| " +[com]\n" + |
| " +jetbrains\n" + |
| " +org\n" + |
| " +xUnit\n"); |
| } |
| |
| public void testCallbackOnceOnSelect() throws Exception { |
| buildStructure(myRoot); |
| |
| assertCallbackOnce(new TreeAction() { |
| @Override |
| public void run(Runnable onDone) { |
| getMyBuilder().select(new Object[] {new NodeElement("intellij"), new NodeElement("fabrique")}, onDone); |
| } |
| }); |
| |
| assertTree( |
| "-/\n" + |
| " -com\n" + |
| " +[intellij]\n" + |
| " -jetbrains\n" + |
| " +[fabrique]\n" + |
| " +org\n" + |
| " +xUnit\n"); |
| } |
| |
| public void testCallbackOnceOnExpand() throws Exception { |
| buildStructure(myRoot); |
| |
| assertCallbackOnce(new TreeAction() { |
| @Override |
| public void run(Runnable onDone) { |
| getMyBuilder().expand(new Object[] {new NodeElement("intellij"), new NodeElement("fabrique")}, onDone); |
| } |
| }); |
| |
| assertTree( |
| "-/\n" + |
| " -com\n" + |
| " -intellij\n" + |
| " openapi\n" + |
| " -jetbrains\n" + |
| " -fabrique\n" + |
| " ide\n" + |
| " +org\n" + |
| " +xUnit\n"); |
| } |
| |
| public void testNoInfiniteAutoExpand() throws Exception { |
| mySmartExpand = false; |
| |
| assertNoInfiniteAutoExpand(new Runnable() { |
| @Override |
| public void run() { |
| myAutoExpand.add(new NodeElement("level2")); |
| myAutoExpand.add(new NodeElement("level3")); |
| myAutoExpand.add(new NodeElement("level4")); |
| myAutoExpand.add(new NodeElement("level5")); |
| myAutoExpand.add(new NodeElement("level6")); |
| myAutoExpand.add(new NodeElement("level7")); |
| myAutoExpand.add(new NodeElement("level8")); |
| myAutoExpand.add(new NodeElement("level9")); |
| myAutoExpand.add(new NodeElement("level10")); |
| myAutoExpand.add(new NodeElement("level11")); |
| myAutoExpand.add(new NodeElement("level12")); |
| myAutoExpand.add(new NodeElement("level13")); |
| myAutoExpand.add(new NodeElement("level14")); |
| myAutoExpand.add(new NodeElement("level15")); |
| } |
| }); |
| } |
| |
| public void testNoInfiniteSmartExpand() throws Exception { |
| mySmartExpand = false; |
| |
| assertNoInfiniteAutoExpand(new Runnable() { |
| @Override |
| public void run() { |
| mySmartExpand = true; |
| } |
| }); |
| } |
| |
| private void assertNoInfiniteAutoExpand(final Runnable enableExpand) throws Exception { |
| class Level extends Node { |
| int myLevel; |
| |
| Level(Node parent, int level) { |
| super(parent, "level" + level); |
| myLevel = level; |
| } |
| |
| @Override |
| public Object[] getChildElements() { |
| if (super.getChildElements().length == 0) { |
| addChild(new Level(this, myLevel + 1)); |
| } |
| |
| return super.getChildElements(); |
| } |
| } |
| |
| myRoot.addChild(new Level(myRoot, 0)); |
| |
| activate(); |
| buildNode("level0", false); |
| |
| assertTree("-/\n" + |
| " -level0\n" + |
| " +level1\n"); |
| |
| enableExpand.run(); |
| |
| expand(getPath("level1")); |
| |
| assertTree("-/\n" + |
| " -level0\n" + |
| " -level1\n" + |
| " -level2\n" + |
| " -level3\n" + |
| " -level4\n" + |
| " -level5\n" + |
| " +level6\n"); |
| |
| expand(getPath("level6")); |
| assertTree("-/\n" + |
| " -level0\n" + |
| " -level1\n" + |
| " -level2\n" + |
| " -level3\n" + |
| " -level4\n" + |
| " -level5\n" + |
| " -level6\n" + |
| " -level7\n" + |
| " -level8\n" + |
| " -level9\n" + |
| " -level10\n" + |
| " +level11\n"); |
| } |
| |
| private void assertCallbackOnce(final TreeAction action) { |
| final int[] notifyCount = new int[1]; |
| final boolean[] done = new boolean[1]; |
| invokeLaterIfNeeded(new Runnable() { |
| @Override |
| public void run() { |
| action.run(new Runnable() { |
| @Override |
| public void run() { |
| notifyCount[0]++; |
| done[0] = true; |
| } |
| }); |
| } |
| }); |
| |
| new WaitFor(60000) { |
| @Override |
| protected boolean condition() { |
| return done[0] && getMyBuilder().getUi().isReady(); |
| } |
| }; |
| |
| assertTrue(done[0]); |
| assertEquals(1, notifyCount[0]); |
| } |
| |
| public void testSelectMultiple() throws Exception { |
| buildStructure(myRoot); |
| assertTree( |
| "+/\n"); |
| |
| select(new Object[] {new NodeElement("openapi"), new NodeElement("fabrique")}, false); |
| assertTree( |
| "-/\n" + |
| " -com\n" + |
| " -intellij\n" + |
| " [openapi]\n" + |
| " -jetbrains\n" + |
| " +[fabrique]\n" + |
| " +org\n" + |
| " +xUnit\n"); |
| } |
| |
| public void testUnsuccessfulSelect() throws Exception { |
| buildStructure(myRoot); |
| select(new Object[] {new NodeElement("openapi"), new NodeElement("fabrique")}, false); |
| |
| assertTree( |
| "-/\n" + |
| " -com\n" + |
| " -intellij\n" + |
| " [openapi]\n" + |
| " -jetbrains\n" + |
| " +[fabrique]\n" + |
| " +org\n" + |
| " +xUnit\n"); |
| |
| select(new Object[] {new NodeElement("whatever1"), new NodeElement("whatever2")}, false); |
| |
| assertTree( |
| "-/\n" + |
| " -com\n" + |
| " -intellij\n" + |
| " [openapi]\n" + |
| " -jetbrains\n" + |
| " +[fabrique]\n" + |
| " +org\n" + |
| " +xUnit\n"); |
| } |
| |
| public void testSelectionWhenChildMoved() throws Exception { |
| buildStructure(myRoot); |
| assertTree("+/\n"); |
| |
| final Node refactoring = notNull(myCom.getChildNode("intellij")).addChild("refactoring"); |
| |
| buildNode("refactoring", true); |
| |
| assertTree( |
| "-/\n" + |
| " -com\n" + |
| " -intellij\n" + |
| " openapi\n" + |
| " [refactoring]\n" + |
| " +jetbrains\n" + |
| " +org\n" + |
| " +xUnit\n"); |
| |
| refactoring.delete(); |
| notNull(notNull(myCom.getChildNode("intellij")).getChildNode("openapi")).addChild("refactoring"); |
| |
| updateFromRoot(); |
| |
| assertTree( |
| "-/\n" + |
| " -com\n" + |
| " -intellij\n" + |
| " -openapi\n" + |
| " [refactoring]\n" + |
| " +jetbrains\n" + |
| " +org\n" + |
| " +xUnit\n"); |
| } |
| |
| public void testSelectionGoesToParentWhenOnlyChildRemove() throws Exception { |
| buildStructure(myRoot); |
| buildNode("openapi", true); |
| |
| assertTree( |
| "-/\n" + |
| " -com\n" + |
| " -intellij\n" + |
| " [openapi]\n" + |
| " +jetbrains\n" + |
| " +org\n" + |
| " +xUnit\n"); |
| |
| notNull(notNull(myCom.getChildNode("intellij")).getChildNode("openapi")).delete(); |
| |
| updateFromRoot(); |
| |
| assertTree( |
| "-/\n" + |
| " -com\n" + |
| " [intellij]\n" + |
| " +jetbrains\n" + |
| " +org\n" + |
| " +xUnit\n"); |
| } |
| |
| public void testCollapsedPathOnExpandedCallback() throws Exception { |
| Node com = myRoot.addChild("com"); |
| |
| activate(); |
| assertTree("+/\n"); |
| |
| expand(getPath("/")); |
| assertTree("-/\n" + |
| " com\n"); |
| |
| com.addChild("intellij"); |
| |
| collapsePath(getPath("/")); |
| |
| final Ref<Boolean> done = new Ref<Boolean>(); |
| invokeLaterIfNeeded(new Runnable() { |
| @Override |
| public void run() { |
| getBuilder().expand(new NodeElement("com"), new Runnable() { |
| @Override |
| public void run() { |
| notNull(getBuilder().getTree()).collapsePath(getPath("com")); |
| done.set(Boolean.TRUE); |
| } |
| }); |
| } |
| }); |
| |
| waitBuilderToCome(new Condition<Object>() { |
| @Override |
| public boolean value(Object o) { |
| return (done.get() != null) && done.get().booleanValue(); |
| } |
| }); |
| |
| assertTree("-/\n" + |
| " +com\n"); |
| } |
| |
| public void testSelectionGoesToParentWhenOnlyChildMoved() throws Exception { |
| buildStructure(myRoot); |
| buildNode("openapi", true); |
| |
| assertTree( |
| "-/\n" + |
| " -com\n" + |
| " -intellij\n" + |
| " [openapi]\n" + |
| " +jetbrains\n" + |
| " +org\n" + |
| " +xUnit\n"); |
| |
| notNull(notNull(myCom.getChildNode("intellij")).getChildNode("openapi")).delete(); |
| notNull(myRoot.getChildNode("xUnit")).addChild("openapi"); |
| |
| updateFromRoot(); |
| |
| assertTree( |
| "-/\n" + |
| " -com\n" + |
| " intellij\n" + |
| " +jetbrains\n" + |
| " +org\n" + |
| " -xUnit\n" + |
| " [openapi]\n" + |
| " runner\n"); |
| } |
| |
| public void testSelectionGoesToParentWhenOnlyChildMoved2() throws Exception { |
| buildStructure(myRoot); |
| buildNode("openapi", true); |
| |
| assertTree( |
| "-/\n" + |
| " -com\n" + |
| " -intellij\n" + |
| " [openapi]\n" + |
| " +jetbrains\n" + |
| " +org\n" + |
| " +xUnit\n"); |
| |
| notNull(notNull(myCom.getChildNode("intellij")).getChildNode("openapi")).delete(); |
| notNull(myRoot.getChildNode("xUnit")).addChild("openapi"); |
| |
| getBuilder().addSubtreeToUpdateByElement(new NodeElement("intellij")); |
| getBuilder().addSubtreeToUpdateByElement(new NodeElement("xUnit")); |
| |
| doAndWaitForBuilder(new Runnable() { |
| @Override |
| public void run() { |
| notNull(getBuilder().getUpdater()).performUpdate(); |
| } |
| }); |
| |
| assertTree( |
| "-/\n" + |
| " -com\n" + |
| " intellij\n" + |
| " +jetbrains\n" + |
| " +org\n" + |
| " -xUnit\n" + |
| " [openapi]\n" + |
| " runner\n"); |
| } |
| |
| public void testSelectionGoesToParentWhenChildrenFold() throws Exception { |
| buildStructure(myRoot); |
| buildNode("openapi", true); |
| |
| assertTree( |
| "-/\n" + |
| " -com\n" + |
| " -intellij\n" + |
| " [openapi]\n" + |
| " +jetbrains\n" + |
| " +org\n" + |
| " +xUnit\n"); |
| |
| collapsePath(new TreePath(notNull(findNode("intellij", false)).getPath())); |
| |
| assertTree( |
| "-/\n" + |
| " -com\n" + |
| " +[intellij]\n" + |
| " +jetbrains\n" + |
| " +org\n" + |
| " +xUnit\n"); |
| } |
| |
| public void testUpdateWithNewDescriptor() throws Exception { |
| buildStructure(myRoot); |
| |
| expand(getPath("/")); |
| |
| assertTree( |
| "-/\n" + |
| " +com\n" + |
| " +jetbrains\n" + |
| " +org\n" + |
| " +xUnit\n"); |
| |
| Node google = myStructure.getNodeFor(new NodeElement("jetbrains")); |
| google.myElement.myName = "google"; |
| |
| updateFromRoot(); |
| |
| assertTree( |
| "-/\n" + |
| " +com\n" + |
| " +google\n" + |
| " +org\n" + |
| " +xUnit\n"); |
| } |
| |
| public void testDeferredSelection() throws Exception { |
| buildStructure(myRoot, false); |
| |
| final Ref<Boolean> queued = new Ref<Boolean>(false); |
| final Ref<Boolean> intellijSelected = new Ref<Boolean>(false); |
| final Ref<Boolean> jetbrainsSelected = new Ref<Boolean>(false); |
| invokeLaterIfNeeded(new Runnable() { |
| @Override |
| public void run() { |
| try { |
| getBuilder().select(new NodeElement("intellij"), new Runnable() { |
| @Override |
| public void run() { |
| intellijSelected.set(true); |
| } |
| }, true); |
| queued.set(true); |
| } |
| catch (Exception e) { |
| e.printStackTrace(); |
| fail(); |
| } |
| } |
| }); |
| |
| new WaitFor() { |
| @Override |
| protected boolean condition() { |
| return queued.get(); |
| } |
| }; |
| |
| assertTrue(getBuilder().getUi().isIdle()); |
| assertTreeNow("+null\n"); |
| assertNull(((DefaultMutableTreeNode)notNull(getBuilder().getTreeModel()).getRoot()).getUserObject()); |
| |
| invokeLaterIfNeeded(new Runnable() { |
| @Override |
| public void run() { |
| getBuilder().getUi().activate(true); |
| getBuilder().select(new NodeElement("jetbrains"), new Runnable() { |
| @Override |
| public void run() { |
| jetbrainsSelected.set(true); |
| } |
| }, true); |
| } |
| }); |
| |
| waitBuilderToCome(new Condition<Object>() { |
| @Override |
| public boolean value(Object object) { |
| return intellijSelected.get() && jetbrainsSelected.get(); |
| } |
| }); |
| |
| assertTree("-/\n" + |
| " -com\n" + |
| " +[intellij]\n" + |
| " +[jetbrains]\n" + |
| " +org\n" + |
| " +xUnit\n"); |
| } |
| |
| private void expandNext(final NodeElement[] elements, final int index, final ProgressIndicator indicator, final ActionCallback callback) { |
| if (indicator.isCanceled()) { |
| callback.setRejected(); |
| return; |
| } |
| |
| if (index >= elements.length) { |
| callback.setDone(); |
| return; |
| } |
| |
| getBuilder().expand(elements[index], new Runnable() { |
| @Override |
| public void run() { |
| expandNext(elements, index + 1, indicator, callback); |
| } |
| }); |
| } |
| |
| public void testSelectAfterCancelledUpdate() throws Exception { |
| Node intellij = myRoot.addChild("com").addChild("intellij"); |
| myRoot.addChild("jetbrains"); |
| activate(); |
| |
| buildNode(new NodeElement("intellij"), false); |
| assertTree("-/\n" + |
| " -com\n" + |
| " intellij\n" + |
| " jetbrains\n"); |
| |
| intellij.addChild("ide"); |
| |
| runAndInterrupt(new MyRunnable() { |
| @Override |
| public void runSafe() throws Exception { |
| updateFromRoot(); |
| } |
| }, "getChildren", new NodeElement("intellij"), Interruption.invokeCancel); |
| |
| assertTree("-/\n" + |
| " -com\n" + |
| " intellij\n" + |
| " jetbrains\n"); |
| |
| select(new NodeElement("ide"), false); |
| |
| assertTree("-/\n" + |
| " -com\n" + |
| " -intellij\n" + |
| " [ide]\n" + |
| " jetbrains\n"); |
| } |
| |
| private void assertInterruption(Interruption cancelled) throws Exception { |
| buildStructure(myRoot); |
| |
| expand(getPath("/")); |
| expand(getPath("com")); |
| expand(getPath("jetbrains")); |
| expand(getPath("org")); |
| expand(getPath("xUnit")); |
| |
| assertTree("-/\n" + |
| " -com\n" + |
| " +intellij\n" + |
| " -jetbrains\n" + |
| " +fabrique\n" + |
| " -org\n" + |
| " +eclipse\n" + |
| " -xUnit\n" + |
| " runner\n"); |
| |
| runAndInterrupt(new MyRunnable() { |
| @Override |
| public void runSafe() throws Exception { |
| updateFrom(new NodeElement("/")); |
| } |
| }, "update", new NodeElement("jetbrains"), cancelled); |
| |
| runAndInterrupt(new MyRunnable() { |
| @Override |
| public void runSafe() throws Exception { |
| updateFrom(new NodeElement("/")); |
| } |
| }, "getChildren", new NodeElement("jetbrains"), cancelled); |
| } |
| |
| public void testBigTreeUpdate() throws Exception { |
| Node msg = myRoot.addChild("Messages"); |
| |
| buildSiblings(msg, 0, 1, null, null); |
| |
| doAndWaitForBuilder(new Runnable() { |
| @Override |
| public void run() { |
| getBuilder().getUi().activate(true); |
| } |
| }); |
| |
| buildNode("Messages", false); |
| |
| assertTree("-/\n" + |
| " -Messages\n" + |
| " -File 0\n" + |
| " message 1 for 0\n" + |
| " message 2 for 0\n" + |
| " -File 1\n" + |
| " message 1 for 1\n" + |
| " message 2 for 1\n"); |
| |
| buildSiblings(msg, 2, 1000, new Runnable() { |
| @Override |
| public void run() { |
| getBuilder().queueUpdate(); |
| } |
| }, null); |
| |
| waitBuilderToCome(); |
| } |
| |
| private void buildSiblings(final Node node, |
| final int start, |
| final int end, |
| @Nullable final Runnable eachRunnable, |
| @Nullable final Runnable endRunnable) throws InvocationTargetException, InterruptedException { |
| UIUtil.invokeAndWaitIfNeeded(new Runnable() { |
| @Override |
| public void run() { |
| for (int i = start; i <= end; i++) { |
| Node eachFile = node.addChild("File " + i); |
| myAutoExpand.add(eachFile.getElement()); |
| eachFile.addChild("message 1 for " + i); |
| eachFile.addChild("message 2 for " + i); |
| |
| if (eachRunnable != null) { |
| eachRunnable.run(); |
| } |
| } |
| |
| if (endRunnable != null) { |
| endRunnable.run(); |
| } |
| } |
| }); |
| } |
| |
| private enum Interruption { |
| throwProcessCancelled, invokeCancel |
| } |
| |
| private void runAndInterrupt(final Runnable action, |
| final String interruptAction, |
| final Object interruptElement, |
| final Interruption interruption) throws Exception { |
| myElementUpdate.clear(); |
| |
| final boolean[] wasInterrupted = new boolean[]{false}; |
| myElementUpdateHook = new ElementUpdateHook() { |
| @Override |
| public void onElementAction(String action, Object element) { |
| boolean toInterrupt = element.equals(interruptElement) && action.equals(interruptAction); |
| |
| if (wasInterrupted[0]) { |
| if (myCancelRequest == null) { |
| getBuilder().getUi().getStatus(); |
| final String message = "Not supposed to be update after interruption request: action=" + action + " element=" + element + |
| " interruptAction=" + interruptAction + " interruptElement=" + interruptElement; |
| myCancelRequest = new AssertionError(message); |
| } |
| } |
| else if (toInterrupt) { |
| wasInterrupted[0] = true; |
| switch (interruption) { |
| case throwProcessCancelled: |
| throw new ProcessCanceledException(); |
| case invokeCancel: |
| getBuilder().cancelUpdate(); |
| break; |
| } |
| } |
| } |
| }; |
| |
| action.run(); |
| |
| myCancelRequest = null; |
| myElementUpdateHook = null; |
| } |
| |
| public void testQueryStructure() throws Exception { |
| buildStructure(myRoot); |
| |
| assertTree("+/\n"); |
| assertUpdates("/: update"); |
| |
| expand(getPath("/")); |
| assertTree("-/\n" + |
| " +com\n" + |
| " +jetbrains\n" + |
| " +org\n" + |
| " +xUnit\n"); |
| assertUpdates("/: update getChildren\n" + |
| "com: update getChildren\n" + |
| "eclipse: update\n" + |
| "fabrique: update\n" + |
| "intellij: update\n" + |
| "jetbrains: update getChildren\n" + |
| "org: update getChildren\n" + |
| "runner: update\n" + |
| "xUnit: update getChildren"); |
| |
| collapsePath(getPath("/")); |
| assertTree("+/\n"); |
| assertUpdates(""); |
| |
| expand(getPath("/")); |
| assertTree("-/\n" + |
| " +com\n" + |
| " +jetbrains\n" + |
| " +org\n" + |
| " +xUnit\n"); |
| assertUpdates("/: update getChildren\n" + |
| "com: update getChildren\n" + |
| "eclipse: update\n" + |
| "fabrique: update\n" + |
| "intellij: update\n" + |
| "jetbrains: update getChildren\n" + |
| "org: update getChildren\n" + |
| "runner: update\n" + |
| "xUnit: update getChildren"); |
| |
| updateFromRoot(); |
| assertTree("-/\n" + |
| " +com\n" + |
| " +jetbrains\n" + |
| " +org\n" + |
| " +xUnit\n"); |
| |
| assertUpdates("/: update getChildren\n" + |
| "com: update getChildren\n" + |
| "eclipse: update\n" + |
| "fabrique: update\n" + |
| "intellij: update\n" + |
| "jetbrains: update getChildren\n" + |
| "org: update getChildren\n" + |
| "runner: update\n" + |
| "xUnit: update getChildren"); |
| } |
| |
| public void testQueryWhenUpdatingPresentation() throws Exception { |
| buildStructure(myRoot); |
| expand(getPath("/")); |
| assertTree("-/\n" + |
| " +com\n" + |
| " +jetbrains\n" + |
| " +org\n" + |
| " +xUnit\n"); |
| |
| myElementUpdate.clear(); |
| |
| updateFromRoot(false); |
| |
| assertUpdates("/: update\n" + |
| "com: update\n" + |
| "jetbrains: update\n" + |
| "org: update\n" + |
| "xUnit: update"); |
| } |
| |
| public void testInfiniteUpdatingWhenReQueueingUpdates() throws Exception { |
| buildStructure(myRoot, false); |
| myCom.addChild("ibm").addChild("alphaWorks"); |
| myCom.addChild("apple").addChild("cocoa"); |
| |
| doAndWaitForBuilder(new Runnable() { |
| @Override |
| public void run() { |
| getBuilder().getUi().activate(true); |
| } |
| }); |
| |
| buildNode("/", false); |
| assertTree("-/\n" + |
| " +com\n" + |
| " +jetbrains\n" + |
| " +org\n" + |
| " +xUnit\n"); |
| |
| myElementUpdateHook = new ElementUpdateHook() { |
| @SuppressWarnings("deprecation") |
| @Override |
| public void onElementAction(String action, Object element) { |
| if (new NodeElement("apple").equals(element) && "getChildren".equals(action)) { |
| notNull(getBuilder().getUpdater()).addSubtreeToUpdate(new TreeUpdatePass(notNull(findNode("ibm", false))).setUpdateStamp(1)); |
| notNull(getBuilder().getUpdater()).addSubtreeToUpdate(new TreeUpdatePass(notNull(findNode("intellij", false))).setUpdateStamp(1)); |
| } |
| } |
| }; |
| |
| doAndWaitForBuilder(new Runnable() { |
| @Override |
| public void run() { |
| myTree.expandPath(getPath("com")); |
| } |
| }); |
| |
| assertTree("-/\n" + |
| " -com\n" + |
| " +apple\n" + |
| " +ibm\n" + |
| " +intellij\n" + |
| " +jetbrains\n" + |
| " +org\n" + |
| " +xUnit\n"); |
| } |
| |
| public void testQueryStructureWhenExpand() throws Exception { |
| buildStructure(myRoot); |
| |
| assertTree("+/\n"); |
| assertUpdates("/: update"); |
| |
| buildNode("ide", false); |
| assertTree("-/\n" + |
| " +com\n" + |
| " -jetbrains\n" + |
| " -fabrique\n" + |
| " ide\n" + |
| " +org\n" + |
| " +xUnit\n"); |
| |
| assertUpdates("/: update getChildren\n" + |
| "com: update getChildren\n" + |
| "eclipse: update\n" + |
| "fabrique: update (2) getChildren\n" + |
| "ide: update getChildren\n" + |
| "intellij: update\n" + |
| "jetbrains: update getChildren\n" + |
| "org: update getChildren\n" + |
| "runner: update\n" + |
| "xUnit: update getChildren"); |
| } |
| |
| public void testQueryStructureIsAlwaysShowsPlus() throws Exception { |
| buildStructure(myRoot); |
| myAlwaysShowPlus.add(new NodeElement("jetbrains")); |
| myAlwaysShowPlus.add(new NodeElement("ide")); |
| |
| expand(getPath("/")); |
| assertTree("-/\n" + |
| " +com\n" + |
| " +jetbrains\n" + |
| " +org\n" + |
| " +xUnit\n"); |
| |
| assertUpdates("/: update (2) getChildren\n" + |
| "com: update getChildren\n" + |
| "eclipse: update\n" + |
| "intellij: update\n" + |
| "jetbrains: update\n" + |
| "org: update getChildren\n" + |
| "runner: update\n" + |
| "xUnit: update getChildren"); |
| |
| expand(getPath("jetbrains")); |
| expand(getPath("fabrique")); |
| |
| assertTree("-/\n" + |
| " +com\n" + |
| " -jetbrains\n" + |
| " -fabrique\n" + |
| " +ide\n" + |
| " +org\n" + |
| " +xUnit\n"); |
| |
| assertUpdates("fabrique: update getChildren\n" + |
| "ide: update\n" + |
| "jetbrains: update getChildren"); |
| |
| expand(getPath("ide")); |
| assertTree("-/\n" + |
| " +com\n" + |
| " -jetbrains\n" + |
| " -fabrique\n" + |
| " ide\n" + |
| " +org\n" + |
| " +xUnit\n"); |
| |
| assertUpdates("ide: update getChildren"); |
| } |
| |
| public void testQueryStructureIsAlwaysLeaf() throws Exception { |
| buildStructure(myRoot); |
| myStructure.addLeaf(new NodeElement("openapi")); |
| |
| buildNode("jetbrains", false); |
| assertTree("-/\n" + |
| " +com\n" + |
| " -jetbrains\n" + |
| " +fabrique\n" + |
| " +org\n" + |
| " +xUnit\n"); |
| |
| assertUpdates("/: update (2) getChildren\n" + |
| "com: update getChildren\n" + |
| "eclipse: update\n" + |
| "fabrique: update (2) getChildren\n" + |
| "ide: update\n" + |
| "intellij: update\n" + |
| "jetbrains: update getChildren\n" + |
| "org: update getChildren\n" + |
| "runner: update\n" + |
| "xUnit: update getChildren"); |
| |
| expand(getPath("fabrique")); |
| assertTree("-/\n" + |
| " +com\n" + |
| " -jetbrains\n" + |
| " -fabrique\n" + |
| " ide\n" + |
| " +org\n" + |
| " +xUnit\n"); |
| assertUpdates("ide: update getChildren"); |
| |
| buildNode("com", false); |
| assertTree("-/\n" + |
| " -com\n" + |
| " +intellij\n" + |
| " -jetbrains\n" + |
| " -fabrique\n" + |
| " ide\n" + |
| " +org\n" + |
| " +xUnit\n"); |
| |
| myElementUpdate.clear(); |
| |
| expand(getPath("intellij")); |
| assertTree("-/\n" + |
| " -com\n" + |
| " -intellij\n" + |
| " openapi\n" + |
| " -jetbrains\n" + |
| " -fabrique\n" + |
| " ide\n" + |
| " +org\n" + |
| " +xUnit\n"); |
| |
| assertUpdates("openapi: update"); |
| } |
| |
| public void testToggleIsAlwaysLeaf() throws Exception { |
| buildStructure(myRoot); |
| |
| buildNode("openapi", true); |
| |
| assertTree("-/\n" + |
| " -com\n" + |
| " -intellij\n" + |
| " [openapi]\n" + |
| " +jetbrains\n" + |
| " +org\n" + |
| " +xUnit\n"); |
| |
| myStructure.addLeaf(new NodeElement("intellij")); |
| |
| updateFrom(new NodeElement("com")); |
| |
| assertTree("-/\n" + |
| " -com\n" + |
| " [intellij]\n" + |
| " +jetbrains\n" + |
| " +org\n" + |
| " +xUnit\n"); |
| |
| myStructure.removeLeaf(new NodeElement("intellij")); |
| updateFrom(new NodeElement("com")); |
| |
| assertTree("-/\n" + |
| " -com\n" + |
| " +[intellij]\n" + |
| " +jetbrains\n" + |
| " +org\n" + |
| " +xUnit\n"); |
| |
| expand(getPath("intellij")); |
| |
| assertTree("-/\n" + |
| " -com\n" + |
| " -[intellij]\n" + |
| " openapi\n" + |
| " +jetbrains\n" + |
| " +org\n" + |
| " +xUnit\n"); |
| } |
| |
| public void testSorting() throws Exception { |
| buildStructure(myRoot); |
| assertSorted(""); |
| |
| buildNode("/", false); |
| assertTree("-/\n" + |
| " +com\n" + |
| " +jetbrains\n" + |
| " +org\n" + |
| " +xUnit\n"); |
| |
| assertSorted("/\n" + |
| "com\n" + |
| "jetbrains\n" + |
| "org\n" + |
| "xUnit"); |
| |
| updateFromRoot(); |
| assertTree("-/\n" + |
| " +com\n" + |
| " +jetbrains\n" + |
| " +org\n" + |
| " +xUnit\n"); |
| assertSorted("/\n" + |
| "com\n" + |
| "jetbrains\n" + |
| "org\n" + |
| "xUnit"); |
| |
| updateFrom(new NodeElement("/"), false); |
| assertTree("-/\n" + |
| " +com\n" + |
| " +jetbrains\n" + |
| " +org\n" + |
| " +xUnit\n"); |
| assertSorted(""); |
| |
| expand(getPath("com")); |
| assertTree("-/\n" + |
| " -com\n" + |
| " +intellij\n" + |
| " +jetbrains\n" + |
| " +org\n" + |
| " +xUnit\n"); |
| assertSorted("intellij"); |
| } |
| |
| public void testResorting() throws Exception { |
| final boolean[] invert = new boolean[]{false}; |
| NodeDescriptor.NodeComparator<NodeDescriptor> c = new NodeDescriptor.NodeComparator<NodeDescriptor>() { |
| @Override |
| public int compare(NodeDescriptor o1, NodeDescriptor o2) { |
| return invert[0] ? AlphaComparator.INSTANCE.compare(o2, o1) : AlphaComparator.INSTANCE.compare(o1, o2); |
| } |
| }; |
| |
| myComparator.setDelegate(c); |
| |
| buildStructure(myRoot); |
| |
| buildNode("/", false); |
| assertTree("-/\n" + |
| " +com\n" + |
| " +jetbrains\n" + |
| " +org\n" + |
| " +xUnit\n"); |
| |
| updateFromRoot(); |
| updateFromRoot(); |
| updateFromRoot(); |
| |
| assertTrue(getMyBuilder().getUi().myOwnComparatorStamp > c.getStamp()); |
| invert[0] = true; |
| c.incStamp(); |
| |
| updateFrom(new NodeElement("/"), false); |
| assertTree("-/\n" + |
| " +xUnit\n" + |
| " +org\n" + |
| " +jetbrains\n" + |
| " +com\n"); |
| } |
| |
| public void testRestoreSelectionOfRemovedElement() throws Exception { |
| buildStructure(myRoot); |
| buildNode("openapi", true); |
| assertTree("-/\n" + |
| " -com\n" + |
| " -intellij\n" + |
| " [openapi]\n" + |
| " +jetbrains\n" + |
| " +org\n" + |
| " +xUnit\n"); |
| |
| removeFromParentButKeepRef(new NodeElement("openapi")); |
| |
| updateFromRoot(); |
| |
| assertTree("-/\n" + |
| " -com\n" + |
| " [intellij]\n" + |
| " +jetbrains\n" + |
| " +org\n" + |
| " +xUnit\n"); |
| } |
| |
| public void testElementMove1() throws Exception { |
| assertMove(new Runnable() { |
| @SuppressWarnings("deprecation") |
| @Override |
| public void run() { |
| notNull(getBuilder().getUpdater()).addSubtreeToUpdateByElement(new NodeElement("com")); |
| notNull(getBuilder().getUpdater()).addSubtreeToUpdateByElement(new NodeElement("jetbrains")); |
| } |
| }); |
| } |
| |
| public void testElementMove2() throws Exception { |
| assertMove(new Runnable() { |
| @SuppressWarnings("deprecation") |
| @Override |
| public void run() { |
| notNull(getBuilder().getUpdater()).addSubtreeToUpdateByElement(new NodeElement("jetbrains")); |
| notNull(getBuilder().getUpdater()).addSubtreeToUpdateByElement(new NodeElement("com")); |
| } |
| }); |
| } |
| |
| public void testSelectionOnDelete() throws Exception { |
| doTestSelectionOnDelete(false); |
| } |
| |
| public void testSelectionOnDeleteButKeepRef() throws Exception { |
| doTestSelectionOnDelete(true); |
| } |
| |
| public void testMultipleSelectionOnDelete() throws Exception { |
| buildStructure(myRoot); |
| select(new NodeElement("fabrique"), false); |
| select(new NodeElement("openapi"), true); |
| select(new NodeElement("runner"), true); |
| select(new NodeElement("eclipse"), true); |
| |
| assertTree("-/\n" + |
| " -com\n" + |
| " -intellij\n" + |
| " [openapi]\n" + |
| " -jetbrains\n" + |
| " +[fabrique]\n" + |
| " -org\n" + |
| " +[eclipse]\n" + |
| " -xUnit\n" + |
| " [runner]\n"); |
| |
| myStructure.getNodeFor(new NodeElement("runner")).delete(); |
| myStructure.getNodeFor(new NodeElement("eclipse")).delete(); |
| myStructure.getNodeFor(new NodeElement("openapi")).delete(); |
| |
| updateFromRoot(); |
| |
| assertTree("-/\n" + |
| " -com\n" + |
| " intellij\n" + |
| " -jetbrains\n" + |
| " +[fabrique]\n" + |
| " org\n" + |
| " xUnit\n"); |
| |
| myStructure.getNodeFor(new NodeElement("fabrique")).delete(); |
| |
| updateFromRoot(); |
| assertTree("-/\n" + |
| " -com\n" + |
| " intellij\n" + |
| " [jetbrains]\n" + |
| " org\n" + |
| " xUnit\n"); |
| } |
| |
| public void testRevalidateStructure() throws Exception { |
| final NodeElement com = new NodeElement("com"); |
| final NodeElement actionSystem = new NodeElement("actionSystem"); |
| actionSystem.setForcedParent(com); |
| |
| final NodeElement fabrique = new NodeElement("fabrique"); |
| final NodeElement ide = new NodeElement("ide"); |
| fabrique.setForcedParent(myRoot.getElement()); |
| |
| doAndWaitForBuilder(new Runnable() { |
| @Override |
| public void run() { |
| myRoot.addChild(com).addChild(actionSystem); |
| myRoot.addChild(fabrique).addChild(ide); |
| getBuilder().getUi().activate(true); |
| } |
| }); |
| |
| select(actionSystem, false); |
| expand(getPath("ide")); |
| |
| assertTree("-/\n" + |
| " -com\n" + |
| " [actionSystem]\n" + |
| " -fabrique\n" + |
| " ide\n"); |
| |
| removeFromParentButKeepRef(actionSystem); |
| removeFromParentButKeepRef(fabrique); |
| |
| final NodeElement newActionSystem = new NodeElement("actionSystem"); |
| final NodeElement newFabrique = new NodeElement("fabrique"); |
| |
| myStructure.getNodeFor(com).addChild("intellij").addChild("openapi").addChild(newActionSystem); |
| myRoot.addChild("jetbrains").addChild("tools").addChild(newFabrique).addChild("ide"); |
| |
| assertSame(com, myStructure.getParentElement(actionSystem)); |
| assertNotSame(com, newActionSystem); |
| assertEquals(new NodeElement("openapi"), myStructure.getParentElement(newActionSystem)); |
| |
| assertSame(myRoot.getElement(), myStructure.getParentElement(fabrique)); |
| |
| myStructure.setReValidator(new ReValidator() { |
| @Nullable |
| @Override |
| public AsyncResult<Object> revalidate(NodeElement element) { |
| if (element == actionSystem) { |
| return new AsyncResult.Done<Object>(newActionSystem); |
| } |
| else if (element == fabrique) { |
| return new AsyncResult.Done<Object>(newFabrique); |
| } |
| return null; |
| } |
| }); |
| |
| updateFromRoot(); |
| |
| assertTree("-/\n" + |
| " -com\n" + |
| " -intellij\n" + |
| " -openapi\n" + |
| " [actionSystem]\n" + |
| " -jetbrains\n" + |
| " -tools\n" + |
| " -fabrique\n" + |
| " ide\n"); |
| } |
| |
| public void testNoReValidationIfInvalid() throws Exception { |
| buildStructure(myRoot); |
| |
| final NodeElement intellij = new NodeElement("intellij"); |
| buildNode(intellij, true); |
| |
| assertTree("-/\n" + " -com\n" + " +[intellij]\n" + " +jetbrains\n" + " +org\n" + " +xUnit\n"); |
| |
| removeFromParentButKeepRef(new NodeElement("intellij")); |
| myValidator = new Validator() { |
| @Override |
| public boolean isValid(Object element) { |
| return !element.equals(intellij); |
| } |
| }; |
| final Ref<Object> reValidatedElement = new Ref<Object>(); |
| myStructure.setReValidator(new ReValidator() { |
| @Nullable |
| @Override |
| public AsyncResult<Object> revalidate(NodeElement element) { |
| reValidatedElement.set(element); |
| return null; |
| } |
| }); |
| |
| updateFromRoot(); |
| |
| assertTree("-/\n" + |
| " [com]\n" + |
| " +jetbrains\n" + |
| " +org\n" + |
| " +xUnit\n"); |
| assertNull(reValidatedElement.get() != null ? reValidatedElement.get().toString() : null, reValidatedElement.get()); |
| } |
| |
| private void doTestSelectionOnDelete(boolean keepRef) throws Exception { |
| myComparator.setDelegate(new NodeDescriptor.NodeComparator<NodeDescriptor>() { |
| @Override |
| public int compare(NodeDescriptor o1, NodeDescriptor o2) { |
| boolean isParent1 = myStructure._getChildElements(o1.getElement(), false).length > 0; |
| boolean isParent2 = myStructure._getChildElements(o2.getElement(), false).length > 0; |
| |
| int result = AlphaComparator.INSTANCE.compare(o1, o2); |
| |
| if (isParent1) { |
| result -= 1000; |
| } |
| |
| if (isParent2) { |
| result += 1000; |
| } |
| |
| return result; |
| } |
| }); |
| |
| buildStructure(myRoot); |
| myRoot.addChild("toDelete"); |
| |
| select(new NodeElement("toDelete"), false); |
| assertTree("-/\n" + |
| " +com\n" + |
| " +jetbrains\n" + |
| " +org\n" + |
| " +xUnit\n" + |
| " [toDelete]\n"); |
| |
| if (keepRef) { |
| removeFromParentButKeepRef(new NodeElement("toDelete")); |
| } else { |
| myStructure.getNodeFor(new NodeElement("toDelete")).delete(); |
| } |
| |
| getMyBuilder().addSubtreeToUpdateByElement(new NodeElement("/")); |
| |
| assertTree("-/\n" + " +com\n" + " +jetbrains\n" + " +org\n" + " +[xUnit]\n"); |
| } |
| |
| public void testGetChildrenOnInvalidNode() throws Exception { |
| buildStructure(myRoot); |
| |
| final Set<NodeElement> invalid = new HashSet<NodeElement>(); |
| myValidator = new Validator<NodeElement>() { |
| @Override |
| public boolean isValid(NodeElement element) { |
| return !invalid.contains(element); |
| } |
| }; |
| |
| expand(getPath("/")); |
| assertTree("-/\n" + |
| " +com\n" + |
| " +jetbrains\n" + |
| " +org\n" + |
| " +xUnit\n"); |
| |
| invalid.add(new NodeElement("com")); |
| |
| updateFrom(new NodeElement("com")); |
| assertTree("-/\n" + |
| " com\n" + |
| " +jetbrains\n" + |
| " +org\n" + |
| " +xUnit\n"); |
| |
| updateFromRoot(); |
| assertTree("-/\n" + |
| " +jetbrains\n" + |
| " +org\n" + |
| " +xUnit\n"); |
| } |
| |
| public void testSelectWhenUpdatesArePending() throws Exception { |
| notNull(getBuilder().getUpdater()).setDelay(1000); |
| |
| buildStructure(myRoot); |
| |
| buildNode("intellij", false); |
| select(new Object[]{new NodeElement("intellij")}, false); |
| assertTree("-/\n" + " -com\n" + " -[intellij]\n" + " openapi\n" + " +jetbrains\n" + " +org\n" + " +xUnit\n"); |
| |
| myIntellij.addChild("ui"); |
| |
| DefaultMutableTreeNode intellijNode = findNode("intellij", false); |
| assertNotNull(intellijNode); |
| assertTrue(myTree.isExpanded(new TreePath(intellijNode.getPath()))); |
| getMyBuilder().addSubtreeToUpdate(intellijNode); |
| assertFalse(getMyBuilder().getUi().isReady()); |
| |
| select(new Object[]{new NodeElement("ui")}, false); |
| assertTree("-/\n" + " -com\n" + " -intellij\n" + " openapi\n" + " [ui]\n" + " +jetbrains\n" + " +org\n" + " +xUnit\n"); |
| } |
| |
| public void testAddNewElementToLeafElementAlwaysShowPlus() throws Exception { |
| myAlwaysShowPlus.add(new NodeElement("openapi")); |
| |
| buildStructure(myRoot); |
| select(new Object[]{new NodeElement("openapi")}, false); |
| |
| assertTree("-/\n" + " -com\n" + " -intellij\n" + " +[openapi]\n" + " +jetbrains\n" + " +org\n" + " +xUnit\n"); |
| |
| expand(getPath("openapi")); |
| assertTree("-/\n" + |
| " -com\n" + |
| " -intellij\n" + |
| " [openapi]\n" + |
| " +jetbrains\n" + |
| " +org\n" + |
| " +xUnit\n"); |
| |
| myOpenApi.addChild("ui"); |
| |
| getMyBuilder().addSubtreeToUpdate(findNode("openapi", false)); |
| |
| assertTree("-/\n" + |
| " -com\n" + |
| " -intellij\n" + |
| " +[openapi]\n" + |
| " +jetbrains\n" + |
| " +org\n" + |
| " +xUnit\n"); |
| } |
| |
| public void testAddNewElementToLeafElement() throws Exception { |
| buildStructure(myRoot); |
| select(new Object[]{new NodeElement("openapi")}, false); |
| |
| assertTree("-/\n" + " -com\n" + " -intellij\n" + " [openapi]\n" + " +jetbrains\n" + " +org\n" + " +xUnit\n"); |
| |
| expand(getPath("openapi")); |
| assertTree("-/\n" + " -com\n" + " -intellij\n" + " [openapi]\n" + " +jetbrains\n" + " +org\n" + " +xUnit\n"); |
| |
| myOpenApi.addChild("ui"); |
| |
| getMyBuilder().addSubtreeToUpdate(findNode("openapi", false)); |
| |
| assertTree("-/\n" + " -com\n" + " -intellij\n" + " +[openapi]\n" + " +jetbrains\n" + " +org\n" + " +xUnit\n"); |
| } |
| |
| public void testUpdateAlwaysLeaf() throws Exception { |
| myStructure.addLeaf(new NodeElement("openapi")); |
| |
| buildStructure(myRoot); |
| buildNode(new NodeElement("intellij"), false); |
| expand(getPath("intellij")); |
| |
| assertTree("-/\n" + " -com\n" + " -intellij\n" + " openapi\n" + " +jetbrains\n" + " +org\n" + " +xUnit\n"); |
| |
| myElementUpdate.clear(); |
| |
| invokeAndWaitIfNeeded(new Runnable() { |
| @Override |
| public void run() { |
| getBuilder().queueUpdateFrom(new NodeElement("openapi"), false); |
| } |
| }); |
| waitBuilderToCome(); |
| |
| assertUpdates("openapi: update"); |
| } |
| |
| private void assertMove(Runnable updateRoutine) throws Exception { |
| buildStructure(myRoot); |
| |
| buildNode("intellij", true); |
| assertTree("-/\n" + |
| " -com\n" + |
| " +[intellij]\n" + |
| " +jetbrains\n" + |
| " +org\n" + |
| " +xUnit\n"); |
| |
| AbstractTreeBuilderTest.Node intellij = removeFromParentButKeepRef(new NodeElement("intellij")); |
| notNull(myRoot.getChildNode("jetbrains")).addChild(intellij); |
| |
| updateRoutine.run(); |
| |
| assertTree("-/\n" + |
| " com\n" + |
| " -jetbrains\n" + |
| " +fabrique\n" + |
| " +[intellij]\n" + |
| " +org\n" + |
| " +xUnit\n"); |
| } |
| |
| public void testChangeRootElement() throws Exception { |
| buildStructure(myRoot); |
| |
| select(new NodeElement("com"), false); |
| |
| assertTree("-/\n" + |
| " +[com]\n" + |
| " +jetbrains\n" + |
| " +org\n" + |
| " +xUnit\n"); |
| |
| myRoot = new Node(null, "root"); |
| myStructure.reInitRoot(myRoot); |
| |
| myRoot.addChild("com"); |
| |
| updateFromRoot(); |
| assertTree("+root\n"); |
| } |
| |
| public void testQueueUpdate() throws Exception { |
| buildStructure(myRoot); |
| |
| buildNode(new NodeElement("com"), false); |
| |
| assertTree("-/\n" + |
| " -com\n" + |
| " +intellij\n" + |
| " +jetbrains\n" + |
| " +org\n" + |
| " +xUnit\n"); |
| |
| myCom.addChild("ibm"); |
| |
| getBuilder().queueUpdateFrom(new NodeElement("com"), false, true); |
| getBuilder().queueUpdateFrom(new NodeElement("/"), false, false); |
| |
| assertTree("-/\n" + |
| " -com\n" + |
| " ibm\n" + |
| " +intellij\n" + |
| " +jetbrains\n" + |
| " +org\n" + |
| " +xUnit\n"); |
| } |
| |
| public void testReleaseBuilderDuringUpdate() throws Exception { |
| assertReleaseDuringBuilding("update", "fabrique", new Runnable() { |
| @Override |
| public void run() { |
| try { |
| select(new NodeElement("ide"), false); |
| } |
| catch (Exception e) { |
| myCancelRequest = e; |
| } |
| } |
| }); |
| } |
| |
| public void testStickyLoadingNodeIssue() throws Exception { |
| buildStructure(myRoot); |
| |
| final boolean[] done = new boolean[] {false}; |
| invokeLaterIfNeeded(new Runnable() { |
| @Override |
| public void run() { |
| getBuilder().select(new NodeElement("jetbrains"), new Runnable() { |
| @Override |
| public void run() { |
| getBuilder().expand(new NodeElement("fabrique"), new Runnable() { |
| @Override |
| public void run() { |
| done[0] = true; |
| } |
| }); |
| } |
| }); |
| } |
| }); |
| |
| waitBuilderToCome(new Condition<Object>() { |
| @Override |
| public boolean value(Object o) { |
| return done[0]; |
| } |
| }); |
| |
| assertTree("-/\n" + " +com\n" + " -[jetbrains]\n" + " -fabrique\n" + " ide\n" + " +org\n" + " +xUnit\n"); |
| } |
| |
| public void testUpdateCollapsedBuiltNode() throws Exception { |
| buildStructure(myRoot, false); |
| |
| myCom.removeAll(); |
| myAlwaysShowPlus.add(new NodeElement("com")); |
| |
| activate(); |
| |
| buildNode("/", false); |
| assertTree("-/\n" + |
| " +com\n" + |
| " +jetbrains\n" + |
| " +org\n" + |
| " +xUnit\n"); |
| |
| final DefaultMutableTreeNode com = findNode("com", false); |
| assertNotNull(com); |
| assertEquals(1, com.getChildCount()); |
| assertEquals(LoadingNode.getText(), com.getChildAt(0).toString()); |
| |
| expand(getPath("com")); |
| assertTree("-/\n" + |
| " com\n" + |
| " +jetbrains\n" + |
| " +org\n" + |
| " +xUnit\n"); |
| |
| myCom.addChild(myIntellij); |
| updateFrom(new NodeElement("com")); |
| assertTree("-/\n" + |
| " +com\n" + |
| " +jetbrains\n" + |
| " +org\n" + |
| " +xUnit\n"); |
| assertEquals(1, com.getChildCount()); |
| assertEquals("intellij", com.getChildAt(0).toString()); |
| |
| myCom.removeAll(); |
| updateFrom(new NodeElement("com")); |
| |
| expand(getPath("com")); |
| assertTree("-/\n" + |
| " com\n" + |
| " +jetbrains\n" + |
| " +org\n" + |
| " +xUnit\n"); |
| } |
| |
| public void testReleaseBuilderDuringGetChildren() throws Exception { |
| assertReleaseDuringBuilding("getChildren", "fabrique", new Runnable() { |
| @Override |
| public void run() { |
| try { |
| select(new NodeElement("ide"), false); |
| } |
| catch (Exception e) { |
| myCancelRequest = e; |
| } |
| } |
| }); |
| } |
| |
| public void testAssertionOnInfiniteTree() throws Exception { |
| final Node com = myRoot.addChild("com"); |
| final Node intellij = com.addChild("intellij"); |
| final Node com2 = intellij.addChild("com"); |
| final Node idea = com2.addChild("idea"); |
| |
| idea.myElement.setForcedParent(com2.myElement); |
| com2.myElement.setForcedParent(intellij.myElement); |
| intellij.myElement.setForcedParent(com.myElement); |
| com.myElement.setForcedParent(myRoot.myElement); |
| |
| activate(); |
| |
| try { |
| System.err.println("The following error is part of the test, no need to fix it"); |
| buildNode("idea", true); |
| } |
| catch (AssertionFailedError e) { |
| } |
| |
| assertTrue(getBuilder().getUi().isReady()); |
| } |
| |
| private void assertReleaseDuringBuilding(final String actionAction, final Object actionElement, Runnable buildAction) throws Exception { |
| buildStructure(myRoot); |
| |
| myElementUpdateHook = new ElementUpdateHook() { |
| @Override |
| public void onElementAction(String action, Object element) { |
| if (!element.toString().equals(actionElement.toString())) return; |
| |
| Runnable runnable = new Runnable() { |
| @Override |
| public void run() { |
| myReadyRequest = true; |
| Disposer.dispose(getBuilder()); |
| } |
| }; |
| |
| if (actionAction.equals(action)) { |
| if (getBuilder().getUi().isPassthroughMode()) { |
| runnable.run(); |
| } else { |
| //noinspection SSBasedInspection |
| SwingUtilities.invokeLater(runnable); |
| } |
| } |
| } |
| }; |
| |
| buildAction.run(); |
| |
| boolean released = new WaitFor(15000) { |
| @Override |
| protected boolean condition() { |
| return getBuilder().getUi() == null; |
| } |
| }.isConditionRealized(); |
| |
| assertTrue(released); |
| } |
| |
| |
| public static class SyncUpdate extends TreeUiTest { |
| public SyncUpdate() { |
| super(false, false); |
| } |
| } |
| |
| |
| public static class PassThrough extends TreeUiTest { |
| public PassThrough() { |
| super(true); |
| } |
| |
| @Override |
| public void testSelectionGoesToParentWhenOnlyChildMoved2() throws Exception { |
| //todo |
| } |
| |
| @Override |
| public void testQueryStructureWhenExpand() throws Exception { |
| //todo |
| } |
| |
| @Override |
| public void testMoveElementToAdjacentEmptyParentWithSmartExpandAndSerialUpdateSubtrees() throws Exception { |
| // doesn't make sense since pass-through mode is always serial, it doesn't queue for updates |
| } |
| |
| @Override |
| public void testElementMove1() throws Exception { |
| //todo |
| } |
| |
| @Override |
| public void testClear() throws Exception { |
| //todo |
| } |
| |
| @Override |
| public void testDoubleCancelUpdate() throws Exception { |
| // doesn't make sense in pass-through mode |
| } |
| |
| @Override |
| public void testNoExtraJTreeModelUpdate() throws Exception { |
| // doesn't make sense in pass-through mode |
| } |
| |
| @Override |
| public void testSelectWhenUpdatesArePending() throws Exception { |
| // doesn't make sense in pass-through mode |
| } |
| |
| @Override |
| public void testBigTreeUpdate() throws Exception { |
| // doesn't make sense in pass-through mode |
| } |
| } |
| |
| |
| public static class YieldingUpdate extends TreeUiTest { |
| public YieldingUpdate() { |
| super(true, false); |
| } |
| } |
| |
| |
| public static class BgLoadingSyncUpdate extends TreeUiTest { |
| public BgLoadingSyncUpdate() { |
| super(false, true); |
| } |
| |
| @Override |
| protected int getChildrenLoadingDelay() { |
| return 100; |
| } |
| |
| @Override |
| protected int getNodeDescriptorUpdateDelay() { |
| return 100; |
| } |
| |
| @Override |
| public void testNoInfiniteSmartExpand() throws Exception { |
| //todo |
| } |
| |
| @Override |
| public void testBigTreeUpdate() throws Exception { |
| //to slow, tested the same in VeryQuickBgLoadingTest |
| } |
| } |
| |
| public static class QuickBgLoadingSyncUpdate extends TreeUiTest { |
| public QuickBgLoadingSyncUpdate() { |
| super(false, true); |
| } |
| |
| @Override |
| public void testQueryStructure() throws Exception { |
| super.testQueryStructure(); |
| } |
| |
| @Override |
| protected int getNodeDescriptorUpdateDelay() { |
| return 300; |
| } |
| |
| @Override |
| public void testNoInfiniteSmartExpand() throws Exception { |
| //todo |
| } |
| |
| @Override |
| public void testBigTreeUpdate() throws Exception { |
| //to slow, tested the same in VeryQuickBgLoadingTest |
| } |
| } |
| |
| |
| public static class VeryQuickBgLoadingSyncUpdate extends TreeUiTest { |
| public VeryQuickBgLoadingSyncUpdate() { |
| super(false, true); |
| } |
| |
| @Override |
| public void testSelectWhileUpdating() throws Exception { |
| super.testSelectWhileUpdating(); |
| } |
| |
| @Override |
| protected int getNodeDescriptorUpdateDelay() { |
| return 0; |
| } |
| |
| @Override |
| protected int getChildrenLoadingDelay() { |
| return 0; |
| } |
| |
| @Override |
| public void testNoInfiniteSmartExpand() throws Exception { |
| // todo; |
| } |
| |
| @Override |
| public void testReleaseBuilderDuringUpdate() throws Exception { |
| // todo |
| } |
| |
| @Override |
| public void testReleaseBuilderDuringGetChildren() throws Exception { |
| // todo |
| } |
| } |
| |
| |
| public static TestSuite suite() { |
| TestSuite suite = new TestSuite(); |
| |
| suite.addTestSuite(PassThrough.class); |
| suite.addTestSuite(SyncUpdate.class); |
| suite.addTestSuite(YieldingUpdate.class); |
| suite.addTestSuite(BgLoadingSyncUpdate.class); |
| |
| // to run on suspecting of race conditions in background loading |
| //suite.addTestSuite(VeryQuickBgLoadingSyncUpdate.class); |
| //suite.addTestSuite(QuickBgLoadingSyncUpdate.class); |
| |
| return suite; |
| } |
| |
| private abstract static class MyRunnable implements Runnable { |
| @Override |
| public final void run() { |
| try { |
| runSafe(); |
| } |
| catch (Exception e) { |
| throw new RuntimeException(e); |
| } |
| } |
| |
| public abstract void runSafe() throws Exception; |
| } |
| } |