blob: 5338923134890b86c80fed89297ec78905fa89e5 [file] [log] [blame]
////////////////////////////////////////////////////////////////////////////////
//
// 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 {
import mx.collections.ArrayList;
import mx.collections.IList;
import mx.collections.ListCollectionView;
import org.flexunit.assertThat;
import org.flexunit.asserts.assertEquals;
import mx.collections.Sort;
import mx.collections.SortField;
public class ListCollectionView_Sort_Tests {
private var _sut:ListCollectionView;
[Before]
public function setUp():void
{
_sut = new ListCollectionView(new ArrayList());
}
[After]
public function tearDown():void
{
_sut = null;
}
[Test]
public function test_numeric_descending_sort_on_simple_objects():void
{
//given
var from0To4:IList = generateNumbers(5);
_sut.addAll(from0To4); //values: 0, 1, 2, 3, 4
const sortByIndexDescending:Sort = new Sort();
sortByIndexDescending.fields = [new SortField(null, false, true, true)];
_sut.sort = sortByIndexDescending;
//when
_sut.refresh(); //should be: 4, 3, 2, 1, 0
//then
assertItemsAre([4, 3, 2, 1, 0]);
assertRemoveAll();
}
[Test]
public function test_numeric_descending_sort_on_simple_objects_adds_new_object_in_right_place():void
{
//given
var from0To4:IList = generateNumbers(5);
_sut.addAll(from0To4); //values: 0, 1, 2, 3, 4
const sortByIndexDescending:Sort = new Sort();
sortByIndexDescending.fields = [new SortField(null, false, true, true)];
_sut.sort = sortByIndexDescending;
_sut.refresh(); //values: 4, 3, 2, 1, 0
//when
_sut.addItem(5); //should be: 5, 4, 3, 2, 1, 0
//then
assertItemsAre([5, 4, 3, 2, 1, 0]);
assertRemoveAll();
}
[Test]
public function test_numeric_descending_sort_on_simple_objects_removes_object_correctly():void
{
//given
var from0To4:IList = generateNumbers(5);
_sut.addAll(from0To4); //values: 0, 1, 2, 3, 4
const sortByIndexDescending:Sort = new Sort();
sortByIndexDescending.fields = [new SortField(null, false, true, true)];
_sut.sort = sortByIndexDescending;
_sut.refresh(); //values: 4, 3, 2, 1, 0
//when
_sut.removeItem(3); //should be: 4, 2, 1, 0
//then
assertItemsAre([4, 2, 1, 0]);
assertRemoveAll();
}
[Test]
public function test_numeric_descending_sort_on_simple_objects_removes_object_at_index_correctly():void
{
//given
var from0To4:IList = generateNumbers(5);
_sut.addAll(from0To4); //values: 0, 1, 2, 3, 4
const sortByIndexDescending:Sort = new Sort();
sortByIndexDescending.fields = [new SortField(null, false, true, true)];
_sut.sort = sortByIndexDescending;
_sut.refresh(); //values: 4, 3, 2, 1, 0
//when
_sut.removeItemAt(3); //should be: 4, 3, 2, 0
//then
assertItemsAre([4, 3, 2, 0]);
assertRemoveAll();
}
[Test]
public function test_numeric_descending_sort_on_simple_objects_moves_replaced_object_in_right_place():void
{
//given
var from0To4:IList = generateNumbers(5);
_sut.addAll(from0To4); //values: 0, 1, 2, 3, 4
const sortByIndexDescending:Sort = new Sort();
sortByIndexDescending.fields = [new SortField(null, false, true, true)];
_sut.sort = sortByIndexDescending;
_sut.refresh(); //values: 4, 3, 2, 1, 0
//when
_sut.setItemAt(100, 3); //before re-sort: 4, 3, 2, 100, 0
//then
assertItemsAre([100, 4, 3, 2, 0]);
assertRemoveAll();
}
[Test]
public function test_numeric_descending_sort_on_simple_objects_adds_new_identical_object_in_right_place():void
{
//given
var from0To4:IList = generateNumbers(5);
_sut.addAll(from0To4); //values: 0, 1, 2, 3, 4
const sortByIndexDescending:Sort = new Sort();
sortByIndexDescending.fields = [new SortField(null, false, true, true)];
_sut.sort = sortByIndexDescending;
_sut.refresh(); //values: 4, 3, 2, 1, 0
//when
_sut.addItem(3); //should be: 5, 4, 3, 2, 1, 0
//then
assertItemsAre([4, 3, 3, 2, 1, 0]);
assertRemoveAll();
}
[Test]
public function test_numeric_descending_sort_on_simple_objects_adds_new_identical_object_in_right_place_even_with_addItemAt():void
{
//given
var from0To4:IList = generateNumbers(5);
_sut.addAll(from0To4); //values: 0, 1, 2, 3, 4
const sortByIndexDescending:Sort = new Sort();
sortByIndexDescending.fields = [new SortField(null, false, true, true)];
_sut.sort = sortByIndexDescending;
_sut.refresh(); //values: 4, 3, 2, 1, 0
//when
_sut.addItemAt(3, 0); //should be: 5, 4, 3, 2, 1, 0
//then
assertItemsAre([4, 3, 3, 2, 1, 0]);
assertRemoveAll();
}
[Test]
public function test_numeric_descending_sort_on_complex_objects():void
{
//given
var from0To4:IList = generateVOs(5);
_sut.addAll(from0To4); //values["name"]: Object0, Object1, Object2, Object3, Object4
const sortByIndexDescending:Sort = new Sort();
sortByIndexDescending.fields = [new SortField("index", false, true, true)];
_sut.sort = sortByIndexDescending;
//when
_sut.refresh(); //should be: Object4, Object3, Object2, Object1, Object0
//then
assertIndexesAre([4, 3, 2, 1, 0]);
assertGetItemIndex(from0To4);
assertRemoveAll();
}
[Test]
public function test_multiple_sort_fields_on_complex_objects():void
{
//given
var from0To4:IList = generateVOs(5);
_sut.addAll(from0To4); //values["name"]: Object0, Object1, Object2, Object3, Object4
const abc2:ListCollectionView_Sort_VO = generateOneObject(2, "ABC");
_sut.addItem(abc2); //values["name"]: Object0, Object1, Object2, Object3, Object4, ABC2
const sortByIndexDescending:Sort = new Sort();
sortByIndexDescending.fields = [new SortField("index", false, true, true), new SortField("name", false, false, false)];
_sut.sort = sortByIndexDescending;
//when
_sut.refresh(); //should be: Object0, Object1, ABC2, Object2, Object3, Object4
//then
assertIndexesAre([4, 3, 2, 2, 1, 0]);
assertNamesAre(["Object4", "Object3", "ABC2", "Object2", "Object1", "Object0"]);
const itemsInSUT:ListCollectionView = new ListCollectionView(new ArrayList());
itemsInSUT.addAll(from0To4);
itemsInSUT.addItem(abc2);
assertGetItemIndex(itemsInSUT);
assertRemoveAll();
}
[Test]
public function test_numeric_descending_sort_on_complex_objects_adds_new_objects_in_right_place():void
{
//given
var from0To4:IList = generateVOs(5);
_sut.addAll(from0To4); //values["name"]: Object0, Object1, Object2, Object3, Object4
const sortByIndexDescending:Sort = new Sort();
sortByIndexDescending.fields = [new SortField("index", false, true, true)];
_sut.sort = sortByIndexDescending;
_sut.refresh(); //values["name"]: Object4, Object3, Object2, Object1, Object0
//when
const item6:ListCollectionView_Sort_VO = generateOneObject(6);
_sut.addItem(item6);
const item3_5:ListCollectionView_Sort_VO = generateOneObject(3.5);
_sut.addItem(item3_5);
//then
assertIndexesAre([6, 4, 3.5, 3, 2, 1, 0]);
const itemsInSUT:ListCollectionView = new ListCollectionView(new ArrayList());
itemsInSUT.addAll(from0To4);
itemsInSUT.addItem(item6);
itemsInSUT.addItem(item3_5);
assertGetItemIndex(itemsInSUT);
assertRemoveAll();
}
[Test]
public function test_numeric_descending_sort_on_complex_objects_moves_replaced_object_in_right_place():void
{
//given
var from0To4:IList = generateVOs(5);
_sut.addAll(from0To4); //values["name"]: Object0, Object1, Object2, Object3, Object4
const sortByIndexDescending:Sort = new Sort();
sortByIndexDescending.fields = [new SortField("index", false, true, true)];
_sut.sort = sortByIndexDescending;
_sut.refresh(); //values["name"]: Object4, Object3, Object2, Object1, Object0
//when
const addedItem:ListCollectionView_Sort_VO = generateOneObject(6);
_sut.setItemAt(addedItem, 1);
//then
assertIndexesAre([6, 4, 2, 1, 0]);
const itemsInSUT:ListCollectionView = new ListCollectionView(new ArrayList());
itemsInSUT.addAll(from0To4);
itemsInSUT.setItemAt(addedItem, 3);
assertGetItemIndex(itemsInSUT);
assertRemoveAll();
}
[Test]
public function test_simple_numeric_ascending_sort_on_complex_objects():void
{
//given
var from4To0:IList = generateVOs(5, true);
_sut.addAll(from4To0); //values["name"]: Object4, Object3, Object2, Object1, Object0
const sortByIndexAscending:Sort = new Sort();
sortByIndexAscending.fields = [new SortField("index", false, false, true)];
_sut.sort = sortByIndexAscending;
//when
_sut.refresh(); //should be: Object0, Object1, Object2, Object3, Object4
//then
assertIndexesAre([0, 1, 2, 3, 4]);
assertGetItemIndex(from4To0);
assertRemoveAll();
}
[Test]
public function test_simple_numeric_ascending_sort_on_complex_objects_with_dot_in_property_name():void
{
//given
var from4To0:IList = generateVOs(5, true);
const fieldName:String = "property.with.dot";
for(var i:int = 0; i < from4To0.length; i++)
{
var object:ListCollectionView_Sort_VO = from4To0.getItemAt(i) as ListCollectionView_Sort_VO;
object[fieldName] = object.index;
}
_sut.addAll(from4To0); //values["name"]: Object4, Object3, Object2, Object1, Object0
const sortByIndexAscending:Sort = new Sort();
sortByIndexAscending.fields = [new SortField(fieldName, false, false, true)];
_sut.sort = sortByIndexAscending;
//when
_sut.refresh(); //should be: Object0, Object1, Object2, Object3, Object4
//then
assertIndexesAre([0, 1, 2, 3, 4]);
assertGetItemIndex(from4To0);
assertRemoveAll();
}
[Test(description="Testing that changing the properties of the Sort doesn't impact the actual sort order")]
public function test_sort_fields_on_complex_objects_dont_change_unless_sort_reapplied():void
{
//given
var from4To0:IList = generateVOs(5, true);
_sut.addAll(from4To0); //values["name"]: Object4, Object3, Object2, Object1, Object0
const sortByIndexAscending:Sort = new Sort();
var originalSortField:SortField = new SortField("index", false, false, true);
sortByIndexAscending.fields = [originalSortField];
_sut.sort = sortByIndexAscending;
_sut.refresh(); //should be: Object0, Object1, Object2, Object3, Object4
//when
sortByIndexAscending.fields = [new SortField("name", false, true, false)]; //should have no effect
//then
assertIndexesAre([0, 1, 2, 3, 4]);
sortByIndexAscending.fields = [originalSortField]; //TODO remove once FLEX-34853 is fixed
assertGetItemIndex(from4To0);
assertRemoveAll();
}
[Test]
public function test_marking_entire_item_as_updated_gets_the_old_object_out_of_the_list():void
{
//given
var from0To4:IList = generateVOs(5, true); //values["name"]: Object4, Object3, Object2, Object1, Object0
_sut.addAll(from0To4);
const sortByNameAscending:Sort = new Sort();
sortByNameAscending.fields = [new SortField("name", false, false, false)];
_sut.sort = sortByNameAscending;
_sut.refresh(); //values["name"]: Object0, Object1, Object2, Object3, Object4
//when
const removedItem:ListCollectionView_Sort_VO = (_sut.list as ArrayList).source[0] as ListCollectionView_Sort_VO;
const newItem:ListCollectionView_Sort_VO = generateOneObject(-1);
(_sut.list as ArrayList).source[0] = newItem;
_sut.itemUpdated(newItem, null, removedItem, newItem);
removedItem.name = "Object7"; //should make no difference
newItem.name = "Object9"; //should place it at the end of the list
//then
const indexOfRemovedItem:int = _sut.getItemIndex(removedItem);
assertEquals("the item should have been removed from the list", -1, indexOfRemovedItem);
for(var i:int = 0; i < _sut.length; i++)
{
assertThat(_sut.getItemAt(i) != removedItem);
}
assertEquals("the new item should have been moved to the end of the list", _sut.length - 1, _sut.getItemIndex(newItem));
}
private function assertIndexesAre(indexes:Array):void
{
assertFieldValuesAre("index", indexes);
}
private function assertNamesAre(names:Array):void
{
assertFieldValuesAre("name", names);
}
private function assertFieldValuesAre(field:String, values:Array):void
{
assertEquals(values.length, _sut.length);
for(var i:int = 0; i < _sut.length; i++)
{
assertEquals(ListCollectionView_Sort_VO(_sut.getItemAt(i))[field], values[i]);
}
}
private function assertItemsAre(indexes:Array):void
{
assertEquals(indexes.length, _sut.length);
for(var i:int = 0; i < _sut.length; i++)
{
assertEquals(indexes[i], _sut.getItemAt(i));
}
}
private function assertGetItemIndex(items:IList):void
{
for(var i:int = 0; i < items.length; i++)
{
var target:ListCollectionView_Sort_VO = items.getItemAt(i) as ListCollectionView_Sort_VO;
assertThat("could not find " + target.name, _sut.getItemIndex(target) != -1); //in some bugs, an RTE is thrown here
}
}
private function assertRemoveAll():void
{
_sut.removeAll(); //in some bugs, an RTE is thrown here
assertEquals(0, _sut.length);
}
private static function generateVOs(no:int, reverse:Boolean = false):IList
{
return generateObjects(no, reverse, generateOneObject);
}
private static function generateNumbers(no:int, reverse:Boolean = false):IList
{
return generateObjects(no, reverse, generateOneNumber);
}
private static function generateObjects(no:int, reverse:Boolean = false, generator:Function = null):IList
{
var result:Array = [];
for(var i:int = 0; i < no; i++)
{
result.push(generator(i));
}
if(reverse)
result.reverse();
return new ArrayList(result);
}
private static function generateOneObject(index:Number, name:String = "Object"):ListCollectionView_Sort_VO
{
return new ListCollectionView_Sort_VO(index, name, "Street");
}
private static function generateOneNumber(value:Number):Number
{
return value;
}
}
}
[Bindable]
dynamic class ListCollectionView_Sort_VO
{
public var name:String;
public var address:ListCollectionView_Sort_AddressVO;
public var index:Number;
public function ListCollectionView_Sort_VO(index:Number, namePrefix:String, streetPrefix:String)
{
this.index = index;
this.name = namePrefix + index;
this.address = new ListCollectionView_Sort_AddressVO(streetPrefix + index);
}
}
[Bindable]
class ListCollectionView_Sort_AddressVO
{
public var street:String;
public function ListCollectionView_Sort_AddressVO(street:String)
{
this.street = street;
}
}