Code Coverage |
||||||||||
Classes and Traits |
Functions and Methods |
Lines |
||||||||
Total | |
0.00% |
0 / 1 |
|
20.93% |
9 / 43 |
CRAP | |
30.73% |
63 / 205 |
Mockery | |
0.00% |
0 / 1 |
|
20.93% |
9 / 43 |
2843.24 | |
30.73% |
63 / 205 |
mock | |
100.00% |
1 / 1 |
1 | |
100.00% |
2 / 2 |
|||
spy | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 2 |
|||
instanceMock | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 2 |
|||
namedMock | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 6 |
|||
self | |
0.00% |
0 / 1 |
6 | |
0.00% |
0 / 3 |
|||
close | |
100.00% |
1 / 1 |
2 | |
100.00% |
5 / 5 |
|||
fetchMock | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 1 |
|||
getContainer | |
100.00% |
1 / 1 |
2 | |
100.00% |
4 / 4 |
|||
setGenerator | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 2 |
|||
getGenerator | |
100.00% |
1 / 1 |
2 | |
100.00% |
4 / 4 |
|||
getDefaultGenerator | |
100.00% |
1 / 1 |
1 | |
100.00% |
11 / 11 |
|||
setLoader | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 2 |
|||
getLoader | |
100.00% |
1 / 1 |
2 | |
100.00% |
4 / 4 |
|||
getDefaultLoader | |
100.00% |
1 / 1 |
1 | |
100.00% |
1 / 1 |
|||
setContainer | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 1 |
|||
resetContainer | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 2 |
|||
any | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 1 |
|||
type | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 1 |
|||
ducktype | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 1 |
|||
subset | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 1 |
|||
contains | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 1 |
|||
hasKey | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 1 |
|||
hasValue | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 1 |
|||
on | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 1 |
|||
mustBe | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 1 |
|||
not | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 1 |
|||
anyOf | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 1 |
|||
notAnyOf | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 1 |
|||
getConfiguration | |
100.00% |
1 / 1 |
2 | |
100.00% |
4 / 4 |
|||
formatArgs | |
0.00% |
0 / 1 |
12 | |
0.00% |
0 / 7 |
|||
formatArgument | |
0.00% |
0 / 1 |
156 | |
0.00% |
0 / 20 |
|||
formatObjects | |
0.00% |
0 / 1 |
30 | |
0.00% |
0 / 15 |
|||
objectToArray | |
0.00% |
0 / 1 |
6 | |
0.00% |
0 / 6 |
|||
extractInstancePublicProperties | |
0.00% |
0 / 1 |
6 | |
0.00% |
0 / 8 |
|||
extractGetters | |
0.00% |
0 / 1 |
42 | |
0.00% |
0 / 13 |
|||
cleanupNesting | |
0.00% |
0 / 1 |
12 | |
0.00% |
0 / 7 |
|||
cleanupArray | |
0.00% |
0 / 1 |
30 | |
0.00% |
0 / 10 |
|||
parseShouldReturnArgs | |
0.00% |
0 / 1 |
5.73 | |
69.23% |
9 / 13 |
|||
buildDemeterChain | |
0.00% |
0 / 1 |
13.12 | |
62.96% |
17 / 27 |
|||
anonymous function | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 2 |
|||
getNewDemeterMock | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 3 |
|||
getExistingDemeterMock | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 3 |
|||
noMoreElementsInChain | |
100.00% |
1 / 1 |
1 | |
100.00% |
1 / 1 |
<?php | |
/** | |
* Mockery | |
* | |
* LICENSE | |
* | |
* This source file is subject to the new BSD license that is bundled | |
* with this package in the file LICENSE.txt. | |
* It is also available through the world-wide-web at this URL: | |
* http://github.com/padraic/mockery/blob/master/LICENSE | |
* If you did not receive a copy of the license and are unable to | |
* obtain it through the world-wide-web, please send an email | |
* to padraic@php.net so we can send you a copy immediately. | |
* | |
* @category Mockery | |
* @package Mockery | |
* @copyright Copyright (c) 2010-2014 Pádraic Brady (http://blog.astrumfutura.com) | |
* @license http://github.com/padraic/mockery/blob/master/LICENSE New BSD License | |
*/ | |
use Mockery\ExpectationInterface; | |
use Mockery\Generator\CachingGenerator; | |
use Mockery\Generator\Generator; | |
use Mockery\Generator\MockConfigurationBuilder; | |
use Mockery\Generator\StringManipulationGenerator; | |
use Mockery\Generator\StringManipulation\Pass\CallTypeHintPass; | |
use Mockery\Generator\StringManipulation\Pass\ClassNamePass; | |
use Mockery\Generator\StringManipulation\Pass\ClassPass; | |
use Mockery\Generator\StringManipulation\Pass\InstanceMockPass; | |
use Mockery\Generator\StringManipulation\Pass\InterfacePass; | |
use Mockery\Generator\StringManipulation\Pass\MethodDefinitionPass; | |
use Mockery\Generator\StringManipulation\Pass\RemoveBuiltinMethodsThatAreFinalPass; | |
use Mockery\Generator\StringManipulation\Pass\RemoveUnserializeForInternalSerializableClassesPass; | |
use Mockery\Loader\EvalLoader; | |
use Mockery\Loader\Loader; | |
class Mockery | |
{ | |
const BLOCKS = 'Mockery_Forward_Blocks'; | |
/** | |
* Global container to hold all mocks for the current unit test running. | |
* | |
* @var \Mockery\Container | |
*/ | |
protected static $_container = null; | |
/** | |
* Global configuration handler containing configuration options. | |
* | |
* @var \Mockery\Configuration | |
*/ | |
protected static $_config = null; | |
/** | |
* @var \Mockery\Generator\Generator | |
*/ | |
protected static $_generator; | |
/** | |
* @var \Mockery\Loader\Loader | |
*/ | |
protected static $_loader; | |
/** | |
* Static shortcut to \Mockery\Container::mock(). | |
* | |
* @return \Mockery\MockInterface | |
*/ | |
public static function mock() | |
{ | |
$args = func_get_args(); | |
return call_user_func_array(array(self::getContainer(), 'mock'), $args); | |
} | |
/** | |
* @return \Mockery\MockInterface | |
*/ | |
public static function spy() | |
{ | |
$args = func_get_args(); | |
return call_user_func_array(array(self::getContainer(), 'mock'), $args)->shouldIgnoreMissing(); | |
} | |
/** | |
* @return \Mockery\MockInterface | |
*/ | |
public static function instanceMock() | |
{ | |
$args = func_get_args(); | |
return call_user_func_array(array(self::getContainer(), 'mock'), $args); | |
} | |
/** | |
* Static shortcut to \Mockery\Container::mock(), first argument names the mock. | |
* | |
* @return \Mockery\MockInterface | |
*/ | |
public static function namedMock() | |
{ | |
$args = func_get_args(); | |
$name = array_shift($args); | |
$builder = new MockConfigurationBuilder(); | |
$builder->setName($name); | |
array_unshift($args, $builder); | |
return call_user_func_array(array(self::getContainer(), 'mock'), $args); | |
} | |
/** | |
* Static shortcut to \Mockery\Container::self(). | |
* | |
* @throws LogicException | |
* | |
* @return \Mockery\MockInterface | |
*/ | |
public static function self() | |
{ | |
if (is_null(self::$_container)) { | |
throw new \LogicException('You have not declared any mocks yet'); | |
} | |
return self::$_container->self(); | |
} | |
/** | |
* Static shortcut to closing up and verifying all mocks in the global | |
* container, and resetting the container static variable to null. | |
* | |
* @return void | |
*/ | |
public static function close() | |
{ | |
if (is_null(self::$_container)) return; | |
self::$_container->mockery_teardown(); | |
self::$_container->mockery_close(); | |
self::$_container = null; | |
} | |
/** | |
* Static fetching of a mock associated with a name or explicit class poser. | |
* | |
* @param $name | |
* | |
* @return \Mockery\Mock | |
*/ | |
public static function fetchMock($name) | |
{ | |
return self::$_container->fetchMock($name); | |
} | |
/** | |
* Get the container. | |
*/ | |
public static function getContainer() | |
{ | |
if (is_null(self::$_container)) { | |
self::$_container = new Mockery\Container(self::getGenerator(), self::getLoader()); | |
} | |
return self::$_container; | |
} | |
/** | |
* @param \Mockery\Generator\Generator $generator | |
*/ | |
public static function setGenerator(Generator $generator) | |
{ | |
self::$_generator = $generator; | |
} | |
public static function getGenerator() | |
{ | |
if (is_null(self::$_generator)) { | |
self::$_generator = self::getDefaultGenerator(); | |
} | |
return self::$_generator; | |
} | |
public static function getDefaultGenerator() | |
{ | |
$generator = new StringManipulationGenerator(array( | |
new CallTypeHintPass(), | |
new ClassPass(), | |
new ClassNamePass(), | |
new InstanceMockPass(), | |
new InterfacePass(), | |
new MethodDefinitionPass(), | |
new RemoveUnserializeForInternalSerializableClassesPass(), | |
new RemoveBuiltinMethodsThatAreFinalPass(), | |
)); | |
return new CachingGenerator($generator); | |
} | |
/** | |
* @param Loader $loader | |
*/ | |
public static function setLoader(Loader $loader) | |
{ | |
self::$_loader = $loader; | |
} | |
/** | |
* @return Loader | |
*/ | |
public static function getLoader() | |
{ | |
if (is_null(self::$_loader)) { | |
self::$_loader = self::getDefaultLoader(); | |
} | |
return self::$_loader; | |
} | |
/** | |
* @return EvalLoader | |
*/ | |
public static function getDefaultLoader() | |
{ | |
return new EvalLoader(); | |
} | |
/** | |
* Set the container. | |
* | |
* @param \Mockery\Container $container | |
* | |
* @return \Mockery\Container | |
*/ | |
public static function setContainer(Mockery\Container $container) | |
{ | |
return self::$_container = $container; | |
} | |
/** | |
* Reset the container to null. | |
*/ | |
public static function resetContainer() | |
{ | |
self::$_container = null; | |
} | |
/** | |
* Return instance of ANY matcher. | |
* | |
* @return \Mockery\Matcher\Any | |
*/ | |
public static function any() | |
{ | |
return new \Mockery\Matcher\Any(); | |
} | |
/** | |
* Return instance of TYPE matcher. | |
* | |
* @param $expected | |
* | |
* @return \Mockery\Matcher\Type | |
*/ | |
public static function type($expected) | |
{ | |
return new \Mockery\Matcher\Type($expected); | |
} | |
/** | |
* Return instance of DUCKTYPE matcher. | |
* | |
* @return \Mockery\Matcher\Ducktype | |
*/ | |
public static function ducktype() | |
{ | |
return new \Mockery\Matcher\Ducktype(func_get_args()); | |
} | |
/** | |
* Return instance of SUBSET matcher. | |
* | |
* @param array $part | |
* | |
* @return \Mockery\Matcher\Subset | |
*/ | |
public static function subset(array $part) | |
{ | |
return new \Mockery\Matcher\Subset($part); | |
} | |
/** | |
* Return instance of CONTAINS matcher. | |
* | |
* @return \Mockery\Matcher\Contains | |
*/ | |
public static function contains() | |
{ | |
return new \Mockery\Matcher\Contains(func_get_args()); | |
} | |
/** | |
* Return instance of HASKEY matcher. | |
* | |
* @param $key | |
* | |
* @return \Mockery\Matcher\HasKey | |
*/ | |
public static function hasKey($key) | |
{ | |
return new \Mockery\Matcher\HasKey($key); | |
} | |
/** | |
* Return instance of HASVALUE matcher. | |
* | |
* @param $val | |
* | |
* @return \Mockery\Matcher\HasValue | |
*/ | |
public static function hasValue($val) | |
{ | |
return new \Mockery\Matcher\HasValue($val); | |
} | |
/** | |
* Return instance of CLOSURE matcher. | |
* | |
* @param $closure | |
* | |
* @return \Mockery\Matcher\Closure | |
*/ | |
public static function on($closure) | |
{ | |
return new \Mockery\Matcher\Closure($closure); | |
} | |
/** | |
* Return instance of MUSTBE matcher. | |
* | |
* @param $expected | |
* | |
* @return \Mockery\Matcher\MustBe | |
*/ | |
public static function mustBe($expected) | |
{ | |
return new \Mockery\Matcher\MustBe($expected); | |
} | |
/** | |
* Return instance of NOT matcher. | |
* | |
* @param $expected | |
* | |
* @return \Mockery\Matcher\Not | |
*/ | |
public static function not($expected) | |
{ | |
return new \Mockery\Matcher\Not($expected); | |
} | |
/** | |
* Return instance of ANYOF matcher. | |
* | |
* @return \Mockery\Matcher\AnyOf | |
*/ | |
public static function anyOf() | |
{ | |
return new \Mockery\Matcher\AnyOf(func_get_args()); | |
} | |
/** | |
* Return instance of NOTANYOF matcher. | |
* | |
* @return \Mockery\Matcher\NotAnyOf | |
*/ | |
public static function notAnyOf() | |
{ | |
return new \Mockery\Matcher\NotAnyOf(func_get_args()); | |
} | |
/** | |
* Get the global configuration container. | |
*/ | |
public static function getConfiguration() | |
{ | |
if (is_null(self::$_config)) { | |
self::$_config = new \Mockery\Configuration(); | |
} | |
return self::$_config; | |
} | |
/** | |
* Utility method to format method name and arguments into a string. | |
* | |
* @param string $method | |
* @param array $arguments | |
* | |
* @return string | |
*/ | |
public static function formatArgs($method, array $arguments = null) | |
{ | |
if (is_null($arguments)) { | |
return $method . '()'; | |
} | |
$formattedArguments = array(); | |
foreach ($arguments as $argument) { | |
$formattedArguments[] = self::formatArgument($argument); | |
} | |
return $method . '(' . implode(', ', $formattedArguments) . ')'; | |
} | |
private static function formatArgument($argument, $depth = 0) | |
{ | |
if (is_object($argument)) { | |
return 'object(' . get_class($argument) . ')'; | |
} | |
if (is_int($argument) || is_float($argument)) { | |
return $argument; | |
} | |
if (is_array($argument)) { | |
if ($depth === 1) { | |
$argument = 'array(...)'; | |
} else { | |
$sample = array(); | |
foreach ($argument as $key => $value) { | |
$sample[$key] = self::formatArgument($value, $depth + 1); | |
} | |
$argument = preg_replace("{\s}", '', var_export($sample, true)); | |
} | |
return ((strlen($argument) > 1000) ? substr($argument, 0, 1000).'...)' : $argument); | |
} | |
if (is_bool($argument)) { | |
return $argument ? 'true' : 'false'; | |
} | |
if (is_resource($argument)) { | |
return 'resource(...)'; | |
} | |
$argument = (string) $argument; | |
return $depth === 0 ? '"' . $argument . '"' : $argument; | |
} | |
/** | |
* Utility function to format objects to printable arrays. | |
* | |
* @param array $objects | |
* | |
* @return string | |
*/ | |
public static function formatObjects(array $objects = null) | |
{ | |
static $formatting; | |
if ($formatting) { | |
return '[Recursion]'; | |
} | |
if (is_null($objects)) { | |
return ''; | |
} | |
$objects = array_filter($objects, 'is_object'); | |
if (empty($objects)) { | |
return ''; | |
} | |
$formatting = true; | |
$parts = array(); | |
foreach($objects as $object) { | |
$parts[get_class($object)] = self::objectToArray($object); | |
} | |
$formatting = false; | |
return 'Objects: ( ' . var_export($parts, true) . ')'; | |
} | |
/** | |
* Utility function to turn public properties and public get* and is* method values into an array. | |
* | |
* @param $object | |
* @param int $nesting | |
* | |
* @return array | |
*/ | |
private static function objectToArray($object, $nesting = 3) | |
{ | |
if ($nesting == 0) { | |
return array('...'); | |
} | |
return array( | |
'class' => get_class($object), | |
'properties' => self::extractInstancePublicProperties($object, $nesting), | |
'getters' => self::extractGetters($object, $nesting) | |
); | |
} | |
/** | |
* Returns all public instance properties. | |
* | |
* @param $object | |
* @param $nesting | |
* | |
* @return array | |
*/ | |
private static function extractInstancePublicProperties($object, $nesting) | |
{ | |
$reflection = new \ReflectionClass(get_class($object)); | |
$properties = $reflection->getProperties(\ReflectionProperty::IS_PUBLIC & ~ \ReflectionProperty::IS_STATIC); | |
$cleanedProperties = array(); | |
foreach ($properties as $publicProperty) { | |
$name = $publicProperty->getName(); | |
$cleanedProperties[$name] = self::cleanupNesting($object->$name, $nesting); | |
} | |
return $cleanedProperties; | |
} | |
/** | |
* Returns all object getters. | |
* | |
* @param $object | |
* @param $nesting | |
* | |
* @return array | |
*/ | |
private static function extractGetters($object, $nesting) | |
{ | |
$reflection = new \ReflectionClass(get_class($object)); | |
$publicMethods = $reflection->getMethods(\ReflectionProperty::IS_PUBLIC & ~ \ReflectionProperty::IS_STATIC); | |
$getters = array(); | |
foreach ($publicMethods as $publicMethod) { | |
$name = $publicMethod->getName(); | |
$numberOfParameters = $publicMethod->getNumberOfParameters(); | |
if ((substr($name, 0, 3) !== 'get' && substr($name, 0, 2) !== 'is') || $numberOfParameters != 0) { | |
continue; | |
} | |
try { | |
$getters[$name] = self::cleanupNesting($object->$name(), $nesting); | |
} catch(\Exception $e) { | |
$getters[$name] = '!! ' . get_class($e) . ': ' . $e->getMessage() . ' !!'; | |
} | |
} | |
return $getters; | |
} | |
private static function cleanupNesting($argument, $nesting) | |
{ | |
if (is_object($argument)) { | |
$object = self::objectToArray($argument, $nesting - 1); | |
$object['class'] = get_class($argument); | |
return $object; | |
} | |
if (is_array($argument)) { | |
return self::cleanupArray($argument, $nesting - 1); | |
} | |
return $argument; | |
} | |
private static function cleanupArray($argument, $nesting = 3) | |
{ | |
if ($nesting == 0) { | |
return '...'; | |
} | |
foreach ($argument as $key => $value) { | |
if (is_array($value)) { | |
$argument[$key] = self::cleanupArray($value, $nesting - 1); | |
} elseif (is_object($value)) { | |
$argument[$key] = self::objectToArray($value, $nesting - 1); | |
} | |
} | |
return $argument; | |
} | |
/** | |
* Utility function to parse shouldReceive() arguments and generate | |
* expectations from such as needed. | |
* | |
* @param Mockery\MockInterface $mock | |
* @param array $args | |
* @param callable $add | |
* @return \Mockery\CompositeExpectation | |
*/ | |
public static function parseShouldReturnArgs(\Mockery\MockInterface $mock, $args, $add) | |
{ | |
$composite = new \Mockery\CompositeExpectation(); | |
foreach ($args as $arg) { | |
if (is_array($arg)) { | |
foreach($arg as $k => $v) { | |
$expectation = self::buildDemeterChain($mock, $k, $add)->andReturn($v); | |
$composite->add($expectation); | |
} | |
} elseif (is_string($arg)) { | |
$expectation = self::buildDemeterChain($mock, $arg, $add); | |
$composite->add($expectation); | |
} | |
} | |
return $composite; | |
} | |
/** | |
* Sets up expectations on the members of the CompositeExpectation and | |
* builds up any demeter chain that was passed to shouldReceive. | |
* | |
* @param \Mockery\MockInterface $mock | |
* @param string $arg | |
* @param callable $add | |
* @throws Mockery\Exception | |
* @return \Mockery\ExpectationDirector | |
*/ | |
protected static function buildDemeterChain(\Mockery\MockInterface $mock, $arg, $add) | |
{ | |
/** @var Mockery\Container $container */ | |
$container = $mock->mockery_getContainer(); | |
$methodNames = explode('->', $arg); | |
reset($methodNames); | |
if (!\Mockery::getConfiguration()->mockingNonExistentMethodsAllowed() | |
&& !$mock->mockery_isAnonymous() | |
&& !in_array(current($methodNames), $mock->mockery_getMockableMethods()) | |
) { | |
throw new \Mockery\Exception( | |
'Mockery\'s configuration currently forbids mocking the method ' | |
. current($methodNames) . ' as it does not exist on the class or object ' | |
. 'being mocked' | |
); | |
} | |
/** @var ExpectationInterface|null $expectations */ | |
$expectations = null; | |
/** @var Callable $nextExp */ | |
$nextExp = function ($method) use ($add) { | |
return $add($method); | |
}; | |
while (true) { | |
$method = array_shift($methodNames); | |
$expectations = $mock->mockery_getExpectationsFor($method); | |
if (is_null($expectations) || self::noMoreElementsInChain($methodNames)) { | |
$expectations = $nextExp($method); | |
if (self::noMoreElementsInChain($methodNames)) { | |
break; | |
} | |
$mock = self::getNewDemeterMock($container, $method, $expectations); | |
} else { | |
$demeterMockKey = $container->getKeyOfDemeterMockFor($method); | |
if ($demeterMockKey) { | |
$mock = self::getExistingDemeterMock($container, $demeterMockKey); | |
} | |
} | |
$nextExp = function ($n) use ($mock) { | |
return $mock->shouldReceive($n); | |
}; | |
} | |
return $expectations; | |
} | |
/** | |
* @param \Mockery\Container $container | |
* @param string $method | |
* @param Mockery\ExpectationInterface $exp | |
* | |
* @return \Mockery\Mock | |
*/ | |
private static function getNewDemeterMock(Mockery\Container $container, | |
$method, | |
Mockery\ExpectationInterface $exp | |
) { | |
$mock = $container->mock('demeter_' . $method); | |
$exp->andReturn($mock); | |
return $mock; | |
} | |
/** | |
* @param \Mockery\Container $container | |
* @param string $demeterMockKey | |
* | |
* @return mixed | |
*/ | |
private static function getExistingDemeterMock(Mockery\Container $container, $demeterMockKey) | |
{ | |
$mocks = $container->getMocks(); | |
$mock = $mocks[$demeterMockKey]; | |
return $mock; | |
} | |
/** | |
* @param array $methodNames | |
* | |
* @return bool | |
*/ | |
private static function noMoreElementsInChain(array $methodNames) | |
{ | |
return empty($methodNames); | |
} | |
} |