From 76d044bfe84de8acf7127fbea699d7e1614c963b Mon Sep 17 00:00:00 2001 From: TavoNiievez Date: Sat, 30 Oct 2021 04:26:04 -0500 Subject: [PATCH 1/3] Update codebase to PHP 7.4 --- RoboFile.php | 1 + composer.json | 7 +- src/AspectMock/Core/Mocker.php | 80 +++++++++++------- src/AspectMock/Core/Registry.php | 59 +++++++------ .../Intercept/BeforeMockTransformer.php | 8 +- src/AspectMock/Intercept/FunctionInjector.php | 37 ++++++--- src/AspectMock/Intercept/MethodInvocation.php | 25 ++++-- src/AspectMock/Intercept/before_mock.php | 9 +- src/AspectMock/Kernel.php | 9 +- src/AspectMock/Proxy/Anything.php | 27 +++--- src/AspectMock/Proxy/AnythingClassProxy.php | 17 ++-- src/AspectMock/Proxy/ClassProxy.php | 71 +++++++--------- src/AspectMock/Proxy/FuncProxy.php | 64 ++++---------- src/AspectMock/Proxy/FuncVerifier.php | 14 ++-- src/AspectMock/Proxy/InstanceProxy.php | 32 +++---- src/AspectMock/Proxy/Verifier.php | 83 +++++++++---------- src/AspectMock/Test.php | 42 ++++------ src/AspectMock/Util/ArgumentsFormatter.php | 22 +++-- src/AspectMock/Util/Undefined.php | 4 +- tests/_bootstrap.php | 8 +- tests/unit/AccessDemoClassesTest.php | 9 +- tests/unit/ClassProxyTest.php | 5 +- tests/unit/FunctionInjectorTest.php | 21 ++--- tests/unit/MockFailedTest.php | 24 +++--- tests/unit/MockTest.php | 22 +++-- tests/unit/StubTest.php | 12 ++- tests/unit/VerifierTest.php | 14 ++-- tests/unit/testDoubleTest.php | 32 +++---- 28 files changed, 381 insertions(+), 377 deletions(-) diff --git a/RoboFile.php b/RoboFile.php index 4ac3dbe..e494dce 100644 --- a/RoboFile.php +++ b/RoboFile.php @@ -1,4 +1,5 @@ methodMap)) { - $invocation = new \AspectMock\Intercept\MethodInvocation(); + $invocation = new MethodInvocation(); $invocation->setThis($class); $invocation->setMethod($method); $invocation->setArguments($params); @@ -39,40 +46,42 @@ public function fakeMethodsAndRegisterCalls($class, $declaredClass, $method, $pa if (isset($this->objectMap[spl_object_hash($class)])) { Registry::registerInstanceCall($class, $method, $params); } + $class = get_class($class); } if (isset($this->classMap[$class])) { Registry::registerClassCall($class, $method, $params); } + if ($class != $declaredClass && isset($this->classMap[$declaredClass])) { Registry::registerClassCall($declaredClass, $method, $params); } - if ($invocation instanceof \AspectMock\Intercept\MethodInvocation) { + if ($invocation instanceof MethodInvocation) { $result = $this->invokeFakedMethods($invocation); } - + return $result; } public function fakeFunctionAndRegisterCalls($namespace, $function, $args) { $result = __AM_CONTINUE__; - $fullFuncName = "$namespace\\$function"; + $fullFuncName = sprintf('%s\%s', $namespace, $function); Registry::registerFunctionCall($fullFuncName, $args); if (isset($this->funcMap[$fullFuncName])) { $func = $this->funcMap[$fullFuncName]; - if (is_callable($func)) { - $result = call_user_func_array($func, $args); - } else { - $result = $func; - } + $result = is_callable($func) ? call_user_func_array($func, $args) : $func; } + return $result; } + /** + * @return mixed + */ protected function invokeFakedMethods(MethodInvocation $invocation) { $method = $invocation->getMethod(); @@ -155,6 +164,7 @@ protected function invokeFakedMethods(MethodInvocation $invocation) } } } + return __AM_CONTINUE__; } @@ -164,10 +174,12 @@ protected function getObjectMethodStubParams($obj, $method_name) if (!isset($this->objectMap[$oid])) { return false; } + $params = $this->objectMap[$oid]; if (!array_key_exists($method_name, $params)) { return false; } + return $params; } @@ -176,10 +188,12 @@ protected function getClassMethodStubParams($class_name, $method_name) if (!isset($this->classMap[$class_name])) { return false; } + $params = $this->classMap[$class_name]; if (!array_key_exists($method_name, $params)) { return false; } + return $params; } @@ -192,14 +206,15 @@ protected function stub(MethodInvocation $invocation, $params) $replacedMethod = $this->turnToClosure($replacedMethod); if ($invocation->isStatic()) { - $replacedMethod = \Closure::bind($replacedMethod, null, $invocation->getThis()); + $replacedMethod = Closure::bind($replacedMethod, null, $invocation->getThis()); } else { $replacedMethod = $replacedMethod->bindTo($invocation->getThis(), get_class($invocation->getThis())); } + return call_user_func_array($replacedMethod, $invocation->getArguments()); } - protected function stubMagicMethod(MethodInvocation $invocation, $params) + protected function stubMagicMethod(MethodInvocation $invocation, array $params) { $args = $invocation->getArguments(); $name = array_shift($args); @@ -208,56 +223,62 @@ protected function stubMagicMethod(MethodInvocation $invocation, $params) $replacedMethod = $this->turnToClosure($replacedMethod); if ($invocation->isStatic()) { - \Closure::bind($replacedMethod, null, $invocation->getThis()); + Closure::bind($replacedMethod, null, $invocation->getThis()); } else { $replacedMethod = $replacedMethod->bindTo($invocation->getThis(), get_class($invocation->getThis())); } + return call_user_func_array($replacedMethod, $args); } - protected function turnToClosure($returnValue) + protected function turnToClosure($returnValue): Closure { - if ($returnValue instanceof \Closure) { + if ($returnValue instanceof Closure) { return $returnValue; } - return function () use ($returnValue) { - return $returnValue; - }; + + return fn() => $returnValue; } - public function registerClass($class, $params = []) + public function registerClass(string $class, array $params = []): void { $class = ltrim($class, '\\'); if (isset($this->classMap[$class])) { $params = array_merge($this->classMap[$class], $params); } + $this->methodMap = array_merge($this->methodMap, array_keys($params)); $this->classMap[$class] = $params; } - public function registerObject($object, $params = []) + public function registerObject(object $object, array $params = []): void { $hash = spl_object_hash($object); if (isset($this->objectMap[$hash])) { $params = array_merge($this->objectMap[$hash], $params); } + $this->objectMap[$hash] = $params; $this->methodMap = array_merge($this->methodMap, array_keys($params)); } - public function registerFunc($namespace, $func, $body) + /** + * @param string|Closure $func + */ + public function registerFunc(string $namespace, $func, $body): void { $namespace = ltrim($namespace, '\\'); - if (!function_exists("$namespace\\$func")) { + if (!function_exists("{$namespace}\\{$func}")) { $injector = new FunctionInjector($namespace, $func); $injector->save(); $injector->inject(); } - $this->funcMap["$namespace\\$func"] = $body; + + $this->funcMap["{$namespace}\\{$func}"] = $body; } - public function clean($objectOrClass = null) + public function clean($objectOrClass = null): void { if (!$objectOrClass) { $this->classMap = []; @@ -270,5 +291,4 @@ public function clean($objectOrClass = null) unset($this->classMap[$objectOrClass]); } } - } diff --git a/src/AspectMock/Core/Registry.php b/src/AspectMock/Core/Registry.php index 933cf31..10de4a2 100644 --- a/src/AspectMock/Core/Registry.php +++ b/src/AspectMock/Core/Registry.php @@ -1,5 +1,9 @@ registerClass($name, $params); } - static function registerObject($object, $params = array()) + public static function registerObject($object, $params = array()): void { self::$mocker->registerObject($object, $params); } - static function registerFunc($namespace, $function, $resultOrClosure) + public static function registerFunc($namespace, $function, $resultOrClosure): void { self::$mocker->registerFunc($namespace, $function, $resultOrClosure); } - static function getClassCallsFor($class) + public static function getClassCallsFor($class) { $class = ltrim($class,'\\'); - return isset(self::$classCalls[$class]) - ? self::$classCalls[$class] - : []; + return self::$classCalls[$class] ?? []; } - static function getInstanceCallsFor($instance) + public static function getInstanceCallsFor($instance) { $oid = spl_object_hash($instance); - return isset(self::$instanceCalls[$oid]) - ? self::$instanceCalls[$oid] - : []; + return self::$instanceCalls[$oid] ?? []; } - static function getFuncCallsFor($func) + public static function getFuncCallsFor($func) { $func = ltrim($func,'\\'); - return isset(self::$funcCalls[$func]) ? self::$funcCalls[$func] : []; + return self::$funcCalls[$func] ?? []; } - static function clean($classOrInstance = null) + public static function clean($classOrInstance = null): void { $classOrInstance = self::getRealClassOrObject($classOrInstance); self::$mocker->clean($classOrInstance); @@ -73,14 +72,14 @@ static function clean($classOrInstance = null) } } - static function cleanInvocations() + public static function cleanInvocations(): void { self::$instanceCalls = []; self::$classCalls = []; self::$funcCalls = []; } - static function registerInstanceCall($instance, $method, $args = array()) + public static function registerInstanceCall($instance, $method, $args = array()): void { $oid = spl_object_hash($instance); if (!isset(self::$instanceCalls[$oid])) self::$instanceCalls[$oid] = []; @@ -91,7 +90,7 @@ static function registerInstanceCall($instance, $method, $args = array()) } - static function registerClassCall($class, $method, $args = array()) + public static function registerClassCall($class, $method, $args = array()): void { if (!isset(self::$classCalls[$class])) self::$classCalls[$class] = []; @@ -101,7 +100,7 @@ static function registerClassCall($class, $method, $args = array()) } - static function registerFunctionCall($functionName, $args) + public static function registerFunctionCall($functionName, $args): void { if (!isset(self::$funcCalls[$functionName])) self::$funcCalls[$functionName] = []; @@ -113,16 +112,14 @@ static function registerFunctionCall($functionName, $args) public static function getRealClassOrObject($classOrObject) { if ($classOrObject instanceof ClassProxy) return $classOrObject->className; + if ($classOrObject instanceof InstanceProxy) return $classOrObject->getObject(); + return $classOrObject; } - /** - * @param mixed $mocker - */ - public static function setMocker(Mocker $mocker) + public static function setMocker(Mocker $mocker): void { self::$mocker = $mocker; } - } diff --git a/src/AspectMock/Intercept/BeforeMockTransformer.php b/src/AspectMock/Intercept/BeforeMockTransformer.php index 95b09ce..1a73bc8 100644 --- a/src/AspectMock/Intercept/BeforeMockTransformer.php +++ b/src/AspectMock/Intercept/BeforeMockTransformer.php @@ -1,5 +1,9 @@ (.*)(\sor NULL)(.*)\s\]@', $text, $match)) { + if (preg_match('#Parameter\s\#\d+\s\[\s<(required|optional)>(.*)(\sor NULL)(.*)\s\]#', $text, $match)) { $text = $match[2].$match[4]; - } elseif (preg_match('@Parameter\s#[0-9]+\s\[\s<(required|optional)>\s(.*)\s\]@', $text, $match)) { + } elseif (preg_match('#Parameter\s\#\d+\s\[\s<(required|optional)>\s(.*)\s\]#', $text, $match)) { $text = $match[2]; } else { - throw new \Exception('reflection api changed. adjust code.'); + throw new Exception('reflection api changed. adjust code.'); } + if ($internal && $parameter->isOptional()) { $text .= "=NULL"; } + return $text; } - public function placeOptionalAndReferenceFunction($namespace, $function) + public function placeOptionalAndReferenceFunction($namespace, $function): void { - $reflect = new \ReflectionFunction($function); + $reflect = new ReflectionFunction($function); $parameters = []; $args = ''; $byRef = false; @@ -79,32 +88,36 @@ public function placeOptionalAndReferenceFunction($namespace, $function) if (!$optionals && $parameter->isOptional()) { $optionals = true; } + if ($parameter->isPassedByReference()) { $name = '&'.$name; $byRef = true; } + $names[] = $name; $parameters[$newname] = $declaration; } + if ($byRef) { $this->template = $this->templateByRefOptional; - $this->place('arguments', join(', ', $parameters)); + $this->place('arguments', implode(', ', $parameters)); $code = ''; - for ($i = count($parameters); $i > 0; $i--) { - $code .= " case {$i}: \$args = [" . join(', ', $names) . "]; break;\n"; + for ($i = count($parameters); $i > 0; --$i) { + $code .= sprintf(' case %d: $args = [', $i) . implode(', ', $names) . "]; break;\n"; array_pop($names); } + $this->place('code', $code); } } - public function save() + public function save(): void { $this->fileName = tempnam(sys_get_temp_dir(), $this->function); file_put_contents($this->fileName, $this->template); } - public function inject() + public function inject(): void { require_once $this->fileName; } @@ -119,8 +132,8 @@ public function getPHP() return $this->template; } - protected function place($var, $value) + protected function place($var, $value): void { - $this->template = str_replace("{{{$var}}}", $value, $this->template); + $this->template = str_replace(sprintf('{{%s}}', $var), $value, $this->template); } } diff --git a/src/AspectMock/Intercept/MethodInvocation.php b/src/AspectMock/Intercept/MethodInvocation.php index 93f65f3..c646f58 100644 --- a/src/AspectMock/Intercept/MethodInvocation.php +++ b/src/AspectMock/Intercept/MethodInvocation.php @@ -1,17 +1,27 @@ declaredClass = $declaredClass; } @@ -24,23 +34,20 @@ public function getDeclaredClass() return $this->declaredClass; } - /** * @param mixed $isStatic */ public function isStatic($isStatic = null) { if ($isStatic === null) return $this->isStatic; + $this->isStatic = $isStatic; } - - protected $class; - /** * @param mixed $class */ - public function setThis($class) + public function setThis($class): void { $this->class = $class; } @@ -56,7 +63,7 @@ public function getThis() /** * @param mixed $closure */ - public function setClosure($closure) + public function setClosure($closure): void { $this->closure = $closure; } @@ -72,7 +79,7 @@ public function getClosure() /** * @param mixed $method */ - public function setMethod($method) + public function setMethod($method): void { $this->method = $method; } @@ -88,7 +95,7 @@ public function getMethod() /** * @param mixed $params */ - public function setArguments($params) + public function setArguments($params): void { $this->arguments = $params; } diff --git a/src/AspectMock/Intercept/before_mock.php b/src/AspectMock/Intercept/before_mock.php index 5062b3b..15e767c 100644 --- a/src/AspectMock/Intercept/before_mock.php +++ b/src/AspectMock/Intercept/before_mock.php @@ -1,10 +1,15 @@ fakeMethodsAndRegisterCalls($class, $declaredClass, $method, $params, $static); + return Registry::$mocker->fakeMethodsAndRegisterCalls($class, $declaredClass, $method, $params, $static); } function __amock_before_func($namespace, $func, $params) { - $res = \AspectMock\Core\Registry::$mocker->fakeFunctionAndRegisterCalls($namespace, $func, $params); + $res = Registry::$mocker->fakeFunctionAndRegisterCalls($namespace, $func, $params); return $res; } diff --git a/src/AspectMock/Kernel.php b/src/AspectMock/Kernel.php index 7f831c0..85859c8 100644 --- a/src/AspectMock/Kernel.php +++ b/src/AspectMock/Kernel.php @@ -1,4 +1,7 @@ className; } - function __get($key) + function __get($key): Anything { return new Anything($this->className); } @@ -31,27 +37,27 @@ function __set($key, $val) { } - function __call($method, $args) + function __call($method, $args): Anything { return new Anything($this->className); } - public function offsetExists($offset) + public function offsetExists($offset): bool { return false; } - public function offsetGet($offset) + public function offsetGet($offset): Anything { return new Anything($this->className); } - public function offsetSet($offset, $value) + public function offsetSet($offset, $value): void { } - public function offsetUnset($offset) + public function offsetUnset($offset): void { } @@ -60,7 +66,7 @@ public function current() return null; } - public function next() + public function next(): void { } @@ -69,13 +75,12 @@ public function key() return null; } - public function valid() + public function valid(): bool { return false; } - public function rewind() + public function rewind(): void { } - } diff --git a/src/AspectMock/Proxy/AnythingClassProxy.php b/src/AspectMock/Proxy/AnythingClassProxy.php index dfad5f2..505810f 100644 --- a/src/AspectMock/Proxy/AnythingClassProxy.php +++ b/src/AspectMock/Proxy/AnythingClassProxy.php @@ -1,38 +1,41 @@ className = $class_name; - $this->reflected = new \ReflectionClass('AspectMock\Proxy\Anything'); + $this->reflected = new ReflectionClass(Anything::class); } - public function isDefined() + public function isDefined(): bool { return false; } - public function construct() + public function construct(): Anything { return new Anything($this->className); } - public function make() + public function make(): Anything { return new Anything($this->className); } - public function interfaces() + public function interfaces(): array { return array(); } - public function hasMethod($method) + public function hasMethod($method): bool { return false; } - } diff --git a/src/AspectMock/Proxy/ClassProxy.php b/src/AspectMock/Proxy/ClassProxy.php index eb859a7..3f1a594 100644 --- a/src/AspectMock/Proxy/ClassProxy.php +++ b/src/AspectMock/Proxy/ClassProxy.php @@ -1,6 +1,12 @@ save(); * $userModel->verifyInvoked('tableName'); * $userModel->verifyInvoked('save'); - * ?> * ``` * * You can get a class name of a proxy via `className` property. * - * ``` php + * ```php * className; // UserModel - * ?> * ``` * * Also, you can get the list of calls for a specific method. @@ -37,49 +41,39 @@ * $user = test::double('UserModel'); * $user->someMethod('arg1', 'arg2'); * $user->getCallsForMethod('someMethod') // [ ['arg1', 'arg2'] ] - * ?> * ``` */ -class ClassProxy extends Verifier { - - protected $reflected; - +class ClassProxy extends Verifier +{ + protected ReflectionClass $reflected; public function __construct($class_name) { $this->className = $class_name; - $this->reflected = new \ReflectionClass($class_name); - + $this->reflected = new ReflectionClass($class_name); } public function getCallsForMethod($method) { $calls = Registry::getClassCallsFor($this->className); - return isset($calls[$method]) - ? $calls[$method] - : []; + return $calls[$method] ?? []; } /** * Returns true if class exists. * Returns false if class is not defined yet, and was declared via `test::spec`. - * - * @return bool */ - public function isDefined() + public function isDefined(): bool { return true; } /** * Returns an array with all interface names of a class - * - * @return array */ - public function interfaces() + public function interfaces(): array { - $interfaces = $this->getRealClass()->getInterfaceNames(); - return $interfaces; + return $this->getRealClass()->getInterfaceNames(); } /** @@ -91,33 +85,30 @@ public function parent() { $parent = $this->getRealClass()->getParentClass(); if ($parent) return $parent->name; + return null; } /** - * @param $method - * @return bool + * @param mixed $method */ - public function hasMethod($method) + public function hasMethod($method): bool { return $this->getRealClass()->hasMethod($method); } /** - * @param $property - * @return bool + * @param mixed $property */ - public function hasProperty($property) + public function hasProperty($property): bool { return $this->getRealClass()->hasProperty($property); } /** * Returns array of all trait names of a class. - * - * @return array */ - public function traits() + public function traits(): array { return $this->getRealClass()->getTraitNames(); } @@ -127,24 +118,22 @@ private function getRealClass() if (in_array('Go\Aop\Proxy', $this->reflected->getInterfaceNames())) { return $this->reflected->getParentClass(); } + return $this->reflected; } /** * Creates an instance of a class via constructor. * - * ``` php + * ```php * construct([ * 'name' => 'davert', * 'email' => 'davert@mail.ua' * ]); - * - * ?> * ``` - * @return object */ - public function construct() + public function construct(): object { return $this->reflected->newInstanceArgs(func_get_args()); } @@ -152,22 +141,18 @@ public function construct() /** * Creates a class instance without calling a constructor. * - * ``` php + * ```php * make(); - * - * ?> * ``` - * @return object */ - public function make() + public function make(): object { return $this->reflected->newInstanceWithoutConstructor(); } public function __call($method, $args) { - throw new \Exception("Called {$this->className}->$method, but this is a proxy for a class definition.\nProbably you were trying to access an instance method.\nConstruct an instance from this class"); + throw new Exception("Called {$this->className}->{$method}, but this is a proxy for a class definition.\nProbably you were trying to access an instance method.\nConstruct an instance from this class"); } - } diff --git a/src/AspectMock/Proxy/FuncProxy.php b/src/AspectMock/Proxy/FuncProxy.php index 2d67d4f..835c147 100644 --- a/src/AspectMock/Proxy/FuncProxy.php +++ b/src/AspectMock/Proxy/FuncProxy.php @@ -1,4 +1,7 @@ verifyInvoked(['hello']); // true * $func->verifyInvokedMultipleTimes(2); * $func->verifyNeverInvoked(['bye']); - * * ``` - * */ class FuncProxy { - /** - * @var string - */ - protected $func; - - /** - * @var string - */ - protected $ns; + protected string $func; + + protected string $ns; - /** - * @var string - */ - protected $fullFuncName; + protected string $fullFuncName; - /** - * @var FuncVerifier - */ - protected $funcVerifier; + protected FuncVerifier $funcVerifier; - /** - * @param string - * @param string - */ - public function __construct($namespace, $func) + public function __construct(string $namespace, string $func) { $this->func = $func; $this->ns = $namespace; @@ -57,41 +42,29 @@ public function __construct($namespace, $func) $this->funcVerifier = new FuncVerifier($namespace); } - /** - * @param null|array $params - */ - public function verifyInvoked(array $params = null) + public function verifyInvoked(array $params = null): void { $this->funcVerifier->verifyInvoked($this->func, $params); } - /** - * @param null|array $params - */ - public function verifyInvokedOnce(array $params = null) + public function verifyInvokedOnce(array $params = null): void { $this->funcVerifier->verifyInvokedMultipleTimes($this->func, 1, $params); } - /** - * @param null|array $params - */ - public function verifyNeverInvoked(array $params = null) + public function verifyNeverInvoked(array $params = null): void { $this->funcVerifier->verifyNeverInvoked($this->func, $params); } - /** - * @param int $times - * @param null|array $params - */ - public function verifyInvokedMultipleTimes($times, array $params = null) + public function verifyInvokedMultipleTimes(int $times, array $params = null): void { $this->funcVerifier->verifyInvokedMultipleTimes($this->func, $times, $params); } /** * Executes mocked function with provided parameters. + * * @return mixed */ public function __invoke() @@ -99,13 +72,8 @@ public function __invoke() return call_user_func_array($this->ns .'\\'.$this->func, func_get_args()); } - /** - * @param string - * @return array - */ - public function getCallsForMethod($func) + public function getCallsForMethod(string $func): array { - $calls = Registry::getFuncCallsFor($this->ns . '\\' . $func); - return $calls; + return Registry::getFuncCallsFor($this->ns . '\\' . $func); } } diff --git a/src/AspectMock/Proxy/FuncVerifier.php b/src/AspectMock/Proxy/FuncVerifier.php index 7535375..f801226 100644 --- a/src/AspectMock/Proxy/FuncVerifier.php +++ b/src/AspectMock/Proxy/FuncVerifier.php @@ -1,4 +1,7 @@ ns = $namespace; } - protected function callSyntax($method) + protected function callSyntax($method): string { - return ""; + return ''; } public function getCallsForMethod($func) { - $calls = Registry::getFuncCallsFor($this->ns . '\\' . $func); - return $calls; + return Registry::getFuncCallsFor($this->ns . '\\' . $func); } - - -} \ No newline at end of file +} diff --git a/src/AspectMock/Proxy/InstanceProxy.php b/src/AspectMock/Proxy/InstanceProxy.php index 95acb0d..0b78f48 100644 --- a/src/AspectMock/Proxy/InstanceProxy.php +++ b/src/AspectMock/Proxy/InstanceProxy.php @@ -1,7 +1,11 @@ getObject(); // true * - * ?> * ``` * * Contains verification methods and `class` property that points to `ClassProxy`. @@ -29,7 +32,6 @@ * $this->assertEquals('davert', $user->getName()); // success * $user->verifyInvoked('getName'); // success * $this->assertInstanceOf('User', $user); // fail - * ?> * ``` * * A `class` property allows to verify method calls to any instance of this class. @@ -41,7 +43,6 @@ * $user->class->hasMethod('save'); * $user->setName('davert'); * $user->class->verifyInvoked('setName'); - * ?> * ``` * Also, you can get the list of calls for a specific method. * @@ -50,13 +51,10 @@ * $user = test::double(new UserModel); * $user->someMethod('arg1', 'arg2'); * $user->getCallsForMethod('someMethod') // [ ['arg1', 'arg2'] ] - * ?> * ``` - * */ - -class InstanceProxy extends Verifier { - +class InstanceProxy extends Verifier +{ protected $instance; public function __construct($object) @@ -65,9 +63,9 @@ public function __construct($object) $this->className = get_class($object); } - protected function callSyntax($method) + protected function callSyntax($method): string { - return "->"; + return '->'; } /** @@ -79,15 +77,12 @@ public function getObject() { return $this->instance; } - + public function getCallsForMethod($method) { $calls = Registry::getInstanceCallsFor($this->instance); - return isset($calls[$method]) - ? $calls[$method] - : []; + return $calls[$method] ?? []; } - // proxify calls to the methods public function __call($method, $args) @@ -96,7 +91,7 @@ public function __call($method, $args) { // Is the method expecting any argument passed by reference? $passed_args = array(); - $reflMethod = new \ReflectionMethod($this->instance, $method); + $reflMethod = new ReflectionMethod($this->instance, $method); $params = $reflMethod->getParameters(); for($i = 0; $i < count($params); $i++) @@ -139,5 +134,4 @@ public function __set($property, $value) { $this->instance->$property = $value; } - -} \ No newline at end of file +} diff --git a/src/AspectMock/Proxy/Verifier.php b/src/AspectMock/Proxy/Verifier.php index 4ae2757..06fa5a1 100644 --- a/src/AspectMock/Proxy/Verifier.php +++ b/src/AspectMock/Proxy/Verifier.php @@ -1,16 +1,17 @@ className,$method) ? '::' @@ -49,42 +52,32 @@ protected function onlyExpectedArguments($expectedParams, $passedArgs) * $user->verifyInvoked('save'); * $user->verifyInvoked('setName',['davert']); * - * ?> * ``` - * - * @param $name - * @param null $params - * @throws \PHPUnit\Framework\ExpectationFailedException - * @param array $params - * @throws fail */ - public function verifyInvoked($name, $params = null) + public function verifyInvoked(string $name, array $params = null) { $calls = $this->getCallsForMethod($name); $separator = $this->callSyntax($name); - if (empty($calls)) throw new fail(sprintf($this->invokedFail, $this->className.$separator.$name, '')); + if (empty($calls)) throw new ExpectationFailedException(sprintf($this->invokedFail, $this->className.$separator.$name, '')); if (is_array($params)) { foreach ($calls as $args) { if ($this->onlyExpectedArguments($params, $args) === $params) return; } + $params = ArgumentsFormatter::toString($params); $gotParams = ArgumentsFormatter::toString($calls[0]); - - throw new fail(sprintf($this->invokedFail, $this->className.$separator.$name."($params)", $this->className.$separator.$name."($gotParams)")); - } else if(is_callable($params)) { + throw new ExpectationFailedException(sprintf($this->invokedFail, $this->className.$separator.$name.sprintf('(%s)', $params), $this->className.$separator.$name.sprintf('(%s)', $gotParams))); + } elseif (is_callable($params)) { $params($calls); } } /** * Verifies that method was invoked only once. - * - * @param $name - * @param array $params */ - public function verifyInvokedOnce($name, $params = null) + public function verifyInvokedOnce(string $name, array $params = null): void { $this->verifyInvokedMultipleTimes($name, 1, $params); } @@ -97,40 +90,41 @@ public function verifyInvokedOnce($name, $params = null) * $user->verifyInvokedMultipleTimes('save',2); * $user->verifyInvokedMultipleTimes('dispatchEvent',3,['before_validate']); * $user->verifyInvokedMultipleTimes('dispatchEvent',4,['after_save']); - * ?> * ``` * - * @param $name - * @param $times - * @param array $params - * @throws \PHPUnit\Framework\ExpectationFailedException + * @throws ExpectationFailedException */ - public function verifyInvokedMultipleTimes($name, $times, $params = null) + public function verifyInvokedMultipleTimes(string $name, int $times, array $params = null) { if ($times == 0) return $this->verifyNeverInvoked($name, $params); $calls = $this->getCallsForMethod($name); $separator = $this->callSyntax($name); - if (empty($calls)) throw new fail(sprintf($this->notInvokedMultipleTimesFail, $this->className.$separator.$name, $times)); + if (empty($calls)) throw new ExpectationFailedException(sprintf($this->notInvokedMultipleTimesFail, $this->className.$separator.$name, $times)); + if (is_array($params)) { $equals = 0; foreach ($calls as $args) { if ($this->onlyExpectedArguments($params, $args) === $params) { - $equals++; + ++$equals; } } + if ($equals == $times) { Assert::assertTrue(true); return; } + $params = ArgumentsFormatter::toString($params); - throw new fail(sprintf($this->invokedMultipleTimesFail, $this->className.$separator.$name."($params)", $times, $equals)); - } else if(is_callable($params)) { + throw new ExpectationFailedException(sprintf($this->invokedMultipleTimesFail, $this->className.$separator.$name.sprintf('(%s)', $params), $times, $equals)); + } elseif (is_callable($params)) { $params($calls); } + $num_calls = count($calls); - if ($num_calls != $times) throw new fail(sprintf($this->invokedMultipleTimesFail, $this->className.$separator.$name, $times, $num_calls)); + if ($num_calls != $times) throw new ExpectationFailedException(sprintf($this->invokedMultipleTimesFail, $this->className.$separator.$name, $times, $num_calls)); + Assert::assertTrue(true); } @@ -145,14 +139,11 @@ public function verifyInvokedMultipleTimes($name, $times, $params = null) * $user->verifyNeverInvoked('setName',['davert']); // fail * $user->verifyNeverInvoked('setName',['bob']); // success * $user->verifyNeverInvoked('setName',[]); // success - * ?> * ``` * - * @param $name - * @param null $params - * @throws \PHPUnit\Framework\ExpectationFailedException + * @throws ExpectationFailedException */ - public function verifyNeverInvoked($name, $params = null) + public function verifyNeverInvoked(string $name, array $params = null) { $calls = $this->getCallsForMethod($name); $separator = $this->callSyntax($name); @@ -165,16 +156,18 @@ public function verifyNeverInvoked($name, $params = null) foreach ($calls as $args) { if ($this->onlyExpectedArguments($params, $args) === $params) { - throw new fail(sprintf($this->neverInvoked, $this->className)); + throw new ExpectationFailedException(sprintf($this->neverInvoked, $this->className)); } } + Assert::assertTrue(true); return; } - if (count($calls)) { - throw new fail(sprintf($this->neverInvoked, $this->className.$separator.$name)); + + if (count($calls) > 0) { + throw new ExpectationFailedException(sprintf($this->neverInvoked, $this->className.$separator.$name)); } + Assert::assertTrue(true); } - } diff --git a/src/AspectMock/Test.php b/src/AspectMock/Test.php index 1507786..6b22383 100644 --- a/src/AspectMock/Test.php +++ b/src/AspectMock/Test.php @@ -1,11 +1,15 @@ * ``` */ -class Test { - +class Test +{ /** * `test::double` registers class or object to track its calls. * In second argument you may pass values that mocked mathods should return. @@ -81,13 +84,12 @@ class Test { * $user = new User(['name' => 'davert']); * $user->save(); // false * - * ?> * ``` * * @api * @param string|object $classOrObject * @param array $params [ 'methodName' => 'returnValue' ] - * @throws \Exception + * @throws Exception * @return Verifier|Proxy\ClassProxy|Proxy\InstanceProxy */ public static function double($classOrObject, array $params = array()) @@ -95,7 +97,7 @@ public static function double($classOrObject, array $params = array()) $classOrObject = Registry::getRealClassOrObject($classOrObject); if (is_string($classOrObject)) { if (!class_exists($classOrObject)) { - throw new \Exception("Class $classOrObject not loaded.\nIf you want to test undefined class use 'test::spec' method"); + throw new Exception("Class $classOrObject not loaded.\nIf you want to test undefined class use 'test::spec' method"); } Core\Registry::registerClass($classOrObject, $params); @@ -117,7 +119,6 @@ public static function double($classOrObject, array $params = array()) * defined(); // false - * ?> * ``` * * You can create instances of undefined classes and play with them: @@ -128,7 +129,6 @@ public static function double($classOrObject, array $params = array()) * $user->setName('davert'); * $user->setNumPosts(count($user->getPosts())); * $this->assertEquals('davert', $user->getName()); // fail - * ?> * ``` * * The test will be executed normally and will fail at the first assertion. @@ -144,7 +144,6 @@ public static function double($classOrObject, array $params = array()) * foreach ($user->names as $name) { * $name->canBeIterated(); * } - * ?> * ``` * * None of those calls will trigger an error in your test. @@ -174,7 +173,6 @@ public static function spec($classOrObject, array $params = array()) * test::methods($user, ['getName']); * $user->setName('davert'); // not invoked * $user->getName(); // jon - * ?> * ``` * * You can create a dummy without a constructor with all methods disabled: @@ -183,25 +181,24 @@ public static function spec($classOrObject, array $params = array()) * make(); * test::methods($user, []); - * ?> * ``` * * @api * @param string|object $classOrObject * @param string[] $only * @return Verifier|Proxy\ClassProxy|Proxy\InstanceProxy - * @throws \Exception + * @throws Exception */ public static function methods($classOrObject, array $only = array()) { $classOrObject = Registry::getRealClassOrObject($classOrObject); if (is_object($classOrObject)) { - $reflected = new \ReflectionClass(get_class($classOrObject)); + $reflected = new ReflectionClass(get_class($classOrObject)); } else { - if (!class_exists($classOrObject)) throw new \Exception("Class $classOrObject not defined."); - $reflected = new \ReflectionClass($classOrObject); + if (!class_exists($classOrObject)) throw new Exception("Class $classOrObject not defined."); + $reflected = new ReflectionClass($classOrObject); } - $methods = $reflected->getMethods(\ReflectionMethod::IS_PUBLIC); + $methods = $reflected->getMethods(ReflectionMethod::IS_PUBLIC); $params = array(); foreach ($methods as $m) { if ($m->isConstructor()) continue; @@ -243,12 +240,10 @@ public static function methods($classOrObject, array $only = array()) * $func->verifyInvokedOnce(['Y']); * ``` * - * @param string $namespace - * @param string $functionName * @param mixed $body whatever a function might return or Callable substitute * @return Proxy\FuncProxy */ - public static function func($namespace, $functionName, $body) + public static function func(string $namespace, string $functionName, $body) { Core\Registry::registerFunc($namespace, $functionName, $body); return new Proxy\FuncProxy($namespace, $functionName); @@ -261,7 +256,6 @@ public static function func($namespace, $functionName, $body) * ``` php * * ``` * * Also you can clean registry only for the specific class or object. @@ -270,7 +264,6 @@ public static function func($namespace, $functionName, $body) * * ``` * * @api @@ -292,5 +285,4 @@ public static function cleanInvocations() { Core\Registry::cleanInvocations(); } - } diff --git a/src/AspectMock/Util/ArgumentsFormatter.php b/src/AspectMock/Util/ArgumentsFormatter.php index 1870bcf..c71ae34 100644 --- a/src/AspectMock/Util/ArgumentsFormatter.php +++ b/src/AspectMock/Util/ArgumentsFormatter.php @@ -1,22 +1,30 @@ add('AspectMock', __DIR__ . '/../src'); $loader->add('demo', __DIR__ . '/_data'); $loader->register(); -$kernel = \AspectMock\Kernel::getInstance(); +$kernel = Kernel::getInstance(); $kernel->init([ 'cacheDir' => __DIR__.'/_data/cache', 'includePaths' => [__DIR__.'/_data/demo'], 'interceptFunctions' => true -]); \ No newline at end of file +]); diff --git a/tests/unit/AccessDemoClassesTest.php b/tests/unit/AccessDemoClassesTest.php index e820234..438bbdc 100644 --- a/tests/unit/AccessDemoClassesTest.php +++ b/tests/unit/AccessDemoClassesTest.php @@ -1,9 +1,13 @@ create(['name' => 'davert']); } - -} \ No newline at end of file +} diff --git a/tests/unit/ClassProxyTest.php b/tests/unit/ClassProxyTest.php index 9769e1a..6c30c67 100644 --- a/tests/unit/ClassProxyTest.php +++ b/tests/unit/ClassProxyTest.php @@ -1,10 +1,12 @@ hasMethod('method1InTrait'))->true(); verify($class->hasMethod('methodInClass'))->true(); } - } diff --git a/tests/unit/FunctionInjectorTest.php b/tests/unit/FunctionInjectorTest.php index 6ea6368..2526ff5 100644 --- a/tests/unit/FunctionInjectorTest.php +++ b/tests/unit/FunctionInjectorTest.php @@ -1,26 +1,20 @@ equals(1); verify($match[0])->equals('1234'); } - } diff --git a/tests/unit/MockFailedTest.php b/tests/unit/MockFailedTest.php index 915461b..c35d528 100644 --- a/tests/unit/MockFailedTest.php +++ b/tests/unit/MockFailedTest.php @@ -1,35 +1,35 @@ expectException('PHPUnit\Framework\ExpectationFailedException'); - } - + } + protected function _tearDown() { double::clean(); } - protected function user() + protected function user(): InstanceProxy { $user = new UserModel(); double::registerObject($user); - $user = new InstanceProxy($user); - return $user; + return new InstanceProxy($user); } - protected function userProxy() + protected function userProxy(): ClassProxy { $userProxy = new ClassProxy('demo\UserModel'); double::registerClass('demo\UserModel'); @@ -41,7 +41,7 @@ public function testInstanceInvoked() $this->user()->verifyInvoked('setName'); } - public function testInstanceInvokedWothoutParams() + public function testInstanceInvokedWithoutParams() { $user = $this->user(); $user->setName('davert'); @@ -96,7 +96,6 @@ public function testClassMethodInvoked() $userProxy = $this->userProxy(); $user->setName(1111); $userProxy->verifyInvoked('setName',[2222]); - } public function testAnythingFail() @@ -106,5 +105,4 @@ public function testAnythingFail() $any->hello(); $anyProxy->verifyInvoked('hello'); } - } diff --git a/tests/unit/MockTest.php b/tests/unit/MockTest.php index 6224db5..506fb63 100644 --- a/tests/unit/MockTest.php +++ b/tests/unit/MockTest.php @@ -1,13 +1,16 @@ verifyNeverInvoked('save'); $user->verifyNeverInvoked('save',['params']); }); - } public function testVerifyClassMethods() @@ -80,7 +82,6 @@ public function testVerifyClassMethodCalled() $userProxy->verifyNeverInvoked('save'); $userProxy->verifyNeverInvoked('setName',['bob']); verify($user->getName())->equals('jon'); - } /** @@ -95,7 +96,6 @@ public function testVerifyClassMethodCalled() * } * * class B extends A {} - * ?> * * * Verification: @@ -114,23 +114,21 @@ public function testVerifyClassMethodCalled() * // Will pass * $parentProxy->verifyInvoked('super'); * $childProxy->verifyInvoked('super'); - * ?> * */ public function testVerifyClassInheritedMethodCalled() { $adminUser = new AdminUserModel(); - double::registerClass(\demo\UserModel::class); - double::registerClass(\demo\AdminUserModel::class); + double::registerClass(UserModel::class); + double::registerClass(AdminUserModel::class); - $userProxy = new ClassProxy(\demo\UserModel::class); - $adminUserProxy = new ClassProxy(\demo\AdminUserModel::class); + $userProxy = new ClassProxy(UserModel::class); + $adminUserProxy = new ClassProxy(AdminUserModel::class); $adminUser->getName(); $userProxy->verifyInvokedOnce('getName'); $adminUserProxy->verifyInvokedOnce('getName'); } - } \ No newline at end of file diff --git a/tests/unit/StubTest.php b/tests/unit/StubTest.php index 39cf8bf..d79f0e8 100644 --- a/tests/unit/StubTest.php +++ b/tests/unit/StubTest.php @@ -1,14 +1,19 @@ setName('David Bovie'); // $this->assertEquals('Done', $user->dump()); // } - -} \ No newline at end of file +} diff --git a/tests/unit/VerifierTest.php b/tests/unit/VerifierTest.php index d380e0e..17f10b8 100644 --- a/tests/unit/VerifierTest.php +++ b/tests/unit/VerifierTest.php @@ -1,13 +1,17 @@ verifyNeverInvoked('setName', "Bob Jones"); // If i dont fail, my test fail throw new fail('verifyNeverInvoked'); - } catch (\Exception $e) {} + } catch (Exception $e) {} $user->verifyNeverInvoked('setName', ["Boby Jones"]); @@ -106,7 +110,7 @@ public function testverifyWithMutliplesParams() $user->verifyNeverInvoked('setNameAndInfo', ["Bob Jones", "Infos"]); // If i dont fail, my test fail throw new fail('verifyNeverInvoked'); - } catch (\Exception $e) { + } catch (Exception $e) { } }); diff --git a/tests/unit/testDoubleTest.php b/tests/unit/testDoubleTest.php index 6465b3d..284e4ac 100644 --- a/tests/unit/testDoubleTest.php +++ b/tests/unit/testDoubleTest.php @@ -1,8 +1,14 @@ null]); (new demo\UserModel())->save(); $user->verifyInvoked('save'); - \demo\UserModel::tableName(); - \demo\UserModel::tableName(); + UserModel::tableName(); + UserModel::tableName(); $user->verifyInvokedMultipleTimes('tableName',2); $this->specify('disabling all methods', function() use ($user) { test::methods($user, []); - verify(\demo\UserModel::tableName())->null(); + verify(UserModel::tableName())->null(); }); } @@ -32,13 +38,13 @@ public function testDoubleFullyQualifiedClass() $user = test::double('\demo\UserModel', ['save' => null]); (new demo\UserModel())->save(); $user->verifyInvoked('save'); - \demo\UserModel::tableName(); - \demo\UserModel::tableName(); + UserModel::tableName(); + UserModel::tableName(); $user->verifyInvokedMultipleTimes('tableName',2); $this->specify('disabling all methods', function() use ($user) { test::methods($user, []); - verify(\demo\UserModel::tableName())->null(); + verify(UserModel::tableName())->null(); }); } @@ -56,8 +62,6 @@ public function testDoubleObject() verify($user->getName())->null(); verify($user->getObject()->getName())->null(); }); - - } public function testSpecUndefinedClass() @@ -113,7 +117,7 @@ public function testCleanupSpecificClasses() verify(demo\UserModel::tableName())->equals('my_table'); test::clean('demo\UserModel'); verify(demo\UserModel::tableName())->equals('users'); - verify($service->updateName(new \demo\UserModel()))->equals('hello'); + verify($service->updateName(new UserModel()))->equals('hello'); } public function testCleanupSpecificObj() @@ -133,7 +137,7 @@ public function testPhp7Features() if (PHP_MAJOR_VERSION < 7) { $this->markTestSkipped('PHP 7 only'); } - \AspectMock\Kernel::getInstance()->loadFile(codecept_data_dir() . 'php7.php'); + Kernel::getInstance()->loadFile(codecept_data_dir() . 'php7.php'); test::double(TestPhp7Class::class, [ 'stringSth' => true, 'floatSth' => true, @@ -148,7 +152,7 @@ public function testPhp7Features() 'intRth' => 12, 'callableRth' => function() { return function() {}; }, 'arrayRth' => [1], - 'exceptionRth' => new \Exception(), + 'exceptionRth' => new Exception(), ]); $obj = new TestPhp7Class; $this->assertTrue($obj->stringSth('123')); @@ -165,8 +169,6 @@ public function testPhp7Features() $this->assertEquals(12, $obj->intRth(15)); //$this->assertInternalType('callable', $obj->callableRth(function() {})); $this->assertEquals([1], $obj->arrayRth([])); - $this->assertInstanceOf('Exception', $obj->exceptionRth(new \Exception('ups'))); + $this->assertInstanceOf('Exception', $obj->exceptionRth(new Exception('ups'))); } - - } From 5f45fc6fc56b0fa3409f370d53411447a879ecda Mon Sep 17 00:00:00 2001 From: TavoNiievez Date: Sat, 30 Oct 2021 04:26:19 -0500 Subject: [PATCH 2/3] Update docs --- README.md | 33 ++++++------ docs/ClassProxy.md | 58 +++++----------------- docs/FuncProxy.md | 19 ++----- docs/InstanceProxy.md | 34 +++---------- docs/Test.md | 25 +++------- src/AspectMock/Proxy/Anything.php | 8 +-- src/AspectMock/Proxy/Verifier.php | 8 +-- src/AspectMock/Util/ArgumentsFormatter.php | 4 +- tests/unit/ClassProxyTest.php | 3 +- 9 files changed, 56 insertions(+), 136 deletions(-) diff --git a/README.md b/README.md index 92cf7bb..c89c99b 100644 --- a/README.md +++ b/README.md @@ -7,12 +7,10 @@ AspectMock allows you to stub and mock practically anything in your PHP code! **Documentation** | [Test Doubles Builder](https://github.com/Codeception/AspectMock/blob/master/docs/Test.md) | [ClassProxy](https://github.com/Codeception/AspectMock/blob/master/docs/ClassProxy.md) | [InstanceProxy](https://github.com/Codeception/AspectMock/blob/master/docs/InstanceProxy.md) | [FuncProxy](https://github.com/Codeception/AspectMock/blob/master/docs/FuncProxy.md) -[![Build Status](https://travis-ci.org/Codeception/AspectMock.png?branch=master)](https://travis-ci.org/Codeception/AspectMock) +[![Actions Status](https://github.com/Codeception/aspectMock/workflows/CI/badge.svg)](https://github.com/Codeception/aspectMock/actions) [![Latest Stable Version](https://poser.pugx.org/codeception/aspect-mock/v/stable.png)](https://packagist.org/packages/codeception/aspect-mock) [![Total Downloads](https://poser.pugx.org/codeception/aspect-mock/downloads)](https://packagist.org/packages/codeception/aspect-mock) [![Monthly Downloads](https://poser.pugx.org/codeception/aspect-mock/d/monthly)](https://packagist.org/packages/codeception/aspect-mock) -[![PHP 7 ready](http://php7ready.timesplinter.ch/Codeception/AspectMock/master/badge.svg)](https://packagist.org/packages/codeception/aspect-mock) - ## Motivation @@ -45,6 +43,7 @@ Let's redefine static methods and verify their calls at runtime. ``` php assertEquals('users', UserModel::tableName()); @@ -52,7 +51,6 @@ function testTableName() $this->assertEquals('my_users', UserModel::tableName()); $userModel->verifyInvoked('tableName'); } -?> ``` #### Allows replacement of class methods. @@ -61,6 +59,7 @@ Testing code developed with the **ActiveRecord** pattern. Does the use of the Ac ``` php save(); } } -?> ``` Without AspectMock you need to introduce `User` as an explicit dependency into class `UserService` to get it tested. @@ -79,6 +77,7 @@ Instead we will replace it with a dummy and verify that it gets called by `creat ``` php null]); @@ -87,13 +86,13 @@ function testUserCreate() $this->assertEquals('davert', $user->getName()); $user->verifyInvoked('save'); } -?> ``` #### Intercept even parent class methods and magic methods ``` php verifyInvoked('save'); $this->assertEquals('miles', $user->getName()); } -?> ``` #### Override even standard PHP functions ``` php assertEquals('now', time()); @@ -123,8 +122,9 @@ Only 4 methods are necessary for method call verification and one method to defi ``` php 'davert']); $this->assertEquals('davert', $user->getName()); $user->verifyInvoked('getName'); @@ -132,7 +132,6 @@ function testSimpleStubAndMock() $user->verifyNeverInvoked('setName'); $user->verifyInvokedMultipleTimes('setName',1); } -?> ``` To check that method `setName` was called with `davert` as argument. @@ -140,7 +139,6 @@ To check that method `setName` was called with `davert` as argument. ``` php verifyMethodInvoked('setName', ['davert']); -?> ``` ## Wow! But how does it work? @@ -149,7 +147,7 @@ No PECL extensions is required. The [Go! AOP](http://go.aopphp.com/) library doe ## Requirements -PHP >= 5.6 + [Go! AOP Requirements](https://github.com/goaop/framework#requirements) +PHP >= 7.4 [Go! AOP Requirements](https://github.com/goaop/framework#requirements) ## Installation @@ -177,6 +175,7 @@ Include `AspectMock\Kernel` class into your tests bootstrap file. ``` php init([ 'debug' => true, 'includePaths' => [__DIR__.'/../src'] ]); -?> ``` If your project uses Composer's autoloader, that's all you need to get started. @@ -195,6 +193,7 @@ If you use a custom autoloader (like in Yii/Yii2 frameworks), you should explici ``` php init([ 'includePaths' => [__DIR__.'/../src'] ]); $kernel->loadFile('YourAutoloader.php'); // path to your autoloader -?> ``` Load all autoloaders of your project this way, if you do not rely on Composer entirely. @@ -217,6 +215,7 @@ Explicitly load all required files before testing: ``` php init([ ]); require 'YourAutoloader.php'; $kernel->loadPhpFiles('/../common'); -?> ``` ### Customization @@ -244,6 +242,7 @@ Example: ``` php init([ 'appDir' => __DIR__ . '/../../', @@ -251,7 +250,6 @@ $kernel->init([ 'includePaths' => [__DIR__.'/../src'] 'excludePaths' => [__DIR__] // tests dir should be excluded ]); -?> ``` [More configs for different frameworks](https://github.com/Codeception/AspectMock/wiki/Example-configs). @@ -271,6 +269,7 @@ Clear the test doubles registry between tests. ``` php verifyInvokedMultipleTimes('tableName',2); } - -?> ``` ## Usage in Codeception. @@ -298,6 +295,7 @@ We recommend including a call to `test::clean()` from your `CodeHelper` class: ``` php ``` ## Improvements? diff --git a/docs/ClassProxy.md b/docs/ClassProxy.md index a7473e8..b99294b 100644 --- a/docs/ClassProxy.md +++ b/docs/ClassProxy.md @@ -10,7 +10,7 @@ ClassProxy represents a class of your project. * It can be used to check class definitions. -``` php +```php construct(); $user->save(); $userModel->verifyInvoked('tableName'); $userModel->verifyInvoked('save'); -?> ``` You can get a class name of a proxy via `className` property. -``` php +```php className; // UserModel -?> ``` Also, you can get the list of calls for a specific method. @@ -37,7 +35,6 @@ Also, you can get the list of calls for a specific method. $user = test::double('UserModel'); $user->someMethod('arg1', 'arg2'); $user->getCallsForMethod('someMethod') // [ ['arg1', 'arg2'] ] -?> ``` #### *public* getCallsForMethod($method) @@ -45,57 +42,43 @@ $user->getCallsForMethod('someMethod') // [ ['arg1', 'arg2'] ] Returns true if class exists. Returns false if class is not defined yet, and was declared via `test::spec`. - * return bool - #### *public* interfaces() Returns an array with all interface names of a class - * return array - #### *public* parent() Returns a name of the parent of a class. * return null #### *public* hasMethod($method) - * `param` $method - * return bool + * `param mixed` $method #### *public* hasProperty($property) - * `param` $property - * return bool + * `param mixed` $property #### *public* traits() Returns array of all trait names of a class. - * return array - #### *public* construct() Creates an instance of a class via constructor. -``` php +```php construct([ 'name' => 'davert', 'email' => 'davert@mail.ua' ]); - -?> ``` - * return object #### *public* make() Creates a class instance without calling a constructor. -``` php +```php make(); - -?> ``` - * return object -#### *public* verifyInvoked($name, $params = null) +#### *public* verifyInvoked($name, array $params = null) Verifies a method was invoked at least once. In second argument you can specify with which params method expected to be invoked; @@ -104,22 +87,12 @@ In second argument you can specify with which params method expected to be invok $user->verifyInvoked('save'); $user->verifyInvoked('setName',['davert']); -?> ``` - * `param` $name - * `param null` $params - * throws \PHPUnit_Framework_ExpectationFailedException - * `param array` $params - * throws fail - -#### *public* verifyInvokedOnce($name, $params = null) +#### *public* verifyInvokedOnce($name, array $params = null) Verifies that method was invoked only once. - * `param` $name - * `param array` $params - -#### *public* verifyInvokedMultipleTimes($name, $times, $params = null) +#### *public* verifyInvokedMultipleTimes($name, $times, array $params = null) Verifies that method was called exactly $times times. ``` php @@ -127,15 +100,11 @@ Verifies that method was called exactly $times times. $user->verifyInvokedMultipleTimes('save',2); $user->verifyInvokedMultipleTimes('dispatchEvent',3,['before_validate']); $user->verifyInvokedMultipleTimes('dispatchEvent',4,['after_save']); -?> ``` - * `param` $name - * `param` $times - * `param array` $params - * throws \PHPUnit_Framework_ExpectationFailedException + * throws ExpectationFailedException -#### *public* verifyNeverInvoked($name, $params = null) +#### *public* verifyNeverInvoked($name, array $params = null) Verifies that method was not called. In second argument with which arguments is not expected to be called. @@ -146,11 +115,8 @@ $user->verifyNeverInvoked('setName'); // fail $user->verifyNeverInvoked('setName',['davert']); // fail $user->verifyNeverInvoked('setName',['bob']); // success $user->verifyNeverInvoked('setName',[]); // success -?> ``` - * `param` $name - * `param null` $params - * throws \PHPUnit_Framework_ExpectationFailedException + * throws ExpectationFailedException diff --git a/docs/FuncProxy.md b/docs/FuncProxy.md index a9798e1..58e6659 100644 --- a/docs/FuncProxy.md +++ b/docs/FuncProxy.md @@ -18,22 +18,11 @@ $func->verifyInvoked(); // true $func->verifyInvoked(['hello']); // true $func->verifyInvokedMultipleTimes(2); $func->verifyNeverInvoked(['bye']); - ``` - -#### *public* verifyInvoked($params = null) - * `param null` $params - -#### *public* verifyInvokedOnce($params = null) - * `param null` $params - -#### *public* verifyNeverInvoked($params = null) - * `param null` $params - -#### *public* verifyInvokedMultipleTimes($times, $params = null) - * `param` $times - * `param null` $params - +#### *public* verifyInvoked(array $params = null) +#### *public* verifyInvokedOnce(array $params = null) +#### *public* verifyNeverInvoked(array $params = null) +#### *public* verifyInvokedMultipleTimes($times, array $params = null) #### *public* getCallsForMethod($func) diff --git a/docs/InstanceProxy.md b/docs/InstanceProxy.md index dd8868e..88d7e54 100644 --- a/docs/InstanceProxy.md +++ b/docs/InstanceProxy.md @@ -15,7 +15,6 @@ $user2 instanceof AspectMock\Proxy\InstanceProxy; // true $user1 === $user2->getObject(); // true -?> ``` Contains verification methods and `class` property that points to `ClassProxy`. @@ -28,7 +27,6 @@ $user = test::double(new User); $this->assertEquals('davert', $user->getName()); // success $user->verifyInvoked('getName'); // success $this->assertInstanceOf('User', $user); // fail -?> ``` A `class` property allows to verify method calls to any instance of this class. @@ -40,7 +38,6 @@ $user = test::double(new User); $user->class->hasMethod('save'); $user->setName('davert'); $user->class->verifyInvoked('setName'); -?> ``` Also, you can get the list of calls for a specific method. @@ -49,17 +46,15 @@ Also, you can get the list of calls for a specific method. $user = test::double(new UserModel); $user->someMethod('arg1', 'arg2'); $user->getCallsForMethod('someMethod') // [ ['arg1', 'arg2'] ] -?> ``` - #### *public* getObject() Returns a real object that is proxified. * return mixed #### *public* getCallsForMethod($method) -#### *public* verifyInvoked($name, $params = null) +#### *public* verifyInvoked($name, array $params = null) Verifies a method was invoked at least once. In second argument you can specify with which params method expected to be invoked; @@ -68,22 +63,12 @@ In second argument you can specify with which params method expected to be invok $user->verifyInvoked('save'); $user->verifyInvoked('setName',['davert']); -?> ``` - * `param` $name - * `param null` $params - * throws \PHPUnit_Framework_ExpectationFailedException - * `param array` $params - * throws fail - -#### *public* verifyInvokedOnce($name, $params = null) +#### *public* verifyInvokedOnce($name, array $params = null) Verifies that method was invoked only once. - * `param` $name - * `param array` $params - -#### *public* verifyInvokedMultipleTimes($name, $times, $params = null) +#### *public* verifyInvokedMultipleTimes($name, $times, array $params = null) Verifies that method was called exactly $times times. ``` php @@ -91,15 +76,11 @@ Verifies that method was called exactly $times times. $user->verifyInvokedMultipleTimes('save',2); $user->verifyInvokedMultipleTimes('dispatchEvent',3,['before_validate']); $user->verifyInvokedMultipleTimes('dispatchEvent',4,['after_save']); -?> ``` - * `param` $name - * `param` $times - * `param array` $params - * throws \PHPUnit_Framework_ExpectationFailedException + * throws ExpectationFailedException -#### *public* verifyNeverInvoked($name, $params = null) +#### *public* verifyNeverInvoked($name, array $params = null) Verifies that method was not called. In second argument with which arguments is not expected to be called. @@ -110,11 +91,8 @@ $user->verifyNeverInvoked('setName'); // fail $user->verifyNeverInvoked('setName',['davert']); // fail $user->verifyNeverInvoked('setName',['bob']); // success $user->verifyNeverInvoked('setName',[]); // success -?> ``` - * `param` $name - * `param null` $params - * throws \PHPUnit_Framework_ExpectationFailedException + * throws ExpectationFailedException diff --git a/docs/Test.md b/docs/Test.md index 9c71552..1b9a29c 100644 --- a/docs/Test.md +++ b/docs/Test.md @@ -13,12 +13,11 @@ This allows to redefine any method of object with your own, and adds mock verifi ``` php ``` #### *public static* double($classOrObject, array $params = Array ( ) ) `test::double` registers class or object to track its calls. -In second argument you may pass values that mocked methods should return. +In second argument you may pass values that mocked mathods should return. Returns either of [**ClassProxy**](https://github.com/Codeception/AspectMock/blob/master/docs/ClassProxy.md) (when a string was passed) or [**InstanceProxy**](https://github.com/Codeception/AspectMock/blob/master/docs/InstanceProxy.md) (when an object was passed). @@ -58,7 +57,7 @@ $user = new User; test::double($user, ['getName' => 'davert']); test::double($user, ['getEmail' => 'davert@mail.ua']); $user->getName(); // => 'davert' -$user->getEmail();// => 'davert@mail.ua' +$user->getEmail(); => 'davert@mail.ua' # create an instance of mocked class test::double('User')->construct(['name' => 'davert']); // via constructor @@ -74,14 +73,13 @@ test::double('ActiveRecord', ['save' => false]); $user = new User(['name' => 'davert']); $user->save(); // false -?> ``` * api * `param string|object` $classOrObject * `param array` $params [ 'methodName' => 'returnValue' ] - * throws \Exception - * return Verifier Usually Proxy\ClassProxy|Proxy\InstanceProxy + * throws Exception + * return Verifier|Proxy\ClassProxy|Proxy\InstanceProxy #### *public static* spec($classOrObject, array $params = Array ( ) ) If you follow TDD/BDD practices a test should be written before the class is defined. @@ -92,7 +90,6 @@ Instead you can use `test::spec` method that will create a proxy for an undefine defined(); // false -?> ``` You can create instances of undefined classes and play with them: @@ -103,7 +100,6 @@ $user = test::spec('User')->construct(); $user->setName('davert'); $user->setNumPosts(count($user->getPosts())); $this->assertEquals('davert', $user->getName()); // fail -?> ``` The test will be executed normally and will fail at the first assertion. @@ -119,7 +115,6 @@ $user->can['be used as array']; foreach ($user->names as $name) { $name->canBeIterated(); } -?> ``` None of those calls will trigger an error in your test. @@ -130,7 +125,7 @@ If class is already defined, `test::spec` will act as `test::double`. * api * `param string|object` $classOrObject * `param array` $params - * return Verifier Usually Proxy\ClassProxy|Proxy\InstanceProxy + * return Verifier|Proxy\ClassProxy|Proxy\InstanceProxy #### *public static* methods($classOrObject, array $only = Array ( ) ) Replaces all methods in a class with dummies, except those specified in the `$only` param. @@ -141,7 +136,6 @@ $user = new User(['name' => 'jon']); test::methods($user, ['getName']); $user->setName('davert'); // not invoked $user->getName(); // jon -?> ``` You can create a dummy without a constructor with all methods disabled: @@ -150,14 +144,13 @@ You can create a dummy without a constructor with all methods disabled: make(); test::methods($user, []); -?> ``` * api * `param string|object` $classOrObject * `param string[]` $only - * return Verifier Usually Proxy\ClassProxy|Proxy\InstanceProxy - * throws \Exception + * return Verifier|Proxy\ClassProxy|Proxy\InstanceProxy + * throws Exception #### *public static* func($namespace, $functionName, $body) Replaces function in provided namespace with user-defined function or value that function returns. @@ -190,8 +183,6 @@ $func->verifyInvoked(); $func->verifyInvokedOnce(['Y']); ``` - * `param string` $namespace - * `param string` $functionName * `param mixed` $body whatever a function might return or Callable substitute * return Proxy\FuncProxy @@ -202,7 +193,6 @@ Should be called between tests. ``` php ``` Also you can clean registry only for the specific class or object. @@ -211,7 +201,6 @@ Also you can clean registry only for the specific class or object. ``` * api diff --git a/src/AspectMock/Proxy/Anything.php b/src/AspectMock/Proxy/Anything.php index e2ba115..5fa53f9 100644 --- a/src/AspectMock/Proxy/Anything.php +++ b/src/AspectMock/Proxy/Anything.php @@ -23,21 +23,21 @@ public function __construct($className = null) $this->className = $className; } - function __toString() + public function __toString() { return "| Undefined | ".$this->className; } - function __get($key): Anything + public function __get($key): Anything { return new Anything($this->className); } - function __set($key, $val) + public function __set($key, $val) { } - function __call($method, $args): Anything + public function __call($method, $args): Anything { return new Anything($this->className); } diff --git a/src/AspectMock/Proxy/Verifier.php b/src/AspectMock/Proxy/Verifier.php index 06fa5a1..9bac5bb 100644 --- a/src/AspectMock/Proxy/Verifier.php +++ b/src/AspectMock/Proxy/Verifier.php @@ -54,7 +54,7 @@ protected function onlyExpectedArguments($expectedParams, $passedArgs) * * ``` */ - public function verifyInvoked(string $name, array $params = null) + public function verifyInvoked(string $name, $params = null) { $calls = $this->getCallsForMethod($name); $separator = $this->callSyntax($name); @@ -77,7 +77,7 @@ public function verifyInvoked(string $name, array $params = null) /** * Verifies that method was invoked only once. */ - public function verifyInvokedOnce(string $name, array $params = null): void + public function verifyInvokedOnce(string $name, $params = null): void { $this->verifyInvokedMultipleTimes($name, 1, $params); } @@ -94,7 +94,7 @@ public function verifyInvokedOnce(string $name, array $params = null): void * * @throws ExpectationFailedException */ - public function verifyInvokedMultipleTimes(string $name, int $times, array $params = null) + public function verifyInvokedMultipleTimes(string $name, int $times, $params = null) { if ($times == 0) return $this->verifyNeverInvoked($name, $params); @@ -143,7 +143,7 @@ public function verifyInvokedMultipleTimes(string $name, int $times, array $para * * @throws ExpectationFailedException */ - public function verifyNeverInvoked(string $name, array $params = null) + public function verifyNeverInvoked(string $name, $params = null) { $calls = $this->getCallsForMethod($name); $separator = $this->callSyntax($name); diff --git a/src/AspectMock/Util/ArgumentsFormatter.php b/src/AspectMock/Util/ArgumentsFormatter.php index c71ae34..4dfd3f3 100644 --- a/src/AspectMock/Util/ArgumentsFormatter.php +++ b/src/AspectMock/Util/ArgumentsFormatter.php @@ -6,9 +6,9 @@ use Closure; -class ArgumentsFormatter +final class ArgumentsFormatter { - static function toString($args): string + public static function toString($args): string { return implode(',',array_map('self::format', $args)); } diff --git a/tests/unit/ClassProxyTest.php b/tests/unit/ClassProxyTest.php index 6c30c67..e43b9f0 100644 --- a/tests/unit/ClassProxyTest.php +++ b/tests/unit/ClassProxyTest.php @@ -6,7 +6,8 @@ use AspectMock\Test as test; use Codeception\Specify; -final class ClassProxyTest extends \Codeception\TestCase\Test { +final class ClassProxyTest extends \Codeception\TestCase\Test +{ use Specify; From 323f0cf66c888d0bddf66da78e1b6a7f80bfe0f6 Mon Sep 17 00:00:00 2001 From: TavoNiievez Date: Sat, 30 Oct 2021 05:20:04 -0500 Subject: [PATCH 3/3] Fix review comments --- README.md | 5 +++-- tests/unit/testDoubleTest.php | 3 --- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index c89c99b..e4a8ef4 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ AspectMock allows you to stub and mock practically anything in your PHP code! **Documentation** | [Test Doubles Builder](https://github.com/Codeception/AspectMock/blob/master/docs/Test.md) | [ClassProxy](https://github.com/Codeception/AspectMock/blob/master/docs/ClassProxy.md) | [InstanceProxy](https://github.com/Codeception/AspectMock/blob/master/docs/InstanceProxy.md) | [FuncProxy](https://github.com/Codeception/AspectMock/blob/master/docs/FuncProxy.md) -[![Actions Status](https://github.com/Codeception/aspectMock/workflows/CI/badge.svg)](https://github.com/Codeception/aspectMock/actions) +[![Actions Status](https://github.com/Codeception/AspectMock/workflows/CI/badge.svg)](https://github.com/Codeception/AspectMock/actions) [![Latest Stable Version](https://poser.pugx.org/codeception/aspect-mock/v/stable.png)](https://packagist.org/packages/codeception/aspect-mock) [![Total Downloads](https://poser.pugx.org/codeception/aspect-mock/downloads)](https://packagist.org/packages/codeception/aspect-mock) [![Monthly Downloads](https://poser.pugx.org/codeception/aspect-mock/d/monthly)](https://packagist.org/packages/codeception/aspect-mock) @@ -147,7 +147,8 @@ No PECL extensions is required. The [Go! AOP](http://go.aopphp.com/) library doe ## Requirements -PHP >= 7.4 [Go! AOP Requirements](https://github.com/goaop/framework#requirements) +* `PHP 7.4`. +* `Go! AOP 3.0` ## Installation diff --git a/tests/unit/testDoubleTest.php b/tests/unit/testDoubleTest.php index 284e4ac..013cd1f 100644 --- a/tests/unit/testDoubleTest.php +++ b/tests/unit/testDoubleTest.php @@ -134,9 +134,6 @@ public function testCleanupSpecificObj() public function testPhp7Features() { - if (PHP_MAJOR_VERSION < 7) { - $this->markTestSkipped('PHP 7 only'); - } Kernel::getInstance()->loadFile(codecept_data_dir() . 'php7.php'); test::double(TestPhp7Class::class, [ 'stringSth' => true,