FLEX-43119 moved the unit test where it can be run by 'ant test'. Also, the main test runner is an Application, rather than WindowedApplication, so I changed how uncaught client errors are captured.
Project: http://git-wip-us.apache.org/repos/asf/flex-sdk/repo Commit: http://git-wip-us.apache.org/repos/asf/flex-sdk/commit/84e7b0a1 Tree: http://git-wip-us.apache.org/repos/asf/flex-sdk/tree/84e7b0a1 Diff: http://git-wip-us.apache.org/repos/asf/flex-sdk/diff/84e7b0a1 Branch: refs/heads/master Commit: 84e7b0a14e7de05b84152a91610853e821d85744 Parents: eded640 Author: Mihai Chira <mih...@apache.org> Authored: Tue Mar 10 16:44:06 2015 +0100 Committer: Erik de Bruin <e...@ixsoftware.nl> Committed: Fri Mar 20 09:51:24 2015 +0100 ---------------------------------------------------------------------- ...icalCollectionViewCursor_FLEX_34119_Tests.as | 364 ++++++++++++++++++ ...hicalCollectionViewCursor_FLEX_34119_Test.as | 369 ------------------- 2 files changed, 364 insertions(+), 369 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/flex-sdk/blob/84e7b0a1/frameworks/projects/advancedgrids/tests/mx/collections/HierarchicalCollectionViewCursor_FLEX_34119_Tests.as ---------------------------------------------------------------------- diff --git a/frameworks/projects/advancedgrids/tests/mx/collections/HierarchicalCollectionViewCursor_FLEX_34119_Tests.as b/frameworks/projects/advancedgrids/tests/mx/collections/HierarchicalCollectionViewCursor_FLEX_34119_Tests.as new file mode 100644 index 0000000..5119ed4 --- /dev/null +++ b/frameworks/projects/advancedgrids/tests/mx/collections/HierarchicalCollectionViewCursor_FLEX_34119_Tests.as @@ -0,0 +1,364 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You 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 mx.collections +{ + import flash.events.UncaughtErrorEvent; + + import flexunit.framework.AssertionFailedError; + + import mx.core.FlexGlobals; + + import org.flexunit.assertThat; + import org.flexunit.asserts.assertEquals; + import org.flexunit.asserts.assertNotNull; + import org.flexunit.asserts.assertTrue; + import org.flexunit.runners.Parameterized; + + import spark.components.Application; + + /** + * README + * + * -This unit test was initially created to test FLEX-34119, and ended up uncovering FLEX-34424 as well. + * -This test builds a hierarchical collection from a string (see HIERARCHY_STRING), so that it's easy + * to edit and change it for specific scenarios. + * -This test uses utility functions from HierarchicalCollectionViewTestUtils, and data objects from DataNode. + * -Running the test takes about 3min on my machine. It will vary on yours, of course, but it shouldn't + * be wildly different. + * -To speed it up you can decrease the size of the hierarchical collection by editing HIERARCHY_STRING. + */ + [RunWith("org.flexunit.runners.Parameterized")] + public class HierarchicalCollectionViewCursor_FLEX_34119_Tests + { + 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; 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 + { + if(FlexGlobals.topLevelApplication is Application) + (FlexGlobals.topLevelApplication as Application).loaderInfo.uncaughtErrorEvents.addEventListener(UncaughtErrorEvent.UNCAUGHT_ERROR, onUncaughtClientError); + } + + [AfterClass] + public static function tearDownAfterClass():void + { + if(FlexGlobals.topLevelApplication is Application) + (FlexGlobals.topLevelApplication as Application).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; + + var selectedNodeOrDirectAncestorWasRemoved:Boolean; + //3. Perform operation + if (operation == OP_ADD) + selectedNodeOrDirectAncestorWasRemoved = testAddition(_operationCursor); + else if (operation == OP_REMOVE) + selectedNodeOrDirectAncestorWasRemoved = testRemoval(_operationCursor, selectedNode); + else if(operation == OP_SET) + selectedNodeOrDirectAncestorWasRemoved = testReplacement(_operationCursor, selectedNode); + + //THEN 1 + assertTrue(_noErrorsThrown); + + if(selectedNodeOrDirectAncestorWasRemoved) + return; //it means that _sut.current is now (correctly) null + + //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; + return _utils.nodesHaveCommonAncestor(itemToPerformOperationOn, selectedNode, _currentHierarchy); + } + + private function testRemoval(where:HierarchicalCollectionViewCursor, selectedNode:DataNode):Boolean + { + var itemToDelete:DataNode = where.current as DataNode; + assertNotNull(itemToDelete); + + var currentWillBeNulled:Boolean = itemToDelete == selectedNode || _utils.isAncestor(itemToDelete, selectedNode, _currentHierarchy); + + //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=" + nextItem); + _operationPerformedInLastStep = true; + collectionToChange.removeItem(itemToDelete); + + return currentWillBeNulled; + } + + + private function testAddition(where:HierarchicalCollectionViewCursor):Boolean + { + 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 + "); + return false; + } + + private function testReplacement(where:HierarchicalCollectionViewCursor, selectedNode:DataNode):Boolean + { + var itemToBeReplaced:DataNode = where.current as DataNode; + assertNotNull(itemToBeReplaced); + + var currentWillBeNulled:Boolean = itemToBeReplaced == selectedNode || _utils.isAncestor(itemToBeReplaced, selectedNode, _currentHierarchy); + + var parentOfReplacementLocation:DataNode = _currentHierarchy.getParentItem(itemToBeReplaced) as DataNode; + var collectionToChange:ArrayCollection = parentOfReplacementLocation ? parentOfReplacementLocation.children : _utils.getRoot(_currentHierarchy) as ArrayCollection; + var replacedItemIndex:int = collectionToChange.getItemIndex(itemToBeReplaced); + + _operationPerformedInLastStep = true; + collectionToChange.setItemAt(_utils.createSimpleNode(itemToBeReplaced.label + " [REPLACED NODE]"), replacedItemIndex); + //trace("REPLACE: sel=" + selectedNode + "); + return currentWillBeNulled; + } + + + + + + 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/84e7b0a1/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 deleted file mode 100644 index 39e509c..0000000 --- a/frameworks/tests/unitTests/mx/collections/HierarchicalCollectionViewCursor_FLEX_34119_Test.as +++ /dev/null @@ -1,369 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// Licensed to the Apache Software Foundation (ASF) under one or more -// contributor license agreements. See the NOTICE file distributed with -// this work for additional information regarding copyright ownership. -// The ASF licenses this file to You 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 mx.collections -{ - 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; - - /** - * README - * - * -This unit test was initially created to test FLEX-34119, and ended up uncovering FLEX-34424 as well. - * -This test builds a hierarchical collection from a string (see HIERARCHY_STRING), so that it's easy - * to edit and change it for specific scenarios. - * -This test uses utility functions from HierarchicalCollectionViewTestUtils, and data objects from DataNode. - * -Running the test takes about 3min on my machine. It will vary on yours, of course, but it shouldn't - * be wildly different. - * -To speed it up you can decrease the size of the hierarchical collection by editing HIERARCHY_STRING. - */ - [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; 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 - { - if(FlexGlobals.topLevelApplication is WindowedApplication) - (FlexGlobals.topLevelApplication as WindowedApplication).loaderInfo.uncaughtErrorEvents.addEventListener(UncaughtErrorEvent.UNCAUGHT_ERROR, onUncaughtClientError); - } - - [AfterClass] - public static function tearDownAfterClass():void - { - if(FlexGlobals.topLevelApplication is WindowedApplication) - (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; - - var selectedNodeOrDirectAncestorWasRemoved:Boolean; - //3. Perform operation - if (operation == OP_ADD) - selectedNodeOrDirectAncestorWasRemoved = testAddition(_operationCursor); - else if (operation == OP_REMOVE) - selectedNodeOrDirectAncestorWasRemoved = testRemoval(_operationCursor, selectedNode); - else if(operation == OP_SET) - selectedNodeOrDirectAncestorWasRemoved = testReplacement(_operationCursor, selectedNode); - - //THEN 1 - assertTrue(_noErrorsThrown); - - if(selectedNodeOrDirectAncestorWasRemoved) - return; //it means that _sut.current is now (correctly) null - - //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; - return _utils.nodesHaveCommonAncestor(itemToPerformOperationOn, selectedNode, _currentHierarchy); - } - - private function testRemoval(where:HierarchicalCollectionViewCursor, selectedNode:DataNode):Boolean - { - var itemToDelete:DataNode = where.current as DataNode; - assertNotNull(itemToDelete); - - var currentWillBeNulled:Boolean = itemToDelete == selectedNode || _utils.isAncestor(itemToDelete, selectedNode, _currentHierarchy); - - //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=" + nextItem); - _operationPerformedInLastStep = true; - collectionToChange.removeItem(itemToDelete); - - return currentWillBeNulled; - } - - - private function testAddition(where:HierarchicalCollectionViewCursor):Boolean - { - 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 + "); - return false; - } - - private function testReplacement(where:HierarchicalCollectionViewCursor, selectedNode:DataNode):Boolean - { - var itemToBeReplaced:DataNode = where.current as DataNode; - assertNotNull(itemToBeReplaced); - - var currentWillBeNulled:Boolean = itemToBeReplaced == selectedNode || _utils.isAncestor(itemToBeReplaced, selectedNode, _currentHierarchy); - - var parentOfReplacementLocation:DataNode = _currentHierarchy.getParentItem(itemToBeReplaced) as DataNode; - var collectionToChange:ArrayCollection = parentOfReplacementLocation ? parentOfReplacementLocation.children : _utils.getRoot(_currentHierarchy) as ArrayCollection; - var replacedItemIndex:int = collectionToChange.getItemIndex(itemToBeReplaced); - - _operationPerformedInLastStep = true; - collectionToChange.setItemAt(_utils.createSimpleNode(itemToBeReplaced.label + " [REPLACED NODE]"), replacedItemIndex); - //trace("REPLACE: sel=" + selectedNode + "); - return currentWillBeNulled; - } - - - - - - 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