diff --git a/.gitignore b/.gitignore index 4744d2960..9e947c64d 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,5 @@ pearfarm.spec *.sublime-project library/Hamcrest/* +composer.lock +vendor/ diff --git a/library/Mockery/Generator.php b/library/Mockery/Generator.php index 099eb28a0..18e29b0e4 100644 --- a/library/Mockery/Generator.php +++ b/library/Mockery/Generator.php @@ -311,6 +311,8 @@ public static function _getStandardMethods($callTypehint = true, $makeInstanceMo protected \$_mockery_ignoreMissing = false; + protected \$_mockery_deferMissing = false; + protected \$_mockery_verified = false; protected \$_mockery_name = null; @@ -372,6 +374,12 @@ public function shouldReceive() return \$lastExpectation; } + public function shouldDeferMissing() + { + \$this->_mockery_deferMissing = true; + return \$this; + } + public function shouldIgnoreMissing() { \$this->_mockery_ignoreMissing = true; @@ -406,6 +414,8 @@ public function __call(\$method, $typehint \$args) return \$handler->call(\$args); } elseif (!is_null(\$this->_mockery_partial) && method_exists(\$this->_mockery_partial, \$method)) { return call_user_func_array(array(\$this->_mockery_partial, \$method), \$args); + } elseif (\$this->_mockery_deferMissing && is_callable("parent::\$method")) { + return call_user_func_array("parent::\$method", \$args); } elseif (\$this->_mockery_ignoreMissing) { \$return = new \Mockery\Undefined; return \$return; diff --git a/library/Mockery/Mock.php b/library/Mockery/Mock.php index d3389dcef..0dd944327 100644 --- a/library/Mockery/Mock.php +++ b/library/Mockery/Mock.php @@ -45,6 +45,14 @@ class Mock implements MockInterface */ protected $_mockery_ignoreMissing = false; + /** + * Flag to indicate whether we can defer method calls missing from our + * expectations + * + * @var bool + */ + protected $_mockery_deferMissing = false; + /** * Flag to indicate whether this mock was verified * @@ -169,6 +177,20 @@ public function shouldIgnoreMissing() return $this; } + /** + * Set mock to defer unexpected methods to it's parent + * + * This is particularly useless for this class, as it doesn't have a parent, + * but included for completeness + * + * @return Mock + */ + public function shouldDeferMissing() + { + $this->_mockery_deferMissing = true; + return $this; + } + /** * Accepts a closure which is executed with an object recorder which proxies * to the partial source object. The intent being to record the @@ -216,6 +238,8 @@ public function __call($method, array $args) return $handler->call($args); } elseif (!is_null($this->_mockery_partial) && method_exists($this->_mockery_partial, $method)) { return call_user_func_array(array($this->_mockery_partial, $method), $args); + } elseif ($this->_mockery_deferMissing && is_callable("parent::$method")) { + return call_user_func_array("parent::$method", $args); } elseif ($this->_mockery_ignoreMissing) { $return = new \Mockery\Undefined; return $return; diff --git a/library/Mockery/MockInterface.php b/library/Mockery/MockInterface.php index e33ca44c9..b3b2b6522 100644 --- a/library/Mockery/MockInterface.php +++ b/library/Mockery/MockInterface.php @@ -48,6 +48,13 @@ public function shouldReceive(); */ public function shouldIgnoreMissing(); + /** + * Set mock to defer unexpected methods to it's parent if possible + * + * @return Mock + */ + public function shouldDeferMissing(); + /** * In the event shouldReceive() accepting an array of methods/returns * this method will switch them from normal expectations to default diff --git a/tests/Mockery/ContainerTest.php b/tests/Mockery/ContainerTest.php index 9650625ec..c3d939a1e 100644 --- a/tests/Mockery/ContainerTest.php +++ b/tests/Mockery/ContainerTest.php @@ -95,6 +95,25 @@ public function testNamedMockWithConstructorArgsWithInternalCallToMockedMethod() $this->assertEquals(123, $m->bar()); } + public function testNamedMockWithShouldDeferMissing() + { + $m = $this->container->mock("MockeryTest_ClassConstructor2", array($param1 = new stdClass())); + $m->shouldDeferMissing(); + $this->assertEquals('foo', $m->bar()); + $m->shouldReceive("bar")->andReturn(123); + $this->assertEquals(123, $m->bar()); + } + + /** + * @expectedException BadMethodCallException + */ + public function testNamedMockWithShouldDeferMissingThrowsIfNotAvailable() + { + $m = $this->container->mock("MockeryTest_ClassConstructor2", array($param1 = new stdClass())); + $m->shouldDeferMissing(); + $m->foorbar123(); + } + public function testMockingAKnownConcreteClassSoMockInheritsClassType() { $m = $this->container->mock('stdClass');