Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Give Mocker the ability to Mock non li3 classes. #802

Merged
merged 1 commit into from

3 participants

@blainesch
Collaborator

Before, we only allowed a class/object to be filtered if it extended Object or StaticObject, however now we allow any object/class to be extended by delegating the filters to the Mocker class.

Thanks @jails for the idea! -> #788 code comments

test/Mocker.php
((6 lines not shown))
} elseif (is_string($mock) && class_exists($mock) && isset($mock::$results)) {
$results = $mock::$results;
}
return new MockerChain($results);
}
+ public static function mergeResults($results, $secondary) {
@blainesch Collaborator

Forgot docblocks on this one.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
test/Mocker.php
((98 lines not shown))
+ public static function invokeMethod($method, $params = array()) {
+ switch (count($params)) {
+ case 0:
+ return static::$method();
+ case 1:
+ return static::$method($params[0]);
+ case 2:
+ return static::$method($params[0], $params[1]);
+ case 3:
+ return static::$method($params[0], $params[1], $params[2]);
+ case 4:
+ return static::$method($params[0], $params[1], $params[2], $params[3]);
+ case 5:
+ return static::$method($params[0], $params[1], $params[2], $params[3], $params[4]);
+ default:
+ return forward_static_call_array(array(get_called_class(), $method), $params);
@nateabele Owner

You can just replace the switch block with a call to forward_static_call_array(). It used to be faster to dispatch manually, but subsequent PHP versions have been sufficiently optimized that this is actually slower. Come to think of it, we should probably update Object and StaticObject as well.

@blainesch Collaborator

Looks like this trick may be slower but allows for a way to get around passing by reference dynamically.

https://travis-ci.org/BlaineSch/lithium/jobs/4404751

It also looks like the travis thing isn't working as expected. I assumed if there were quality checks that failed, it would fail, and if it passed the build would pass. However right now it lets failing tests pass as long as quality passes.

The only way around it, that I see, is to put it all on a single line to have a single pass/fail flag. This would be a very long line though, even if we 'alias' some of it. I'll submit a pr soon.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@nateabele
Owner

Other than my one comment, this looks good.

@jails
Collaborator

To be honest I am having a hard time making sense of this. Not that because it's bad but because I don't understand/see where this will lead us.

A - Below the API I think reasonable for the Mocker.

1) Dynamically configuring a sub (from scratch) i.e:

$std = new \stdClass\Mock();
$std->stub('hello', function($name) {return "hi {$name} !";});

$this->assertTrue('hi bob !', $std->hello('bob'));

2) Which can be completed with a 'mocking' feature i.e:

$std = new \stdClass\Mock();
$std->stub('hello', function($name) {return "hi {$name} !";});

$this->assertTrue('hi bob !', $std->hello('bob'));
$this->assertTrue(Mocker::chain($std)->called('hello')->with('bob')->returned('hi bob !')->success());

3) And allowing the filtering feature specific to li3

$std = new \stdClass\Mock();
$std->stub('hello', function($name) {return "hi {$name} !";});

$std->applyFilter('hello', function($self, $params, $chain) {
    $params[0] = 'BILL';
    return $chain->next($self, $params, $chain);
})

$this->assertTrue('hi BILL !', $std->hello('bob'));
$this->assertTrue(Mocker::chain($std)->called('hello')->with('bob')->returned('hi BILL !')->success());

With this in mind, I think the Mocker will provide all the tools for Mocking/Stubbing any kind of class.

B - Static class support

  • I didn't manage to figure out how static is managed. is it possible to do something like: Mocker::chain('\MyClass')->staticCalled('method') ?

  • If a class own static and dynamic methods, is it possible to have an mock instance plus another static mock on the same class ?

C - Conclusion

So it was just some thought on this subject and maybe it's already possible to do all of this. And maybe I just didn't understand the way.

Ps:
I used a syntax which seems compatible with the current Mocker but It was just for explaining what I have in mind.

@blainesch
Collaborator

Hey @jails!
1) No, currently we can't add new methods to a mock, this really just makes them filterable, although I see the value with adding new methods since maybe the target class doesn't care and you want to make it as simple as possible.

3B) No, once we get it into chain it merges the results so you cannot check if the methods were called statically or not, via chain. However, we could do something like this, but giving chain allResults, instanceResults and staticResults then adding two extra methods staticCalled and instanceCalled.

@blainesch
Collaborator

@jails I'm not sure how we'd implement creating new methods with the current implementation.

If they have no methods like stdClass it would be standard, however what if you added a method for foo() when the class had a foo() method, would it simply add it as a filter since it couldn't overwrite it?

What if foo() didn't exist, but the target class had a __call() magic method? We'd now overwrite the __call() method, and only pass it through if no filters exists, which would overwrite the default behavior. The other alternative would be to pass it through regardless and possibly get a BadMethodCallException.

In practice, when you are testing method1() you know it calls $obj->foo() and $obj->bar() at which point you can just mock $obj and filter it's methods without creating $obj->baz() on it, because we know method1() would never call that unique method.

Thoughts?

@blainesch
Collaborator

@jails can this be closed/merged? The topic discussed was resolved in #li3-core and was off topic from the current pr either way, right?

@nateabele
Owner

@jails @BlaineSch Do we have a conclusion on this? Personally, I'm pro-merging it, because the idea of mocking relates to the identity and API of the specific classes you're working with. If you want to create completely custom classes with arbitrary methods, we should have a separate thing for that. Spies, maybe?

Anyway, if we are, in fact, merging this, it needs to be rebased against dev HEAD. Thanks, guys.

@blainesch blainesch Give Mocker the ability to Mock non li3 classes.
Before, we only allowed a class/object to be filtered if it extended `Object` or `StaticObject`, however now we allow any object/class to be extended by delegating the filters to the `Mocker` class.
40d1121
@blainesch
Collaborator

@nateabele rebased !!

@nateabele nateabele merged commit 9fd82d5 into UnionOfRAD:dev
@blainesch blainesch deleted the unknown repository branch
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Feb 4, 2013
  1. @blainesch

    Give Mocker the ability to Mock non li3 classes.

    blainesch authored
    Before, we only allowed a class/object to be filtered if it extended `Object` or `StaticObject`, however now we allow any object/class to be extended by delegating the filters to the `Mocker` class.
This page is out of date. Refresh to see the latest.
View
2  analysis/Debugger.php
@@ -16,7 +16,7 @@
* The `Debugger` class provides basic facilities for generating and rendering meta-data about the
* state of an application in its current context.
*/
-class Debugger extends \lithium\core\StaticObject {
+class Debugger {
/**
* Used for temporary closure caching.
View
211 test/Mocker.php
@@ -9,6 +9,7 @@
namespace lithium\test;
use lithium\util\String;
+use lithium\util\collection\Filters;
use ReflectionClass;
use ReflectionMethod;
use Reflection;
@@ -62,6 +63,13 @@
class Mocker {
/**
+ * Stores the closures that represent the method filters. They are indexed by called class.
+ *
+ * @var array Method filters, indexed by class.
+ */
+ protected static $_methodFilters = array();
+
+ /**
* A list of code to be generated for the delegator.
*
* The MockDelgate directly extends the mocker and makes all methods
@@ -78,18 +86,19 @@ class Mocker {
),
'constructor' => array(
'{:modifiers} function __construct({:args}) {',
- ' $args = func_get_args();',
- ' $this->parent = array_pop($args);',
+ ' $args = compact({:stringArgs});',
+ ' $this->parent = func_get_arg(count(func_get_args()) - 1);',
' $this->parent->mocker = $this;',
- ' call_user_func_array("parent::__construct", $args);',
+ ' if (method_exists("{:mocker}", "__construct")) {',
+ ' call_user_func_array("parent::__construct", $args);',
+ ' }',
'}',
),
'method' => array(
'{:modifiers} function {:method}({:args}) {',
- ' $args = func_get_args();',
+ ' $args = compact({:stringArgs});',
' $token = spl_object_hash($this);',
- ' $id = count($args) - 1;',
- ' if (!isset($args[$id]) || $args[$id] !== $token) {',
+ ' if (func_get_arg(count(func_get_args()) - 1) !== $token) {',
' $method = array($this->parent, "{:method}");',
' return call_user_func_array($method, $args);',
' }',
@@ -98,10 +107,10 @@ class Mocker {
),
'staticMethod' => array(
'{:modifiers} function {:method}({:args}) {',
- ' $args = func_get_args();',
+ ' $args = compact({:stringArgs});',
' $token = "1f3870be274f6c49b3e31a0c6728957f";',
- ' $id = count($args) - 1;',
- ' if (!isset($args[$id]) || $args[$id] !== $token) {',
+ ' $id = func_get_arg(count(func_get_args()) - 1);',
+ ' if (func_get_arg(count(func_get_args()) - 1) !== $token) {',
' $method = \'{:namespace}\Mock::{:method}\';',
' return call_user_func_array($method, $args);',
' }',
@@ -131,13 +140,15 @@ class Mocker {
'namespace {:namespace};',
'class Mock extends \{:mocker} {',
' public $mocker;',
- ' public {:static} $results = array();',
+ ' public $results = array();',
+ ' public static $staticResults = array();',
' protected $_safeVars = array(',
' "_classes",',
' "_methodFilters",',
' "mocker",',
' "_safeVars",',
' "results",',
+ ' "staticResults",',
' );',
),
'get' => array(
@@ -153,7 +164,7 @@ class Mocker {
),
'constructor' => array(
'{:modifiers} function __construct({:args}) {',
- ' $args = array_values(get_defined_vars());',
+ ' $args = compact({:stringArgs});',
' array_push($args, $this);',
' foreach ($this as $key => $value) {',
' if (!in_array($key, $this->_safeVars)) {',
@@ -172,13 +183,18 @@ class Mocker {
' $args = compact({:stringArgs});',
' $args["hash"] = "1f3870be274f6c49b3e31a0c6728957f";',
' $method = \'{:namespace}\MockDelegate::{:method}\';',
- ' $result = self::_filter("{:method}", $args, function($self, $args) use(&$method) {',
- ' return call_user_func_array($method, $args);',
- ' });',
- ' if (!isset(self::$results["{:method}"])) {',
- ' self::$results["{:method}"] = array();',
+ ' $result = {:master}::invokeMethod("_filter", array(',
+ ' __CLASS__, ',
+ ' "{:method}",',
+ ' $args,',
+ ' function($self, $args) use(&$method) {',
+ ' return call_user_func_array($method, $args);',
+ ' }',
+ ' ));',
+ ' if (!isset(self::$staticResults["{:method}"])) {',
+ ' self::$staticResults["{:method}"] = array();',
' }',
- ' self::$results["{:method}"][] = array(',
+ ' self::$staticResults["{:method}"][] = array(',
' "args" => func_get_args(),',
' "result" => $result,',
' "time" => microtime(true),',
@@ -191,9 +207,14 @@ class Mocker {
' $args = compact({:stringArgs});',
' $args["hash"] = spl_object_hash($this->mocker);',
' $method = array($this->mocker, "{:method}");',
- ' $result = $this->_filter(__METHOD__, $args, function($self, $args) use(&$method) {',
- ' return call_user_func_array($method, $args);',
- ' });',
+ ' $result = {:master}::invokeMethod("_filter", array(',
+ ' __CLASS__,',
+ ' "{:method}",',
+ ' $args,',
+ ' function($self, $args) use(&$method) {',
+ ' return call_user_func_array($method, $args);',
+ ' }',
+ ' ));',
' if (!isset($this->results["{:method}"])) {',
' $this->results["{:method}"] = array();',
' }',
@@ -205,6 +226,11 @@ class Mocker {
' return $result;',
'}',
),
+ 'applyFilter' => array(
+ 'public {:static} function applyFilter($method, $filter = null) {',
+ ' return {:master}::applyFilter(__CLASS__, $method, $filter);',
+ '}',
+ ),
'endClass' => array(
'}',
),
@@ -259,10 +285,15 @@ public static function create($mockee) {
$reflectedClass = new ReflectionClass($mocker);
$reflecedMethods = $reflectedClass->getMethods();
$getByReference = false;
+ $staticApplyFilter = true;
+ $constructor = false;
foreach ($reflecedMethods as $methodId => $method) {
if (!in_array($method->name, self::$_blackList)) {
$key = $method->isStatic() ? 'staticMethod' : 'method';
- $key = $method->name === '__construct' ? 'constructor' : $key;
+ if ($method->name === '__construct') {
+ $key = 'constructor';
+ $constructor = true;
+ }
$docs = ReflectionMethod::export($mocker, $method->name, true);
if (preg_match('/&' . $method->name . '/', $docs) === 1) {
continue;
@@ -280,14 +311,31 @@ public static function create($mockee) {
} elseif ($method->name === '__get') {
$docs = ReflectionMethod::export($mocker, '__get', true);
$getByReference = preg_match('/&__get/', $docs) === 1;
+ } elseif ($method->name === 'applyFilter') {
+ $staticApplyFilter = $method->isStatic();
}
}
+ if (!$constructor) {
+ $tokens = array(
+ 'namespace' => self::_namespace($mockee),
+ 'modifiers' => 'public',
+ 'args' => null,
+ 'stringArgs' => 'array()',
+ 'mocker' => $mocker,
+ );
+ $mock .= self::_dynamicCode('mock', 'constructor', $tokens);
+ $mockDelegate .= self::_dynamicCode('mockDelegate', 'constructor', $tokens);
+ }
+
$mockDelegate .= self::_dynamicCode('mockDelegate', 'endClass');
$mock .= self::_dynamicCode('mock', 'get', array(
'reference' => $getByReference ? '&' : '',
));
$mock .= self::_dynamicCode('mock', 'set');
+ $mock .= self::_dynamicCode('mock', 'applyFilter', array(
+ 'static' => $staticApplyFilter ? 'static' : '',
+ ));
$mock .= self::_dynamicCode('mock', 'destructor');
$mock .= self::_dynamicCode('mock', 'endClass');
@@ -352,6 +400,10 @@ protected static function _stringMethodParams(ReflectionMethod $method) {
* @return string
*/
protected static function _dynamicCode($type, $key, $tokens = array()) {
+ $defaults = array(
+ 'master' => '\lithium\test\Mocker',
+ );
+ $tokens += $defaults;
$name = '_' . $type . 'Ingredients';
$code = implode("\n", self::${$name}[$key]);
return String::insert($code, $tokens) . "\n";
@@ -364,12 +416,10 @@ protected static function _dynamicCode($type, $key, $tokens = array()) {
* @return array
*/
protected static function _mocker($mockee) {
- $matches = array();
- preg_match_all('/^(.*)\\\\([^\\\\]+)\\\\Mock$/', $mockee, $matches);
- if (!isset($matches[1][0])) {
- return;
- }
- return $matches[1][0] . '\\' . ucfirst($matches[2][0]);
+ $sections = explode('\\', $mockee);
+ array_pop($sections);
+ $sections[] = ucfirst(array_pop($sections));
+ return implode('\\', $sections);
}
/**
@@ -387,20 +437,14 @@ protected static function _namespace($mockee) {
/**
* Will validate if mockee is a valid class we should mock.
*
+ * Will fail if the mock already exists, or it doesn't contain `\Mock` in
+ * the namespace.
+ *
* @param string $mockee The fully namespaced `\Mock` class
* @return bool
*/
protected static function _validateMockee($mockee) {
- if (class_exists($mockee) || preg_match('/\\\\Mock$/', $mockee) !== 1) {
- return false;
- }
- $mocker = self::_mocker($mockee);
- $isObject = is_subclass_of($mocker, 'lithium\core\Object');
- $isStatic = is_subclass_of($mocker, 'lithium\core\StaticObject');
- if (!$isObject && !$isStatic) {
- return false;
- }
- return true;
+ return preg_match('/\\\\Mock$/', $mockee) === 1;
}
/**
@@ -412,13 +456,100 @@ protected static function _validateMockee($mockee) {
public static function chain($mock) {
$results = array();
if (is_object($mock) && isset($mock->results)) {
- $results = $mock->results;
- } elseif (is_string($mock) && class_exists($mock) && isset($mock::$results)) {
- $results = $mock::$results;
+ $results = static::mergeResults($mock->results, $mock::$staticResults);
+ } elseif (is_string($mock) && class_exists($mock) && isset($mock::$staticResults)) {
+ $results = $mock::$staticResults;
}
return new MockerChain($results);
}
+ /**
+ * Will merge two sets of results into each other.
+ *
+ * @param array $results
+ * @param array $secondary
+ * @return array
+ */
+ public static function mergeResults($results, $secondary) {
+ foreach ($results as $method => $calls) {
+ if (isset($secondary[$method])) {
+ $results['method1'] = array_merge($results['method1'], $secondary['method1']);
+ usort($results['method1'], function($el1, $el2) {
+ return strcmp($el1['time'], $el2['time']);
+ });
+ unset($secondary['method1']);
+ }
+ }
+ return $results + $secondary;
+ }
+
+ /**
+ * Apply a closure to a method of the current static object.
+ *
+ * @see lithium\core\StaticObject::_filter()
+ * @see lithium\util\collection\Filters
+ * @param string $class Fully namespaced class to apply filters.
+ * @param mixed $method The name of the method to apply the closure to. Can either be a single
+ * method name as a string, or an array of method names. Can also be false to remove
+ * all filters on the current object.
+ * @param closure $filter The closure that is used to filter the method(s), can also be false
+ * to remove all the current filters for the given method.
+ * @return void
+ */
+ public static function applyFilter($class, $method, $filter = null) {
+ if ($method === false) {
+ static::$_methodFilters[$class] = array();
+ return;
+ }
+ foreach ((array) $method as $m) {
+ if (!isset(static::$_methodFilters[$class][$m]) || $filter === false) {
+ static::$_methodFilters[$class][$m] = array();
+ }
+ if ($filter !== false) {
+ static::$_methodFilters[$class][$m][] = $filter;
+ }
+ }
+ }
+
+ /**
+ * Executes a set of filters against a method by taking a method's main implementation as a
+ * callback, and iteratively wrapping the filters around it.
+ *
+ * @see lithium\util\collection\Filters
+ * @param string $class Fully namespaced class to apply filters.
+ * @param string|array $method The name of the method being executed, or an array containing
+ * the name of the class that defined the method, and the method name.
+ * @param array $params An associative array containing all the parameters passed into
+ * the method.
+ * @param Closure $callback The method's implementation, wrapped in a closure.
+ * @param array $filters Additional filters to apply to the method for this call only.
+ * @return mixed
+ */
+ protected static function _filter($class, $method, $params, $callback, $filters = array()) {
+ $hasNoFilters = empty(static::$_methodFilters[$class][$method]);
+ if ($hasNoFilters && !$filters && !Filters::hasApplied($class, $method)) {
+ return $callback($class, $params, null);
+ }
+ if (!isset(static::$_methodFilters[$class][$method])) {
+ static::$_methodFilters += array($class => array());
+ static::$_methodFilters[$class][$method] = array();
+ }
+ $data = array_merge(static::$_methodFilters[$class][$method], $filters, array($callback));
+ return Filters::run($class, $params, compact('data', 'class', 'method'));
+ }
+
+ /**
+ * Calls a method on this object with the given parameters. Provides an OO wrapper for
+ * `forward_static_call_array()`.
+ *
+ * @param string $method Name of the method to call.
+ * @param array $params Parameter list to use when calling `$method`.
+ * @return mixed Returns the result of the method call.
+ */
+ public static function invokeMethod($method, $params = array()) {
+ return forward_static_call_array(array(get_called_class(), $method), $params);
+ }
+
}
?>
View
17 tests/cases/test/MockerChainTest.php
@@ -23,6 +23,23 @@ public function testStartSuccessful() {
$this->assertTrue($chain->success());
}
+ public function testStaticSuccessful() {
+ $class = '\lithium\tests\mocks\test\mockStdStaticClass\Mock';
+ $class::applyFilter(false);
+ $chain = Mocker::chain($class);
+
+ $this->assertTrue($chain->success());
+ }
+
+ public function testBasicStaticCalled() {
+ $class = '\lithium\tests\mocks\test\mockStdStaticClass\Mock';
+ $class::applyFilter(false);
+ $class::method1();
+ $chain = Mocker::chain($class);
+
+ $this->assertTrue($chain->called('method1')->success());
+ }
+
public function testBasicNotCalled() {
$mock = new \lithium\tests\mocks\test\mockStdClass\Mock();
$chain = Mocker::chain($mock);
View
162 tests/cases/test/MockerTest.php
@@ -41,10 +41,35 @@ public function testBasicCreationExtendsCorrectParent() {
$this->assertTrue(is_a($mockeeObj, $mocker));
}
- public function testCannotMockNonLithiumClasses() {
+ public function testCanMockNonLithiumClasses() {
$mockee = 'stdClass\Mock';
Mocker::create($mockee);
- $this->assertTrue(!class_exists($mockee));
+ $this->assertTrue(class_exists($mockee));
+ }
+
+ public function testNonLithiumInstanceClass() {
+ $std = new \lithium\tests\mocks\test\mockNonLi3StdClass\Mock;
+
+ $this->assertInternalType('bool', $std->method1());
+
+ $std->applyFilter('method1', function($self, $params, $chain) {
+ return array();
+ });
+
+ $this->assertInternalType('array', $std->method1());
+ }
+
+ public function testNonLithiumStaticClass() {
+ $class = 'lithium\analysis\debugger\Mock';
+ $var = array('foo', 'bar', 'baz');
+
+ $this->assertInternalType('string', $class::export($var));
+
+ $class::applyFilter('export', function($self, $params, $chain) {
+ return array();
+ });
+
+ $this->assertInternalType('array', $class::export($var));
}
public function testCannotCreateNonStandardMockClass() {
@@ -144,19 +169,19 @@ public function testStaticResults() {
$docblock::applyFilter(array('comment', 'tags'), function($self, $params, $chain) {
return false;
});
- $docblock::comment('foo', 'foobar');
+ $docblock::comment('foobar');
$docblock::comment('bar');
- $docblock::tags('baz');
+ $docblock::tags('baz', 'foo');
- $this->assertIdentical(2, count($docblock::$results['comment']));
- $this->assertIdentical(array('foo', 'foobar'), $docblock::$results['comment'][0]['args']);
- $this->assertIdentical(false, $docblock::$results['comment'][0]['result']);
- $this->assertIdentical(array('bar'), $docblock::$results['comment'][1]['args']);
- $this->assertIdentical(false, $docblock::$results['comment'][1]['result']);
+ $this->assertIdentical(2, count($docblock::$staticResults['comment']));
+ $this->assertIdentical(array('foobar'), $docblock::$staticResults['comment'][0]['args']);
+ $this->assertIdentical(false, $docblock::$staticResults['comment'][0]['result']);
+ $this->assertIdentical(array('bar'), $docblock::$staticResults['comment'][1]['args']);
+ $this->assertIdentical(false, $docblock::$staticResults['comment'][1]['result']);
- $this->assertIdentical(1, count($docblock::$results['tags']));
- $this->assertIdentical(array('baz'), $docblock::$results['tags'][0]['args']);
- $this->assertIdentical(false, $docblock::$results['tags'][0]['result']);
+ $this->assertIdentical(1, count($docblock::$staticResults['tags']));
+ $this->assertIdentical(array('baz', 'foo'), $docblock::$staticResults['tags'][0]['args']);
+ $this->assertIdentical(false, $docblock::$staticResults['tags'][0]['result']);
}
public function testInstanceResults() {
@@ -202,6 +227,119 @@ public function testChainReturnsMockerChain() {
$this->assertTrue(Mocker::chain(new \stdClass) instanceof \lithium\test\MockerChain);
}
+ public function testMergeWithEmptyArray() {
+ $results = array();
+ $staticResults = array(
+ 'method1' => array(
+ array(
+ 'args' => array(),
+ 'results' => true,
+ 'time' => 100,
+ ),
+ ),
+ );
+
+ $this->assertEqual($staticResults, Mocker::mergeResults($results, $staticResults));
+ $this->assertEqual($staticResults, Mocker::mergeResults($staticResults, $results));
+ }
+
+ public function testMultipleResultsSimple() {
+ $results = array(
+ 'method1' => array(
+ array(
+ 'args' => array(),
+ 'results' => true,
+ 'time' => 100,
+ ),
+ ),
+ );
+ $staticResults = array(
+ 'method1' => array(
+ array(
+ 'args' => array(),
+ 'results' => true,
+ 'time' => 0,
+ ),
+ ),
+ );
+ $expected = array(
+ 'method1' => array(
+ array(
+ 'args' => array(),
+ 'results' => true,
+ 'time' => 0,
+ ),
+ array(
+ 'args' => array(),
+ 'results' => true,
+ 'time' => 100,
+ ),
+ ),
+ );
+ $this->assertEqual($expected, Mocker::mergeResults($results, $staticResults));
+ }
+
+ public function testMultipleResultsComplex() {
+ $results = array(
+ 'method1' => array(
+ array(
+ 'args' => array(),
+ 'results' => true,
+ 'time' => 100,
+ ),
+ ),
+ 'method2' => array(
+ array(
+ 'args' => array(),
+ 'results' => true,
+ 'time' => 100,
+ ),
+ ),
+ );
+ $staticResults = array(
+ 'method1' => array(
+ array(
+ 'args' => array(),
+ 'results' => true,
+ 'time' => 0,
+ ),
+ array(
+ 'args' => array(),
+ 'results' => true,
+ 'time' => 200,
+ ),
+ ),
+ );
+ $expected = array(
+ 'method1' => array(
+ array(
+ 'args' => array(),
+ 'results' => true,
+ 'time' => 0,
+ ),
+ array(
+ 'args' => array(),
+ 'results' => true,
+ 'time' => 100,
+ ),
+ array(
+ 'args' => array(),
+ 'results' => true,
+ 'time' => 200,
+ ),
+ ),
+ 'method2' => array(
+ array(
+ 'args' => array(),
+ 'results' => true,
+ 'time' => 100,
+ ),
+ ),
+ );
+
+ $this->assertEqual($expected, Mocker::mergeResults($results, $staticResults));
+ }
+
}
?>
View
17 tests/mocks/test/MockNonLi3StdClass.php
@@ -0,0 +1,17 @@
+<?php
+
+namespace lithium\tests\mocks\test;
+
+class MockNonLi3StdClass {
+
+ public function method1() {
+ return true;
+ }
+
+ public function method2() {
+ return false;
+ }
+
+}
+
+?>
View
17 tests/mocks/test/MockStdStaticClass.php
@@ -0,0 +1,17 @@
+<?php
+
+namespace lithium\tests\mocks\test;
+
+class MockStdStaticClass {
+
+ public static function method1() {
+ return true;
+ }
+
+ public static function method2() {
+ return false;
+ }
+
+}
+
+?>
Something went wrong with that request. Please try again.