You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@flex.apache.org by jm...@apache.org on 2015/11/18 05:21:45 UTC
[30/47] git commit: [flex-sdk] [refs/heads/develop] - FLEX-34778
Adding a unit test which verifies that replacements in the
HierarchicalCollectionView work as expected in various circumstances,
so that a fix for this bug can be made knowing that we're no
FLEX-34778 Adding a unit test which verifies that replacements in the HierarchicalCollectionView work as expected in various circumstances, so that a fix for this bug can be made knowing that we're not breaking something else.
Project: http://git-wip-us.apache.org/repos/asf/flex-sdk/repo
Commit: http://git-wip-us.apache.org/repos/asf/flex-sdk/commit/83e4a9b2
Tree: http://git-wip-us.apache.org/repos/asf/flex-sdk/tree/83e4a9b2
Diff: http://git-wip-us.apache.org/repos/asf/flex-sdk/diff/83e4a9b2
Branch: refs/heads/develop
Commit: 83e4a9b21d9592ada8ba0ae38619acad070373e2
Parents: 3ddcfee
Author: Mihai Chira <mi...@apache.org>
Authored: Tue Mar 10 12:37:59 2015 +0100
Committer: Erik de Bruin <er...@ixsoftware.nl>
Committed: Fri Mar 20 09:51:21 2015 +0100
----------------------------------------------------------------------
.../tests/unitTests/mx/collections/DataNode.as | 107 +++---
.../HierarchicalCollectionViewTestUtils.as | 1 +
...erarchicalCollectionView_FLEX_34778_Tests.as | 15 +-
.../HierarchicalCollectionView_REPLACE_Tests.as | 325 +++++++++++++++++++
4 files changed, 402 insertions(+), 46 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/flex-sdk/blob/83e4a9b2/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
index aef1829..730825a 100644
--- a/frameworks/tests/unitTests/mx/collections/DataNode.as
+++ b/frameworks/tests/unitTests/mx/collections/DataNode.as
@@ -18,64 +18,83 @@
////////////////////////////////////////////////////////////////////////////////
package mx.collections {
-import mx.collections.ArrayCollection;
+ 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 class DataNode {
+ private var _label:String;
+ private var _children:ArrayCollection;
+ private var _isSelected:Boolean = false;
+ private var _isPreviousSiblingRemoved:Boolean = false;
+ private var _parent:DataNode;
- public function DataNode(label:String)
- {
- _label = label;
- }
+ public function DataNode(label:String)
+ {
+ _label = label;
+ }
- public function get children():ArrayCollection {
- return _children;
- }
+ public function get children():ArrayCollection
+ {
+ return _children;
+ }
- public function set children(value:ArrayCollection):void {
- _children = value;
- }
+ public function set children(value:ArrayCollection):void
+ {
+ _children = value;
+ }
- public function get label():String {
- return _label + (_isSelected ? " [SEL]" : "") + (_isPreviousSiblingRemoved ? " [PREV ITEM REMOVED]" : "");
- }
+ public function get label():String
+ {
+ return _label + (_isSelected ? " [SEL]" : "") + (_isPreviousSiblingRemoved ? " [PREV ITEM REMOVED]" : "");
+ }
- public function toString():String
- {
- return label;
- }
+ public function toString():String
+ {
+ return label;
+ }
- public function addChild(node:DataNode):void {
- if(!_children)
- _children = new ArrayCollection();
+ public function addChild(node:DataNode):void
+ {
+ if(!_children)
+ _children = new ArrayCollection();
- _children.addItem(node);
- }
+ _children.addItem(node);
+ node.parent = this;
+ }
- public function set isSelected(value:Boolean):void {
- _isSelected = value;
- }
+ public function set isSelected(value:Boolean):void
+ {
+ _isSelected = value;
+ }
- public function get isSelected():Boolean {
- return _isSelected;
- }
+ public function get isSelected():Boolean
+ {
+ return _isSelected;
+ }
- public function clone():DataNode
- {
- var newNode:DataNode = new DataNode(_label);
- for each(var childNode:DataNode in children)
+ public function clone():DataNode
{
- newNode.addChild(childNode.clone());
+ var newNode:DataNode = new DataNode(_label);
+ for each(var childNode:DataNode in children)
+ {
+ newNode.addChild(childNode.clone());
+ }
+
+ return newNode;
}
- return newNode;
- }
+ public function set isPreviousSiblingRemoved(value:Boolean):void
+ {
+ _isPreviousSiblingRemoved = value;
+ }
+
+ public function get parent():DataNode
+ {
+ return _parent;
+ }
- public function set isPreviousSiblingRemoved(value:Boolean):void {
- _isPreviousSiblingRemoved = value;
+ public function set parent(value:DataNode):void
+ {
+ _parent = value;
+ }
}
}
-}
http://git-wip-us.apache.org/repos/asf/flex-sdk/blob/83e4a9b2/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
index bc1ca36..94b094b 100644
--- a/frameworks/tests/unitTests/mx/collections/HierarchicalCollectionViewTestUtils.as
+++ b/frameworks/tests/unitTests/mx/collections/HierarchicalCollectionViewTestUtils.as
@@ -19,6 +19,7 @@
package mx.collections
{
+ import mx.collections.*;
import mx.utils.StringUtil;
import mx.collections.ArrayCollection;
import mx.collections.CursorBookmark;
http://git-wip-us.apache.org/repos/asf/flex-sdk/blob/83e4a9b2/frameworks/tests/unitTests/mx/collections/HierarchicalCollectionView_FLEX_34778_Tests.as
----------------------------------------------------------------------
diff --git a/frameworks/tests/unitTests/mx/collections/HierarchicalCollectionView_FLEX_34778_Tests.as b/frameworks/tests/unitTests/mx/collections/HierarchicalCollectionView_FLEX_34778_Tests.as
index 9a85102..f436538 100644
--- a/frameworks/tests/unitTests/mx/collections/HierarchicalCollectionView_FLEX_34778_Tests.as
+++ b/frameworks/tests/unitTests/mx/collections/HierarchicalCollectionView_FLEX_34778_Tests.as
@@ -17,8 +17,7 @@
//
////////////////////////////////////////////////////////////////////////////////
-package mx.collections
-{
+package mx.collections {
import mx.collections.ArrayCollection;
import mx.collections.HierarchicalCollectionView;
@@ -60,6 +59,18 @@ package mx.collections
assertEquals(1, _sut.length);
}
+ //this did NOT reproduce it, but it's good to test, because the code is in a different function
+ //(collectionChangeHandler) than the previous case (nestedCollectionChangeHandler).
+ [Test]
+ public function test_replacing_inaccessible_root_node():void
+ {
+ //when
+ _level0.setItemAt(new DataNode("Microsoft"), 0);
+
+ //then
+ assertEquals(1, _sut.length);
+ }
+
private static function generateHierarchyViewWithClosedNodes():HierarchicalCollectionView
{
return _utils.generateHCV(_utils.generateHierarchySourceFromString(HIERARCHY_STRING));
http://git-wip-us.apache.org/repos/asf/flex-sdk/blob/83e4a9b2/frameworks/tests/unitTests/mx/collections/HierarchicalCollectionView_REPLACE_Tests.as
----------------------------------------------------------------------
diff --git a/frameworks/tests/unitTests/mx/collections/HierarchicalCollectionView_REPLACE_Tests.as b/frameworks/tests/unitTests/mx/collections/HierarchicalCollectionView_REPLACE_Tests.as
new file mode 100644
index 0000000..c4d49a6
--- /dev/null
+++ b/frameworks/tests/unitTests/mx/collections/HierarchicalCollectionView_REPLACE_Tests.as
@@ -0,0 +1,325 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// 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 mx.collections.HierarchicalCollectionView;
+ import mx.collections.IList;
+ import mx.events.CollectionEvent;
+ import mx.events.CollectionEventKind;
+ import mx.utils.StringUtil;
+
+ import org.flexunit.asserts.assertEquals;
+ import org.flexunit.asserts.assertFalse;
+ import org.flexunit.asserts.assertNotNull;
+ import org.flexunit.asserts.assertNull;
+ import org.flexunit.asserts.assertTrue;
+
+ public class HierarchicalCollectionView_REPLACE_Tests {
+
+ private static var _sut:HierarchicalCollectionView;
+ private static var _utils:HierarchicalCollectionViewTestUtils = new HierarchicalCollectionViewTestUtils();
+ private var _root:IList;
+ private static var noItemsInHierarchy:int = NaN;
+
+ [BeforeClass]
+ public static function setUpBeforeClass():void
+ {
+ const hierarchyLines:Array = HIERARCHY_STRING.split("\n");
+ for(var i:int = 0; i < hierarchyLines.length; i++)
+ {
+ if(StringUtil.trim(hierarchyLines[i]))
+ noItemsInHierarchy++;
+ }
+ }
+
+ [Before]
+ public function setUp():void
+ {
+ _sut = _utils.generateOpenHierarchyFromRootListWithAllNodesMethod(_utils.generateHierarchySourceFromString(HIERARCHY_STRING));
+ _root = _utils.getRoot(_sut) as IList;
+ }
+
+ [After]
+ public function tearDown():void
+ {
+ _sut = null;
+ _root = null;
+ }
+
+ [Test]
+ public function test_make_sure_we_count_nodes_correctly():void
+ {
+ //when
+ var noChildren:int = 0;
+ for(var i:int = 0; i < _root.length; i++)
+ {
+ noChildren += countAllChildrenOf(_root.getItemAt(i) as DataNode);
+ }
+
+ //then
+ assertEquals(noItemsInHierarchy, noChildren);
+ }
+
+ [Test]
+ public function test_make_sure_isDescendantOf_works_correctly():void
+ {
+ //when
+ var region1:DataNode = _root.getItemAt(0) as DataNode;
+ var region2:DataNode = _root.getItemAt(1) as DataNode;
+ var city2:DataNode = region2.children.getItemAt(1) as DataNode;
+ var company2:DataNode = city2.children.getItemAt(1) as DataNode;
+ var department2:DataNode = company2.children.getItemAt(1) as DataNode;
+
+ //then
+ assertTrue(isDescendantOf(department2, company2));
+ assertTrue(isDescendantOf(department2, city2));
+ assertTrue(isDescendantOf(department2, region2));
+ assertFalse(isDescendantOf(department2, region1));
+ }
+
+ [Test]
+ public function test_replacing_a_childless_node_does_not_dispatch_REMOVED_collection_event_but_changes_parent_references():void
+ {
+ function onCollectionChanged(event:CollectionEvent):void
+ {
+ if(event.kind == CollectionEventKind.REMOVE)
+ removeEvent = event;
+ else if(event.kind == CollectionEventKind.REPLACE)
+ replaceEvent = event;
+ }
+
+ var removeEvent:CollectionEvent = null;
+ var replaceEvent:CollectionEvent = null;
+
+ //GIVEN
+ _sut.addEventListener(CollectionEvent.COLLECTION_CHANGE, onCollectionChanged);
+ var company2:DataNode = getDirectChildrenOf(1, 1).getItemAt(1) as DataNode;
+ var departmentsOfCompany2:IList = company2.children;
+ var firstDepartment:DataNode = departmentsOfCompany2.getItemAt(0) as DataNode;
+
+ //WHEN
+ const newDepartment:DataNode = new DataNode("Region(2)->City(1)->Company(2)->DepartmentX");
+ departmentsOfCompany2.setItemAt(newDepartment, 0);
+
+ //THEN
+ assertNotNull(replaceEvent);
+ assertNull(removeEvent); //because the replaced node had no children
+ assertNull(_sut.getParentItem(firstDepartment));
+ assertEquals(company2, _sut.getParentItem(newDepartment));
+ assertEquals(noItemsInHierarchy, _sut.length);
+ }
+
+ [Test]
+ public function test_replacing_a_node_with_children_dispatches_REMOVED_collection_event_and_changes_parent_references():void
+ {
+ function onCollectionChanged(event:CollectionEvent):void
+ {
+ if(event.kind == CollectionEventKind.REMOVE)
+ {
+ removeEvent = event;
+
+ if(event.items && event.items.length == noChildrenOfSecondDepartment)
+ {
+ for(var i:int = 0; i < noChildrenOfSecondDepartment; i++)
+ {
+ if(event.items.indexOf(secondDepartment.children.getItemAt(i)) == -1)
+ REMOVEDEventHasChildrenOfSecondDepartment = false;
+ }
+ }
+ }
+ else if(event.kind == CollectionEventKind.REPLACE)
+ replaceEvent = event;
+ }
+
+ var removeEvent:CollectionEvent = null;
+ var replaceEvent:CollectionEvent = null;
+ var REMOVEDEventHasChildrenOfSecondDepartment:Boolean = true;
+
+ //GIVEN
+ _sut.addEventListener(CollectionEvent.COLLECTION_CHANGE, onCollectionChanged);
+ var company2:DataNode = getDirectChildrenOf(1, 1).getItemAt(1) as DataNode;
+ var departmentsOfCompany2:IList = company2.children;
+ var secondDepartment:DataNode = departmentsOfCompany2.getItemAt(1) as DataNode;
+ const noChildrenOfSecondDepartment:int = secondDepartment.children.length;
+
+ //WHEN
+ const newDepartment:DataNode = new DataNode("Region(2)->City(1)->Company(2)->DepartmentX");
+ departmentsOfCompany2.setItemAt(newDepartment, 1);
+
+ //THEN
+ assertNotNull(replaceEvent);
+ assertNotNull(removeEvent); //because the replaced node had children
+ assertTrue(REMOVEDEventHasChildrenOfSecondDepartment);
+ assertEquals(-1, removeEvent.items.indexOf(secondDepartment));
+ assertNull(_sut.getParentItem(secondDepartment));
+ assertEquals(company2, _sut.getParentItem(newDepartment));
+ assertEquals(noItemsInHierarchy - noChildrenOfSecondDepartment, _sut.length);
+ }
+
+ [Test]
+ public function test_replacing_a_root_node_with_children_dispatches_REMOVED_collection_event_and_changes_parent_references():void
+ {
+ function onCollectionChanged(event:CollectionEvent):void
+ {
+ if(event.kind == CollectionEventKind.REMOVE)
+ {
+ removeEvent = event;
+ if(event.items && event.items.length == noChildrenOfSecondRegion)
+ {
+ for(var i:int = 0; i < noChildrenOfSecondRegion; i++)
+ {
+ if(!isDescendantOf(event.items[1] as DataNode, region2))
+ REMOVEDEventHasAllChildrenOfSecondRegion = false;
+ }
+ }
+ }
+ else if(event.kind == CollectionEventKind.REPLACE)
+ replaceEvent = event;
+ }
+
+ var removeEvent:CollectionEvent = null;
+ var replaceEvent:CollectionEvent = null;
+ var REMOVEDEventHasAllChildrenOfSecondRegion:Boolean = true;
+
+ //GIVEN
+ _sut.addEventListener(CollectionEvent.COLLECTION_CHANGE, onCollectionChanged);
+ var region2:DataNode = _root.getItemAt(1) as DataNode;
+ var noChildrenOfSecondRegion:int = countAllChildrenOf(region2);
+
+ //WHEN
+ const newRegion:DataNode = new DataNode("Region(X)");
+ _root.setItemAt(newRegion, 1);
+
+ //THEN
+ assertNotNull(replaceEvent);
+ assertNotNull(removeEvent); //because the replaced node had children
+ assertTrue(REMOVEDEventHasAllChildrenOfSecondRegion);
+ assertEquals(-1, removeEvent.items.indexOf(region2));
+ assertNull(_sut.getParentItem(region2));
+ assertEquals(null, _sut.getParentItem(newRegion));
+ assertEquals(noItemsInHierarchy - noChildrenOfSecondRegion + 1, _sut.length);
+ }
+
+ [Test]
+ public function test_replacing_inaccessible_node_does_not_dispatch_REMOVED_collection_event_nor_changes_parent_references():void
+ {
+ function onCollectionChanged(event:CollectionEvent):void
+ {
+ if(event.kind == CollectionEventKind.REMOVE)
+ removeEvent = event;
+ else if(event.kind == CollectionEventKind.REPLACE)
+ replaceEvent = event;
+ }
+
+ var removeEvent:CollectionEvent = null;
+ var replaceEvent:CollectionEvent = null;
+
+ //GIVEN
+ _sut.addEventListener(CollectionEvent.COLLECTION_CHANGE, onCollectionChanged);
+ var company2:DataNode = getDirectChildrenOf(1, 1).getItemAt(1) as DataNode;
+ var departmentsOfCompany2:IList = company2.children;
+ var firstDepartment:DataNode = departmentsOfCompany2.getItemAt(0) as DataNode;
+
+ //WHEN
+ _sut.closeNode(_root.getItemAt(1)); //close second region
+ const newDepartment:DataNode = new DataNode("Region(2)->City(1)->Company(2)->DepartmentX");
+ departmentsOfCompany2.setItemAt(newDepartment, 0);
+
+ //THEN
+ assertNotNull(replaceEvent);
+ assertNull(removeEvent); //because the replaced node had no children
+ assertNull(_sut.getParentItem(firstDepartment));
+ assertEquals(company2, _sut.getParentItem(newDepartment));
+
+ var secondRegion:DataNode = DataNode(_root.getItemAt(1));
+ assertEquals(noItemsInHierarchy - countAllChildrenOf(secondRegion) + 1, _sut.length);
+ }
+
+
+ private function getDirectChildrenOf(...indexesOfSubsequentParents):IList
+ {
+ var currentLevel:IList = _root;
+ var i:int = -1;
+ while(currentLevel && ++i < indexesOfSubsequentParents.length)
+ {
+ var currentParent:DataNode = currentLevel.getItemAt(indexesOfSubsequentParents[i]) as DataNode;
+ currentLevel = currentParent ? currentParent.children : null;
+ }
+
+ return currentLevel;
+ }
+
+ private function isDescendantOf(node:DataNode, potentialAncestor:DataNode):Boolean
+ {
+ if(!potentialAncestor || !node)
+ return false;
+
+ var currentParent:DataNode = node.parent;
+ while(currentParent && currentParent != potentialAncestor)
+ {
+ currentParent = currentParent.parent;
+ }
+
+ return currentParent == potentialAncestor;
+ }
+
+ private function countAllChildrenOf(parent:DataNode):int
+ {
+ if(!parent.children || !parent.children.length)
+ return 1;
+ else
+ {
+ var noChildren:int = 0;
+ for(var i:int = 0; i < parent.children.length; i++)
+ {
+ noChildren += countAllChildrenOf(parent.children.getItemAt(i) as DataNode);
+ }
+
+ return noChildren + 1;
+ }
+
+ return NaN;
+ }
+
+
+ private static const HIERARCHY_STRING:String = (<![CDATA[
+ Region(1)
+ Region(2)
+ Region(2)->City(0)
+ 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(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)
+ ]]>).
+ toString();
+ }
+}