/* Copyright (c) Citrix Systems, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, * with or without modification, are permitted provided * that the following conditions are met: * * * Redistributions of source code must retain the above * copyright notice, this list of conditions and the * following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the * following disclaimer in the documentation and/or other * materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ using System.Windows.Forms; using NUnit.Framework; using XenAdmin.Controls; using System; using System.Drawing; namespace XenAdminTests.TreeTests { [TestFixture, Category(TestCategories.UICategoryB)] public class VirtualTreeViewTests { private VirtualTreeView _vtv; private TreeView _tv; private static void AssertNodeIsDummy(TreeNode node) { Assert.IsFalse(node is VirtualTreeNode); Assert.AreEqual("DummyTreeNode", node.GetType().Name, "node isn't DummyTreeNode"); } [SetUp] public void Setup() { _vtv = new VirtualTreeView(); _tv = _vtv; // ensure handle is created. Some tests fail if you don't do this. IntPtr h = _vtv.Handle; } [Test] public void TestAddRootNode() { _vtv.Nodes.Add(new VirtualTreeNode("rootNode")); Assert.AreEqual(1, _tv.Nodes.Count); Assert.AreEqual("rootNode", _tv.Nodes[0].Text); } [Test] public void TestAddChildNodeWhenRootCollapsed() { _vtv.Nodes.Add(new VirtualTreeNode("root")); _vtv.Nodes[0].Collapse(); _vtv.Nodes[0].Nodes.Add(new VirtualTreeNode("child")); Assert.AreEqual(1, _tv.Nodes[0].Nodes.Count); AssertNodeIsDummy(_tv.Nodes[0].Nodes[0]); // now expand the rootnode, and the child should be there. _vtv.Nodes[0].Expand(); Assert.AreEqual(1, _tv.Nodes[0].Nodes.Count); Assert.AreEqual("child", _tv.Nodes[0].Nodes[0].Text); } [Test] public void TestAddChildNodesWithRootCollapsed() { // add root node _vtv.Nodes.Add(new VirtualTreeNode("root")); // ensure root node collapsed _vtv.Nodes[0].Collapse(); // now add some child nodes. _vtv.Nodes[0].Nodes.Add(new VirtualTreeNode("firstChild")); _vtv.Nodes[0].Nodes[0].Nodes.Add(new VirtualTreeNode("secondChild")); // now expand the rootnode, and the first child should be there but the second child shouldn't _vtv.Nodes[0].Expand(); Assert.AreEqual(1, _tv.Nodes[0].Nodes.Count); Assert.AreEqual("firstChild", _tv.Nodes[0].Nodes[0].Text); Assert.AreEqual(1, _tv.Nodes[0].Nodes[0].Nodes.Count); AssertNodeIsDummy(_tv.Nodes[0].Nodes[0].Nodes[0]); // now expand firstChild to make secondChild visible _tv.Nodes[0].Nodes[0].Expand(); Assert.AreEqual(1, _tv.Nodes[0].Nodes[0].Nodes.Count); Assert.AreEqual("secondChild", _tv.Nodes[0].Nodes[0].Nodes[0].Text); } [Test] public void TestAddChildNodeWhenRootExpanded() { _vtv.Nodes.Add(new VirtualTreeNode("root")); _vtv.Nodes[0].Nodes.Add(new VirtualTreeNode("child")); _vtv.Nodes[0].Expand(); _vtv.Nodes[0].Nodes.Add(new VirtualTreeNode("child2")); Assert.AreEqual(2, _tv.Nodes[0].Nodes.Count); Assert.AreEqual("child", _tv.Nodes[0].Nodes[0].Text); Assert.AreEqual("child2", _tv.Nodes[0].Nodes[1].Text); } [Test] public void TestAddChildNodesWhenRootExpanded() { _vtv.Nodes.Add(new VirtualTreeNode("root")); // now add some child node and expand. _vtv.Nodes[0].Nodes.Add(new VirtualTreeNode("child")); _vtv.Nodes[0].Expand(); _vtv.Nodes[0].Nodes.Add(new VirtualTreeNode("child2")); _vtv.Nodes[0].Nodes.Add(new VirtualTreeNode("child3")); Assert.AreEqual(3, _tv.Nodes[0].Nodes.Count); Assert.AreEqual("child", _tv.Nodes[0].Nodes[0].Text); Assert.AreEqual("child2", _tv.Nodes[0].Nodes[1].Text); Assert.AreEqual("child3", _tv.Nodes[0].Nodes[2].Text); } [Test] public void TestAddSubtreeWithRootCollapsed() { _vtv.Nodes.Add(new VirtualTreeNode("root")); // build subtree VirtualTreeNode subTree = new VirtualTreeNode("firstChild"); subTree.Nodes.Add(new VirtualTreeNode("secondChild")); subTree.Nodes[0].Nodes.Add(new VirtualTreeNode("thirdChild")); // only expand secondChild subTree.Nodes[0].Expand(); // now add subtree _vtv.Nodes[0].Nodes.Add(subTree); // root node should only have dummy Assert.AreEqual(1, _tv.Nodes[0].Nodes.Count); AssertNodeIsDummy(_tv.Nodes[0].Nodes[0]); // in the virtual collections, the expanded states should still be correct Assert.IsFalse(subTree.IsExpanded); Assert.IsTrue(subTree.Nodes[0].IsExpanded); Assert.IsFalse(subTree.Nodes[0].Nodes[0].IsExpanded); // now expand the root node. only the first child should be visible _vtv.Nodes[0].Expand(); Assert.AreEqual(1, _tv.Nodes[0].Nodes.Count); Assert.AreEqual("firstChild", _tv.Nodes[0].Nodes[0].Text); Assert.AreEqual(1, _tv.Nodes[0].Nodes[0].Nodes.Count); AssertNodeIsDummy(_tv.Nodes[0].Nodes[0].Nodes[0]); // now expand the first child, this should result in the secondChild AND thirdChild becoming visible (as secondChild was expanded before it was added to the treeview) _vtv.Nodes[0].Nodes[0].Expand(); Assert.AreEqual(1, _tv.Nodes[0].Nodes[0].Nodes.Count); Assert.AreEqual("secondChild", _tv.Nodes[0].Nodes[0].Nodes[0].Text); Assert.AreEqual(1, _tv.Nodes[0].Nodes[0].Nodes[0].Nodes.Count); Assert.AreEqual("thirdChild", _tv.Nodes[0].Nodes[0].Nodes[0].Nodes[0].Text); } [Test] public void TestSelectedSiblingWhichIsntVisible() { _vtv.Nodes.Add(new VirtualTreeNode("root")); _vtv.Nodes[0].Nodes.Insert(0, new VirtualTreeNode("firstChild")); _vtv.Nodes[0].Nodes.Insert(1, new VirtualTreeNode("secondChild")); _vtv.SelectedNode = _vtv.Nodes[0].Nodes[1]; Assert.AreEqual(_vtv.SelectedNode, _vtv.Nodes[0].Nodes[1], "Sibling was not correctly selected."); } [Test] public void TestSelectedSiblingWhichIsntVisible2() { _vtv.Nodes.Add(new VirtualTreeNode("root")); _vtv.Nodes[0].Nodes.Insert(0, new VirtualTreeNode("firstChild")); _vtv.Nodes[0].Nodes.Insert(1, new VirtualTreeNode("secondChild")); _vtv.SelectedNode = _vtv.Nodes[0].Nodes[0]; Assert.AreEqual(_vtv.SelectedNode, _vtv.Nodes[0].Nodes[0], "Sibling was not correctly selected."); } [Test] public void RemoveAndReAddTest() { _vtv.Nodes.Add(new VirtualTreeNode("root")); _vtv.Nodes[0].Nodes.Insert(0, new VirtualTreeNode("firstChild")); VirtualTreeNode secondChild = new VirtualTreeNode("secondChild"); _vtv.Nodes[0].Nodes.Insert(1, secondChild); // expand and then collapse root node _vtv.Nodes[0].Expand(); _vtv.Nodes[0].Collapse(); // now remove secondChild _vtv.Nodes[0].Nodes.RemoveAt(1); // now re-add it _vtv.Nodes.Add(secondChild); Assert.AreEqual(1, _vtv.Nodes[0].Nodes.Count, "node wasn't removed."); Assert.AreEqual(secondChild, _vtv.Nodes[1], "node wasn't re-added"); } [Test] public void TestSimpleRootNodeUpdateWhenCollapsed() { _vtv.Nodes.Add(new VirtualTreeNode("root")); _vtv.Nodes[0].Nodes.Add(new VirtualTreeNode("child")); VirtualTreeNode newRoot = new VirtualTreeNode("newRoot"); newRoot.Nodes.Add(new VirtualTreeNode("newChild")); _vtv.UpdateRootNodes(new VirtualTreeNode[] { newRoot }); Assert.AreEqual(1, _vtv.Nodes.Count, "Virtual nodes weren't correctly updated."); Assert.AreEqual(1, _vtv.Nodes[0].Nodes.Count, "Virtual nodes weren't correctly updated."); Assert.AreEqual("newRoot", _vtv.Nodes[0].Text, "Virtual nodes weren't correctly updated."); Assert.AreEqual("newChild", _vtv.Nodes[0].Nodes[0].Text, "Virtual nodes weren't correctly updated."); Assert.AreEqual(1, _tv.Nodes.Count, "Nodes weren't correctly updated."); Assert.AreEqual(1, _tv.Nodes[0].Nodes.Count, "Nodes weren't correctly updated."); Assert.AreEqual("newRoot", _tv.Nodes[0].Text, "Nodes weren't correctly updated."); AssertNodeIsDummy(_tv.Nodes[0].Nodes[0]); } [Test] public void TestPropertiesOnSimpleRootNodeUpdate() { _vtv.Nodes.Add(new VirtualTreeNode("root")); _vtv.Nodes[0].Nodes.Add(new VirtualTreeNode("child")); VirtualTreeNode newRoot = new VirtualTreeNode("newRoot"); //newRoot.ImageIndexFetcher = delegate { return 1; }; newRoot.ImageIndex = 3; newRoot.SelectedImageIndex = 4; newRoot.Text = "hello"; newRoot.NodeFont = SystemFonts.CaptionFont; newRoot.BackColor = Color.Beige; newRoot.ForeColor = Color.Bisque; _vtv.UpdateRootNodes(new VirtualTreeNode[] { newRoot }); //Assert.IsNotNull(_vtv.Nodes[0].ImageIndexFetcher, "ImageIndexFetcher"); Assert.AreEqual(3, _vtv.Nodes[0].ImageIndex); Assert.AreEqual(4, _vtv.Nodes[0].SelectedImageIndex); Assert.AreEqual("hello", _vtv.Nodes[0].Text); Assert.AreEqual(SystemFonts.CaptionFont, _vtv.Nodes[0].NodeFont); Assert.AreEqual(Color.Beige, _vtv.Nodes[0].BackColor); Assert.AreEqual(Color.Bisque, _vtv.Nodes[0].ForeColor); Assert.AreEqual(3, _tv.Nodes[0].ImageIndex); Assert.AreEqual(4, _tv.Nodes[0].SelectedImageIndex); Assert.AreEqual("hello", _tv.Nodes[0].Text); Assert.AreEqual(SystemFonts.CaptionFont, _tv.Nodes[0].NodeFont); Assert.AreEqual(Color.Beige, _tv.Nodes[0].BackColor); Assert.AreEqual(Color.Bisque, _tv.Nodes[0].ForeColor); } [Test] public void TestNodeDeleteOnRootNodeUpdate() { _vtv.Nodes.Add(new VirtualTreeNode("root")); _vtv.Nodes.Add(new VirtualTreeNode("root2")); _vtv.Nodes.Add(new VirtualTreeNode("root3")); _vtv.Nodes[0].Nodes.Add(new VirtualTreeNode("child")); _vtv.Nodes[0].Nodes.Add(new VirtualTreeNode("child2")); _vtv.Nodes[0].Nodes.Add(new VirtualTreeNode("child3")); _vtv.Nodes[0].Nodes[0].Nodes.Add(new VirtualTreeNode("grandchild")); _vtv.Nodes[0].Nodes[0].Nodes.Add(new VirtualTreeNode("grandchild2")); _vtv.Nodes[0].Nodes[0].Nodes.Add(new VirtualTreeNode("grandchild3")); _vtv.Nodes[0].Expand(); _vtv.Nodes[1].Expand(); _vtv.Nodes[2].Expand(); _vtv.Nodes[0].Nodes[0].Expand(); VirtualTreeNode newRoot = new VirtualTreeNode("newRoot"); newRoot.Nodes.Add(new VirtualTreeNode("newChild")); newRoot.Nodes[0].Nodes.Add(new VirtualTreeNode("newGrandChild")); _vtv.UpdateRootNodes(new VirtualTreeNode[] { newRoot }); Assert.AreEqual(1, _vtv.Nodes.Count); Assert.AreEqual(1, _vtv.Nodes[0].Nodes.Count); Assert.AreEqual(1, _vtv.Nodes[0].Nodes[0].Nodes.Count); Assert.AreEqual(1, _tv.Nodes.Count); Assert.AreEqual(1, _tv.Nodes[0].Nodes.Count); Assert.AreEqual("newRoot", _tv.Nodes[0].Text); Assert.AreEqual("newChild", _tv.Nodes[0].Nodes[0].Text); Assert.AreEqual("newGrandChild", _tv.Nodes[0].Nodes[0].Nodes[0].Text); } [Test] public void TestChildNodesRemovedWhenUpdatingParentNodes() { _vtv.Nodes.Add(new VirtualTreeNode("root")); _vtv.Nodes[0].Nodes.Add(new VirtualTreeNode("child")); _vtv.Nodes[0].Nodes.Add(new VirtualTreeNode("child2")); _vtv.Nodes[0].Nodes.Add(new VirtualTreeNode("child3")); _vtv.UpdateRootNodes(new VirtualTreeNode[] { new VirtualTreeNode("newRoot") }); Assert.AreEqual(0, _vtv.Nodes[0].Nodes.Count, "The last virtual child node wasn't removed"); Assert.AreEqual(0, _tv.Nodes[0].Nodes.Count, "The last real child node wasn't removed"); } [Test] public void TestUpdateWhenRemoveAllChildNodesOfExandedParent() { // this is a test for the bug shown in CA-34486 and CA-36409. // When merging sets of tree-nodes using UpdateRootNodes, if you remove all of // the child-nodes from a node, the node still remembers its IsExpanded state // from before the nodes were removed regardless of whether you call Collapse() // or Expand() after the nodes were removed. // This causes problems for the Virtual treeview as it // relies the BeforeExpanded event to convert DummyTreeNodes into VirtualTreeNodes // on population. VirtualTreeNode rootNode = new VirtualTreeNode("root"); rootNode.Nodes.Add(new VirtualTreeNode("child")); rootNode.Nodes[0].Nodes.Add(new VirtualTreeNode("grandchild")); rootNode.Nodes[0].Nodes[0].Nodes.Add(new VirtualTreeNode("grandgrandchild")); _vtv.UpdateRootNodes(new VirtualTreeNode[] { rootNode }); _vtv.EndUpdate(); // expand all nodes so that all DummyNodes are replaced. _vtv.ExpandAll(); // now merge with smaller tree VirtualTreeNode rootNode2 = new VirtualTreeNode("root2"); rootNode2.Nodes.Add(new VirtualTreeNode("child2")); rootNode2.Nodes[0].Nodes.Add(new VirtualTreeNode("grandchild2")); _vtv.UpdateRootNodes(new VirtualTreeNode[] { rootNode2 }); _vtv.EndUpdate(); // collapse all so the next merge doesn't replace DummyNodes. _vtv.CollapseAll(); // now re-merge with big tree VirtualTreeNode rootNode3 = new VirtualTreeNode("root3"); rootNode3.Nodes.Add(new VirtualTreeNode("child3")); rootNode3.Nodes[0].Nodes.Add(new VirtualTreeNode("grandchild3")); rootNode3.Nodes[0].Nodes[0].Nodes.Add(new VirtualTreeNode("grandgrandchild3")); _vtv.UpdateRootNodes(new VirtualTreeNode[] { rootNode3 }); _vtv.EndUpdate(); _vtv.Nodes[0].Expand(); _vtv.Nodes[0].Nodes[0].Expand(); Assert.IsFalse(_vtv.Nodes[0].Nodes[0].Nodes[0].IsExpanded, "Expanded state was remembered. It shouldn't be."); } } }