From 206c2ffad8d63f6299db58adccbab6b92e18c605 Mon Sep 17 00:00:00 2001 From: javalizard <> Date: Sun, 18 Apr 2010 15:58:37 +0000 Subject: TPriorityList works like TList if no class specific methods are called. Adds the Unit test. TPriorityList needs more unit testing but I wanted to submit this so the method names can be peer reviewed. --- .gitattributes | 1 + framework/Collections/TPriorityList.php | 322 ++++++++++++----- tests/unit/Collections/TPriorityListTest.php | 504 +++++++++++++++++++++++++++ 3 files changed, 738 insertions(+), 89 deletions(-) create mode 100644 tests/unit/Collections/TPriorityListTest.php diff --git a/.gitattributes b/.gitattributes index 37da8a90..fe708dd6 100644 --- a/.gitattributes +++ b/.gitattributes @@ -3635,6 +3635,7 @@ tests/unit/Collections/TListTest.php -text tests/unit/Collections/TMapTest.php -text tests/unit/Collections/TPagedDataSourceTest.php -text tests/unit/Collections/TPagedListTest.php -text +tests/unit/Collections/TPriorityListTest.php -text tests/unit/Collections/TQueueTest.php -text tests/unit/Collections/TStackTest.php -text tests/unit/Data/DataGateway/AllTests.php -text diff --git a/framework/Collections/TPriorityList.php b/framework/Collections/TPriorityList.php index e924d8ef..25c5388c 100644 --- a/framework/Collections/TPriorityList.php +++ b/framework/Collections/TPriorityList.php @@ -13,23 +13,29 @@ /** * TPriorityList class * - * TPriorityList implements a priority ordered list collection class. + * TPriorityList implements a priority ordered list collection class. It allows you to specify + * floating numbers for priorities up to a specific precision. There is also a default priority if + * no priority is specified. If you replace TList with this class it will work exactly the same with + * priorities set to the default. * - ** You can access, append, insert, remove an item by using - ** {@link itemAt}, {@link add}, {@link insertAt}, and {@link remove}. - ** To get the number of the items in the list, use {@link getCount}. - ** TPriorityList can also be used like a regular array as follows, - ** - ** $list[]=$item; // append with the default priority - ** $list[$index]=$item; // $index must be between 0 and $list->Count. This sets the element regardless of priority. Priority stays the same. - ** unset($list[$index]); // remove the item at $index - ** if(isset($list[$index])) // if the list has an item at $index - ** foreach($list as $index=>$item) // traverse each item in the list - ** $n=count($list); // returns the number of items in the list - ** + * As you access the array features of this class it flattens and caches the results. It flushes the + * cache when elements are changed. + * + * You can access, append, insert, remove an item by using + * {@link itemAt}, {@link add}, {@link insertAt}, {@link insertAtPriority}, and {@link remove}. + * To get the number of the items in the list, use {@link getCount}. + * TPriorityList can also be used like a regular array as follows, + * + * $list[]=$item; // append with the default priority + * $list[$index]=$item; // $index must be between 0 and $list->Count. This sets the element regardless of priority. Priority stays the same. + * unset($list[$index]); // remove the item at $index + * if(isset($list[$index])) // if the list has an item at $index + * foreach($list as $index=>$item) // traverse each item in the list in proper priority order and add/insert order + * $n=count($list); // returns the number of items in the list + * * ** To extend TPriorityList by doing additional operations with each addition or removal - ** operation, override {@link insertAt()}, and {@link removeAt()}. + ** operation, override {@link insertAtIndexInPriority()}, and {@link removeAtIndexInPriority()}. * * @author Brad Anderson * @version $Id: TPriorityList.php 2541 2008-10-21 15:05:13Z javalizard $ @@ -54,20 +60,28 @@ class TPriorityList extends TList * @var numeric the default priority of items added if not specified */ private $_dp=10; + /** + * @var numeric the precision of the floating point priorities within this priority list + */ + private $_p=10; /** * Constructor. * Initializes the list with an array or an iterable object. * @param array|Iterator the intial data. Default is null, meaning no initialization. * @param boolean whether the list is read-only + * @param float the default priority of items without priorities. + * @param numeric the precision of the floating priorities * @throws TInvalidDataTypeException If data is not null and neither an array nor an iterator. */ - public function __construct($data=null,$readOnly=false,$defaultPriority=10) + public function __construct($data=null,$readOnly=false,$defaultPriority=10,$precision=8) { + parent::__construct(); if($data!==null) $this->copyFrom($data); $this->setReadOnly($readOnly); $this->setDefaultPriority($defaultPriority); + $this->setPrecision($precision); } /** @@ -88,6 +102,20 @@ class TPriorityList extends TList return $this->_c; } + /** + * @param numeric optional priority at which to count items. if no parameter, it takes the default {@link getDefaultPriority} + * @return integer the number of items in the list at the + */ + public function getPriorityCount($priority=null) + { + if($priority === null) + $priority = $this->DefaultPriority; + $priority = (string)round(TPropertyValue::ensureFloat($priority), $this->_p); + + if(!isset($this->_d[$priority]) || !is_array($this->_d[$priority])) return false; + return count($this->_d[$priority]); + } + /** * @return boolean whether this map is read-only or not. Defaults to false. */ @@ -105,46 +133,39 @@ class TPriorityList extends TList } /** - * Returns an iterator for traversing the items in the list. - * This method is required by the interface IteratorAggregate. - * @return Iterator an iterator for traversing the items in the list. + * @return numeric the precision of the floating priorities, defaults with 10 */ - public function getIterator() + public function getPrecision() { - return new TPriorityListIterator($this->flattenPriorities()); + return $this->_p; } /** - * @return integer the number of items in the list + * TPriorityList uses php function {@link round} on its priorities and thus it uses precision. + * @param numeric this sets the precision of the floating point priorities. */ - public function getPriorityCount($priority=null) + protected function setPrecision($value) { - if($priority === null) - $priority = $this->DefaultPriority; - $priority = (string)TPropertyValue::ensureFloat($priority); - - if(!isset($this->_d[$priority])) return 0; - return count($this->_d[$priority]); + $this->_p=TPropertyValue::ensureInteger($value); } /** - * @return array the key list + * Returns an iterator for traversing the items in the list. + * This method is required by the interface IteratorAggregate. + * @return Iterator an iterator for traversing the items in the list. */ - public function getPriorities() + public function getIterator() { - return array_keys($this->_d); + return new TPriorityListIterator($this->flattenPriorities()); } /** * @return array the key list */ - public function getPriority($priority=null) + public function getPriorities() { - if($priority === null) - $priority = $this->DefaultPriority; - $priority = (string)TPropertyValue::ensureFloat($priority); - - return isset($this->_d[$priority]) ? $this->_d[$priority] : false; + $this->flattenPriorities(); + return array_keys($this->_d); } @@ -178,19 +199,31 @@ class TPriorityList extends TList throw new TInvalidDataValueException('list_index_invalid',$index); } + /** + * @return array the key list + */ + public function itemsAtPriority($priority=null) + { + if($priority === null) + $priority = $this->DefaultPriority; + $priority = (string)round(TPropertyValue::ensureFloat($priority), $this->_p); + + return isset($this->_d[$priority]) ? $this->_d[$priority] : false; + } + /** * Returns the item with the specified key. * This method is exactly the same as {@link offsetGet}. * @param mixed the key * @return mixed the element at the offset, null if no element is found at the offset */ - public function itemAtPriority($priority, $index) + public function itemAtPriorityIndex($priority=null, $index) // IS THIS EVEN POSSIBLE??? { if($priority === null) $priority = $this->DefaultPriority; - return !isset($this->_d[$priority]) ? null : ( - isset($this->_d[$priority][$index]) ? $this->_d[$priority][$index] : null + return !isset($this->_d[$priority]) ? false : ( + isset($this->_d[$priority][$index]) ? $this->_d[$priority][$index] : false ); } @@ -201,9 +234,9 @@ class TPriorityList extends TList * @param mixed value * @throws TInvalidOperationException if the map is read-only */ - public function add($item, $priority=null, $index=false) + public function add($item) { - $this->insertAt($item, $priority, $index); + $this->insertAtPriority($item); return $this->_c-1; } @@ -216,15 +249,49 @@ class TPriorityList extends TList * @throws TInvalidDataValueException If the index specified exceeds the bound * @throws TInvalidOperationException if the list is read-only */ - public function insertAt($item, $priority=null, $index=false) + public function insertAt($index, $item) { - if($priority === null) - $priority = $this->DefaultPriority; + if($this->ReadOnly) + throw new TInvalidOperationException('list_readonly',get_class($this)); - $priority = (string)TPropertyValue::ensureFloat($priority); + if(($priority = $this->priorityAt($index, true)) !== false) + $this->insertAtIndexInPriority($item, $priority[1], $priority[0]); + else + throw new TInvalidDataValueException('list_index_invalid',$index); + } + + /** + * Inserts an item at the specified position. + * Original item at the position and the next items + * will be moved one step towards the end. + * @param integer the specified position. + * @param mixed new item + * @throws TInvalidDataValueException If the index specified exceeds the bound + * @throws TInvalidOperationException if the list is read-only + */ + public function insertAtPriority($item, $priority=null) + { + $this->insertAtIndexInPriority($item, false, $priority); + } + + /** + * Inserts an item at the specified position. + * Original item at the position and the next items + * will be moved one step towards the end. + * @param integer the specified position. + * @param mixed new item + * @throws TInvalidDataValueException If the index specified exceeds the bound + * @throws TInvalidOperationException if the list is read-only + */ + public function insertAtIndexInPriority($item, $index=false, $priority=null) + { if(!$this->ReadOnly) { + if($priority === null) + $priority = $this->DefaultPriority; + + $priority = (string)round(TPropertyValue::ensureFloat($priority), $this->_p); if($index === false) { //This string conversion allows floats as keys $this->_d[$priority][]=$item; @@ -232,15 +299,16 @@ class TPriorityList extends TList array_splice($this->_d[$priority],$index,0,array($item)); else $this->_d[$priority]=array($item); - + + $this->_fd = null; + + return $this->_c++; } else throw new TInvalidOperationException('list_readonly',get_class($this)); - $this->_fd = null; - - return ++$this->_c; } + /** * Removes an item from the list. @@ -252,14 +320,49 @@ class TPriorityList extends TList */ public function remove($item) { - if(($priority=$this->priorityOf($item, true)) !== null) + if(($priority=$this->priorityOf($item, true)) !== false) { - return $this->removeAt($item, $priority[0], $priority[1]); + $this->removeAtIndexInPriority($priority[1], $priority[0]); + return $priority[2]; } else throw new TInvalidDataValueException('list_item_inexistent'); } + /** + * Removes an item at the specified position. + * @param integer the index of the item to be removed. + * @return mixed the removed item. + * @throws TInvalidDataValueException If the index specified exceeds the bound + * @throws TInvalidOperationException if the list is read-only + */ + public function removeAt($index) + { + if($this->ReadOnly) + throw new TInvalidOperationException('list_readonly',get_class($this)); + + if(($priority = $this->priorityAt($index, true)) !== false) + return $this->removeAtIndexInPriority($priority[1], $priority[0]); + throw new TInvalidDataValueException('list_index_invalid',$index); + } + + /** + * Removes an item from the list. + * The list will first search for the item. + * The first item found will be removed from the list. + * @param mixed the item to be removed. + * @return integer the index at which the item is being removed + * @throws TInvalidDataValueException If the item does not exist + */ + public function removeAtPriority($item, $priority=null) + { + if($priority === null) + $priority = $this->DefaultPriority; + if(isset($this->_d[$priority]) && ($index=array_search($item,$this->_d[$priority],true))!==false) + return $this->removeAtIndexInPriority($index, $priority); + throw new TInvalidDataValueException('list_item_inexistent'); + } + /** * Removes an item from the list. * The list will first search for the item. @@ -268,32 +371,24 @@ class TPriorityList extends TList * @return integer the index at which the item is being removed * @throws TInvalidDataValueException If the item does not exist */ - public function removeAt($item, $priority=null, $index=false) + public function removeAtIndexInPriority($index, $priority=null) { if(!$this->ReadOnly) { if($priority === null) $priority = $this->DefaultPriority; - $priority = (string)TPropertyValue::ensureFloat($priority); + $priority = (string)round(TPropertyValue::ensureFloat($priority), $this->_p); + if(!isset($this->_d[$priority]) || !isset($this->_d[$priority][$index])) + throw new TInvalidDataValueException('list_item_inexistent'); - if($priority === false) { - if(($priority=$this->priorityOf($item, true)) !== null) { - $index = $priority[1]; - $priority = $priority[0]; - } - } else if($index === false) { - if(($index=array_search($item,$this->_d[$priority],true))===false) - return false; - } - if(!isset($this->_d[$priority]) || !isset($this->_d[$priority][$index])) return false; - - //$value = $this->_d[$priority][$index]; - //unset($this->_d[$priority][$index]); + // $value is an array of elements removed, only one $value = array_splice($this->_d[$priority],$index,1); $value = $value[0]; + if(!count($this->_d[$priority])) unset($this->_d[$priority]); + $this->_c--; $this->_fd = null; return $value; @@ -309,8 +404,8 @@ class TPriorityList extends TList { foreach($this->_d as $priority => $items) { $items = array_reverse($items); - foreach($items as $index => $item) - $this->removeAt($item, array($priority, $index)); + for($index = count($items) - 1; $index >= 0; $index--) + $this->removeAtIndexInPriority($index, $priority); unset($this->_d[$priority]); } } @@ -342,22 +437,58 @@ class TPriorityList extends TList */ public function priorityOf($item, $withindex = false) { - foreach($this->_d as $priority => $items) - if(($index=array_search($item,$items,true))!==false) - return $withindex ? array($priority, $index, 'priority' => $priority, 'index' => $index) : $priority; + // this is to ensure priority order + $this->flattenPriorities(); + + $absindex = 0; + foreach($this->_d as $priority => $items) { + if(($index=array_search($item,$items,true))!==false) { + $absindex += $index; + return $withindex ? + array($priority, $index, $absindex, + 'priority' => $priority, 'index' => $index, 'absindex' => $absindex) : $priority; + } else + $absindex += count($items); + } return false; } + /** + * @param mixed the item + * @return integer the index of the item in the list (0 based), false if not found. + */ + public function priorityAt($index, $withindex = false) + { + if($index < 0 || $index >= $this->Count) + throw new TInvalidDataValueException('list_index_invalid',$index); + + // this is to ensure priority order + $absindex = $index; + $this->flattenPriorities(); + foreach($this->_d as $priority => $items) { + if($index >= ($c = count($items))) + $index -= $c; + else + return $withindex ? + array($priority, $index, $absindex, + 'priority' => $priority, 'index' => $inde, 'absindex' => $absindexx) : $priority; + } + return false; + } + /** * @param mixed the item to index * @param mixed the item */ public function insertBefore($indexitem, $item) { - if(($priority = $this->priorityOf($indexitem, true)) == -1) return -1; + if(($priority = $this->priorityOf($indexitem, true)) === false) + throw new TInvalidDataValueException('list_item_inexistent'); - return $this->insertAt($item, $priority[0], $priority[1]); + $this->insertAtIndexInPriority($item, $priority[1], $priority[0]); + + return $priority[2]; } /** @@ -366,9 +497,12 @@ class TPriorityList extends TList */ public function insertAfter($indexitem, $item) { - if(($priority = $this->priorityOf($indexitem, true)) == -1) return -1; + if(($priority = $this->priorityOf($indexitem, true)) === false) + throw new TInvalidDataValueException('list_item_inexistent'); - return $this->insertAt($item, $priority[0], $priority[1] + 1); + $this->insertAtIndexInPriority($item, $priority[1]+1, $priority[0]); + + return $priority[2]+1; } /** @@ -378,6 +512,15 @@ class TPriorityList extends TList { return $this->flattenPriorities(); } + + /** + * @return array the list of items in array with array keys as priorities and items as arrays of items + */ + public function toPriorityArray() + { + $this->flattenPriorities(); + return $this->_d; + } /** @@ -392,14 +535,15 @@ class TPriorityList extends TList if($this->getCount()>0) $this->clear(); foreach($data->Priorities as $priority) { - foreach($data->getPriority($priority) as $index => $item) - $this->add($item, $priority); + foreach($data->itemsAtPriority($priority) as $index => $item) + $this->insertAtIndexInPriority($item, $index, $priority); } + } else if(is_array($data) || $data instanceof Traversable) { if($this->getCount()>0) $this->clear(); - foreach($data as $priority=>$item) - $this->add($item, $priority); + foreach($data as $key=>$item) + $this->add($item); } else if($data!==null) throw new TInvalidDataTypeException('map_data_not_iterable'); @@ -415,12 +559,13 @@ class TPriorityList extends TList { if($data instanceof TPriorityList) { foreach($data->Priorities as $priority) { - foreach($data->getPriority($priority) as $index => $item) - $this->add($item, $priority); + foreach($data->itemsAtPriority($priority) as $index => $item) + $this->insertAtIndexInPriority($item, $index, $priority); } } else if(is_array($data) || $data instanceof Traversable) { - foreach($data as $priority=>$value) - $this->add($value, $priority); + foreach($data as $priority=>$item) + $this->add($item); + } else if($data!==null) throw new TInvalidDataTypeException('map_data_not_iterable'); } @@ -457,10 +602,9 @@ class TPriorityList extends TList { if($offset === null) return $this->add($item); - $olditem = $this->itemAt($offset); - $priority = $this->priorityOf($olditem, true); - $this->removeAt($olditem, $priority[0], $priority[1]); - $this->add($item, $priority[0], $priority[1]); + $priority = $this->priorityAt($offset, true); + $this->removeAtIndexInPriority($priority[1], $priority[0]); + $this->insertAtIndexInPriority($item, $priority[1], $priority[0]); } /** @@ -470,7 +614,7 @@ class TPriorityList extends TList */ public function offsetUnset($offset) { - $this->remove($this->itemAt($offset)); + $this->removeAt($offset); } } diff --git a/tests/unit/Collections/TPriorityListTest.php b/tests/unit/Collections/TPriorityListTest.php new file mode 100644 index 00000000..3fb9d68e --- /dev/null +++ b/tests/unit/Collections/TPriorityListTest.php @@ -0,0 +1,504 @@ +list=new TPriorityList; + $this->item1=new PriorityListItem; + $this->item2=new PriorityListItem; + $this->item3=new PriorityListItem; + $this->item4=new PriorityListItem; + $this->list->add($this->item1); + $this->list->add($this->item2); + + // **** start the setup for non-TList things + $this->plist=new TPriorityList; + $this->pfirst=new PriorityListItem; + $this->pitem1=new PriorityListItem; + $this->pitem2=new PriorityListItem; + $this->pitem3=new PriorityListItem; + $this->pitem4=new PriorityListItem; + $this->pitem5=new PriorityListItem; + $this->plist->add($this->pitem1); + $this->plist->add($this->pitem2); + $this->plist->insertAtPriority($this->pfirst, -10000000); + $this->plist->insertAtPriority($this->pitem3, 100); + // 4 and 5 are not inserted + // ending setup: pfirst @ -10000000[0], pitem1 @ 10[0], pitem2 @ 10[1], pitem3 @ 100[0] + } + + public function tearDown() { + $this->list=null; + $this->item1=null; + $this->item2=null; + $this->item3=null; + $this->item4=null; + + // **** start the setup for non-TList things + $this->list=null; + $this->item1=null; + $this->item2=null; + $this->item3=null; + $this->item4=null; + $this->item5=null; + } + + //***************************************************************** + //******* start test cases for TList operations + //******* TPriorityList should act exactly like a TList if no special functions are used + + public function testConstructTList() { + $a=array(1,2,3); + $list=new TPriorityList($a); + $this->assertEquals(3,$list->getCount()); + $list2=new TPriorityList($this->list); + $this->assertEquals(2,$list2->getCount()); + } + + public function testGetReadOnlyTList() { + $list = new TPriorityList(null, true); + self::assertEquals(true, $list->getReadOnly(), 'List is not read-only'); + $list = new TPriorityList(null, false); + self::assertEquals(false, $list->getReadOnly(), 'List is read-only'); + } + + public function testGetCountTList() { + $this->assertEquals(2,$this->list->getCount()); + $this->assertEquals(2,$this->list->Count); + } + + public function testAddTList() { + $this->assertEquals(2,$this->list->add(null)); + $this->assertEquals(3,$this->list->add($this->item3)); + $this->assertEquals(4,$this->list->getCount()); + $this->assertEquals(3,$this->list->indexOf($this->item3)); + } + + public function testInsertAtTList() { + $this->assertNull($this->list->insertAt(0,$this->item3)); + $this->assertEquals(3,$this->list->getCount()); + $this->assertEquals(2,$this->list->indexOf($this->item2)); + $this->assertEquals(0,$this->list->indexOf($this->item3)); + $this->assertEquals(1,$this->list->indexOf($this->item1)); + try { + $this->list->insertAt(4,$this->item3); + $this->fail('exception not raised when adding item at an out-of-range index'); + } catch(TInvalidDataValueException $e) { + + } + } + + public function testInsertBeforeTList() { + try { + $this->list->insertBefore($this->item4,$this->item3); + $this->fail('exception not raised when adding item before a non-existant base item'); + } catch(TInvalidDataValueException $e) { + } + $this->assertEquals(2,$this->list->getCount()); + $this->assertEquals(0,$this->list->insertBefore($this->item1,$this->item3)); + $this->assertEquals(3,$this->list->getCount()); + $this->assertEquals(0,$this->list->indexOf($this->item3)); + $this->assertEquals(1,$this->list->indexOf($this->item1)); + $this->assertEquals(2,$this->list->indexOf($this->item2)); + } + + public function testInsertAfterTList() { + try { + $this->list->insertAfter($this->item4,$this->item3); + $this->fail('exception not raised when adding item after a non-existant base item'); + } catch(TInvalidDataValueException $e) { + } + $this->assertEquals(2,$this->list->getCount()); + $this->assertEquals(2,$this->list->insertAfter($this->item2,$this->item3)); + $this->assertEquals(3,$this->list->getCount()); + $this->assertEquals(0,$this->list->indexOf($this->item1)); + $this->assertEquals(1,$this->list->indexOf($this->item2)); + $this->assertEquals(2,$this->list->indexOf($this->item3)); + } + + public function testCanNotInsertWhenReadOnlyTList() { + $list = new TPriorityList(array(), true); + try { + $list->insertAt(1, 2); + self::fail('An expected TInvalidOperationException was not raised'); + } catch(TInvalidOperationException $e) { + } + try { + $list->insertAt(0, 2); + self::fail('An expected TInvalidOperationException was not raised'); + } catch(TInvalidOperationException $e) { + } + } + + public function testRemoveTList() { + $this->assertEquals(0,$this->list->remove($this->item1)); + $this->assertEquals(1,$this->list->getCount()); + $this->assertEquals(-1,$this->list->indexOf($this->item1)); + $this->assertEquals(0,$this->list->indexOf($this->item2)); + try { + $this->list->remove($this->item1); + $this->fail('exception not raised when removing nonexisting item'); + } catch(Exception $e) { + + } + } + + public function testRemoveAtTList() { + $this->list->add($this->item3); + $this->assertEquals($this->item2, $this->list->removeAt(1)); + $this->assertEquals(-1,$this->list->indexOf($this->item2)); + $this->assertEquals(1,$this->list->indexOf($this->item3)); + $this->assertEquals(0,$this->list->indexOf($this->item1)); + try { + $this->list->removeAt(2); + $this->fail('exception not raised when removing item with invalid index'); + } catch(TInvalidDataValueException $e) { + + } + } + + public function testCanNotRemoveWhenReadOnlyTList() { + $list = new TPriorityList(array(1, 2, 3), true); + try { + $list->removeAt(2); + } catch(TInvalidOperationException $e) { + return; + } + self::fail('An expected TInvalidOperationException was not raised'); + } + + public function testClearTList() { + $this->list->clear(); + $this->assertEquals(0,$this->list->getCount()); + $this->assertEquals(-1,$this->list->indexOf($this->item1)); + $this->assertEquals(-1,$this->list->indexOf($this->item2)); + } + + public function testContainTLists() { + $this->assertTrue($this->list->contains($this->item1)); + $this->assertTrue($this->list->contains($this->item2)); + $this->assertFalse($this->list->contains($this->item3)); + } + + public function testIndexOfTList() { + $this->assertEquals(0,$this->list->indexOf($this->item1)); + $this->assertEquals(1,$this->list->indexOf($this->item2)); + $this->assertEquals(-1,$this->list->indexOf($this->item3)); + } + + public function testCopyFromTList() { + $array=array($this->item3,$this->item1); + $this->list->copyFrom($array); + $this->assertTrue(count($array)==2 && $this->list[0]===$this->item3 && $this->list[1]===$this->item1); + try { + $this->list->copyFrom($this); + $this->fail('exception not raised when copying from non-traversable object'); + } catch(TInvalidDataTypeException $e) { + + } + } + + public function testMergeWithTList() { + $array=array($this->item3,$this->item1); + $this->list->mergeWith($array); + $this->assertTrue($this->list->getCount()==4 && $this->list[0]===$this->item1 && $this->list[3]===$this->item1); + try { + $this->list->mergeWith($this); + $this->fail('exception not raised when copying from non-traversable object'); + } catch(TInvalidDataTypeException $e) { + + } + } + + public function testToArrayTList() { + $array=$this->list->toArray(); + $this->assertTrue(count($array)==2 && $array[0]===$this->item1 && $array[1]===$this->item2); + } + + public function testArrayReadTList() { + $this->assertTrue($this->list[0]===$this->item1); + $this->assertTrue($this->list[1]===$this->item2); + try { + $a=$this->list[2]; + $this->fail('exception not raised when accessing item with out-of-range index'); + } catch(TInvalidDataValueException $e) { + + } + } + + public function testGetIteratorTList() { + $n=0; + $found=0; + foreach($this->list as $index=>$item) { + foreach($this->list as $a=>$b); // test of iterator + $n++; + if($index===0 && $item===$this->item1) + $found++; + if($index===1 && $item===$this->item2) + $found++; + } + $this->assertTrue($n==2 && $found==2); + } + + public function testArrayMiscTList() { + $this->assertEquals($this->list->Count,count($this->list)); + $this->assertTrue(isset($this->list[1])); + $this->assertFalse(isset($this->list[2])); + } + + public function testOffsetSetAddTList() { + $list = new TPriorityList(array(1, 2, 3)); + $list->offsetSet(null, 4); + self::assertEquals(array(1, 2, 3, 4), $list->toArray()); + } + + public function testOffsetSetReplaceTList() { + $list = new TPriorityList(array(1, 2, 3)); + $list->offsetSet(1, 4); + self::assertEquals(array(1, 4, 3), $list->toArray()); + } + + public function testOffsetUnsetTList() { + $list = new TPriorityList(array(1, 2, 3)); + $list->offsetUnset(1); + self::assertEquals(array(1, 3), $list->toArray()); + } + + //******* end test cases for TList operations + //***************************************************************** + + + public function testConstructPriorities() { + $a=array('a' => 1, '0.5' => 2, 9 => 8); + + $list=new TPriorityList($a); + $this->assertEquals(3,$list->getCount()); + + $list2=new TPriorityList($this->plist); + $this->assertEquals(4,$list2->getCount()); + $this->assertEquals(-10000000,$list2->priorityOf($this->pfirst)); + $this->assertEquals(100,$list2->priorityOf($this->pitem3)); + $this->assertEquals(-10000000,$list2->priorityAt(0)); + $this->assertEquals($this->plist->DefaultPriority,$list2->priorityAt(2)); + $this->assertEquals(100,$list2->priorityAt(3)); + } + + public function testGetCountPriorities() { + $this->assertEquals(4,$this->plist->getCount()); + $this->assertEquals(4,$this->plist->Count); + } + + public function testAddPriorities() { + $this->assertEquals(3,$this->plist->add(null)); + $this->assertEquals(4,$this->plist->add($this->item3)); + $this->assertEquals(4,$this->plist->getCount()); + $this->assertEquals(3,$this->plist->indexOf($this->item3)); + } + + public function testInsertAtPriorities() { + $this->assertNull($this->plist->insertAt(0,$this->item3)); + $this->assertEquals(3,$this->plist->getCount()); + $this->assertEquals(2,$this->plist->indexOf($this->item2)); + $this->assertEquals(0,$this->plist->indexOf($this->item3)); + $this->assertEquals(1,$this->plist->indexOf($this->item1)); + try { + $this->plist->insertAt(4,$this->item3); + $this->fail('exception not raised when adding item at an out-of-range index'); + } catch(TInvalidDataValueException $e) { + + } + } + + public function testInsertBeforePriorities() { + try { + $this->plist->insertBefore($this->item4,$this->item3); + $this->fail('exception not raised when adding item before a non-existant base item'); + } catch(TInvalidDataValueException $e) { + } + $this->assertEquals(2,$this->plist->getCount()); + $this->plist->insertBefore($this->item1,$this->item3); + $this->assertEquals(3,$this->plist->getCount()); + $this->assertEquals(0,$this->plist->indexOf($this->item3)); + $this->assertEquals(1,$this->plist->indexOf($this->item1)); + $this->assertEquals(2,$this->plist->indexOf($this->item2)); + } + + public function testInsertAfterPriorities() { + try { + $this->plist->insertAfter($this->item4,$this->item3); + $this->fail('exception not raised when adding item after a non-existant base item'); + } catch(TInvalidDataValueException $e) { + } + $this->assertEquals(2,$this->plist->getCount()); + $this->plist->insertAfter($this->item2,$this->item3); + $this->assertEquals(3,$this->plist->getCount()); + $this->assertEquals(0,$this->plist->indexOf($this->item1)); + $this->assertEquals(1,$this->plist->indexOf($this->item2)); + $this->assertEquals(2,$this->plist->indexOf($this->item3)); + } + + public function testCanNotInsertWhenReadOnlyPriorities() { + $list = new TPriorityList(array(), true); + try { + $list->insertAt(1, 2); + } catch(TInvalidOperationException $e) { + return; + } + self::fail('An expected TInvalidOperationException was not raised'); + } + + public function testRemovePriorities() { + $this->assertEquals(0,$this->plist->remove($this->item1)); + $this->assertEquals(1,$this->plist->getCount()); + $this->assertEquals(-1,$this->plist->indexOf($this->item1)); + $this->assertEquals(0,$this->plist->indexOf($this->item2)); + try { + $this->plist->remove($this->item1); + $this->fail('exception not raised when removing nonexisting item'); + } catch(Exception $e) { + + } + } + + public function testRemoveAtPriorities() { + $this->plist->add($this->item3); + $this->assertEquals($this->item2, $this->plist->removeAt(1)); + $this->assertEquals(-1,$this->plist->indexOf($this->item2)); + $this->assertEquals(1,$this->plist->indexOf($this->item3)); + $this->assertEquals(0,$this->plist->indexOf($this->item1)); + try { + $this->plist->removeAt(2); + $this->fail('exception not raised when removing item with invalid index'); + } catch(TInvalidDataValueException $e) { + + } + } + + public function testCanNotRemoveWhenReadOnlyPriorities() { + $list = new TPriorityList(array(1, 2, 3), true); + try { + $list->removeAt(2); + } catch(TInvalidOperationException $e) { + return; + } + self::fail('An expected TInvalidOperationException was not raised'); + } + + public function testClearPriorities() { + $this->plist->clear(); + $this->assertEquals(0,$this->plist->getCount()); + $this->assertEquals(-1,$this->plist->indexOf($this->item1)); + $this->assertEquals(-1,$this->plist->indexOf($this->item2)); + } + + public function testContainsPriorities() { + $this->assertTrue($this->plist->contains($this->item1)); + $this->assertTrue($this->plist->contains($this->item2)); + $this->assertFalse($this->plist->contains($this->item3)); + } + + public function testIndexOfPriorities() { + $this->assertEquals(0,$this->plist->indexOf($this->item1)); + $this->assertEquals(1,$this->plist->indexOf($this->item2)); + $this->assertEquals(-1,$this->plist->indexOf($this->item3)); + } + + public function testCopyFromPriorities() { + $array=array($this->item3,$this->item1); + $this->plist->copyFrom($array); + $this->assertTrue(count($array)==2 && $this->plist[0]===$this->item3 && $this->plist[1]===$this->item1); + try { + $this->plist->copyFrom($this); + $this->fail('exception not raised when copying from non-traversable object'); + } catch(TInvalidDataTypeException $e) { + + } + } + + public function testMergeWithPriorities() { + $array=array($this->item3,$this->item1); + $this->plist->mergeWith($array); + $this->assertTrue($this->plist->getCount()==4 && $this->plist[0]===$this->item1 && $this->plist[3]===$this->item1); + try { + $this->plist->mergeWith($this); + $this->fail('exception not raised when copying from non-traversable object'); + } catch(TInvalidDataTypeException $e) { + + } + } + + public function testToArrayPriorities() { + $array=$this->plist->toArray(); + $this->assertTrue(count($array)==2 && $array[0]===$this->item1 && $array[1]===$this->item2); + } + + public function testArrayReadPriorities() { + $this->assertTrue($this->plist[0]===$this->item1); + $this->assertTrue($this->plist[1]===$this->item2); + try { + $a=$this->plist[2]; + $this->fail('exception not raised when accessing item with out-of-range index'); + } catch(TInvalidDataValueException $e) { + + } + } + + public function testGetIteratorPriorities() { + $n=0; + $found=0; + foreach($this->plist as $index=>$item) { + foreach($this->plist as $a=>$b); // test of iterator + $n++; + if($index===0 && $item===$this->item1) + $found++; + if($index===1 && $item===$this->item2) + $found++; + } + $this->assertTrue($n==2 && $found==2); + } + + public function testArrayMiscPriorities() { + $this->assertEquals($this->plist->Count,count($this->plist)); + $this->assertTrue(isset($this->plist[1])); + $this->assertFalse(isset($this->plist[2])); + } + + public function testOffsetSetAddPriorities() { + $list = new TPriorityList(array(1, 2, 3)); + $list->offsetSet(null, 4); + self::assertEquals(array(1, 2, 3, 4), $list->toArray()); + } + + public function testOffsetSetReplacePriorities() { + $list = new TPriorityList(array(1, 2, 3)); + $list->offsetSet(1, 4); + self::assertEquals(array(1, 4, 3), $list->toArray()); + } + + public function testOffsetUnsetPriorities() { + $list = new TPriorityList(array(1, 2, 3)); + $list->offsetUnset(1); + self::assertEquals(array(1, 3), $list->toArray()); + } + + +} \ No newline at end of file -- cgit v1.2.3