Skip to content

Commit

Permalink
Merge adbd764 into d141c5b
Browse files Browse the repository at this point in the history
  • Loading branch information
yeka committed Mar 4, 2015
2 parents d141c5b + adbd764 commit 33e5c98
Show file tree
Hide file tree
Showing 4 changed files with 98 additions and 3 deletions.
13 changes: 12 additions & 1 deletion library/Mockery.php
Expand Up @@ -83,6 +83,17 @@ public static function spy()
return call_user_func_array(array(self::getContainer(), 'mock'), $args)->shouldIgnoreMissing();
}

/**
* @return \Mockery\MockInterface
*/
public static function stub()
{
$args = func_get_args();
return call_user_func_array(array(self::getContainer(), 'mock'), $args)->shouldIgnoreMissing()
->disallowMockingNonExistentMethods()
;
}

/**
* @return \Mockery\MockInterface
*/
Expand Down Expand Up @@ -651,7 +662,7 @@ protected static function buildDemeterChain(\Mockery\MockInterface $mock, $arg,
$methodNames = explode('->', $arg);
reset($methodNames);

if (!\Mockery::getConfiguration()->mockingNonExistentMethodsAllowed()
if (!$mock->mockingNonExistentMethodsAllowed()
&& !$mock->mockery_isAnonymous()
&& !in_array(current($methodNames), $mock->mockery_getMockableMethods())
) {
Expand Down
44 changes: 42 additions & 2 deletions library/Mockery/Mock.php
Expand Up @@ -48,6 +48,13 @@ class Mock implements MockInterface
*/
protected $_mockery_deferMissing = false;

/**
* Local flag to indicate whether mocking non-existing methods allowed.
*
* @var bool
*/
protected $_mockery_allowMockingNotExistentMethod = null;

/**
* Flag to indicate whether this mock was verified
*
Expand Down Expand Up @@ -156,7 +163,13 @@ public function mockery_init(\Mockery\Container $container = null, $partialObjec
$this->_mockery_partial = $partialObject;
}

if (!\Mockery::getConfiguration()->mockingNonExistentMethodsAllowed()) {
$this->collectMockableMethods();
}

protected function collectMockableMethods()
{
$this->_mockery_mockableMethods = array();
if (!$this->mockingNonExistentMethodsAllowed()) {
foreach ($this->mockery_getMethods() as $method) {
if ($method->isPublic() && !$method->isStatic()) {
$this->_mockery_mockableMethods[] = $method->getName();
Expand Down Expand Up @@ -281,6 +294,33 @@ public function makePartial()
return $this->shouldDeferMissing();
}

/**
* Disable mocking non-existent methods
*
* @return Mock
*/
public function disallowMockingNonExistentMethods()
{
$this->_mockery_allowMockingNotExistentMethod = false;
$this->collectMockableMethods();
return $this;
}

/**
* Return flag indicating whether mocking non-existent methods allowed
*
* @return bool
*/
public function mockingNonExistentMethodsAllowed()
{
// When local flag isn't set, fallback to global configuration
$allowed = $this->_mockery_allowMockingNotExistentMethod;
if (null === $allowed) {
$allowed = \Mockery::getConfiguration()->mockingNonExistentMethodsAllowed();
}
return $allowed;
}

/**
* Accepts a closure which is executed with an object recorder which proxies
* to the partial source object. The intent being to record the
Expand Down Expand Up @@ -698,7 +738,7 @@ protected function _mockery_handleMethodCall($method, array $args)
// _mockery_ignoreMissing and break the API with an error.
return sprintf("%s#%s", __CLASS__, spl_object_hash($this));
} elseif ($this->_mockery_ignoreMissing) {
if (\Mockery::getConfiguration()->mockingNonExistentMethodsAllowed() || (method_exists($this->_mockery_partial, $method) || is_callable("parent::$method"))) {
if ($this->mockingNonExistentMethodsAllowed() || (method_exists($this->_mockery_partial, $method) || is_callable("parent::$method"))) {
if ($this->_mockery_defaultReturnValue instanceof \Mockery\Undefined) {
return call_user_func_array(array($this->_mockery_defaultReturnValue, $method), $args);
} else {
Expand Down
15 changes: 15 additions & 0 deletions library/Mockery/MockInterface.php
Expand Up @@ -80,6 +80,21 @@ public function shouldDeferMissing();
*/
public function makePartial();

/**
* Disable mocking non-existent methods
*
* @return Mock
*/
public function disallowMockingNonExistentMethods();

/**
* Return flag indicating whether mocking non-existent methods allowed
* Fallback to global configuration
*
* @return bool
*/
public function mockingNonExistentMethodsAllowed();

/**
* @param $method
* @param null $args
Expand Down
29 changes: 29 additions & 0 deletions tests/Mockery/MockTest.php
Expand Up @@ -135,6 +135,35 @@ public function testShouldIgnoreMissingCallingNonExistentMethods()
assertThat($mock->bar(), equalTo('bar'));
assertThat($mock->nonExistentMethod(), equalTo('result'));
}

public function testShouldIgnoreMissingAllowMockingExistentMethods()
{
$mock = $this->container->mock('ClassWithMethods')->shouldIgnoreMissing()->disallowMockingNonExistentMethods();
assertThat(nullValue($mock->foo()));
$mock->shouldReceive('foo')->andReturn('new_foo');
assertThat($mock->foo(), equalTo('new_foo'));
$mock->shouldReceive('bar')->passthru();
assertThat($mock->bar(), equalTo('bar'));
}

/**
* @expectedException Mockery\Exception
*/
public function testShouldIgnoreMissingDisallowMockingNonExistentMethods()
{
$mock = $this->container->mock('ClassWithMethods')->shouldIgnoreMissing()->disallowMockingNonExistentMethods();
$mock->shouldReceive('nonExistentMethod');
}

/**
* @expectedException \BadMethodCallException
*/
public function testShouldIgnoreMissingDisallowCallingNonExistentMethods()
{
Mockery::getConfiguration()->allowMockingNonExistentMethods(true);
$mock = $this->container->mock('ClassWithNoToString')->shouldIgnoreMissing()->disallowMockingNonExistentMethods();
$mock->nonExistentMethod();
}
}


Expand Down

0 comments on commit 33e5c98

Please sign in to comment.