Adding new Set::merge() and Set class test case, thanks Felix

git-svn-id: https://svn.cakephp.org/repo/branches/1.2.x.x@4779 3807eeeb-6ff5-0310-8944-8be069107fe0
This commit is contained in:
nate 2007-04-05 05:57:52 +00:00
parent 1c6c32981e
commit ac904cd4d4
2 changed files with 202 additions and 18 deletions

View file

@ -60,23 +60,67 @@ class Set extends Object {
function &get() {
return $this->value;
}
/**
* Merges the contents of the array object with $array
*
* @param mixed $array An array, another Set object, or a value to be appended
* @return array
* @access public
*/
function merge($array = null, $array2 = null) {
if ($array2 !== null && is_array($array2)) {
return array_merge_recursive($array, $array2);
}
if(!isset($this->value)) {
$this->value = array();
/**
* This function can be thought of as a hybrid between PHP's array_merge and array_merge_recursive. The difference
* to the two is that if an array key contains another array then the function behaves recursive (unlike array_merge)
* but does not do if for keys containing strings (unlike array_merge_recursive). See the unit test for more information.
*
* Note: This function will work with an unlimited amount of arguments and typecasts non-array parameters into arrays.
*
* @param array $arr1
* @param array $arr2
* @return array
*/
function merge($arr1, $arr2 = null) {
// Get all arguments that were passed to the function
$args = func_get_args();
// If $this is a Set class
if (is_a($this, 'set')) {
// Get the call stack
$backtrace = debug_backtrace();
// And the previous call
$previousCall = low($backtrace[1]['class'].'::'.$backtrace[1]['function']);
// If this is not a recursive call
if ($previousCall != 'set::merge') {
// Reference this Set's value as our resulting $r array
$r =& $this->value;
// And push an empty args at the beginning of the $args array which will be discarded later on
array_unshift($args, null);
}
}
$this->value = array_merge_recursive($this->value, Set::__array($array));
return $this->value;
// If $r has not been set yet
if (!isset($r)) {
// Tpecast the first argument into an array and use it as our resulting $r array
$r = (array)current($args);
}
// Loop through all $args we were given
while(($arg = next($args)) !== false) {
// If a Set object was passed in
if (is_a($arg, 'set')) {
// Use it's value for the merging
$arg = $arg->get();
}
// Loop through all $key / $val pairs of our current $arg
foreach ((array)$arg as $key => $val) {
// If the current $key holds an array and the current $arg and all previous ones ($r)
if (is_array($val) && isset($r[$key]) && is_array($r[$key])) {
// Go for recursive merging
$r[$key] = Set::merge($r[$key], $val);
} elseif (is_int($key)) {
// If it's a numerical index go for auto-incremeting
$r[] = $val;
} else {
// And in case of an associative one do an overwrite
$r[$key] = $val;
}
}
}
// Return the merged array
return $r;
}
/**
* Pushes the differences in $array2 onto the end of $array
@ -117,7 +161,7 @@ class Set extends Object {
if (is_array($class)) {
$val = $class;
$class = $tmp;
} elseif (is_a($this, 'set') || is_a($this, 'Set')) {
} elseif (is_a($this, 'set')) {
$val = $this->get();
}
@ -129,10 +173,10 @@ class Set extends Object {
function __array($array) {
if ($array == null) {
$array = $this->value;
} elseif (is_object($array) && (is_a($array, 'set') || is_a($array, 'Set'))) {
} elseif (is_object($array) && (is_a($array, 'set'))) {
$array = $array->get();
} elseif (is_object($array)) {
// Throw an error
$array = get_object_vars($array);
} elseif (!is_array($array)) {
$array = array($array);
}

View file

@ -0,0 +1,140 @@
<?php
// Include the class to be tested
uses('set');
/**
* UnitTestCase for the Set class
*
*
* @package cake
* @subpackage cake.cake.libs
*/
class SetTest extends UnitTestCase {
function testMerge() {
// Test that passing in just 1 array returns it "as-is"
$r = Set::merge(array('foo'));
$this->assertIdentical($r, array('foo'));
// Test that passing in a non-array turns it into one
$r = Set::merge('foo');
$this->assertIdentical($r, array('foo'));
// Test that this works for 2 strings as well
$r = Set::merge('foo', 'bar');
$this->assertIdentical($r, array('foo', 'bar'));
// Test that this works for arguments of mixed types as well
$r = Set::merge('foo', array('user' => 'bob', 'no-bar'), 'bar');
$this->assertIdentical($r, array('foo', 'user' => 'bob', 'no-bar', 'bar'));
// Test merging two simple numerical indexed arrays
$a = array('foo', 'foo2');
$b = array('bar', 'bar2');
$this->assertIdentical(Set::merge($a, $b), array('foo', 'foo2', 'bar', 'bar2'));
// Test merging two simple associative arrays
$a = array('foo' => 'bar', 'bar' => 'foo');
$b = array('foo' => 'no-bar', 'bar' => 'no-foo');
$this->assertIdentical(Set::merge($a, $b), array('foo' => 'no-bar', 'bar' => 'no-foo'));
// Test merging two simple nested arrays
$a = array('users' => array('bob', 'jim'));
$b = array('users' => array('lisa', 'tina'));
$this->assertIdentical(Set::merge($a, $b), array(
'users' => array('bob', 'jim', 'lisa', 'tina')
));
// Test that merging an key holding a string over an array one causes an overwrite
$a = array('users' => array('jim', 'bob'));
$b = array('users' => 'none');
$this->assertIdentical(Set::merge($a, $b), array('users' => 'none'));
// Test merging two somewhat complex nested arrays
$a = array(
'users' => array(
'lisa' => array(
'id' => 5,
'pw' => 'secret'
)
),
'cakephp'
);
$b = array(
'users' => array(
'lisa' => array(
'pw' => 'new-pass',
'age' => 23
)
),
'ice-cream'
);
$this->assertIdentical(Set::merge($a, $b), array(
'users' => array(
'lisa' => array(
'id' => 5,
'pw' => 'new-pass',
'age' => 23
)
),
'cakephp',
'ice-cream'
));
// And now go for the ultimate tripple-play ; )
$c = array(
'users' => array(
'lisa' => array(
'pw' => 'you-will-never-guess',
'age' => 25,
'pet' => 'dog'
)
),
'chocolate'
);
$expected = array(
'users' => array(
'lisa' => array(
'id' => 5,
'pw' => 'you-will-never-guess',
'age' => 25,
'pet' => 'dog'
)
),
'cakephp',
'ice-cream',
'chocolate'
);
$this->assertIdentical(Set::merge($a, $b, $c), $expected);
// Test that passing in an empty array does not mess things up
$this->assertIdentical(Set::merge($a, $b, array(), $c), $expected);
// Create a new Set instance from the $a array
$Set =& new Set($a);
// Merge $b, an empty array and $c over it
$r = $Set->merge($b, array(), $c);
// And test that it produces the same result as a static call would
$this->assertIdentical($r, $expected);
// And also updates it's own value property
$this->assertIdentical($Set->value, $expected);
// Let the garbage collector eat the Set instance
unset($Set);
$Set =& new Set();
$SetA =& new Set($a);
$SetB =& new Set($b);
$SetC =& new Set($c);
$r = $Set->merge($SetA, $SetB, $SetC);
// And test that it produces the same result as a static call would
$this->assertIdentical($r, $expected);
// And also updates it's own value property
$this->assertIdentical($Set->value, $expected);
}
}
?>