summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitattributes1
-rw-r--r--framework/Collections/TPriorityList.php322
-rw-r--r--tests/unit/Collections/TPriorityListTest.php504
3 files changed, 738 insertions, 89 deletions
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,
- ** <code>
- ** $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
- ** </code>
+ * 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,
+ * <code>
+ * $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
+ * </code>
*
** 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 <javalizard@gmail.com>
* @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);
}
/**
@@ -89,6 +103,20 @@ class TPriorityList extends TList
}
/**
+ * @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.
*/
public function getDefaultPriority()
@@ -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);
}
@@ -179,18 +200,30 @@ class TPriorityList extends TList
}
/**
+ * @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,15 +320,50 @@ 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.
* The first item found will be removed from the list.
@@ -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 @@
+<?php
+require_once dirname(__FILE__).'/../phpunit.php';
+
+class PriorityListItem {
+ public $data='data';
+}
+Prado::using('System.Collections.TPriorityList');
+
+/**
+ * All Test cases for the TList are here. The TPriorityList should act just like a TList when used exactly like a TList
+ *
+ * The TPriority List should start behaving differently when using the class outside of the standard TList Function calls
+ *
+ * @package System.Collections
+ */
+class TPriorityListTest extends PHPUnit_Framework_TestCase {
+
+ protected $list;
+ protected $item1, $item2, $item3, $item4;
+
+ protected $plist;
+ protected $pfirst, $pitem1, $pitem2, $pitem3, $pitem4, $pitem5;
+
+ public function setUp() {
+ $this->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