Repository: flex-sdk
Updated Branches:
  refs/heads/FLEX-34119 0a2c3bd83 -> 75e8db424


FLEX-34119 Adding two unit tests for HierarchicalCollectionViewCursor (HCVC). 
HierarchicalCollectionViewCursor_Basics_Test is meant to ensure that HCVC works 
as expected in non-corner cases (it's definitely incomplete, and could use more 
tests. I created it mainly to test the few functions I needed when working with 
FLEX-34119), while HierarchicalCollectionViewCursor_FLEX_34119_Test reproduces 
the FLEX-34119 bug (and, incidentally, also uncovered FLEX-34424). FYI The 
latter test lasts just under 3 minutes on my machine.


Project: http://git-wip-us.apache.org/repos/asf/flex-sdk/repo
Commit: http://git-wip-us.apache.org/repos/asf/flex-sdk/commit/0c4c9c00
Tree: http://git-wip-us.apache.org/repos/asf/flex-sdk/tree/0c4c9c00
Diff: http://git-wip-us.apache.org/repos/asf/flex-sdk/diff/0c4c9c00

Branch: refs/heads/FLEX-34119
Commit: 0c4c9c00d09eab81e6c43340df245f4c9ca239b0
Parents: 0a2c3bd
Author: Mihai Chira <mihai.ch...@gmail.com>
Authored: Tue Jul 22 09:18:18 2014 +0100
Committer: Mihai Chira <mihai.ch...@gmail.com>
Committed: Tue Jul 22 09:18:18 2014 +0100

----------------------------------------------------------------------
 .../tests/unitTests/mx/collections/DataNode.as  |  62 ++++
 ...rarchicalCollectionViewCursor_Basics_Test.as | 164 ++++++++++
 ...hicalCollectionViewCursor_FLEX_34119_Test.as | 325 +++++++++++++++++++
 .../HierarchicalCollectionViewTestUtils.as      | 172 ++++++++++
 4 files changed, 723 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/flex-sdk/blob/0c4c9c00/frameworks/tests/unitTests/mx/collections/DataNode.as
----------------------------------------------------------------------
diff --git a/frameworks/tests/unitTests/mx/collections/DataNode.as 
b/frameworks/tests/unitTests/mx/collections/DataNode.as
new file mode 100644
index 0000000..da4f7fd
--- /dev/null
+++ b/frameworks/tests/unitTests/mx/collections/DataNode.as
@@ -0,0 +1,62 @@
+package {
+import mx.collections.ArrayCollection;
+
+public class DataNode {
+    private var _label:String;
+    private var _children:ArrayCollection;
+    private var _isSelected:Boolean = false;
+    private var _isPreviousSiblingRemoved:Boolean = false;
+
+    public function DataNode(label:String)
+    {
+        _label = label;
+    }
+
+    public function get children():ArrayCollection {
+        return _children;
+    }
+
+    public function set children(value:ArrayCollection):void {
+        _children = value;
+    }
+
+    public function get label():String {
+        return _label + (_isSelected ? " [SEL]" : "") + 
(_isPreviousSiblingRemoved ? " [PREV ITEM REMOVED]" : "");
+    }
+
+    public function toString():String
+    {
+        return label;
+    }
+
+    public function addChild(node:DataNode):void {
+        if(!_children)
+            _children = new ArrayCollection();
+
+        _children.addItem(node);
+    }
+
+    public function set isSelected(value:Boolean):void {
+        _isSelected = value;
+    }
+
+    public function get isSelected():Boolean {
+        return _isSelected;
+    }
+
+    public function clone():DataNode
+    {
+        var newNode:DataNode = new DataNode(_label);
+        for each(var childNode:DataNode in children)
+        {
+            newNode.addChild(childNode.clone());
+        }
+
+        return newNode;
+    }
+
+    public function set isPreviousSiblingRemoved(value:Boolean):void {
+        _isPreviousSiblingRemoved = value;
+    }
+}
+}

http://git-wip-us.apache.org/repos/asf/flex-sdk/blob/0c4c9c00/frameworks/tests/unitTests/mx/collections/HierarchicalCollectionViewCursor_Basics_Test.as
----------------------------------------------------------------------
diff --git 
a/frameworks/tests/unitTests/mx/collections/HierarchicalCollectionViewCursor_Basics_Test.as
 
b/frameworks/tests/unitTests/mx/collections/HierarchicalCollectionViewCursor_Basics_Test.as
new file mode 100644
index 0000000..65e2cb9
--- /dev/null
+++ 
b/frameworks/tests/unitTests/mx/collections/HierarchicalCollectionViewCursor_Basics_Test.as
@@ -0,0 +1,164 @@
+package
+{
+    import flash.events.UncaughtErrorEvent;
+    
+    import mx.collections.ArrayCollection;
+    import mx.collections.CursorBookmark;
+    import mx.collections.HierarchicalCollectionView;
+    import mx.collections.HierarchicalCollectionViewCursor;
+    import mx.core.FlexGlobals;
+    
+    import spark.components.WindowedApplication;
+    
+    import org.flexunit.asserts.assertEquals;
+
+    public class HierarchicalCollectionViewCursor_Basics_Test
+       {
+               private static var _utils:HierarchicalCollectionViewTestUtils = 
new HierarchicalCollectionViewTestUtils();
+               private static var _currentHierarchy:HierarchicalCollectionView;
+               private static var _noErrorsThrown:Boolean = true;
+               private var _level0:ArrayCollection;
+               
+               private var _sut:HierarchicalCollectionViewCursor;
+               
+               [BeforeClass]
+               public static function setUpBeforeClass():void
+               {
+                       (FlexGlobals.topLevelApplication as 
WindowedApplication).loaderInfo.uncaughtErrorEvents.addEventListener(UncaughtErrorEvent.UNCAUGHT_ERROR,
 handleUncaughtClientError);
+               }
+               
+               [AfterClass]
+               public static function tearDownAfterClass():void
+               {
+                       (FlexGlobals.topLevelApplication as 
WindowedApplication).loaderInfo.uncaughtErrorEvents.removeEventListener(UncaughtErrorEvent.UNCAUGHT_ERROR,
 handleUncaughtClientError);
+               }
+               
+               [Before]
+               public function setUp():void
+               {
+            _currentHierarchy = generateHierarchyViewWithOpenNodes();
+            _level0 = _utils.getRoot(_currentHierarchy) as ArrayCollection;
+            _sut = _currentHierarchy.createCursor() as 
HierarchicalCollectionViewCursor;
+
+                       _noErrorsThrown = true;
+               }
+               
+               [After]
+               public function tearDown():void
+               {
+                       _sut = null;
+            _currentHierarchy = null;
+            _level0 = null;
+               }
+
+
+
+        [Test]
+        public function testMovingAround():void
+        {
+            //given
+            var lastCompany:DataNode = _level0.getItemAt(_level0.length - 1) 
as DataNode;
+            var firstCompany:DataNode = _level0.getItemAt(0) as DataNode;
+            var firstLocation:DataNode = firstCompany.children.getItemAt(0) as 
DataNode;
+            var secondLocation:DataNode = firstCompany.children.getItemAt(1) 
as DataNode;
+            var firstDepartment:DataNode = firstLocation.children.getItemAt(0) 
as DataNode;
+            var secondDepartment:DataNode = 
firstLocation.children.getItemAt(1) as DataNode;
+
+            //when
+            _sut.moveNext();
+
+            //then
+            assertEquals(firstLocation, _sut.current);
+
+            //when
+            _sut.moveNext();
+
+            //then
+            assertEquals(firstDepartment, _sut.current);
+
+            //when
+            _sut.moveNext();
+
+            //then
+            assertEquals(secondDepartment, _sut.current);
+
+            //when
+            _sut.movePrevious();
+
+            //then
+            assertEquals(firstDepartment, _sut.current);
+
+            //when
+            _sut.moveToLast();
+
+            //then
+            assertEquals(lastCompany, _sut.current);
+
+            //when
+            _sut.seek(new CursorBookmark(4));
+
+            //then
+            assertEquals(secondLocation, _sut.current);
+        }
+
+        [Test]
+        public function testCollectionChangeInRootDoesNotChangeCurrent():void
+        {
+            //given
+            var lastCompany:DataNode = _level0.getItemAt(_level0.length - 1) 
as DataNode;
+
+            //when
+            _sut.moveToLast();
+
+            var newFirstCompany:DataNode = _utils.createSimpleNode("[INS] 
Company");
+            _level0.addItemAt(newFirstCompany, 0);
+
+            var newLastCompany:DataNode = _utils.createSimpleNode("[INS] 
Company");
+            _level0.addItemAt(newLastCompany, _level0.length);
+
+            //then
+            assertEquals(lastCompany, _sut.current);
+
+            //when
+            _sut.moveToLast();
+
+            //then
+            assertEquals(newLastCompany, _sut.current);
+        }
+               
+               
+               private static function 
handleUncaughtClientError(event:UncaughtErrorEvent):void
+               {
+                       event.preventDefault();
+                       event.stopImmediatePropagation();
+                       _noErrorsThrown = false;
+                       
+                       trace("\n" + event.error);
+                       _utils.printHCollectionView(_currentHierarchy);
+               }
+
+               
+               private static function 
generateHierarchyViewWithOpenNodes():HierarchicalCollectionView
+               {
+                       return 
_utils.generateOpenHierarchyFromRootList(_utils.generateHierarchySourceFromString(HIERARCHY_STRING));
+               }
+
+               private static const HIERARCHY_STRING:String = (<![CDATA[
+                       Company(1)
+                       Company(1)->Location(1)
+                       Company(1)->Location(1)->Department(1)
+                       Company(1)->Location(1)->Department(2)
+                       Company(1)->Location(2)
+                       Company(1)->Location(2)->Department(1)
+                       Company(1)->Location(2)->Department(2)
+                       Company(1)->Location(2)->Department(3)
+                       Company(1)->Location(3)
+                       Company(2)
+                       Company(2)->Location(1)
+                       Company(2)->Location(2)
+                       Company(2)->Location(2)->Department(1)
+                       Company(2)->Location(3)
+                       Company(3)
+               ]]>).toString();
+       }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/flex-sdk/blob/0c4c9c00/frameworks/tests/unitTests/mx/collections/HierarchicalCollectionViewCursor_FLEX_34119_Test.as
----------------------------------------------------------------------
diff --git 
a/frameworks/tests/unitTests/mx/collections/HierarchicalCollectionViewCursor_FLEX_34119_Test.as
 
b/frameworks/tests/unitTests/mx/collections/HierarchicalCollectionViewCursor_FLEX_34119_Test.as
new file mode 100644
index 0000000..6f52139
--- /dev/null
+++ 
b/frameworks/tests/unitTests/mx/collections/HierarchicalCollectionViewCursor_FLEX_34119_Test.as
@@ -0,0 +1,325 @@
+package
+{
+       import flash.events.UncaughtErrorEvent;
+       
+       import mx.collections.ArrayCollection;
+       import mx.collections.CursorBookmark;
+       import mx.collections.HierarchicalCollectionView;
+       import mx.collections.HierarchicalCollectionViewCursor;
+       import mx.collections.IViewCursor;
+       import mx.core.FlexGlobals;
+       
+       import spark.components.WindowedApplication;
+       
+       import flexunit.framework.AssertionFailedError;
+       
+       import org.flexunit.assertThat;
+       import org.flexunit.asserts.assertEquals;
+       import org.flexunit.asserts.assertNotNull;
+       import org.flexunit.asserts.assertTrue;
+       import org.flexunit.runners.Parameterized;
+
+       [RunWith("org.flexunit.runners.Parameterized")]
+       public class HierarchicalCollectionViewCursor_FLEX_34119_Test
+       {
+        private static const OP_ADD:int = 0;
+        private static const OP_REMOVE:int = 1;
+        private static const OP_SET:int = 2;
+        private static const OPERATIONS:Array = [OP_ADD, OP_REMOVE, OP_SET];
+        private static var _generatedHierarchy:HierarchicalCollectionView;
+        private static var _utils:HierarchicalCollectionViewTestUtils = new 
HierarchicalCollectionViewTestUtils();
+        public static var positionAndOperation:Array = [];
+
+           {
+               _generatedHierarchy = 
_utils.generateOpenHierarchyFromRootList(_utils.generateHierarchySourceFromString(HIERARCHY_STRING));
+               NO_ITEMS_IN_HIERARCHY = _generatedHierarchy.length;
+       
+               private static var SELECTED_INDEX:int = 0;
+               private static var OPERATION_LOCATION:int = 0;
+               private static var OPERATION_INDEX:int = 0;
+               for(SELECTED_INDEX = 0; SELECTED_INDEX < NO_ITEMS_IN_HIERARCHY; 
SELECTED_INDEX++)
+                       for(OPERATION_LOCATION = SELECTED_INDEX -1; 
OPERATION_LOCATION >= 0; OPERATION_LOCATION--)
+                           for(OPERATION_INDEX = 0; OPERATION_INDEX < 
OPERATIONS.length; OPERATION_INDEX++)
+                               positionAndOperation.push([SELECTED_INDEX, 
OPERATION_LOCATION, OPERATIONS[OPERATION_INDEX]]);
+           }
+
+        private static var NO_ITEMS_IN_HIERARCHY:int = NaN;
+        private static var _noErrorsThrown:Boolean = true;
+               private static var _operationPerformedInLastStep:Boolean = 
false;
+        private static var _currentHierarchy:HierarchicalCollectionView;
+        private static var _sut:HierarchicalCollectionViewCursor;
+        private static var _operationCursor:HierarchicalCollectionViewCursor;
+               private static var _mirrorCursor:IViewCursor;
+
+        private static var foo:Parameterized;
+
+               [BeforeClass]
+               public static function setUpBeforeClass():void
+               {
+            (FlexGlobals.topLevelApplication as 
WindowedApplication).loaderInfo.uncaughtErrorEvents.addEventListener(UncaughtErrorEvent.UNCAUGHT_ERROR,
 onUncaughtClientError);
+        }
+               
+               [AfterClass]
+               public static function tearDownAfterClass():void
+               {
+                       (FlexGlobals.topLevelApplication as 
WindowedApplication).loaderInfo.uncaughtErrorEvents.removeEventListener(UncaughtErrorEvent.UNCAUGHT_ERROR,
 onUncaughtClientError);
+               }
+               
+               [Before]
+               public function setUp():void
+               {
+                       if(_operationPerformedInLastStep || !_currentHierarchy)
+                       {
+                               _operationPerformedInLastStep = false;
+                               
+                               _currentHierarchy = 
_utils.clone(_generatedHierarchy);
+                               _utils.openAllNodes(_currentHierarchy);
+                               _sut = _currentHierarchy.createCursor() as 
HierarchicalCollectionViewCursor;
+                       }
+               }
+               
+               [After]
+               public function tearDown():void
+               {
+                       if(_operationPerformedInLastStep)
+                       {
+                               _sut = null;
+                               _currentHierarchy = null;
+                       }
+                       
+                       _operationCursor = null;
+                       _mirrorCursor = null;
+               }
+
+               [Test]
+               public function reproduce_FLEX_34119_WithADDSimple():void
+               {
+                       //given
+                       var _level0:ArrayCollection = 
_utils.getRoot(_currentHierarchy) as ArrayCollection;
+                       
+                       var secondRegion:DataNode = _level0.getItemAt(1) as 
DataNode;
+                       var firstCity:DataNode = 
secondRegion.children.getItemAt(0) as DataNode;
+                       var secondCompany:DataNode = 
firstCity.children.getItemAt(1) as DataNode;
+                       
+                       //when
+                       _sut.seek(new CursorBookmark(4)); 
//Region(2)->City(1)->Company(2)
+                       
secondRegion.children.addItemAt(_utils.createSimpleNode("City [INS]"), 0); 
//RTE should be thrown here
+                       
+                       //then
+                       assertEquals(secondCompany, _sut.current);
+                       assertTrue(_noErrorsThrown);
+               }
+               
+               [Test(dataProvider="positionAndOperation")]
+        public function 
testReproduce_FLEX_34119_Comprehensive(selectedItemIndex:int, 
operationIndex:int, operation:int):void
+        {
+                       assertThat(operationIndex < selectedItemIndex);
+                       
+            try {
+                               //WHEN
+                               //1. Select a random node
+                               _sut.seek(new 
CursorBookmark(selectedItemIndex));
+                               
+                var selectedNode:DataNode = DataNode(_sut.current);
+                assertNotNull(selectedNode);
+
+                //2. Make sure FLEX-34119 can be reproduced with the current 
indexes
+               if(!isFLEX_34119_Reproducible(operationIndex, selectedNode, 
operation))
+                          {
+                                  //trace("can't reproduce " + operation + "; 
" + operationIndex + "; " + selectedNode);
+                                  return;
+                          }
+                          
+                          selectedNode.isSelected = true;
+
+                //3. Perform operation
+                if (operation == OP_ADD)
+                    testAddition(_operationCursor);
+                else if (operation == OP_REMOVE)
+                    testRemoval(_operationCursor);
+
+                //THEN 1
+                assertTrue(_noErrorsThrown);
+
+                               
+                               
+                //4. Create mirror HierarchicalCollectionView from the changed 
root, as the source of truth
+                _mirrorCursor = 
_utils.navigateToItem(_currentHierarchy.createCursor() as 
HierarchicalCollectionViewCursor, selectedNode);
+
+                //5. Navigate somewhere in both HierarchicalCollectionViews 
and make sure they do the same thing
+                _sut.moveNext();
+                _mirrorCursor.moveNext();
+
+                //THEN 2
+                assertEquals(_mirrorCursor.current, _sut.current);
+            }
+            catch(error:AssertionFailedError)
+            {
+                trace("FAIL ("+selectedItemIndex + "," + operationIndex + "," 
+ operation + "): " + error.message);
+                _utils.printHCollectionView(_currentHierarchy);
+                throw(error);
+            }
+        }
+               
+               private function isFLEX_34119_Reproducible(where:int, 
selectedNode:DataNode, operation:int):Boolean
+               {
+                       var hasParent:Boolean = 
_currentHierarchy.getParentItem(selectedNode) != null;
+                       if(!hasParent)
+                               return false;
+       
+                       _operationCursor = _currentHierarchy.createCursor() as 
HierarchicalCollectionViewCursor;
+                       _operationCursor.seek(new CursorBookmark(where));
+                       var itemToPerformOperationOn:DataNode = 
_operationCursor.current as DataNode;
+                       
+                       switch(operation)
+                       {
+                               case OP_ADD:
+                                       return 
_utils.nodesHaveCommonAncestor(itemToPerformOperationOn, selectedNode, 
_currentHierarchy);
+                               case OP_REMOVE:
+                                       return 
!_utils.isAncestor(itemToPerformOperationOn, selectedNode, _currentHierarchy);
+                               case OP_SET:
+                                       return false;
+                               default:
+                                       return false;
+                       }
+               }
+       
+           private function 
testRemoval(where:HierarchicalCollectionViewCursor):void
+           {
+               var itemToDelete:DataNode = where.current as DataNode;
+               assertNotNull(itemToDelete);
+       
+               //mark the next item, so we know which item disappeared
+                       where.moveNext();
+               var nextItem:DataNode = where.current as DataNode;
+               if (nextItem)
+                   nextItem.isPreviousSiblingRemoved = true;
+       
+                       //remove the item
+               var parentOfItemToRemove:DataNode = 
_currentHierarchy.getParentItem(itemToDelete) as DataNode;
+               var collectionToChange:ArrayCollection = parentOfItemToRemove ? 
parentOfItemToRemove.children : _utils.getRoot(_currentHierarchy) as 
ArrayCollection;
+                       //trace("REM: sel=" + selectedNode + "; before=" + 
itemToDelete);
+                       _operationPerformedInLastStep = true;
+               collectionToChange.removeItem(itemToDelete);
+           }
+
+
+        /**
+         * @return true when the where parameter designates an item on the 
root collection (last ancestor of modified node)
+         */
+        private function 
testAddition(where:HierarchicalCollectionViewCursor):void
+        {
+            var itemBeforeWhichWereAdding:DataNode = where.current as DataNode;
+            assertNotNull(itemBeforeWhichWereAdding);
+
+            var parentOfAdditionLocation:DataNode = 
_currentHierarchy.getParentItem(itemBeforeWhichWereAdding) as DataNode;
+            var collectionToChange:ArrayCollection = parentOfAdditionLocation 
? parentOfAdditionLocation.children : _utils.getRoot(_currentHierarchy) as 
ArrayCollection;
+            var positionOfItemBeforeWhichWereAdding:int = 
collectionToChange.getItemIndex(itemBeforeWhichWereAdding);
+
+                       _operationPerformedInLastStep = true;
+            
collectionToChange.addItemAt(_utils.createSimpleNode(itemBeforeWhichWereAdding.label
 + " [INSERTED NODE]"), positionOfItemBeforeWhichWereAdding);
+                       //trace("ADD: sel=" + selectedNode + "; before=" + 
itemBeforeWhichWereAdding);
+        }
+
+
+
+               
+               
+               private static function 
onUncaughtClientError(event:UncaughtErrorEvent):void
+               {
+                       event.preventDefault();
+                       event.stopImmediatePropagation();
+                       _noErrorsThrown = false;
+                       
+                       trace("\n" + event.error);
+                       _utils.printHCollectionView(_currentHierarchy);
+               }
+
+
+        private static const HIERARCHY_STRING:String = (<![CDATA[
+         Region(1)
+         Region(2)
+         Region(2)->City(1)
+         Region(2)->City(1)->Company(1)
+         Region(2)->City(1)->Company(2)
+         Region(2)->City(1)->Company(2)->Department(1)
+         Region(2)->City(1)->Company(2)->Department(1)->Employee(1)
+         Region(2)->City(1)->Company(2)->Department(1)->Employee(2)
+         Region(2)->City(1)->Company(2)->Department(2)
+         Region(2)->City(1)->Company(2)->Department(2)->Employee(1)
+         Region(2)->City(1)->Company(2)->Department(2)->Employee(2)
+         Region(2)->City(1)->Company(2)->Department(2)->Employee(3)
+         Region(2)->City(1)->Company(2)->Department(3)
+         Region(2)->City(1)->Company(2)->Department(3)->Employee(1)
+         Region(2)->City(1)->Company(2)->Department(3)->Employee(2)
+         Region(2)->City(1)->Company(2)->Department(3)->Employee(3)
+         Region(2)->City(1)->Company(2)->Department(3)->Employee(4)
+         Region(2)->City(1)->Company(3)
+         Region(2)->City(1)->Company(3)->Department(1)
+         Region(2)->City(1)->Company(3)->Department(1)->Employee(1)
+         Region(2)->City(1)->Company(3)->Department(2)
+         Region(2)->City(1)->Company(3)->Department(2)->Employee(1)
+         Region(2)->City(1)->Company(3)->Department(2)->Employee(2)
+         Region(2)->City(1)->Company(3)->Department(3)
+         Region(2)->City(1)->Company(3)->Department(3)->Employee(1)
+         Region(2)->City(1)->Company(3)->Department(3)->Employee(2)
+         Region(2)->City(1)->Company(3)->Department(3)->Employee(3)
+         Region(2)->City(1)->Company(3)->Department(3)->Employee(4)
+         Region(2)->City(1)->Company(3)->Department(3)->Employee(5)
+         Region(2)->City(1)->Company(3)->Department(4)
+         Region(2)->City(1)->Company(3)->Department(4)->Employee(1)
+         Region(2)->City(1)->Company(3)->Department(4)->Employee(2)
+         Region(2)->City(1)->Company(3)->Department(4)->Employee(3)
+         Region(2)->City(1)->Company(3)->Department(4)->Employee(4)
+         Region(2)->City(1)->Company(4)
+         Region(2)->City(1)->Company(4)->Department(1)
+         Region(2)->City(1)->Company(4)->Department(1)->Employee(1)
+         Region(2)->City(1)->Company(4)->Department(1)->Employee(2)
+         Region(2)->City(1)->Company(4)->Department(1)->Employee(3)
+         Region(3)
+         Region(3)->City(1)
+         Region(3)->City(1)->Company(1)
+         Region(3)->City(1)->Company(1)->Department(1)
+         Region(3)->City(1)->Company(1)->Department(1)->Employee(1)
+         Region(3)->City(1)->Company(1)->Department(1)->Employee(2)
+         Region(3)->City(1)->Company(1)->Department(1)->Employee(3)
+         Region(3)->City(1)->Company(1)->Department(1)->Employee(4)
+         Region(3)->City(1)->Company(1)->Department(2)
+         Region(3)->City(1)->Company(1)->Department(2)->Employee(1)
+         Region(3)->City(1)->Company(1)->Department(2)->Employee(2)
+         Region(3)->City(1)->Company(1)->Department(2)->Employee(3)
+         Region(3)->City(1)->Company(1)->Department(3)
+         Region(3)->City(1)->Company(1)->Department(3)->Employee(1)
+         Region(3)->City(1)->Company(1)->Department(3)->Employee(2)
+         Region(3)->City(1)->Company(1)->Department(3)->Employee(3)
+         Region(3)->City(1)->Company(2)
+         Region(3)->City(1)->Company(2)->Department(1)
+         Region(3)->City(1)->Company(2)->Department(1)->Employee(1)
+         Region(3)->City(1)->Company(2)->Department(2)
+         Region(3)->City(1)->Company(2)->Department(2)->Employee(1)
+         Region(3)->City(1)->Company(2)->Department(2)->Employee(2)
+         Region(3)->City(1)->Company(2)->Department(3)
+         Region(3)->City(1)->Company(2)->Department(4)
+         Region(3)->City(1)->Company(3)
+         Region(3)->City(1)->Company(4)
+         Region(3)->City(1)->Company(4)->Department(1)
+         Region(3)->City(1)->Company(4)->Department(1)->Employee(1)
+         Region(3)->City(1)->Company(4)->Department(1)->Employee(2)
+         Region(3)->City(1)->Company(4)->Department(1)->Employee(3)
+         Region(3)->City(1)->Company(4)->Department(1)->Employee(4)
+         Region(3)->City(1)->Company(4)->Department(2)
+         Region(3)->City(1)->Company(4)->Department(2)->Employee(1)
+         Region(3)->City(1)->Company(4)->Department(2)->Employee(2)
+         Region(3)->City(1)->Company(4)->Department(2)->Employee(3)
+         Region(3)->City(1)->Company(4)->Department(3)
+         Region(3)->City(1)->Company(5)
+         Region(3)->City(2)
+         Region(3)->City(3)
+         Region(3)->City(4)
+         Region(3)->City(4)->Company(1)
+         Region(4)
+         Region(4)->City(1)
+         Region(4)->City(1)->Company(1)
+       ]]>).toString();
+       }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/flex-sdk/blob/0c4c9c00/frameworks/tests/unitTests/mx/collections/HierarchicalCollectionViewTestUtils.as
----------------------------------------------------------------------
diff --git 
a/frameworks/tests/unitTests/mx/collections/HierarchicalCollectionViewTestUtils.as
 
b/frameworks/tests/unitTests/mx/collections/HierarchicalCollectionViewTestUtils.as
new file mode 100644
index 0000000..82d00c7
--- /dev/null
+++ 
b/frameworks/tests/unitTests/mx/collections/HierarchicalCollectionViewTestUtils.as
@@ -0,0 +1,172 @@
+package
+{
+       import com.adobe.utils.StringUtil;
+       
+       import mx.collections.ArrayCollection;
+       import mx.collections.HierarchicalCollectionView;
+       import mx.collections.HierarchicalCollectionViewCursor;
+       import mx.collections.HierarchicalData;
+       import mx.collections.IViewCursor;
+
+       public class HierarchicalCollectionViewTestUtils
+       {
+               //assumes the root is an ArrayCollection of DataNodes
+               public function 
clone(hcv:HierarchicalCollectionView):HierarchicalCollectionView
+               {
+                       var oldRoot:ArrayCollection = 
ArrayCollection(getRoot(hcv));
+                       var newRoot:ArrayCollection = new ArrayCollection();
+                       
+                       for each(var rootNode:DataNode in oldRoot)
+                       {
+                               newRoot.addItem(rootNode.clone());
+                       }
+                       
+                       return generateHCV(newRoot);
+               }
+               
+               public function createNodes(level:String, 
no:int):ArrayCollection
+               {
+                       var nodes:ArrayCollection = new ArrayCollection();
+                       for(var i:int = 0; i < no; i++)
+                       {
+                               nodes.addItem(createSimpleNode(level));
+                       }
+                       
+                       return nodes;
+               }
+               
+               public function 
generateOpenHierarchyFromRootList(root:ArrayCollection):HierarchicalCollectionView
+               {
+                       var hcv:HierarchicalCollectionView = generateHCV(root);
+                       openAllNodes(hcv);
+                       return hcv;
+               }
+               
+               public function 
generateHCV(rootCollection:ArrayCollection):HierarchicalCollectionView
+               {
+                       return new HierarchicalCollectionView(new 
HierarchicalData(rootCollection));
+               }
+               
+               public function 
openAllNodes(hcv:HierarchicalCollectionView):void
+               {
+                       var cursor:HierarchicalCollectionViewCursor = 
hcv.createCursor() as HierarchicalCollectionViewCursor;
+                       while(!cursor.afterLast)
+                       {
+                               hcv.openNode(cursor.current);
+                               cursor.moveNext();
+                       }
+               }
+               
+               public function getRoot(hcv:HierarchicalCollectionView):Object
+               {
+                       return hcv.source.getRoot();
+               }
+               
+               public function 
printHCollectionView(hcv:HierarchicalCollectionView):void
+               {
+                       trace("");
+                       var cursor:HierarchicalCollectionViewCursor = 
hcv.createCursor() as HierarchicalCollectionViewCursor;
+                       while(!cursor.afterLast)
+                       {
+                               trace(DataNode(cursor.current).label);
+                               cursor.moveNext();
+                       }
+               }
+
+        public function createSimpleNode(label:String):DataNode
+               {
+            return new DataNode(label);
+        }
+
+        public function isAncestor(node:DataNode, forNode:DataNode, 
hcv:HierarchicalCollectionView):Boolean
+        {
+            do
+            {
+                forNode = hcv.getParentItem(forNode) as DataNode;
+            } while(forNode && forNode != node)
+
+            return forNode == node;
+        }
+               
+               public function nodesHaveCommonAncestor(node:DataNode, 
withNode:DataNode, hcv:HierarchicalCollectionView):Boolean
+               {
+                       var nodeAndAncestors:Array = 
[node].concat(getNodeAncestors(node, hcv));
+                       var otherNodeAndAncestors:Array = 
[withNode].concat(getNodeAncestors(withNode, hcv));
+                       for each(var ancestor:DataNode in nodeAndAncestors)
+                               if(otherNodeAndAncestors.indexOf(ancestor) != 
-1)
+                                       return true;
+                               
+                       return false;
+               }
+               
+               public function getNodeAncestors(node:DataNode, 
hcv:HierarchicalCollectionView):Array
+               {
+                       var nodeParents:Array = [];
+                       
+                       // Make a list of parents of the node.
+                       var parent:Object = hcv.getParentItem(node);
+                       while (parent)
+                       {
+                               nodeParents.push(parent);
+                               parent = hcv.getParentItem(parent);
+                       }
+                       
+                       return nodeParents;
+               }
+               
+               public function navigateToItem(cursor:IViewCursor, 
item:DataNode):IViewCursor
+               {
+                       while(!cursor.afterLast && cursor.current != item)
+                       {
+                               cursor.moveNext();
+                       }
+                       
+                       return cursor;
+               }
+               
+               public function 
generateHierarchySourceFromString(source:String):ArrayCollection
+               {
+                       var rootCollection:ArrayCollection = new 
ArrayCollection();
+                       var alreadyCreatedNodes:Array = [];
+                       var node:DataNode;
+                       
+                       var lines:Array = source.split("\n");
+                       for each(var line:String in lines)
+                       {
+                               if(!line)
+                                       continue;
+                               
+                               var currentLabel:String = "";
+                               var previousNode:DataNode = null;
+                               var nodesOnThisLine:Array = 
StringUtil.trim(line).split("->");
+                               for each(var nodeName:String in nodesOnThisLine)
+                               {
+                                       if(!nodeName)
+                                               continue;
+                                       
+                                       currentLabel += currentLabel ? "->" + 
nodeName : nodeName;
+                                       
+                                       var nodeAlreadyCreated:Boolean = 
alreadyCreatedNodes[currentLabel] != undefined;
+                                       
+                                       if(nodeAlreadyCreated)
+                                               node = 
alreadyCreatedNodes[currentLabel];
+                                       else {
+                                               node = 
createSimpleNode(currentLabel);
+                                               
alreadyCreatedNodes[currentLabel] = node;
+                                       }
+                                       
+                                       if(!nodeAlreadyCreated) {
+                                               if (previousNode)
+                                                       
previousNode.addChild(node);
+                                               else
+                                                       
rootCollection.addItem(node);
+                                       }
+                                       
+                                       previousNode = node;
+                               }
+                       }
+                       
+                       return rootCollection;
+               }
+       }
+}
\ No newline at end of file

Reply via email to