tree tests moved to community

This commit is contained in:
Kirill Kalishev
2010-01-23 16:14:20 +03:00
parent 262c5cc8b2
commit 595e4677d7
9 changed files with 3145 additions and 74 deletions
@@ -155,78 +155,6 @@ public class IdeaTestUtil extends PlatformTestUtil {
assertDirectoriesEqual(dirAfter, dirBefore, CVS_FILE_FILTER);
}
public static StringBuffer print(AbstractTreeStructure structure,
Object node,
int currentLevel,
Comparator comparator,
int maxRowCount,
char paddingChar) {
StringBuffer buffer = new StringBuffer();
doPrint(buffer, currentLevel, node, structure, comparator, maxRowCount, 0, paddingChar);
return buffer;
}
private static int doPrint(StringBuffer buffer,
int currentLevel,
Object node,
AbstractTreeStructure structure,
Comparator comparator,
int maxRowCount,
int currentLine,
char paddingChar) {
if (currentLine >= maxRowCount && maxRowCount != -1) return currentLine;
StringUtil.repeatSymbol(buffer, paddingChar, currentLevel);
buffer.append(toString(node)).append("\n");
currentLine++;
Object[] children = structure.getChildElements(node);
if (comparator != null) {
ArrayList<?> list = new ArrayList<Object>(Arrays.asList(children));
Collections.sort(list, comparator);
children = list.toArray(new Object[list.size()]);
}
for (Object child : children) {
currentLine = doPrint(buffer, currentLevel + 1, child, structure, comparator, maxRowCount, currentLine, paddingChar);
}
return currentLine;
}
public static String print(Object[] objects) {
return print(Arrays.asList(objects));
}
public static String print(Collection c) {
StringBuilder result = new StringBuilder();
for (Iterator iterator = c.iterator(); iterator.hasNext();) {
Object each = iterator.next();
result.append(toString(each));
if (iterator.hasNext()) {
result.append("\n");
}
}
return result.toString();
}
public static String print(ListModel model) {
StringBuilder result = new StringBuilder();
for (int i = 0; i < model.getSize(); i++) {
result.append(toString(model.getElementAt(i)));
result.append("\n");
}
return result.toString();
}
public static String print(JTree tree) {
return print(tree, false);
}
public static void assertTreeStructureEquals(final AbstractTreeStructure treeStructure, final String expected) {
Assert.assertEquals(expected, print(treeStructure, treeStructure.getRootElement(), 0, null, -1, ' ').toString());
}
public static void assertTiming(String message, long expected, long actual) {
if (COVERAGE_ENABLED_BUILD) return;
long expectedOnMyMachine = expected * Timings.MACHINE_TIMING / ETALON_TIMING;
+1
View File
@@ -23,6 +23,7 @@
<orderEntry type="module" module-name="lvcs-api" exported="" />
<orderEntry type="library" scope="TEST" name="JUnit4" level="project" />
<orderEntry type="library" name="JavaHelp" level="project" />
<orderEntry type="module" module-name="testFramework" />
</component>
</module>
@@ -0,0 +1,277 @@
package com.intellij.ide.util.treeView;
import com.intellij.openapi.util.Disposer;
import com.intellij.ui.treeStructure.Tree;
import org.jetbrains.annotations.NotNull;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreePath;
import java.util.ArrayList;
public abstract class AbstractTreeBuilderCrashTest extends BaseTreeTestCase {
private AbstractTreeStructure myStructure;
private DefaultTreeModel myTreeModel;
private CachedNode myRoot;
protected AbstractTreeBuilderCrashTest(boolean yeild, boolean bg) {
super(yeild, bg);
}
public void testElementMovedButNodeIsStillInStructure() throws Exception {
assertNodeMove(new Runnable() {
public void run() {
getBuilder().addSubtreeToUpdateByElement(myRoot.getChild("folder1"));
getBuilder().addSubtreeToUpdateByElement(myRoot.getChild("folder2"));
}
});
}
public void testElementMovedButNodeIsStillInStructure2() throws Exception {
assertNodeMove(new Runnable() {
public void run() {
getBuilder().addSubtreeToUpdateByElement(myRoot.getChild("folder2"));
getBuilder().addSubtreeToUpdateByElement(myRoot.getChild("folder1"));
}
});
}
private void assertNodeMove(final Runnable update) throws Exception {
myRoot = new CachedNode("root");
final CachedNode folder1 = myRoot.addChild("folder1");
final CachedNode file = folder1.addChild("file");
final CachedNode folder2 = myRoot.addChild("folder2");
initTree(myRoot);
getBuilder().updateFromRoot();
getBuilder().select(file, null);
assertTree(
"-root\n" +
" -folder1\n" +
" [file]\n" +
" folder2\n");
folder1.myChildren.remove(file);
folder2.addChild("file");
update.run();
assertTree(
"-root\n" +
" folder1\n" +
" -folder2\n" +
" [file]\n");
}
public void testNewUniqueChilden() throws Exception {
final boolean[] changes = new boolean[1];
final Node root = new Node("root", null) {
@Override
Node[] getChildren() {
if (changes[0]) {
return new Node[] {new Node("node1", this, "node1id", "changedNode1") {
@Override
Node[] getChildren() {
return new Node[] {new Node("newNode11", this, "node11id"), new Node("node13", this, "node13id")};
}
}, new Node("node2", this, "node2id")};
} else {
return new Node[] {new Node("node1", this, "node1id") {
@Override
Node[] getChildren() {
return new Node[] {new Node("node11", this, "node11id"), new Node("node12", this, "node12id")};
}
}, new Node("node2", this, "node2id")};
}
}
};
initTree(root);
updateFromRoot();
assertTree("-root\n" +
" -node1\n" +
" node11\n" +
" node12\n" +
" node2\n");
collapsePath(new TreePath(myTreeModel.getRoot()));
getBuilder().expand(root, null);
assertTree("-root\n" +
" -node1\n" +
" node11\n" +
" node12\n" +
" node2\n");
updateFromRoot();
assertTree("-root\n" +
" -node1\n" +
" node11\n" +
" node12\n" +
" node2\n");
changes[0] = true;
updateFromRoot();
assertTree("-root\n" +
" -node1\n" +
" newNode11\n" +
" node13\n" +
" node2\n");
}
private void initTree(final Node root) throws Exception {
myStructure = new BaseStructure() {
public Object getRootElement() {
return root;
}
public Object[] doGetChildElements(final Object element) {
return ((Node)element).getChildren();
}
public Object getParentElement(final Object element) {
return ((Node)element).getParent();
}
@NotNull
public NodeDescriptor doCreateDescriptor(final Object element, final NodeDescriptor parentDescriptor) {
return (NodeDescriptor)element;
}
public void commit() {
}
public boolean hasSomethingToCommit() {
return false;
}
};
myTreeModel = new DefaultTreeModel(new DefaultMutableTreeNode());
myTree = new Tree(myTreeModel);
myTree.setRootVisible(false);
initBuilder(new BaseTreeBuilder(myTree, myTreeModel, myStructure, AlphaComparator.INSTANCE) {
@Override
protected boolean isAutoExpandNode(final NodeDescriptor nodeDescriptor) {
return true;
}
@Override
protected boolean isDisposeOnCollapsing(final NodeDescriptor nodeDescriptor) {
return false;
}
});
getBuilder().getUi().setCheckStructure(false);
Disposer.register(getRootDisposable(), getBuilder());
showTree();
}
class Node extends NodeDescriptor {
Node myParent;
String myId;
String myEqualityString;
String myComment;
Node(String id, final Node parent) {
this(id, parent, id, null);
}
Node(String id, final Node parent, String equalityString) {
this(id, parent, equalityString, null);
}
Node(String id, final Node parent, String equalityString, String comment) {
super(null, parent);
myParent = parent;
myId = id;
myEqualityString = equalityString;
myComment = comment;
}
Node getParent() {
return myParent;
}
Node[] getChildren() {
return new Node[0];
}
public boolean update() {
return false;
}
public Object getElement() {
return this;
}
@Override
public String toString() {
return myId;
}
@Override
public boolean equals(final Object o) {
if (this == o) return true;
if (!(o instanceof Node)) return false;
final Node node = (Node)o;
if (!myEqualityString.equals(node.myEqualityString)) return false;
return true;
}
@Override
public int hashCode() {
return myId.hashCode();
}
}
class CachedNode extends Node {
private final ArrayList<CachedNode> myChildren = new ArrayList<CachedNode>();
CachedNode(final String id) {
super(id, null);
}
CachedNode addChild(String id) {
final CachedNode node = new CachedNode(id);
myChildren.add(node);
node.myParent = this;
return node;
}
CachedNode getChild(String id) {
for (CachedNode each : myChildren) {
if (id.equals(each.myId)) return each;
}
return null;
}
@Override
final Node[] getChildren() {
return myChildren.toArray(new Node[myChildren.size()]);
}
}
public static class NoYieldNoBackground extends AbstractTreeBuilderCrashTest {
public NoYieldNoBackground() {
super(false, false);
}
}
}
@@ -0,0 +1,611 @@
package com.intellij.ide.util.treeView;
import com.intellij.openapi.util.Condition;
import com.intellij.testFramework.PlatformTestUtil;
import com.intellij.ui.treeStructure.Tree;
import com.intellij.util.Time;
import com.intellij.util.WaitFor;
import com.intellij.util.containers.HashMap;
import junit.framework.Assert;
import org.jetbrains.annotations.NotNull;
import javax.swing.event.*;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreeNode;
import javax.swing.tree.TreePath;
import java.util.*;
abstract class AbstractTreeBuilderTest extends BaseTreeTestCase<BaseTreeTestCase.NodeElement> {
protected MyStructure myStructure;
Node myRoot;
DefaultTreeModel myTreeModel;
Node myCom;
Node myOpenApi;
Node myIde;
Node myRunner;
Node myRcp;
boolean myEnsureSelection = false;
AbstractTreeBuilderTest.Node myFabrique;
Map<NodeElement, ElementEntry> myElementUpdate = new TreeMap<NodeElement, ElementEntry>();
ElementUpdateHook myElementUpdateHook;
Map<String, Integer> mySortedParent = new TreeMap<String, Integer>();
NodeDescriptor.NodeComparator.Delegate<NodeDescriptor> myComparator;
Node myIntellij;
protected AbstractTreeBuilderTest(boolean passthrougth) {
super(passthrougth);
}
protected AbstractTreeBuilderTest(boolean yieldingUiBuild, boolean bgStructureBuilding) {
super(yieldingUiBuild, bgStructureBuilding);
}
@Override
protected void setUp() throws Exception {
super.setUp();
myComparator = new NodeDescriptor.NodeComparator.Delegate<NodeDescriptor>(new NodeDescriptor.NodeComparator<NodeDescriptor>() {
public int compare(NodeDescriptor o1, NodeDescriptor o2) {
return AlphaComparator.INSTANCE.compare(o1, o2);
}
});
mySortedParent.clear();
myTreeModel = new DefaultTreeModel(new DefaultMutableTreeNode(null));
myTreeModel.addTreeModelListener(new TreeModelListener() {
public void treeNodesChanged(TreeModelEvent e) {
assertEdt();
}
public void treeNodesInserted(TreeModelEvent e) {
assertEdt();
}
public void treeNodesRemoved(TreeModelEvent e) {
assertEdt();
}
public void treeStructureChanged(TreeModelEvent e) {
assertEdt();
}
});
myTree = new Tree(myTreeModel);
myStructure = new MyStructure();
myRoot = new Node(null, "/");
initBuilder(new MyBuilder());
myTree.getSelectionModel().addTreeSelectionListener(new TreeSelectionListener() {
public void valueChanged(TreeSelectionEvent e) {
assertEdt();
}
});
myTree.addTreeExpansionListener(new TreeExpansionListener() {
public void treeExpanded(TreeExpansionEvent event) {
assertEdt();
}
public void treeCollapsed(TreeExpansionEvent event) {
assertEdt();
}
});
}
@Override
protected void tearDown() throws Exception {
myElementUpdate.clear();
myElementUpdateHook = null;
super.tearDown();
}
Node removeFromParentButKeepRef(NodeElement child) {
NodeElement parent = (NodeElement)myStructure.getParentElement(child);
AbstractTreeBuilderTest.Node node = myStructure.getNodeFor(parent).remove(child, false);
Assert.assertEquals(parent, myStructure.getParentElement(child));
Assert.assertFalse(Arrays.asList(myStructure._getChildElements(parent, false)).contains(child));
return node;
}
void assertSorted(String expected) {
Iterator<String> keys = mySortedParent.keySet().iterator();
StringBuffer result = new StringBuffer();
while (keys.hasNext()) {
String each = keys.next();
result.append(each);
int count = mySortedParent.get(each);
if (count > 1) {
result.append(" (" + count + ")");
}
if (keys.hasNext()) {
result.append("\n");
}
}
Assert.assertEquals(expected + "\n", result + "\n");
mySortedParent.clear();
}
private void addEntry(String value) {
if (mySortedParent.containsKey(value)) {
mySortedParent.put(value, mySortedParent.get(value) + 1);
} else {
mySortedParent.put(value, 0);
}
}
void assertUpdates(String expected) {
List<Object> entries = Arrays.asList(myElementUpdate.values().toArray());
Assert.assertEquals(expected + "\n", PlatformTestUtil.print(entries) + "\n");
myElementUpdate.clear();
}
public void _testNoUpdateIfHidden() throws Exception {
final ArrayList processedNodes = new ArrayList();
final boolean[] toHide = new boolean[] {false};
myElementUpdateHook = new ElementUpdateHook() {
public void onElementAction(String action, Object element) {
if (toHide[0]) {
if ("jetbrains".equals(element.toString())) {
getBuilder().getUi().deactivate();
}
}
}
};
buildStructure(myRoot);
waitBuilderToCome();
processedNodes.clear();
buildNode("/", false);
assertTree(
"-/\n" +
" +com\n" +
" +jetbrains\n" +
" +org\n" +
" +xunit\n");
Assert.assertEquals("/\n" +
"com\n" +
"jetbrains\n" +
"xunit\n" +
"org\n" +
"intellij\n" +
"fabrique\n" +
"runner\n" +
"eclipse", PlatformTestUtil.print(processedNodes));
processedNodes.clear();
toHide[0] = true;
updateFromRoot();
Assert.assertEquals("/\n" +
"com\n" +
"intellij\n" +
"jetbrains", PlatformTestUtil.print(processedNodes));
processedNodes.clear();
toHide[0] = false;
showTree();
assertTree(
"-/\n" +
" +com\n" +
" +jetbrains\n" +
" +org\n" +
" +xunit\n");
Assert.assertEquals("/\n" +
"com\n" +
"intellij\n" +
"jetbrains\n" +
"fabrique\n" +
"org\n" +
"eclipse\n" +
"xunit\n" +
"runner", PlatformTestUtil.print(processedNodes));
}
void buildStructure(final Node root) throws Exception {
doAndWaitForBuilder(new Runnable() {
public void run() {
myCom = root.addChild("com");
myIntellij = myCom.addChild("intellij");
myOpenApi = myIntellij.addChild("openapi");
myFabrique = root.addChild("jetbrains").addChild("fabrique");
myIde = myFabrique.addChild("ide");
myRunner = root.addChild("xunit").addChild("runner");
myRcp = root.addChild("org").addChild("eclipse").addChild("rcp");
getBuilder().getUi().activate(true);
}
});
}
protected void activate() throws Exception {
doAndWaitForBuilder(new Runnable() {
public void run() {
getBuilder().getUi().activate(true);
}
});
}
void hideTree() throws Exception {
Assert.assertFalse(getMyBuilder().myWasCleanedUp);
invokeLaterIfNeeded(new Runnable() {
public void run() {
getBuilder().getUi().deactivate();
}
});
final WaitFor waitFor = new WaitFor() {
protected boolean condition() {
return getMyBuilder().myWasCleanedUp || myCancelRequest != null;
}
};
if (myCancelRequest != null) {
throw new Exception(myCancelRequest);
}
waitFor.assertCompleted("Tree cleanup was not performed");
Assert.assertTrue(getMyBuilder().myWasCleanedUp);
}
void buildNode(String elementText, boolean select) throws Exception {
buildNode(new NodeElement(elementText), select);
}
void buildNode(Node node, boolean select) throws Exception {
buildNode(node.myElement, select);
}
void buildNode(final NodeElement element, final boolean select) throws Exception {
buildNode(element, select, true);
}
void buildNode(final NodeElement element, final boolean select, final boolean addToSelection) throws Exception {
final boolean[] done = new boolean[] {false};
doAndWaitForBuilder(new Runnable() {
public void run() {
if (select) {
getBuilder().select(element, new Runnable() {
public void run() {
done[0] = true;
}
}, addToSelection);
} else {
getBuilder().expand(element, new Runnable() {
public void run() {
done[0] = true;
}
});
}
}
}, new Condition() {
public boolean value(Object o) {
return done[0];
}
});
Assert.assertNotNull(findNode(element, select));
}
DefaultMutableTreeNode findNode(String elementText, boolean shouldBeSelected) {
return findNode(new NodeElement(elementText), shouldBeSelected);
}
DefaultMutableTreeNode findNode(NodeElement element, boolean shouldBeSelected) {
return findNode((DefaultMutableTreeNode)myTree.getModel().getRoot(), element, shouldBeSelected);
}
private DefaultMutableTreeNode findNode(DefaultMutableTreeNode treeNode, NodeElement toFind, boolean shouldBeSelected) {
final Object object = treeNode.getUserObject();
Assert.assertNotNull(object);
if (!(object instanceof NodeDescriptor)) return null;
final NodeElement element = (NodeElement)((NodeDescriptor)object).getElement();
if (toFind.equals(element)) return treeNode;
for (int i = 0; i < treeNode.getChildCount(); i++) {
final DefaultMutableTreeNode result = findNode((DefaultMutableTreeNode)treeNode.getChildAt(i), toFind, shouldBeSelected);
if (result != null) {
if (shouldBeSelected) {
final TreePath path = new TreePath(result.getPath());
Assert.assertTrue("Path should be selected: " + path, myTree.isPathSelected(path));
}
return result;
}
}
return null;
}
class Node {
final NodeElement myElement;
final ArrayList<Node> myChildElements = new ArrayList<Node>();
Node(Node parent, String textName) {
this(parent, new NodeElement(textName));
}
Node(Node parent, NodeElement name) {
myElement = name;
setParent(parent);
}
private void setParent(Node parent) {
myStructure.register(parent != null ? parent.myElement : null, this);
}
public NodeElement getElement() {
return myElement;
}
public Node addChild(Node node) {
myChildElements.add(node);
node.setParent(this);
return node;
}
public Node addChild(String name) {
final Node node = new Node(this, name);
myChildElements.add(node);
return node;
}
@Override
public String toString() {
return myElement.toString();
}
public void removeAll() {
myChildElements.clear();
}
public Node getChildNode(String name) {
for (Node each : myChildElements) {
if (name.equals(each.myElement.myName)) return each;
}
return null;
}
public Object[] getChildElements() {
Object[] elements = new Object[myChildElements.size()];
for (int i = 0; i < myChildElements.size(); i++) {
elements[i] = myChildElements.get(i).myElement;
}
return elements;
}
public void delete() {
final NodeElement parent = (NodeElement)myStructure.getParentElement(myElement);
Assert.assertNotNull(myElement.toString(), parent);
myStructure.getNodeFor(parent).remove(myElement, true);
}
private Node remove(final NodeElement name, boolean removeRefToParent) {
final Iterator<Node> kids = myChildElements.iterator();
Node removed = null;
while (kids.hasNext()) {
Node each = kids.next();
if (name.equals(each.myElement)) {
kids.remove();
removed = each;
break;
}
}
if (removeRefToParent) {
myStructure.myChild2Parent.remove(name);
}
return removed;
}
}
class MyStructure extends BaseStructure {
private final Map<NodeElement, NodeElement> myChild2Parent = new HashMap<NodeElement, NodeElement>();
private final Map<NodeElement, Node> myElement2Node = new HashMap<NodeElement, Node>();
private Set<NodeElement> myLeaves = new HashSet<NodeElement>();
public Object getRootElement() {
return myRoot.myElement;
}
public void reinitRoot(Node root) {
myRoot = root;
myElement2Node.clear();
myLeaves.clear();
myElement2Node.put(root.myElement, root);
}
@Override
public Object[] doGetChildElements(Object element) {
onElementAction("getChildren", (NodeElement)element);
final AbstractTreeBuilderTest.Node node = myElement2Node.get((NodeElement)element);
return node.getChildElements();
}
private Node getNodeFor(Object element) {
return myElement2Node.get(element);
}
public Object getParentElement(final Object element) {
return myChild2Parent.get((NodeElement)element);
}
@Override
public boolean isAlwaysLeaf(Object element) {
return myLeaves.contains(element);
}
public void addLeaf(NodeElement element) {
myLeaves.add(element);
}
public void removeLeaf(NodeElement element) {
myLeaves.remove(element);
}
@NotNull
public NodeDescriptor doCreateDescriptor(final Object element, final NodeDescriptor parentDescriptor) {
return new NodeDescriptor(null, parentDescriptor) {
public boolean update() {
onElementAction("update", (NodeElement)element);
return true;
}
public Object getElement() {
return element;
}
@Override
public String toString() {
return getElement().toString();
}
};
}
public void register(final NodeElement parent, final Node child) {
myChild2Parent.put(child.myElement, parent);
myElement2Node.put(child.myElement, child);
}
public void clear() {
myChild2Parent.clear();
myElement2Node.clear();
myElement2Node.put(myRoot.myElement, myRoot);
}
public Node getNodeFor(NodeElement element) {
return myElement2Node.get(element);
}
}
class MyBuilder extends BaseTreeBuilder {
public MyBuilder() {
super(AbstractTreeBuilderTest.this.myTree, AbstractTreeBuilderTest.this.myTreeModel, AbstractTreeBuilderTest.this.myStructure, myComparator,
false);
initRootNode();
getUi().setJantorPollPeriod(Time.SECOND * 2);
}
@Override
protected void sortChildren(Comparator<TreeNode> nodeComparator, DefaultMutableTreeNode node, ArrayList<TreeNode> children) {
super.sortChildren(nodeComparator, node, children);
addEntry(node.toString());
}
@Override
public boolean isToEnsureSelectionOnFocusGained() {
return myEnsureSelection;
}
}
private void onElementAction(String action, NodeElement element) {
ElementEntry entry = myElementUpdate.get(element);
if (entry == null) {
entry = new ElementEntry(element);
myElementUpdate.put(element, entry);
}
entry.onElementAction(action);
if (myElementUpdateHook != null) {
myElementUpdateHook.onElementAction(action, element);
}
}
static interface ElementUpdateHook {
void onElementAction(String action, Object element);
}
private class ElementEntry {
NodeElement myElement;
int myUpdateCount;
int myGetChildrenCount;
private ElementEntry(NodeElement element) {
myElement = element;
}
void onElementAction(String action) {
try {
if ("update".equals(action)) {
myUpdateCount++;
} else if ("getChildren".equals(action)) {
Assert.assertTrue("getChildren() is called before update(), node=" + myElement, myUpdateCount > 0);
myGetChildrenCount++;
}
}
catch (Throwable e) {
myCancelRequest = e;
}
}
@Override
public String toString() {
return (myElement + ": " + asString(myUpdateCount, "update") + " " + asString(myGetChildrenCount, "getChildren")).trim();
}
private String asString(int count, String text) {
if (count == 0) return "";
return count > 1 ? text + " (" + count + ")" : text;
}
}
MyBuilder getMyBuilder() {
return (MyBuilder)getBuilder();
}
interface TreeAction {
void run(Runnable onDone);
}
TreePath getPath(String s) {
return new TreePath(findNode(s, false).getPath());
}
}
@@ -0,0 +1,465 @@
package com.intellij.ide.util.treeView;
import com.intellij.openapi.util.Condition;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.Ref;
import com.intellij.openapi.util.SimpleTimer;
import com.intellij.testFramework.FlyIdeaTestCase;
import com.intellij.testFramework.PlatformTestUtil;
import com.intellij.ui.treeStructure.Tree;
import com.intellij.util.WaitFor;
import com.intellij.util.ui.UIUtil;
import com.intellij.util.ui.update.ComparableObject;
import com.intellij.util.ui.update.MergingUpdateQueue;
import junit.framework.Assert;
import junit.framework.AssertionFailedError;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreePath;
import java.awt.*;
import java.util.Comparator;
import java.util.HashSet;
import java.util.Set;
abstract class BaseTreeTestCase<StructureElement> extends FlyIdeaTestCase {
private BaseTreeBuilder myBuilder;
Tree myTree;
Throwable myCancelRequest;
boolean myReadyRequest;
private boolean myYieldingUiBuild;
private boolean myBgStructureBuilding;
private boolean myPassthroughMode;
final Set<StructureElement> myAutoExpand = new HashSet<StructureElement>();
final Set<StructureElement> myAlwaysShowPlus = new HashSet<StructureElement>();
boolean mySmartExpand;
private Thread myTestThread;
protected BaseTreeTestCase(boolean passthrougth) {
this(false, false);
myPassthroughMode = passthrougth;
}
protected BaseTreeTestCase(boolean yieldingUiBuild, boolean bgStructureBuilding) {
myYieldingUiBuild = yieldingUiBuild;
myBgStructureBuilding = bgStructureBuilding;
}
void doAndWaitForBuilder(final Runnable runnable, final Condition condition) throws Exception {
final Ref<Boolean> started = new Ref<Boolean>();
invokeLaterIfNeeded(new Runnable() {
public void run() {
started.set(true);
runnable.run();
}
});
waitBuilderToCome(new Condition() {
public boolean value(Object o) {
return started.get() && condition.value(null);
}
});
}
void waitBuilderToCome() {
try {
waitBuilderToCome(Condition.TRUE);
}
catch (Exception e) {
throw new AssertionError(e);
}
}
void waitBuilderToCome(final Condition<Object> condition) throws Exception {
boolean success = new WaitFor(600000) {
protected boolean condition() {
final boolean[] ready = new boolean[]{false};
invokeAndWaitIfNeeded(new Runnable() {
public void run() {
AbstractTreeUi ui = getBuilder().getUi();
if (ui == null) {
ready[0] = true;
return;
}
ready[0] = (myCancelRequest != null || myReadyRequest) || (condition.value(null) && (ui.isReady()));
}
});
return ready[0];
}
}.isConditionRealized();
if (myCancelRequest != null) {
Thread.dumpStack();
throw new Exception(myCancelRequest);
}
Assert.assertTrue(getBuilder().getUi().getNodeActions().isEmpty());
Assert.assertTrue(success);
}
void expand(final TreePath p) throws Exception {
invokeAndWaitIfNeeded(new Runnable() {
public void run() {
myTree.expandPath(p);
}
});
waitBuilderToCome();
}
void collapsePath(final TreePath p) throws Exception {
invokeAndWaitIfNeeded(new Runnable() {
public void run() {
myTree.collapsePath(p);
}
});
waitBuilderToCome();
}
AbstractTreeBuilder getBuilder() {
return myBuilder;
}
protected void initBuilder(BaseTreeBuilder builder) {
myBuilder = builder;
myBuilder.setCanYieldUpdate(myYieldingUiBuild);
myBuilder.setPassthroughMode(myPassthroughMode);
}
class BaseTreeBuilder extends AbstractTreeBuilder {
volatile boolean myWasCleanedUp;
public BaseTreeBuilder(JTree tree,
DefaultTreeModel treeModel,
AbstractTreeStructure treeStructure,
@Nullable Comparator<NodeDescriptor> comparator) {
super(tree, treeModel, treeStructure, comparator);
}
public BaseTreeBuilder(JTree tree,
DefaultTreeModel treeModel,
AbstractTreeStructure treeStructure,
@Nullable Comparator<NodeDescriptor> comparator,
boolean updateIfInactive) {
super(tree, treeModel, treeStructure, comparator, updateIfInactive);
}
public BaseTreeBuilder() {
}
@Override
protected final boolean updateNodeDescriptor(NodeDescriptor descriptor) {
checkThread();
int delay = getNodeDescriptorUpdateDelay();
if (delay > 0) {
try {
Thread.currentThread().sleep(delay);
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
return super.updateNodeDescriptor(descriptor);
}
protected boolean isAutoExpandNode(final NodeDescriptor nodeDescriptor) {
return myAutoExpand.contains(nodeDescriptor.getElement());
}
@Override
protected boolean isSmartExpand() {
return mySmartExpand;
}
@Override
protected boolean isAlwaysShowPlus(NodeDescriptor descriptor) {
return myAlwaysShowPlus.contains(descriptor.getElement());
}
@Override
protected AbstractTreeUpdater createUpdater() {
return _createUpdater(this);
}
@Override
protected void updateAfterLoadedInBackground(Runnable runnable) {
_updateAfterLoadedInBackground(runnable);
}
@Override
protected void runBackgroundLoading(Runnable runnable) {
_runBackgroundLoading(runnable);
}
@Override
public void cleanUp() {
super.cleanUp();
myWasCleanedUp = true;
}
@Override
protected AbstractTreeUi createUi() {
return _createUi();
}
}
void _updateAfterLoadedInBackground(Runnable runnable) {
SwingUtilities.invokeLater(runnable);
}
void _runBackgroundLoading(Runnable runnable) {
SimpleTimer.getInstance().setUp(runnable, getChildrenLoadingDelay());
}
AbstractTreeUi _createUi() {
return new AbstractTreeUi() {
@Override
protected void yield(Runnable runnable) {
SimpleTimer.getInstance().setUp(runnable, 100);
}
@Override
protected boolean canYield() {
return myYieldingUiBuild;
}
@Override
protected void runOnYieldingDone(Runnable onDone) {
SwingUtilities.invokeLater(onDone);
}
};
}
AbstractTreeUpdater _createUpdater(AbstractTreeBuilder builder) {
final AbstractTreeUpdater updater = new AbstractTreeUpdater(builder) {
@Override
protected void invokeLater(Runnable runnable) {
runnable.run();
}
@Override
protected boolean isEdt() {
return SwingUtilities.isEventDispatchThread();
}
};
updater.setModalityStateComponent(MergingUpdateQueue.ANY_COMPONENT);
return updater;
}
abstract class BaseStructure extends AbstractTreeStructure {
@Override
public boolean isToBuildChildrenInBackground(Object element) {
return myBgStructureBuilding;
}
@Override
public void commit() {
}
@Override
public boolean hasSomethingToCommit() {
return false;
}
@NotNull
@Override
public final NodeDescriptor createDescriptor(Object element, NodeDescriptor parentDescriptor) {
checkThread();
return doCreateDescriptor(element, parentDescriptor);
}
@NotNull
public abstract NodeDescriptor doCreateDescriptor(Object element, NodeDescriptor parentDescriptor);
@Override
public final Object[] getChildElements(Object element) {
return _getChildElements(element, true);
}
public final Object[] _getChildElements(Object element, boolean checkThread) {
if (checkThread) {
checkThread();
}
return doGetChildElements(element);
}
public abstract Object[] doGetChildElements(Object element);
}
@Override
protected void setUp() throws Exception {
super.setUp();
myCancelRequest = null;
myReadyRequest = false;
mySmartExpand = false;
myAutoExpand.clear();
myAlwaysShowPlus.clear();
myTestThread = Thread.currentThread();
}
@Override
protected void tearDown() throws Exception {
invokeLaterIfNeeded(new Runnable() {
public void run() {
if (getBuilder() != null) {
Disposer.dispose(getBuilder());
}
}
});
super.tearDown();
}
void assertTree(final String expected) throws Exception {
waitBuilderToCome();
Assert.assertEquals(expected, PlatformTestUtil.print(myTree, true));
}
void doAndWaitForBuilder(final Runnable runnable) throws Exception {
doAndWaitForBuilder(runnable, Condition.TRUE);
}
void updateFromRoot() throws Exception {
doAndWaitForBuilder(new Runnable() {
public void run() {
getBuilder().updateFromRoot();
}
});
}
void updateFrom(final NodeElement element) throws Exception {
updateFrom(element, false);
}
void updateFrom(final NodeElement element, final boolean forceResort) throws Exception {
doAndWaitForBuilder(new Runnable() {
public void run() {
getBuilder().queueUpdateFrom(element, forceResort);
}
});
}
void showTree() throws Exception {
doAndWaitForBuilder(new Runnable() {
public void run() {
getBuilder().getUi().activate(true);
}
});
}
void select(final Object element, final boolean addToSelection) throws Exception {
select(new Object[] {element}, addToSelection);
}
void select(final Object[] elements, final boolean addToSelection) throws Exception {
final Ref<Boolean> done = new Ref<Boolean>(false);
doAndWaitForBuilder(new Runnable() {
public void run() {
getBuilder().select(elements, new Runnable() {
public void run() {
done.set(true);
}
}, addToSelection);
}
}, new Condition() {
public boolean value(Object o) {
return done.get();
}
});
}
protected final boolean isYieldingUiBuild() {
return myYieldingUiBuild;
}
protected final boolean isBgStructureBuilding() {
return myBgStructureBuilding;
}
protected int getChildrenLoadingDelay() {
return 0;
}
protected int getNodeDescriptorUpdateDelay() {
return 0;
}
private void checkThread() {
String message = "Wrong thread used for query structure, thread=" + Thread.currentThread();
if (myPassthroughMode) {
Assert.assertSame(message, myTestThread, Thread.currentThread());
} else {
if (isBgStructureBuilding()) {
Assert.assertFalse(message, EventQueue.isDispatchThread());
} else {
Assert.assertTrue(message, EventQueue.isDispatchThread());
}
}
}
protected final void invokeLaterIfNeeded(Runnable runnable) {
if (myPassthroughMode) {
runnable.run();
} else {
UIUtil.invokeLaterIfNeeded(runnable);
}
}
protected final void invokeAndWaitIfNeeded(Runnable runnable) {
if (myPassthroughMode) {
runnable.run();
} else {
UIUtil.invokeAndWaitIfNeeded(runnable);
}
}
protected final void assertEdt() {
if (myPassthroughMode) {
checkThread();
} else if (!EventQueue.isDispatchThread()) {
myCancelRequest = new AssertionFailedError("Must be event dispatch thread");
throw new RuntimeException(myCancelRequest);
}
}
public static class NodeElement extends ComparableObject.Impl implements Comparable<NodeElement>{
final String myName;
public NodeElement(String name) {
super(name);
myName = name;
}
public String toString() {
return myName;
}
public int compareTo(NodeElement o) {
return myName.compareTo(o.myName);
}
}
}
@@ -0,0 +1,252 @@
package com.intellij.ide.util.treeView;
import com.intellij.openapi.util.ActionCallback;
import com.intellij.openapi.util.Condition;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.Ref;
import com.intellij.ui.TreeUIHelper;
import com.intellij.ui.speedSearch.ElementFilter;
import com.intellij.ui.treeStructure.*;
import com.intellij.ui.treeStructure.filtered.FilteringTreeBuilder;
import com.intellij.ui.treeStructure.filtered.FilteringTreeStructure;
import java.util.LinkedHashMap;
public class FilteringTreeBuilderTest extends BaseTreeTestCase {
private FilteringTreeBuilder myBuilder;
private MyFilter myFilter;
private Node myRoot;
private SimpleTreeStructure myStructure;
public FilteringTreeBuilderTest() {
super(false, false);
}
@Override
protected void setUp() throws Exception {
super.setUp();
myTree = new SimpleTree() {
@Override
protected void configureUiHelper(final TreeUIHelper helper) {
}
};
myFilter = new MyFilter();
myRoot = new Node(null, "/");
myStructure = new SimpleTreeStructure.Impl(myRoot);
}
private void initBuilder() throws Exception {
myBuilder = new FilteringTreeBuilder(null, myTree, myFilter, myStructure, AlphaComparator.INSTANCE) {
@Override
protected AbstractTreeUpdater createUpdater() {
return _createUpdater(this);
}
};
showTree();
Disposer.register(getRootDisposable(), myBuilder);
}
public void testFilter() throws Exception {
myTree.setRootVisible(false);
final Node f1 = myRoot.addChild("folder1");
f1.addChild("file11");
f1.addChild("file12");
Node f11 = f1.addChild("folder11");
f11.addChild("element111");
myRoot.addChild("folder2").addChild("file21");
initBuilder();
assertTree("-/\n"
+ " -folder1\n"
+ " file11\n"
+ " file12\n"
+ " -folder11\n"
+ " element111\n"
+ " -folder2\n"
+ " file21\n");
update("", findNode("file11"));
assertTree("-/\n"
+ " -folder1\n"
+ " [file11]\n"
+ " file12\n"
+ " -folder11\n"
+ " element111\n"
+ " -folder2\n"
+ " file21\n");
update("f", null);
assertTree("-/\n"
+ " -folder1\n"
+ " [file11]\n"
+ " file12\n"
+ " folder11\n"
+ " -folder2\n"
+ " file21\n");
update("fo", null);
assertTree("-/\n"
+ " -folder1\n"
+ " [folder11]\n"
+ " folder2\n");
update("fo_", null);
assertTree("+/\n");
update("", null);
assertTree("-/\n"
+ " -[folder1]\n"
+ " file11\n"
+ " file12\n"
+ " -folder11\n"
+ " element111\n"
+ " -folder2\n"
+ " file21\n");
select("element111");
assertTree("-/\n"
+ " -folder1\n"
+ " file11\n"
+ " file12\n"
+ " -folder11\n"
+ " [element111]\n"
+ " -folder2\n"
+ " file21\n");
update("folder2", null);
assertTree("-/\n"
+ " [folder2]\n");
update("", null);
assertTree("-/\n"
+ " -folder1\n"
+ " file11\n"
+ " file12\n"
+ " -folder11\n"
+ " element111\n"
+ " -[folder2]\n"
+ " file21\n");
update("file1", null);
assertTree("-/\n"
+ " -[folder1]\n"
+ " file11\n"
+ " file12\n");
select("file12");
assertTree("-/\n"
+ " -folder1\n"
+ " file11\n"
+ " [file12]\n");
update("", null);
assertTree("-/\n"
+ " -folder1\n"
+ " file11\n"
+ " [file12]\n"
+ " -folder11\n"
+ " element111\n"
+ " -folder2\n"
+ " file21\n");
}
private void select(String element) throws Exception {
FilteringTreeStructure.Node node = myBuilder.getVisibleNodeFor(findNode(element));
select(new Object[] {node}, false);
}
private void update(final String text, final Object selection) throws Exception {
final ActionCallback result = new ActionCallback();
doAndWaitForBuilder(new Runnable() {
public void run() {
myFilter.update(text, selection).notify(result);
}
}, new Condition<Object>() {
public boolean value(Object o) {
return result.isProcessed();
}
});
}
private class Node extends CachingSimpleNode {
private final LinkedHashMap<String, Node> myKids = new LinkedHashMap<String, Node>();
private Node(final SimpleNode aParent, String name) {
super(aParent);
myName = name;
}
public Node addChild(String name) {
if (!myKids.containsKey(name)) {
myKids.put(name, new Node(this, name));
}
return myKids.get(name);
}
@Override
protected void doUpdate() {
setPlainText(myName);
}
protected SimpleNode[] buildChildren() {
return myKids.values().toArray(new Node[myKids.size()]);
}
@Override
public String toString() {
return myName;
}
@Override
protected void updateFileStatus() {
}
}
private Object findNode(final String name) {
final Ref<Object> node = new Ref<Object>();
((SimpleTree)myTree).accept(myBuilder, new SimpleNodeVisitor() {
public boolean accept(final SimpleNode simpleNode) {
if (name.equals(simpleNode.toString())) {
node.set(myBuilder.getOriginalNode(simpleNode));
return true;
} else {
return false;
}
}
});
return node.get();
}
private class MyFilter extends ElementFilter.Active.Impl {
String myPattern = "";
public boolean shouldBeShowing(final Object value) {
return value.toString().startsWith(myPattern);
}
public ActionCallback update(final String pattern, Object selection) {
myPattern = pattern;
return fireUpdate(selection, true, false);
}
}
@Override
AbstractTreeBuilder getBuilder() {
return myBuilder;
}
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,44 @@
package com.intellij.testFramework;
import com.intellij.mock.MockApplication;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.application.ex.ApplicationManagerEx;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.io.FileUtil;
import junit.framework.TestCase;
import java.io.File;
import java.io.IOException;
public abstract class FlyIdeaTestCase extends TestCase {
private Disposable myRootDisposable;
private File myTempDir;
protected void setUp() throws Exception {
MockApplication app = new MockApplication();
myRootDisposable = Disposer.newDisposable();
ApplicationManagerEx.setApplication(app, myRootDisposable);
}
public File getTempDir() throws IOException {
if (myTempDir == null) {
myTempDir = FileUtil.createTempDirectory(getName(), getClass().getName());
}
return myTempDir;
}
public Disposable getRootDisposable() {
return myRootDisposable;
}
protected void tearDown() throws Exception {
super.tearDown();
if (myTempDir != null) {
FileUtil.asyncDelete(myTempDir);
}
Disposer.dispose(myRootDisposable);
}
}
@@ -16,6 +16,7 @@
package com.intellij.testFramework;
import com.intellij.ide.util.treeView.AbstractTreeNode;
import com.intellij.ide.util.treeView.AbstractTreeStructure;
import com.intellij.idea.Bombed;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.application.ApplicationManager;
@@ -37,8 +38,7 @@ import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreePath;
import java.util.Calendar;
import java.util.Date;
import java.util.*;
/**
* @author yole
@@ -200,4 +200,76 @@ public class PlatformTestUtil {
private static boolean isItMe(final String who) {
return Comparing.equal(who, SystemProperties.getUserName(), false);
}
public static StringBuffer print(AbstractTreeStructure structure,
Object node,
int currentLevel,
Comparator comparator,
int maxRowCount,
char paddingChar) {
StringBuffer buffer = new StringBuffer();
doPrint(buffer, currentLevel, node, structure, comparator, maxRowCount, 0, paddingChar);
return buffer;
}
private static int doPrint(StringBuffer buffer,
int currentLevel,
Object node,
AbstractTreeStructure structure,
Comparator comparator,
int maxRowCount,
int currentLine,
char paddingChar) {
if (currentLine >= maxRowCount && maxRowCount != -1) return currentLine;
StringUtil.repeatSymbol(buffer, paddingChar, currentLevel);
buffer.append(toString(node)).append("\n");
currentLine++;
Object[] children = structure.getChildElements(node);
if (comparator != null) {
ArrayList<?> list = new ArrayList<Object>(Arrays.asList(children));
Collections.sort(list, comparator);
children = list.toArray(new Object[list.size()]);
}
for (Object child : children) {
currentLine = doPrint(buffer, currentLevel + 1, child, structure, comparator, maxRowCount, currentLine, paddingChar);
}
return currentLine;
}
public static String print(Object[] objects) {
return print(Arrays.asList(objects));
}
public static String print(Collection c) {
StringBuilder result = new StringBuilder();
for (Iterator iterator = c.iterator(); iterator.hasNext();) {
Object each = iterator.next();
result.append(toString(each));
if (iterator.hasNext()) {
result.append("\n");
}
}
return result.toString();
}
public static String print(ListModel model) {
StringBuilder result = new StringBuilder();
for (int i = 0; i < model.getSize(); i++) {
result.append(toString(model.getElementAt(i)));
result.append("\n");
}
return result.toString();
}
public static String print(JTree tree) {
return print(tree, false);
}
public static void assertTreeStructureEquals(final AbstractTreeStructure treeStructure, final String expected) {
Assert.assertEquals(expected, print(treeStructure, treeStructure.getRootElement(), 0, null, -1, ' ').toString());
}
}