From 0f5c096e201bded84acc08ded405ca8f96b60859 Mon Sep 17 00:00:00 2001 From: Angelo Giuffredi Date: Wed, 28 Jun 2017 14:17:07 +0200 Subject: [PATCH 01/46] require doctrine/instantiator --- composer.json | 6 +- src/Moka/Generator/ProxyArgumentGenerator.php | 69 ++++++++++++++ src/Moka/Generator/ProxyClassGenerator.php | 66 ++++++++++++++ src/Moka/Generator/ProxyMethodGenerator.php | 64 +++++++++++++ src/Moka/Generator/ProxyReturnGenerator.php | 32 +++++++ src/Moka/Generator/ProxyTrait.php | 40 ++++++++ tests/GeneratorTest.php | 91 +++++++++++++++++++ 7 files changed, 366 insertions(+), 2 deletions(-) create mode 100644 src/Moka/Generator/ProxyArgumentGenerator.php create mode 100644 src/Moka/Generator/ProxyClassGenerator.php create mode 100644 src/Moka/Generator/ProxyMethodGenerator.php create mode 100644 src/Moka/Generator/ProxyReturnGenerator.php create mode 100644 src/Moka/Generator/ProxyTrait.php create mode 100644 tests/GeneratorTest.php diff --git a/composer.json b/composer.json index 03b80ef..8935671 100644 --- a/composer.json +++ b/composer.json @@ -27,7 +27,8 @@ ], "autoload": { "psr-4": { - "Moka\\": "src/Moka/" + "Moka\\": "src/Moka/", + "Coffee\\": "src/Coffee/" }, "files": [ "src/Moka/Plugin/Mockery/MockeryPlugin.php", @@ -45,7 +46,8 @@ "php": ">=7.0", "phpcollection/phpcollection": "^0.5.0", "psr/container": "^1.0", - "phpunit/phpunit-mock-objects": "^3.4||^4.0" + "phpunit/phpunit-mock-objects": "^3.4||^4.0", + "doctrine/instantiator": "^1.0" }, "require-dev": { "friendsofphp/php-cs-fixer": "^2.3", diff --git a/src/Moka/Generator/ProxyArgumentGenerator.php b/src/Moka/Generator/ProxyArgumentGenerator.php new file mode 100644 index 0000000..82dbec0 --- /dev/null +++ b/src/Moka/Generator/ProxyArgumentGenerator.php @@ -0,0 +1,69 @@ +allowsNull(); + $defaultValue = null; + if ($allowsNull) { + $defaultValue = 'null'; + } else { + $defaultValue = var_export($parameter->getDefaultValue(), true); + } + + if ($defaultValue) { + $defaultValue = "= $defaultValue"; + } + } catch (\ReflectionException $exception) { + $defaultValue = ''; + } + + try { + $type = $parameter->getType(); + if ($type) { + $type = ' ' . $this->getType($type) . ' '; + } else { + $type = ''; + } + + $name = '$' . $parameter->getName(); + +// $canBePassByValue = $parameter->canBePassedByValue(); + $isPassedByReference = $parameter->isPassedByReference(); + $byReference = ''; + if ($isPassedByReference) { + $byReference = ' &'; + } + + $isVariadic = $parameter->isVariadic(); + if ($isVariadic) { + $type = '...'; + $byReference = ''; + $defaultValue = ''; + } + + + } catch (\ReflectionException $e) { + + } + + return sprintf( + '%s%s%s%s', + $type, + $byReference, + $name, + $defaultValue + ); + } + + protected function getType(\ReflectionType $type) + { + return (string)$type; + } +} diff --git a/src/Moka/Generator/ProxyClassGenerator.php b/src/Moka/Generator/ProxyClassGenerator.php new file mode 100644 index 0000000..21f7977 --- /dev/null +++ b/src/Moka/Generator/ProxyClassGenerator.php @@ -0,0 +1,66 @@ +instantiate("%s"); + '; + + private $methodGenerator; + + public function __construct() + { + $this->methodGenerator = new ProxyMethodGenerator(); + } + + public function generate($object): ProxyInterface + { + $objectFQCN = get_class($object); + $codeWillBeEvalueted = $this->generateCode($objectFQCN); + /** @var ProxyInterface|ProxyTrait $proxy */ + $proxy = eval($codeWillBeEvalueted); + $proxy->setObject($object); + + return $proxy; + } + + protected function generateCode(string $classWillBeEtended): string + { + + $reflection = new \ReflectionClass($classWillBeEtended); + $methods = $reflection->getMethods(); + $methodsArray = []; + foreach ($methods as $method) { + if ($method->getName() !== '__call') { + $methodsArray[] = $this->methodGenerator->generateMethodString($method); + } + } + + $className = 'Cofffee' . '_' . mt_rand(); + + return sprintf( + $this->template, + $className, + $classWillBeEtended, + ProxyInterface::class, + ProxyTrait::class, + implode(PHP_EOL, $methodsArray), + $className + ); + } +} diff --git a/src/Moka/Generator/ProxyMethodGenerator.php b/src/Moka/Generator/ProxyMethodGenerator.php new file mode 100644 index 0000000..460060e --- /dev/null +++ b/src/Moka/Generator/ProxyMethodGenerator.php @@ -0,0 +1,64 @@ +__call("%s", func_get_args()); + } + '; + + private $argumentGenerator; + private $returnGenerator; + + public function __construct() + { + $this->argumentGenerator = new ProxyArgumentGenerator(); + $this->returnGenerator = new ProxyReturnGenerator(); + } + + public function generateMethodString(\ReflectionMethod $method) + { + $static = $method->isStatic() ? 'static' : ''; + $originalReturnType = $method->getReturnType(); + + $returnType = !$originalReturnType ? '' : $this->returnGenerator->generateMethodReturnType($originalReturnType, $method); + + $parameters = $method->getParameters(); + $arguments = []; + if ($parameters) { + foreach ($method->getParameters() as $parameter) { + $arguments[] = $this->argumentGenerator->generateMethodParameter($parameter); + } + } + + $method->getReturnType(); + + $returnStatement = 'return '; + if (null !== $originalReturnType && $this->getType($originalReturnType) === 'void') { + $returnStatement = ''; + } + + + return sprintf( + $this->template, + $static, + $method->getName(), + implode(', ', $arguments), + $returnType, + $returnStatement, + $method->getName() + ); + } + + protected function getType(\ReflectionType $type) + { + return (string)$type; + } + +} diff --git a/src/Moka/Generator/ProxyReturnGenerator.php b/src/Moka/Generator/ProxyReturnGenerator.php new file mode 100644 index 0000000..1c2c6ca --- /dev/null +++ b/src/Moka/Generator/ProxyReturnGenerator.php @@ -0,0 +1,32 @@ +allowsNull()) { + $allowNull = '?'; + } + + $returnType = $this->getType($type); + if ($returnType === 'self') { + $returnType = $method->getDeclaringClass()->getName(); + } + + return sprintf( + ':%s%s', + $allowNull, + $returnType + ); + } + + public function getType(\ReflectionType $type) + { + return (string)$type; + } +} diff --git a/src/Moka/Generator/ProxyTrait.php b/src/Moka/Generator/ProxyTrait.php new file mode 100644 index 0000000..c64f03a --- /dev/null +++ b/src/Moka/Generator/ProxyTrait.php @@ -0,0 +1,40 @@ +serve() instanceof ObjectProphecy) { + return $this->serve()->reveal()->$name(...$arguments); + } + + return $this->serve()->$name(...$arguments); + } + + /** + * @param mixed $object + */ + public function setObject($object) + { + $this->object = $object; + } + + public function stub(array $methodsWithValues): ProxyInterface + { + + } + + public function serve() + { + return $this->object; + } +} diff --git a/tests/GeneratorTest.php b/tests/GeneratorTest.php new file mode 100644 index 0000000..2871527 --- /dev/null +++ b/tests/GeneratorTest.php @@ -0,0 +1,91 @@ +proxyGenerator = new ProxyClassGenerator(); + } + + public function testCreation() + { + /** @var ProxyInterface|FooTestClass $proxy */ + $proxy = $this->proxyGenerator->generate($this->getMockBuilder(FooTestClass::class)->getMock()); + + $this->assertInstanceOf(ProxyInterface::class, $proxy); + } + + public function testForwardPHPUnit() + { + $mock = $this->getMockBuilder(FooTestClass::class)->getMock(); + + $mock->expects($this->any()) + ->method('something') + ->willReturn(new \stdClass()); + + /** @var ProxyInterface|FooTestClass $proxy */ + $proxy = $this->proxyGenerator->generate($mock); + + $this->assertInstanceOf(\stdClass::class, $proxy->something()); + + $this->assertInstanceOf(ProxyInterface::class, $proxy); + + } + + public function testUseMockEngineMethod() + { + $mock = $this->getMockBuilder(FooTestClass::class)->getMock(); + + /** @var ProxyInterface|FooTestClass $proxy */ + $proxy = $this->proxyGenerator->generate($mock); + + $proxy->expects($this->any()) + ->method('something') + ->willReturn(new \stdClass()); + + $this->assertInstanceOf(\stdClass::class, $proxy->something()); + + $this->assertInstanceOf(ProxyInterface::class, $proxy); + } + + public function testForwardProphecy() + { + $mock = $this->prophesize(FooTestClass::class); +// $mock = $this->getMockBuilder(FooTestClass::class)->getMock(); + + $mock->something()->willReturn(new \stdClass()); + + /** @var ProxyInterface|FooTestClass $proxy */ + $proxy = $this->proxyGenerator->generate($mock); + + $this->assertInstanceOf(\stdClass::class, $proxy->something()); + + $this->assertInstanceOf(ProxyInterface::class, $proxy); + + } + +// public function testUseMockEngineMethodProphecy() +// { +// $mock = $this->prophesize(FooTestClass::class); +// /** @var ProxyInterface|FooTestClass $proxy */ +// $proxy = $this->proxyGenerator->generate($mock); +// +// $proxy->something()->willReturn(new \stdClass()); +// +// $this->assertInstanceOf(\stdClass::class, $proxy->something()); +// +// $this->assertInstanceOf(ProxyInterface::class, $proxy); +// } +} From 48247c261242a78d288724abac59ea6d76d6704b Mon Sep 17 00:00:00 2001 From: Angelo Giuffredi Date: Wed, 28 Jun 2017 14:17:21 +0200 Subject: [PATCH 02/46] implement first version of our ProxyGenerator --- src/Moka/Generator/ProxyArgumentGenerator.php | 2 +- src/Moka/Generator/ProxyClassGenerator.php | 3 +-- src/Moka/Generator/ProxyMethodGenerator.php | 2 +- src/Moka/Generator/ProxyReturnGenerator.php | 2 +- src/Moka/Generator/ProxyTrait.php | 2 +- tests/AbstractTestClass.php | 10 ++++++++++ tests/GeneratorTest.php | 6 +++--- 7 files changed, 18 insertions(+), 9 deletions(-) diff --git a/src/Moka/Generator/ProxyArgumentGenerator.php b/src/Moka/Generator/ProxyArgumentGenerator.php index 82dbec0..d22af43 100644 --- a/src/Moka/Generator/ProxyArgumentGenerator.php +++ b/src/Moka/Generator/ProxyArgumentGenerator.php @@ -1,7 +1,7 @@ Date: Wed, 28 Jun 2017 16:02:20 +0200 Subject: [PATCH 03/46] second step of implementation --- src/Moka/Builder/ProxyBuilder.php | 4 +- ...yFactory.php => ProxyGeneratorFactory.php} | 17 ++-- src/Moka/Generator/ProxyArgumentGenerator.php | 6 +- src/Moka/Generator/ProxyClassGenerator.php | 43 ++------- src/Moka/Generator/ProxyGenerator.php | 31 ++++++ src/Moka/Generator/ProxyMethodGenerator.php | 24 ++--- src/Moka/Generator/ProxyReturnGenerator.php | 6 +- src/Moka/Generator/ProxyTrait.php | 41 ++++++-- .../Plugin/PHPUnit/PHPUnitMockingStrategy.php | 2 + .../Prophecy/ProphecyMockingStrategy.php | 7 ++ src/Moka/Proxy/Proxy.php | 96 ------------------- src/Moka/Strategy/AbstractMockingStrategy.php | 7 ++ .../Strategy/MockingStrategyInterface.php | 2 + tests/Builder/ProxyBuilderTest.php | 48 +++++----- tests/Factory/ProxyFactoryTest.php | 29 ------ tests/GeneratorTest.php | 45 ++------- tests/MokaTest.php | 12 ++- tests/Proxy/ProxyContainerTest.php | 9 +- tests/Proxy/ProxyTest.php | 91 ------------------ 19 files changed, 160 insertions(+), 360 deletions(-) rename src/Moka/Factory/{ProxyFactory.php => ProxyGeneratorFactory.php} (62%) create mode 100644 src/Moka/Generator/ProxyGenerator.php delete mode 100644 src/Moka/Proxy/Proxy.php delete mode 100644 tests/Factory/ProxyFactoryTest.php delete mode 100644 tests/Proxy/ProxyTest.php diff --git a/src/Moka/Builder/ProxyBuilder.php b/src/Moka/Builder/ProxyBuilder.php index 517cd94..a9f3aa3 100644 --- a/src/Moka/Builder/ProxyBuilder.php +++ b/src/Moka/Builder/ProxyBuilder.php @@ -5,7 +5,7 @@ use Moka\Exception\InvalidIdentifierException; use Moka\Exception\MockNotCreatedException; -use Moka\Factory\ProxyFactory; +use Moka\Generator\ProxyGenerator; use Moka\Proxy\ProxyContainer; use Moka\Proxy\ProxyInterface; use Moka\Strategy\MockingStrategyInterface; @@ -75,6 +75,6 @@ public function getProxy(string $fqcnOrAlias, string $alias = null): ProxyInterf */ protected function buildProxy(string $fqcn): ProxyInterface { - return ProxyFactory::get($fqcn, $this->mockingStrategy); + return (new ProxyGenerator($this->mockingStrategy))->generate($fqcn); } } diff --git a/src/Moka/Factory/ProxyFactory.php b/src/Moka/Factory/ProxyGeneratorFactory.php similarity index 62% rename from src/Moka/Factory/ProxyFactory.php rename to src/Moka/Factory/ProxyGeneratorFactory.php index 96b61c6..ef9e8c1 100644 --- a/src/Moka/Factory/ProxyFactory.php +++ b/src/Moka/Factory/ProxyGeneratorFactory.php @@ -3,24 +3,19 @@ namespace Moka\Factory; -use Moka\Proxy\Proxy; -use Moka\Proxy\ProxyInterface; -use Moka\Strategy\MockingStrategyInterface; -/** - * Class ProxyFactory - * @package Moka\Factory - */ -class ProxyFactory +use Moka\Generator\ProxyGenerator; + +class ProxyGeneratorFactory { /** * @param string $fqcn * @param MockingStrategyInterface $mockingStrategy * @return ProxyInterface */ - public static function get(string $fqcn, MockingStrategyInterface $mockingStrategy): ProxyInterface + public static function get(string $fqcn, MockingStrategyInterface $mockingStrategy) { - return self::build($fqcn, $mockingStrategy); + return (new ProxyGenerator($mockingStrategy)); } /** @@ -28,7 +23,7 @@ public static function get(string $fqcn, MockingStrategyInterface $mockingStrate * @param MockingStrategyInterface $mockingStrategy * @return ProxyInterface */ - protected static function build(string $fqcn, MockingStrategyInterface $mockingStrategy): ProxyInterface + protected static function build(string $fqcn, MockingStrategyInterface $mockingStrategy) { return new Proxy($fqcn, $mockingStrategy); } diff --git a/src/Moka/Generator/ProxyArgumentGenerator.php b/src/Moka/Generator/ProxyArgumentGenerator.php index d22af43..c772f5c 100644 --- a/src/Moka/Generator/ProxyArgumentGenerator.php +++ b/src/Moka/Generator/ProxyArgumentGenerator.php @@ -6,7 +6,7 @@ class ProxyArgumentGenerator { - public function generateMethodParameter(\ReflectionParameter $parameter) + public static function generateMethodParameter(\ReflectionParameter $parameter) { try { $allowsNull = $parameter->allowsNull(); @@ -27,7 +27,7 @@ public function generateMethodParameter(\ReflectionParameter $parameter) try { $type = $parameter->getType(); if ($type) { - $type = ' ' . $this->getType($type) . ' '; + $type = ' ' . self::getType($type) . ' '; } else { $type = ''; } @@ -62,7 +62,7 @@ public function generateMethodParameter(\ReflectionParameter $parameter) ); } - protected function getType(\ReflectionType $type) + protected static function getType(\ReflectionType $type) { return (string)$type; } diff --git a/src/Moka/Generator/ProxyClassGenerator.php b/src/Moka/Generator/ProxyClassGenerator.php index 53b1f8c..80f8114 100644 --- a/src/Moka/Generator/ProxyClassGenerator.php +++ b/src/Moka/Generator/ProxyClassGenerator.php @@ -8,58 +8,33 @@ class ProxyClassGenerator { - private $template = ' - class %s extends %s implements %s + const UNSAFE_METHODS = ['__call', '__construct', '__destruct', '__clone']; + + private static $template = ' + return new class extends %s implements %s { use %s; %s }; - - $instantiator = new \Doctrine\Instantiator\Instantiator(); - - return $instantiator->instantiate("%s"); '; - private $methodGenerator; - - public function __construct() - { - $this->methodGenerator = new ProxyMethodGenerator(); - } - - public function generate($object): ProxyInterface + public static function generateCode(string $classWillBeEtended): string { - $objectFQCN = get_class($object); - $codeWillBeEvalueted = $this->generateCode($objectFQCN); - /** @var ProxyInterface|ProxyTrait $proxy */ - $proxy = eval($codeWillBeEvalueted); - $proxy->setObject($object); - - return $proxy; - } - - protected function generateCode(string $classWillBeEtended): string - { - $reflection = new \ReflectionClass($classWillBeEtended); $methods = $reflection->getMethods(); $methodsArray = []; foreach ($methods as $method) { - if ($method->getName() !== '__call') { - $methodsArray[] = $this->methodGenerator->generateMethodString($method); + if (!in_array($method->getName(), self::UNSAFE_METHODS, true)) { + $methodsArray[] = ProxyMethodGenerator::generateMethodString($method); } } - $className = 'Cofffee' . '_' . mt_rand(); - return sprintf( - $this->template, - $className, + self::$template, $classWillBeEtended, ProxyInterface::class, ProxyTrait::class, - implode(PHP_EOL, $methodsArray), - $className + implode(PHP_EOL, $methodsArray) ); } } diff --git a/src/Moka/Generator/ProxyGenerator.php b/src/Moka/Generator/ProxyGenerator.php new file mode 100644 index 0000000..737a5ab --- /dev/null +++ b/src/Moka/Generator/ProxyGenerator.php @@ -0,0 +1,31 @@ +mockingStrategy = $mockingStrategy; + } + + final public function generate($fqcn): ProxyInterface + { + $object = $this->mockingStrategy->build($fqcn); + $codeWillBeEvaluated = ProxyClassGenerator::generateCode(get_class($object)); + + /** @var ProxyInterface|ProxyTrait $proxy */ + $proxy = eval($codeWillBeEvaluated); + $proxy->_moka_setObject($object); + $proxy->_moka_setMockingStrategy($this->mockingStrategy); + + return $proxy; + } +} diff --git a/src/Moka/Generator/ProxyMethodGenerator.php b/src/Moka/Generator/ProxyMethodGenerator.php index dff6fe6..a4f801b 100644 --- a/src/Moka/Generator/ProxyMethodGenerator.php +++ b/src/Moka/Generator/ProxyMethodGenerator.php @@ -6,47 +6,37 @@ class ProxyMethodGenerator { - private $template = ' + private static $template = ' public %s function %s(%s)%s { %s$this->__call("%s", func_get_args()); } '; - private $argumentGenerator; - private $returnGenerator; - - public function __construct() - { - $this->argumentGenerator = new ProxyArgumentGenerator(); - $this->returnGenerator = new ProxyReturnGenerator(); - } - - public function generateMethodString(\ReflectionMethod $method) + public static function generateMethodString(\ReflectionMethod $method) { $static = $method->isStatic() ? 'static' : ''; $originalReturnType = $method->getReturnType(); - $returnType = !$originalReturnType ? '' : $this->returnGenerator->generateMethodReturnType($originalReturnType, $method); + $returnType = !$originalReturnType ? '' : ProxyReturnGenerator::generateMethodReturnType($originalReturnType, $method); $parameters = $method->getParameters(); $arguments = []; if ($parameters) { foreach ($method->getParameters() as $parameter) { - $arguments[] = $this->argumentGenerator->generateMethodParameter($parameter); + $arguments[] = ProxyArgumentGenerator::generateMethodParameter($parameter); } } $method->getReturnType(); $returnStatement = 'return '; - if (null !== $originalReturnType && $this->getType($originalReturnType) === 'void') { + if (null !== $originalReturnType && self::getType($originalReturnType) === 'void') { $returnStatement = ''; } - return sprintf( - $this->template, + self::$template, $static, $method->getName(), implode(', ', $arguments), @@ -56,7 +46,7 @@ public function generateMethodString(\ReflectionMethod $method) ); } - protected function getType(\ReflectionType $type) + protected static function getType(\ReflectionType $type) { return (string)$type; } diff --git a/src/Moka/Generator/ProxyReturnGenerator.php b/src/Moka/Generator/ProxyReturnGenerator.php index 818eb00..7fdaeb4 100644 --- a/src/Moka/Generator/ProxyReturnGenerator.php +++ b/src/Moka/Generator/ProxyReturnGenerator.php @@ -6,14 +6,14 @@ class ProxyReturnGenerator { - public function generateMethodReturnType(\ReflectionType $type, \ReflectionMethod $method) + public static function generateMethodReturnType(\ReflectionType $type, \ReflectionMethod $method) { $allowNull = ''; if ($type->allowsNull()) { $allowNull = '?'; } - $returnType = $this->getType($type); + $returnType = self::getType($type); if ($returnType === 'self') { $returnType = $method->getDeclaringClass()->getName(); } @@ -25,7 +25,7 @@ public function generateMethodReturnType(\ReflectionType $type, \ReflectionMetho ); } - public function getType(\ReflectionType $type) + public static function getType(\ReflectionType $type) { return (string)$type; } diff --git a/src/Moka/Generator/ProxyTrait.php b/src/Moka/Generator/ProxyTrait.php index 4daaa06..0205c27 100644 --- a/src/Moka/Generator/ProxyTrait.php +++ b/src/Moka/Generator/ProxyTrait.php @@ -4,35 +4,64 @@ namespace Moka\Generator; +use Moka\Exception\InvalidArgumentException; +use Moka\Exception\MockNotCreatedException; +use Moka\Exception\MockNotServedException; use Moka\Proxy\ProxyInterface; -use Prophecy\Prophecy\ObjectProphecy; +use Moka\Strategy\MockingStrategyInterface; trait ProxyTrait { private $object; + /** + * @var MockingStrategyInterface + */ + private $mockingStrategy; + + public function __construct() + { + } + public function __call($name, array $arguments) { - if ($this->serve() instanceof ObjectProphecy) { - return $this->serve()->reveal()->$name(...$arguments); + if ($this->mockingStrategy instanceof MockingStrategyInterface) { + return $this->mockingStrategy->call($this->object, $name, $arguments); } - - return $this->serve()->$name(...$arguments); } /** * @param mixed $object */ - public function setObject($object) + public function _moka_setObject($object) { $this->object = $object; } + public function _moka_setMockingStrategy(MockingStrategyInterface $mockingStrategy) + { + $this->mockingStrategy = $mockingStrategy; + } + + /** + * @param array $methodsWithValues + * @return ProxyInterface + * + * @throws InvalidArgumentException + * @throws MockNotCreatedException + */ public function stub(array $methodsWithValues): ProxyInterface { + $this->mockingStrategy->decorate($this->object, $methodsWithValues); + return $this; } + /** + * @return object + * + * @throws MockNotServedException + */ public function serve() { return $this->object; diff --git a/src/Moka/Plugin/PHPUnit/PHPUnitMockingStrategy.php b/src/Moka/Plugin/PHPUnit/PHPUnitMockingStrategy.php index 6d5e61c..0862edc 100644 --- a/src/Moka/Plugin/PHPUnit/PHPUnitMockingStrategy.php +++ b/src/Moka/Plugin/PHPUnit/PHPUnitMockingStrategy.php @@ -79,4 +79,6 @@ protected function doGet($mock) { return $mock; } + + } diff --git a/src/Moka/Plugin/Prophecy/ProphecyMockingStrategy.php b/src/Moka/Plugin/Prophecy/ProphecyMockingStrategy.php index a361299..711892c 100644 --- a/src/Moka/Plugin/Prophecy/ProphecyMockingStrategy.php +++ b/src/Moka/Plugin/Prophecy/ProphecyMockingStrategy.php @@ -85,4 +85,11 @@ protected function doGet($mock) ); } } + + public function call($object, string $name, array $arguments) + { + return parent::call($object->reveal(), $name, $arguments); + } + + } diff --git a/src/Moka/Proxy/Proxy.php b/src/Moka/Proxy/Proxy.php deleted file mode 100644 index 04405b5..0000000 --- a/src/Moka/Proxy/Proxy.php +++ /dev/null @@ -1,96 +0,0 @@ -fqcn = $fqcn; - $this->mockingStrategy = $mockingStrategy; - } - - /** - * @param string $name - * @param array $arguments - * @return mixed - * - * @throws MockNotCreatedException - */ - public function __call(string $name, array $arguments) - { - return $this->getMock()->$name(...$arguments); - } - - /** - * @return object - * - * @throws MockNotCreatedException - */ - private function getMock() - { - if (!$this->mock) { - $this->mock = $this->mockingStrategy->build($this->fqcn); - } - - return $this->mock; - } - - /** - * @param array $methodsWithValues - * @return ProxyInterface - * - * @throws InvalidArgumentException - * @throws MockNotCreatedException - */ - public function stub(array $methodsWithValues): ProxyInterface - { - $this->mockingStrategy->decorate($this->getMock(), $methodsWithValues); - - return $this; - } - - /** - * @return object - * - * @throws MockNotServedException - */ - public function serve() - { - try { - return $this->mockingStrategy->get($this->getMock()); - } catch (\Exception $exception) { - throw new MockNotServedException($exception->getMessage()); - } - } -} diff --git a/src/Moka/Strategy/AbstractMockingStrategy.php b/src/Moka/Strategy/AbstractMockingStrategy.php index 613158a..05e5d4f 100644 --- a/src/Moka/Strategy/AbstractMockingStrategy.php +++ b/src/Moka/Strategy/AbstractMockingStrategy.php @@ -163,4 +163,11 @@ final protected function setMockType(string $fqcn) { $this->mockType = $fqcn; } + + public function call($object, string $name, array $arguments) + { + return $object->$name(...$arguments); + } + + } diff --git a/src/Moka/Strategy/MockingStrategyInterface.php b/src/Moka/Strategy/MockingStrategyInterface.php index de9b3e0..386b701 100644 --- a/src/Moka/Strategy/MockingStrategyInterface.php +++ b/src/Moka/Strategy/MockingStrategyInterface.php @@ -43,4 +43,6 @@ public function get($mock); * @throws NotImplementedException */ public function getMockType(): string; + + public function call($object, string $name, array $arguments); } diff --git a/tests/Builder/ProxyBuilderTest.php b/tests/Builder/ProxyBuilderTest.php index 28312b6..ff64640 100644 --- a/tests/Builder/ProxyBuilderTest.php +++ b/tests/Builder/ProxyBuilderTest.php @@ -4,7 +4,8 @@ namespace Tests\Builder; use Moka\Builder\ProxyBuilder; -use Moka\Proxy\Proxy; +use Moka\Plugin\PHPUnit\PHPUnitMockingStrategy; +use Moka\Proxy\ProxyInterface; use Moka\Strategy\MockingStrategyInterface; use PHPUnit\Framework\TestCase; use PHPUnit_Framework_MockObject_MockObject as MockObject; @@ -21,27 +22,12 @@ class ProxyBuilderTest extends TestCase */ private $mockingStrategy; - protected function setUp() - { - $this->mockingStrategy = $this->getMockBuilder(MockingStrategyInterface::class) - ->disableOriginalConstructor() - ->getMock(); - - $this->mockingStrategy - ->method('get') - ->willReturn( - $this->getMockBuilder(\stdClass::class)->getMock() - ); - - $this->proxyBuilder = new ProxyBuilder($this->mockingStrategy); - } - public function testGetProxySuccess() { $proxy1 = $this->proxyBuilder->getProxy(\stdClass::class); $proxy2 = $this->proxyBuilder->getProxy(\stdClass::class); - $this->assertInstanceOf(Proxy::class, $proxy1); + $this->assertInstanceOf(ProxyInterface::class, $proxy1); $this->assertNotSame($proxy1, $proxy2); } @@ -51,8 +37,8 @@ public function testGetProxySuccessWithAlias() $proxy1 = $this->proxyBuilder->getProxy(\stdClass::class, 'bar'); $proxy2 = $this->proxyBuilder->getProxy(\stdClass::class, 'foo'); - $this->assertInstanceOf(Proxy::class, $proxy1); - $this->assertInstanceOf(Proxy::class, $proxy2); + $this->assertInstanceOf(ProxyInterface::class, $proxy1); + $this->assertInstanceOf(ProxyInterface::class, $proxy2); $this->assertNotSame($proxy1, $proxy2); } @@ -62,8 +48,8 @@ public function testGetProxySuccessWithSameAlias() $proxy1 = $this->proxyBuilder->getProxy(\stdClass::class, 'foo'); $proxy2 = $this->proxyBuilder->getProxy(\stdClass::class, 'foo'); - $this->assertInstanceOf(Proxy::class, $proxy1); - $this->assertInstanceOf(Proxy::class, $proxy2); + $this->assertInstanceOf(ProxyInterface::class, $proxy1); + $this->assertInstanceOf(ProxyInterface::class, $proxy2); $this->assertSame($proxy1, $proxy2); } @@ -72,8 +58,26 @@ public function testGetProxySuccessWithSameAliasOnly() { $proxy = $this->proxyBuilder->getProxy(\stdClass::class, 'bar'); - $this->assertInstanceOf(Proxy::class, $proxy); + $this->assertInstanceOf(ProxyInterface::class, $proxy); $this->assertSame($proxy, $this->proxyBuilder->getProxy('bar')); } + + protected function setUp() + { + $this->mockingStrategy = $this->getMockBuilder(MockingStrategyInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->mockingStrategy + ->method('get') + ->willReturn( + $this->getMockBuilder(\stdClass::class)->getMock() + ); + + $this->mockingStrategy = new PHPUnitMockingStrategy(); + + + $this->proxyBuilder = new ProxyBuilder($this->mockingStrategy); + } } diff --git a/tests/Factory/ProxyFactoryTest.php b/tests/Factory/ProxyFactoryTest.php deleted file mode 100644 index 91148bf..0000000 --- a/tests/Factory/ProxyFactoryTest.php +++ /dev/null @@ -1,29 +0,0 @@ -getMockBuilder(MockingStrategyInterface::class)->getMock() - ); - $mock2 = ProxyFactory::get( - \stdClass::class, - $this->getMockBuilder(MockingStrategyInterface::class)->getMock() - ); - - $this->assertInstanceOf(Proxy::class, $mock1); - $this->assertInstanceOf(Proxy::class, $mock2); - - $this->assertNotSame($mock1, $mock2); - } -} diff --git a/tests/GeneratorTest.php b/tests/GeneratorTest.php index 96be8b6..eabedce 100644 --- a/tests/GeneratorTest.php +++ b/tests/GeneratorTest.php @@ -3,7 +3,8 @@ namespace Tests; -use Moka\Generator\ProxyClassGenerator; +use Moka\Generator\ProxyGenerator; +use Moka\Plugin\PHPUnit\PHPUnitMockingStrategy; use Moka\Proxy\ProxyInterface; use PHPUnit\Framework\TestCase; @@ -16,40 +17,24 @@ class GeneratorTest extends TestCase public function setUp() { - $this->proxyGenerator = new ProxyClassGenerator(); + $this->proxyGenerator = new ProxyGenerator( + new PHPUnitMockingStrategy() + ); } public function testCreation() { /** @var ProxyInterface|FooTestClass $proxy */ - $proxy = $this->proxyGenerator->generate($this->getMockBuilder(FooTestClass::class)->getMock()); + $proxy = $this->proxyGenerator->generate(FooTestClass::class); $this->assertInstanceOf(ProxyInterface::class, $proxy); } - public function testForwardPHPUnit() - { - $mock = $this->getMockBuilder(FooTestClass::class)->getMock(); - - $mock->expects($this->any()) - ->method('something') - ->willReturn(new \stdClass()); - - /** @var ProxyInterface|FooTestClass $proxy */ - $proxy = $this->proxyGenerator->generate($mock); - - $this->assertInstanceOf(\stdClass::class, $proxy->something()); - - $this->assertInstanceOf(ProxyInterface::class, $proxy); - - } - public function testUseMockEngineMethod() { - $mock = $this->getMockBuilder(FooTestClass::class)->getMock(); /** @var ProxyInterface|FooTestClass $proxy */ - $proxy = $this->proxyGenerator->generate($mock); + $proxy = $this->proxyGenerator->generate(FooTestClass::class); $proxy->expects($this->any()) ->method('something') @@ -60,22 +45,6 @@ public function testUseMockEngineMethod() $this->assertInstanceOf(ProxyInterface::class, $proxy); } - public function testForwardProphecy() - { - $mock = $this->prophesize(FooTestClass::class); -// $mock = $this->getMockBuilder(FooTestClass::class)->getMock(); - - $mock->something()->willReturn(new \stdClass()); - - /** @var ProxyInterface|FooTestClass $proxy */ - $proxy = $this->proxyGenerator->generate($mock); - - $this->assertInstanceOf(\stdClass::class, $proxy->something()); - - $this->assertInstanceOf(ProxyInterface::class, $proxy); - - } - // public function testUseMockEngineMethodProphecy() // { // $mock = $this->prophesize(FooTestClass::class); diff --git a/tests/MokaTest.php b/tests/MokaTest.php index 791f43a..0e4d1c1 100644 --- a/tests/MokaTest.php +++ b/tests/MokaTest.php @@ -5,7 +5,7 @@ use Moka\Exception\NotImplementedException; use Moka\Moka; -use Moka\Proxy\Proxy; +use Moka\Proxy\ProxyInterface; use PHPUnit\Framework\TestCase; class MokaTest extends TestCase @@ -13,13 +13,19 @@ class MokaTest extends TestCase /** * Moka::brew() is deprecated, but it still needs to be tested. */ - const METHODS = ['brew', 'mockery', 'phake', 'phpunit', 'prophecy']; + const METHODS = [ + 'brew', + 'mockery', + 'phake', + 'phpunit', + 'prophecy' + ]; public function testBrewSuccess() { foreach (self::METHODS as $method) { $this->assertInstanceOf( - Proxy::class, + ProxyInterface::class, Moka::$method(\stdClass::class) ); } diff --git a/tests/Proxy/ProxyContainerTest.php b/tests/Proxy/ProxyContainerTest.php index 42f3e82..8d5b1ef 100644 --- a/tests/Proxy/ProxyContainerTest.php +++ b/tests/Proxy/ProxyContainerTest.php @@ -4,9 +4,8 @@ namespace Tests\Proxy; use Moka\Exception\InvalidIdentifierException; -use Moka\Proxy\Proxy; -use Moka\Proxy\ProxyContainer; use Moka\Proxy\ProxyInterface; +use Moka\Proxy\ProxyContainer; use PHPUnit\Framework\TestCase; class ProxyContainerTest extends TestCase @@ -25,7 +24,7 @@ protected function setUp() { $this->proxyContainer = new ProxyContainer(); /** @var ProxyInterface $proxy */ - $this->proxy = $this->getMockBuilder(Proxy::class) + $this->proxy = $this->getMockBuilder(ProxyInterface::class) ->disableOriginalConstructor() ->getMock(); @@ -39,7 +38,7 @@ public function testGetSuccess() { $proxy = $this->proxyContainer->get('foo'); - $this->assertInstanceOf(Proxy::class, $proxy); + $this->assertInstanceOf(ProxyInterface::class, $proxy); } public function testGetFailure() @@ -66,7 +65,7 @@ public function testSet() { $this->proxyContainer->set('acme', $this->proxy); $this->assertInstanceOf( - Proxy::class, + ProxyInterface::class, $this->proxyContainer->get('acme') ); } diff --git a/tests/Proxy/ProxyTest.php b/tests/Proxy/ProxyTest.php deleted file mode 100644 index 37c2623..0000000 --- a/tests/Proxy/ProxyTest.php +++ /dev/null @@ -1,91 +0,0 @@ -getMockBuilder(BarTestClass::class) - ->getMock(); - - $mock->method('getInt') - ->willReturn(1138); - - $this->mockingStrategy = $this->getMockBuilder(MockingStrategyInterface::class) - ->getMock(); - - $this->mockingStrategy - ->method('build') - ->willReturn($mock); - - $this->proxy = new Proxy( - FooTestClass::class, - $this->mockingStrategy - ); - } - - public function testMethodForwardSuccess() - { - $this->assertSame(1138, $this->proxy->getInt()); - } - - public function testMethodForwardFailure() - { - $this->expectException(\Error::class); - $this->expectExceptionMessageRegExp('/^Call to undefined method/'); - - $this->proxy->fakeMethod(); - } - - public function testStubSuccess() - { - $this->assertSame($this->proxy, $this->proxy->stub([])); - } - - public function testStubAndDecorateSuccess() - { - $this->proxy->serve(); - - $this->assertSame($this->proxy, $this->proxy->stub([])); - } - - public function testServeSuccess() - { - $this->mockingStrategy->method('get')->willReturn( - $this->getMockBuilder(FooTestClass::class)->getMock() - ); - - $this->assertInstanceOf(FooTestClass::class, $this->proxy->serve()); - } - - public function testServeFailure() - { - $this->mockingStrategy->method('get') - ->willThrowException(new MockNotCreatedException()); - - $this->expectException(MockNotServedException::class); - $this->proxy->serve(); - } -} From ffa97ff0b2c6aeaa627b242e72b5cff5af7a11da Mon Sep 17 00:00:00 2001 From: Angelo Giuffredi Date: Wed, 28 Jun 2017 16:08:58 +0200 Subject: [PATCH 04/46] Remove doctrine/instatiator --- composer.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/composer.json b/composer.json index 8935671..de78af4 100644 --- a/composer.json +++ b/composer.json @@ -46,8 +46,7 @@ "php": ">=7.0", "phpcollection/phpcollection": "^0.5.0", "psr/container": "^1.0", - "phpunit/phpunit-mock-objects": "^3.4||^4.0", - "doctrine/instantiator": "^1.0" + "phpunit/phpunit-mock-objects": "^3.4||^4.0" }, "require-dev": { "friendsofphp/php-cs-fixer": "^2.3", From 74d46831b38bf38883688c07921106bd5ee63c7d Mon Sep 17 00:00:00 2001 From: Angelo Giuffredi Date: Wed, 28 Jun 2017 16:12:16 +0200 Subject: [PATCH 05/46] Fix autoloader --- composer.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/composer.json b/composer.json index de78af4..03b80ef 100644 --- a/composer.json +++ b/composer.json @@ -27,8 +27,7 @@ ], "autoload": { "psr-4": { - "Moka\\": "src/Moka/", - "Coffee\\": "src/Coffee/" + "Moka\\": "src/Moka/" }, "files": [ "src/Moka/Plugin/Mockery/MockeryPlugin.php", From 1a68d82222fec42632cca039b10ed8f5612d582a Mon Sep 17 00:00:00 2001 From: Angelo Giuffredi Date: Wed, 28 Jun 2017 16:12:41 +0200 Subject: [PATCH 06/46] Run cs-fixer --- src/Moka/Factory/ProxyGeneratorFactory.php | 1 - src/Moka/Generator/ProxyArgumentGenerator.php | 4 ---- src/Moka/Generator/ProxyClassGenerator.php | 1 - src/Moka/Generator/ProxyGenerator.php | 1 - src/Moka/Generator/ProxyMethodGenerator.php | 2 -- src/Moka/Generator/ProxyReturnGenerator.php | 1 - src/Moka/Generator/ProxyTrait.php | 1 - src/Moka/Plugin/PHPUnit/PHPUnitMockingStrategy.php | 2 -- src/Moka/Plugin/Prophecy/ProphecyMockingStrategy.php | 2 -- src/Moka/Strategy/AbstractMockingStrategy.php | 2 -- tests/AbstractTestClass.php | 1 - 11 files changed, 18 deletions(-) diff --git a/src/Moka/Factory/ProxyGeneratorFactory.php b/src/Moka/Factory/ProxyGeneratorFactory.php index ef9e8c1..54c91dd 100644 --- a/src/Moka/Factory/ProxyGeneratorFactory.php +++ b/src/Moka/Factory/ProxyGeneratorFactory.php @@ -3,7 +3,6 @@ namespace Moka\Factory; - use Moka\Generator\ProxyGenerator; class ProxyGeneratorFactory diff --git a/src/Moka/Generator/ProxyArgumentGenerator.php b/src/Moka/Generator/ProxyArgumentGenerator.php index c772f5c..a1ef581 100644 --- a/src/Moka/Generator/ProxyArgumentGenerator.php +++ b/src/Moka/Generator/ProxyArgumentGenerator.php @@ -3,7 +3,6 @@ namespace Moka\Generator; - class ProxyArgumentGenerator { public static function generateMethodParameter(\ReflectionParameter $parameter) @@ -47,10 +46,7 @@ public static function generateMethodParameter(\ReflectionParameter $parameter) $byReference = ''; $defaultValue = ''; } - - } catch (\ReflectionException $e) { - } return sprintf( diff --git a/src/Moka/Generator/ProxyClassGenerator.php b/src/Moka/Generator/ProxyClassGenerator.php index 80f8114..34eda60 100644 --- a/src/Moka/Generator/ProxyClassGenerator.php +++ b/src/Moka/Generator/ProxyClassGenerator.php @@ -3,7 +3,6 @@ namespace Moka\Generator; - use Moka\Proxy\ProxyInterface; class ProxyClassGenerator diff --git a/src/Moka/Generator/ProxyGenerator.php b/src/Moka/Generator/ProxyGenerator.php index 737a5ab..c2a8f72 100644 --- a/src/Moka/Generator/ProxyGenerator.php +++ b/src/Moka/Generator/ProxyGenerator.php @@ -3,7 +3,6 @@ namespace Moka\Generator; - use Moka\Proxy\ProxyInterface; use Moka\Strategy\MockingStrategyInterface; diff --git a/src/Moka/Generator/ProxyMethodGenerator.php b/src/Moka/Generator/ProxyMethodGenerator.php index a4f801b..f064c59 100644 --- a/src/Moka/Generator/ProxyMethodGenerator.php +++ b/src/Moka/Generator/ProxyMethodGenerator.php @@ -3,7 +3,6 @@ namespace Moka\Generator; - class ProxyMethodGenerator { private static $template = ' @@ -50,5 +49,4 @@ protected static function getType(\ReflectionType $type) { return (string)$type; } - } diff --git a/src/Moka/Generator/ProxyReturnGenerator.php b/src/Moka/Generator/ProxyReturnGenerator.php index 7fdaeb4..1ffbc57 100644 --- a/src/Moka/Generator/ProxyReturnGenerator.php +++ b/src/Moka/Generator/ProxyReturnGenerator.php @@ -3,7 +3,6 @@ namespace Moka\Generator; - class ProxyReturnGenerator { public static function generateMethodReturnType(\ReflectionType $type, \ReflectionMethod $method) diff --git a/src/Moka/Generator/ProxyTrait.php b/src/Moka/Generator/ProxyTrait.php index 0205c27..b9b7490 100644 --- a/src/Moka/Generator/ProxyTrait.php +++ b/src/Moka/Generator/ProxyTrait.php @@ -3,7 +3,6 @@ namespace Moka\Generator; - use Moka\Exception\InvalidArgumentException; use Moka\Exception\MockNotCreatedException; use Moka\Exception\MockNotServedException; diff --git a/src/Moka/Plugin/PHPUnit/PHPUnitMockingStrategy.php b/src/Moka/Plugin/PHPUnit/PHPUnitMockingStrategy.php index 0862edc..6d5e61c 100644 --- a/src/Moka/Plugin/PHPUnit/PHPUnitMockingStrategy.php +++ b/src/Moka/Plugin/PHPUnit/PHPUnitMockingStrategy.php @@ -79,6 +79,4 @@ protected function doGet($mock) { return $mock; } - - } diff --git a/src/Moka/Plugin/Prophecy/ProphecyMockingStrategy.php b/src/Moka/Plugin/Prophecy/ProphecyMockingStrategy.php index 711892c..c25ef3b 100644 --- a/src/Moka/Plugin/Prophecy/ProphecyMockingStrategy.php +++ b/src/Moka/Plugin/Prophecy/ProphecyMockingStrategy.php @@ -90,6 +90,4 @@ public function call($object, string $name, array $arguments) { return parent::call($object->reveal(), $name, $arguments); } - - } diff --git a/src/Moka/Strategy/AbstractMockingStrategy.php b/src/Moka/Strategy/AbstractMockingStrategy.php index 05e5d4f..9a36c03 100644 --- a/src/Moka/Strategy/AbstractMockingStrategy.php +++ b/src/Moka/Strategy/AbstractMockingStrategy.php @@ -168,6 +168,4 @@ public function call($object, string $name, array $arguments) { return $object->$name(...$arguments); } - - } diff --git a/tests/AbstractTestClass.php b/tests/AbstractTestClass.php index 6467999..b9d7f8d 100644 --- a/tests/AbstractTestClass.php +++ b/tests/AbstractTestClass.php @@ -22,7 +22,6 @@ public function getSelf(): TestInterface public function something() { - } public function withArgument(int $argument): int From 6d289ae7fca7f0cf2cc212a5c222a6ae9c86857a Mon Sep 17 00:00:00 2001 From: Angelo Giuffredi Date: Wed, 28 Jun 2017 16:25:03 +0200 Subject: [PATCH 07/46] Clean some code --- src/Moka/Factory/ProxyGeneratorFactory.php | 34 ++++++++++++++----- src/Moka/Generator/ProxyArgumentGenerator.php | 7 ++-- src/Moka/Generator/ProxyTrait.php | 15 +++++--- src/Moka/Proxy/ProxyInterface.php | 2 ++ src/Moka/Strategy/AbstractMockingStrategy.php | 3 ++ 5 files changed, 46 insertions(+), 15 deletions(-) diff --git a/src/Moka/Factory/ProxyGeneratorFactory.php b/src/Moka/Factory/ProxyGeneratorFactory.php index 54c91dd..b153dd0 100644 --- a/src/Moka/Factory/ProxyGeneratorFactory.php +++ b/src/Moka/Factory/ProxyGeneratorFactory.php @@ -4,26 +4,44 @@ namespace Moka\Factory; use Moka\Generator\ProxyGenerator; +use Moka\Strategy\MockingStrategyInterface; class ProxyGeneratorFactory { /** - * @param string $fqcn + * @var array|ProxyGenerator[] + */ + private static $proxyGenerators = []; + + /** + * @param MockingStrategyInterface $mockingStrategy + * @return ProxyGenerator + */ + public static function get(MockingStrategyInterface $mockingStrategy): ProxyGenerator + { + $key = self::key($mockingStrategy); + if (!array_key_exists($key, self::$proxyGenerators) || !self::$proxyGenerators[$key] instanceof ProxyGenerator) { + self::$proxyGenerators[$key] = static::build($mockingStrategy); + } + + return self::$proxyGenerators[$key]; + } + + /** * @param MockingStrategyInterface $mockingStrategy - * @return ProxyInterface + * @return string */ - public static function get(string $fqcn, MockingStrategyInterface $mockingStrategy) + private static function key(MockingStrategyInterface $mockingStrategy): string { - return (new ProxyGenerator($mockingStrategy)); + return get_class($mockingStrategy); } /** - * @param string $fqcn * @param MockingStrategyInterface $mockingStrategy - * @return ProxyInterface + * @return ProxyGenerator */ - protected static function build(string $fqcn, MockingStrategyInterface $mockingStrategy) + protected static function build(MockingStrategyInterface $mockingStrategy): ProxyGenerator { - return new Proxy($fqcn, $mockingStrategy); + return new ProxyGenerator($mockingStrategy); } } diff --git a/src/Moka/Generator/ProxyArgumentGenerator.php b/src/Moka/Generator/ProxyArgumentGenerator.php index a1ef581..5fcbbc3 100644 --- a/src/Moka/Generator/ProxyArgumentGenerator.php +++ b/src/Moka/Generator/ProxyArgumentGenerator.php @@ -3,9 +3,13 @@ namespace Moka\Generator; +/** + * Class ProxyArgumentGenerator + * @package Moka\Generator + */ class ProxyArgumentGenerator { - public static function generateMethodParameter(\ReflectionParameter $parameter) + public static function generateMethodParameter(\ReflectionParameter $parameter): string { try { $allowsNull = $parameter->allowsNull(); @@ -33,7 +37,6 @@ public static function generateMethodParameter(\ReflectionParameter $parameter) $name = '$' . $parameter->getName(); -// $canBePassByValue = $parameter->canBePassedByValue(); $isPassedByReference = $parameter->isPassedByReference(); $byReference = ''; if ($isPassedByReference) { diff --git a/src/Moka/Generator/ProxyTrait.php b/src/Moka/Generator/ProxyTrait.php index b9b7490..6d20a69 100644 --- a/src/Moka/Generator/ProxyTrait.php +++ b/src/Moka/Generator/ProxyTrait.php @@ -11,7 +11,10 @@ trait ProxyTrait { - private $object; + /** + * @var object + */ + private $mock; /** * @var MockingStrategyInterface @@ -25,7 +28,7 @@ public function __construct() public function __call($name, array $arguments) { if ($this->mockingStrategy instanceof MockingStrategyInterface) { - return $this->mockingStrategy->call($this->object, $name, $arguments); + return $this->mockingStrategy->call($this->mock, $name, $arguments); } } @@ -34,7 +37,7 @@ public function __call($name, array $arguments) */ public function _moka_setObject($object) { - $this->object = $object; + $this->mock = $object; } public function _moka_setMockingStrategy(MockingStrategyInterface $mockingStrategy) @@ -51,7 +54,7 @@ public function _moka_setMockingStrategy(MockingStrategyInterface $mockingStrate */ public function stub(array $methodsWithValues): ProxyInterface { - $this->mockingStrategy->decorate($this->object, $methodsWithValues); + $this->mockingStrategy->decorate($this->mock, $methodsWithValues); return $this; } @@ -60,9 +63,11 @@ public function stub(array $methodsWithValues): ProxyInterface * @return object * * @throws MockNotServedException + * + * @deprecated since v2.0.0 */ public function serve() { - return $this->object; + return $this->mock; } } diff --git a/src/Moka/Proxy/ProxyInterface.php b/src/Moka/Proxy/ProxyInterface.php index 0158ec2..e929a57 100644 --- a/src/Moka/Proxy/ProxyInterface.php +++ b/src/Moka/Proxy/ProxyInterface.php @@ -26,6 +26,8 @@ public function stub(array $methodsWithValues): ProxyInterface; * @return object * * @throws MockNotServedException + * + * @deprecated since v2.0.0 */ public function serve(); } diff --git a/src/Moka/Strategy/AbstractMockingStrategy.php b/src/Moka/Strategy/AbstractMockingStrategy.php index 9a36c03..9fb7147 100644 --- a/src/Moka/Strategy/AbstractMockingStrategy.php +++ b/src/Moka/Strategy/AbstractMockingStrategy.php @@ -71,6 +71,9 @@ abstract protected function doBuild(string $fqcn); * @param object $mock * @param array $stubs * @return void + * + * @throws InvalidArgumentException + * @throws NotImplementedException */ public function decorate($mock, array $stubs) { From 3dbefd0c5e9f96a33cde213a22ca2c01906396eb Mon Sep 17 00:00:00 2001 From: Angelo Giuffredi Date: Wed, 28 Jun 2017 16:48:47 +0200 Subject: [PATCH 08/46] Fix call parameters --- src/Moka/Generator/ProxyClassGenerator.php | 22 +++++++++++++++++++++- src/Moka/Generator/ProxyTrait.php | 14 +++++++------- 2 files changed, 28 insertions(+), 8 deletions(-) diff --git a/src/Moka/Generator/ProxyClassGenerator.php b/src/Moka/Generator/ProxyClassGenerator.php index 34eda60..e87e68c 100644 --- a/src/Moka/Generator/ProxyClassGenerator.php +++ b/src/Moka/Generator/ProxyClassGenerator.php @@ -8,12 +8,18 @@ class ProxyClassGenerator { const UNSAFE_METHODS = ['__call', '__construct', '__destruct', '__clone']; +// const CALL_PARAMETERS = ['name', 'arguments']; private static $template = ' return new class extends %s implements %s { use %s; %s + + public function __call(%s $name, %s $arguments) + { + return $this->doCall($name, $arguments); + } }; '; @@ -22,18 +28,32 @@ public static function generateCode(string $classWillBeEtended): string $reflection = new \ReflectionClass($classWillBeEtended); $methods = $reflection->getMethods(); $methodsArray = []; + foreach ($methods as $method) { if (!in_array($method->getName(), self::UNSAFE_METHODS, true)) { $methodsArray[] = ProxyMethodGenerator::generateMethodString($method); } + + if ($method->getName() === '__call') { + $p = []; + $callParameters = $method->getParameters(); + foreach ($callParameters as $callParameter) { + $p[$callParameter->getPosition()] = (string)$callParameter->getType(); + } + } } + $callName = $p[0] ?? ''; + $callArguments = $p[1] ?? ''; + return sprintf( self::$template, $classWillBeEtended, ProxyInterface::class, ProxyTrait::class, - implode(PHP_EOL, $methodsArray) + implode(PHP_EOL, $methodsArray), + $callName, + $callArguments ); } } diff --git a/src/Moka/Generator/ProxyTrait.php b/src/Moka/Generator/ProxyTrait.php index 6d20a69..95e000d 100644 --- a/src/Moka/Generator/ProxyTrait.php +++ b/src/Moka/Generator/ProxyTrait.php @@ -25,13 +25,6 @@ public function __construct() { } - public function __call($name, array $arguments) - { - if ($this->mockingStrategy instanceof MockingStrategyInterface) { - return $this->mockingStrategy->call($this->mock, $name, $arguments); - } - } - /** * @param mixed $object */ @@ -70,4 +63,11 @@ public function serve() { return $this->mock; } + + protected function doCall(string $name, array $arguments) + { + if ($this->mockingStrategy instanceof MockingStrategyInterface) { + return $this->mockingStrategy->call($this->mock, $name, $arguments); + } + } } From 198eaed3fb6a22e8dcf6e16b8b950e30fb91c507 Mon Sep 17 00:00:00 2001 From: Angelo Giuffredi Date: Wed, 28 Jun 2017 17:22:47 +0200 Subject: [PATCH 09/46] override method only when is not final --- src/Moka/Generator/ProxyClassGenerator.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Moka/Generator/ProxyClassGenerator.php b/src/Moka/Generator/ProxyClassGenerator.php index e87e68c..d6184cd 100644 --- a/src/Moka/Generator/ProxyClassGenerator.php +++ b/src/Moka/Generator/ProxyClassGenerator.php @@ -8,7 +8,6 @@ class ProxyClassGenerator { const UNSAFE_METHODS = ['__call', '__construct', '__destruct', '__clone']; -// const CALL_PARAMETERS = ['name', 'arguments']; private static $template = ' return new class extends %s implements %s @@ -30,7 +29,7 @@ public static function generateCode(string $classWillBeEtended): string $methodsArray = []; foreach ($methods as $method) { - if (!in_array($method->getName(), self::UNSAFE_METHODS, true)) { + if (!$method->isFinal() && !in_array($method->getName(), self::UNSAFE_METHODS, true)) { $methodsArray[] = ProxyMethodGenerator::generateMethodString($method); } From 90786f64b1acf13fc069e49ec9b389b7d56b542a Mon Sep 17 00:00:00 2001 From: Angelo Giuffredi Date: Wed, 28 Jun 2017 17:44:01 +0200 Subject: [PATCH 10/46] use list() instead of accessing directly to array indexes --- src/Moka/Generator/ProxyClassGenerator.php | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/Moka/Generator/ProxyClassGenerator.php b/src/Moka/Generator/ProxyClassGenerator.php index d6184cd..a157515 100644 --- a/src/Moka/Generator/ProxyClassGenerator.php +++ b/src/Moka/Generator/ProxyClassGenerator.php @@ -27,6 +27,7 @@ public static function generateCode(string $classWillBeEtended): string $reflection = new \ReflectionClass($classWillBeEtended); $methods = $reflection->getMethods(); $methodsArray = []; + $p = array_fill(0, 2, ''); foreach ($methods as $method) { if (!$method->isFinal() && !in_array($method->getName(), self::UNSAFE_METHODS, true)) { @@ -34,7 +35,6 @@ public static function generateCode(string $classWillBeEtended): string } if ($method->getName() === '__call') { - $p = []; $callParameters = $method->getParameters(); foreach ($callParameters as $callParameter) { $p[$callParameter->getPosition()] = (string)$callParameter->getType(); @@ -42,8 +42,7 @@ public static function generateCode(string $classWillBeEtended): string } } - $callName = $p[0] ?? ''; - $callArguments = $p[1] ?? ''; + list($callName, $callArguments) = $p; return sprintf( self::$template, @@ -51,8 +50,8 @@ public static function generateCode(string $classWillBeEtended): string ProxyInterface::class, ProxyTrait::class, implode(PHP_EOL, $methodsArray), - $callName, - $callArguments + $callName?? '', + $callArguments?? '' ); } } From 7b5af32275a0361d6edd7eb7b0cb73df08005037 Mon Sep 17 00:00:00 2001 From: Angelo Giuffredi Date: Wed, 28 Jun 2017 17:55:34 +0200 Subject: [PATCH 11/46] First update of documentation --- README.md | 44 ++++++++++++++------------------------------ 1 file changed, 14 insertions(+), 30 deletions(-) diff --git a/README.md b/README.md index 7a3b406..761b0c1 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ [![Packagist](https://img.shields.io/packagist/dt/facile-it/moka.svg)](https://packagist.org/packages/facile-it/moka) Tired of spending most of your testing time mocking objects like there's no tomorrow? **Yes.** -**Moka** provides you with three simple methods to reduce your effort on such a tedious task, and with an incredible abstraction layer between the most popular mock engines and **you**. +**Moka** provides you with two simple methods to reduce your effort on such a tedious task, and with an incredible abstraction layer between the most popular mock engines and **you**. ## Installation @@ -20,7 +20,7 @@ composer require --dev facile-it/moka ## Usage -To use **Moka** in your tests simply `use` the `MokaPHPUnitTrait` (see generators section [below](#strategies)) and run `Moka::clean()` before every test. A simple interface will let you create *moka* (mock) objects, *serve* them easily, and decorate them with *stub* methods with a fluent interface. +To use **Moka** in your tests simply `use` the `MokaPHPUnitTrait` (see generators section [below](#strategies)) and run `Moka::clean()` before every test. A simple interface will let you create *moka* (mock) objects, and decorate them with *stub* methods with a fluent interface. A complete example follows: @@ -46,9 +46,9 @@ class FooTest extends \AnyTestCase $this->foo = new Foo( $this->moka(BarInterface::class)->stub([ // Method name => return value. - 'method1' => $this->moka(AcmeInterface::class)->serve(), + 'method1' => $this->moka(AcmeInterface::class), 'method2' => true // Any return value. - ])->serve() + ]) ); } @@ -87,7 +87,7 @@ class FooTest extends TestCase } ``` -You can rely on the original mock object implementation to be accessible (in the example below, PHPUnit's): +You can rely on the original mock object implementation to be accessible (in the example below, PHPUnit's): ```php $this->moka(BarInterface::class, 'bar') @@ -100,10 +100,10 @@ $this->moka('bar') ->method('isValid') ->willThrowException(new \Exception()); -var_dump($this->moka('bar')->serve()->isValid()); +var_dump($this->moka('bar')->isValid()); // bool(true) -var_dump($this->moka('bar')->serve()->isValid()); +var_dump($this->moka('bar')->isValid()); // throws \Exception ``` @@ -114,8 +114,8 @@ var_dump($this->moka('bar')->serve()->isValid()); Creates a proxy containing a mock object (according to the selected strategy) for the provided *FQCN* and optionally assigns an `$alias` to it to be able to get it later: ```php -$mock1 = $this->moka(FooInterface::class)->serve(); // Creates the mock for FooInterface. -$mock2 = $this->moka(FooInterface::class)->serve(); // Gets a different mock. +$mock1 = $this->moka(FooInterface::class); // Creates the mock for FooInterface. +$mock2 = $this->moka(FooInterface::class); // Gets a different mock. var_dump($mock1 === $mock2); // bool(false) @@ -124,8 +124,8 @@ var_dump($mock1 === $mock2); The `$alias` allows you to store mock instances: ```php -$mock1 = $this->moka(FooInterface::class, 'foo')->serve(); // Creates a mock for FooInterface. -$mock2 = $this->moka('foo')->serve(); // Get the mock previously created. +$mock1 = $this->moka(FooInterface::class, 'foo'); // Creates a mock for FooInterface. +$mock2 = $this->moka('foo'); // Get the mock previously created. var_dump($mock1 === $mock2); // bool(true) @@ -138,32 +138,16 @@ Accepts an array of method stubs with format `[$methodName => $methodValue]`, wh ```php $actualMock = $this->moka(BarInterface::class)->stub([ 'isValid' => true, - // Remember to use serve() to pass the actual mock. - 'getMock' => $this->moka(AcmeInterface::class)->serve(), + 'getMock' => $this->moka(AcmeInterface::class), 'throwException' => new \Exception() -])->serve(); +]); var_dump($actualMock->isValid()); // bool(true) ``` **Notice:** the stub is valid for **any** invocation of the method and it cannot be overridden. -If you need more granular control over invocation strategies, see `serve()`. - -### `serve() // Returns the actual mocked object.` - -Returns the final *fake* object good to be used in place of the real implementation: - -```php -function foo(BarInterface $bar) -{ - return $bar->chill(); -} - -$chill = foo( - $this->moka(BarInterface::class)->serve() -); -``` +If you need more granular control over invocation strategies, you can get [access to the original mock object implementation](#original-mock). ## Supported mock object generators From b3c8ea06f7146562e7d32a252462e2e5df08e4d6 Mon Sep 17 00:00:00 2001 From: Angelo Giuffredi Date: Wed, 28 Jun 2017 17:57:00 +0200 Subject: [PATCH 12/46] Use ProxyGeneratorFactory --- src/Moka/Builder/ProxyBuilder.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Moka/Builder/ProxyBuilder.php b/src/Moka/Builder/ProxyBuilder.php index a9f3aa3..b31f14f 100644 --- a/src/Moka/Builder/ProxyBuilder.php +++ b/src/Moka/Builder/ProxyBuilder.php @@ -5,6 +5,7 @@ use Moka\Exception\InvalidIdentifierException; use Moka\Exception\MockNotCreatedException; +use Moka\Factory\ProxyGeneratorFactory; use Moka\Generator\ProxyGenerator; use Moka\Proxy\ProxyContainer; use Moka\Proxy\ProxyInterface; @@ -75,6 +76,6 @@ public function getProxy(string $fqcnOrAlias, string $alias = null): ProxyInterf */ protected function buildProxy(string $fqcn): ProxyInterface { - return (new ProxyGenerator($this->mockingStrategy))->generate($fqcn); + return ProxyGeneratorFactory::get($this->mockingStrategy)->generate($fqcn); } } From 4f3971e09c1e5c898771b95a6c9a292910b4ab51 Mon Sep 17 00:00:00 2001 From: Alberto Villa Date: Thu, 29 Jun 2017 16:08:19 +0200 Subject: [PATCH 13/46] Add moka() and ProxyGeneratorInterface --- composer.json | 6 +- src/Moka/Builder/ProxyBuilder.php | 3 +- src/Moka/Factory/ProxyGeneratorFactory.php | 4 + src/Moka/Generator/ProxyArgumentGenerator.php | 68 ------------- src/Moka/Generator/ProxyClassGenerator.php | 57 ----------- src/Moka/Generator/ProxyGenerator.php | 46 +++++++-- src/Moka/Generator/ProxyMethodGenerator.php | 52 ---------- src/Moka/Generator/ProxyReturnGenerator.php | 31 ------ src/Moka/Generator/ProxyTrait.php | 30 +++++- .../Generator/Template/ProxyClassTemplate.php | 91 +++++++++++++++++ .../Template/ProxyMethodTemplate.php | 65 ++++++++++++ .../Template/ProxyParameterTemplate.php | 65 ++++++++++++ .../Template/ProxyReturnTypeTemplate.php | 44 +++++++++ .../Template/ProxyTemplateInterface.php | 17 ++++ src/Moka/Plugin/Mockery/moka.php | 18 ++++ src/Moka/Plugin/PHPUnit/moka.php | 18 ++++ src/Moka/Plugin/Phake/moka.php | 18 ++++ .../Prophecy/ProphecyMockingStrategy.php | 17 +++- src/Moka/Plugin/Prophecy/moka.php | 18 ++++ src/Moka/Strategy/AbstractMockingStrategy.php | 99 +++++++++++-------- .../Strategy/MockingStrategyInterface.php | 10 +- src/Moka/Traits/MokaMockeryTrait.php | 4 + src/Moka/Traits/MokaPHPUnitTrait.php | 4 + src/Moka/Traits/MokaPhakeTrait.php | 4 + src/Moka/Traits/MokaProphecyTrait.php | 4 + tests/GeneratorTest.php | 6 +- .../Prophecy/ProphecyMockingStrategyTest.php | 24 +++++ tests/Proxy/ProxyContainerTest.php | 2 +- 28 files changed, 556 insertions(+), 269 deletions(-) delete mode 100644 src/Moka/Generator/ProxyArgumentGenerator.php delete mode 100644 src/Moka/Generator/ProxyClassGenerator.php delete mode 100644 src/Moka/Generator/ProxyMethodGenerator.php delete mode 100644 src/Moka/Generator/ProxyReturnGenerator.php create mode 100644 src/Moka/Generator/Template/ProxyClassTemplate.php create mode 100644 src/Moka/Generator/Template/ProxyMethodTemplate.php create mode 100644 src/Moka/Generator/Template/ProxyParameterTemplate.php create mode 100644 src/Moka/Generator/Template/ProxyReturnTypeTemplate.php create mode 100644 src/Moka/Generator/Template/ProxyTemplateInterface.php create mode 100644 src/Moka/Plugin/Mockery/moka.php create mode 100644 src/Moka/Plugin/PHPUnit/moka.php create mode 100644 src/Moka/Plugin/Phake/moka.php create mode 100644 src/Moka/Plugin/Prophecy/moka.php diff --git a/composer.json b/composer.json index 03b80ef..5dfc7d9 100644 --- a/composer.json +++ b/composer.json @@ -31,9 +31,13 @@ }, "files": [ "src/Moka/Plugin/Mockery/MockeryPlugin.php", + "src/Moka/Plugin/Mockery/moka.php", "src/Moka/Plugin/Phake/PhakePlugin.php", + "src/Moka/Plugin/Phake/moka.php", "src/Moka/Plugin/PHPUnit/PHPUnitPlugin.php", - "src/Moka/Plugin/Prophecy/ProphecyPlugin.php" + "src/Moka/Plugin/PHPUnit/moka.php", + "src/Moka/Plugin/Prophecy/ProphecyPlugin.php", + "src/Moka/Plugin/Prophecy/moka.php" ] }, "autoload-dev": { diff --git a/src/Moka/Builder/ProxyBuilder.php b/src/Moka/Builder/ProxyBuilder.php index b31f14f..173ab4d 100644 --- a/src/Moka/Builder/ProxyBuilder.php +++ b/src/Moka/Builder/ProxyBuilder.php @@ -6,7 +6,6 @@ use Moka\Exception\InvalidIdentifierException; use Moka\Exception\MockNotCreatedException; use Moka\Factory\ProxyGeneratorFactory; -use Moka\Generator\ProxyGenerator; use Moka\Proxy\ProxyContainer; use Moka\Proxy\ProxyInterface; use Moka\Strategy\MockingStrategyInterface; @@ -76,6 +75,6 @@ public function getProxy(string $fqcnOrAlias, string $alias = null): ProxyInterf */ protected function buildProxy(string $fqcn): ProxyInterface { - return ProxyGeneratorFactory::get($this->mockingStrategy)->generate($fqcn); + return ProxyGeneratorFactory::get($this->mockingStrategy)->get($fqcn); } } diff --git a/src/Moka/Factory/ProxyGeneratorFactory.php b/src/Moka/Factory/ProxyGeneratorFactory.php index b153dd0..371bd9c 100644 --- a/src/Moka/Factory/ProxyGeneratorFactory.php +++ b/src/Moka/Factory/ProxyGeneratorFactory.php @@ -6,6 +6,10 @@ use Moka\Generator\ProxyGenerator; use Moka\Strategy\MockingStrategyInterface; +/** + * Class ProxyGeneratorFactory + * @package Moka\Factory + */ class ProxyGeneratorFactory { /** diff --git a/src/Moka/Generator/ProxyArgumentGenerator.php b/src/Moka/Generator/ProxyArgumentGenerator.php deleted file mode 100644 index 5fcbbc3..0000000 --- a/src/Moka/Generator/ProxyArgumentGenerator.php +++ /dev/null @@ -1,68 +0,0 @@ -allowsNull(); - $defaultValue = null; - if ($allowsNull) { - $defaultValue = 'null'; - } else { - $defaultValue = var_export($parameter->getDefaultValue(), true); - } - - if ($defaultValue) { - $defaultValue = "= $defaultValue"; - } - } catch (\ReflectionException $exception) { - $defaultValue = ''; - } - - try { - $type = $parameter->getType(); - if ($type) { - $type = ' ' . self::getType($type) . ' '; - } else { - $type = ''; - } - - $name = '$' . $parameter->getName(); - - $isPassedByReference = $parameter->isPassedByReference(); - $byReference = ''; - if ($isPassedByReference) { - $byReference = ' &'; - } - - $isVariadic = $parameter->isVariadic(); - if ($isVariadic) { - $type = '...'; - $byReference = ''; - $defaultValue = ''; - } - } catch (\ReflectionException $e) { - } - - return sprintf( - '%s%s%s%s', - $type, - $byReference, - $name, - $defaultValue - ); - } - - protected static function getType(\ReflectionType $type) - { - return (string)$type; - } -} diff --git a/src/Moka/Generator/ProxyClassGenerator.php b/src/Moka/Generator/ProxyClassGenerator.php deleted file mode 100644 index a157515..0000000 --- a/src/Moka/Generator/ProxyClassGenerator.php +++ /dev/null @@ -1,57 +0,0 @@ -doCall($name, $arguments); - } - }; - '; - - public static function generateCode(string $classWillBeEtended): string - { - $reflection = new \ReflectionClass($classWillBeEtended); - $methods = $reflection->getMethods(); - $methodsArray = []; - $p = array_fill(0, 2, ''); - - foreach ($methods as $method) { - if (!$method->isFinal() && !in_array($method->getName(), self::UNSAFE_METHODS, true)) { - $methodsArray[] = ProxyMethodGenerator::generateMethodString($method); - } - - if ($method->getName() === '__call') { - $callParameters = $method->getParameters(); - foreach ($callParameters as $callParameter) { - $p[$callParameter->getPosition()] = (string)$callParameter->getType(); - } - } - } - - list($callName, $callArguments) = $p; - - return sprintf( - self::$template, - $classWillBeEtended, - ProxyInterface::class, - ProxyTrait::class, - implode(PHP_EOL, $methodsArray), - $callName?? '', - $callArguments?? '' - ); - } -} diff --git a/src/Moka/Generator/ProxyGenerator.php b/src/Moka/Generator/ProxyGenerator.php index c2a8f72..3532839 100644 --- a/src/Moka/Generator/ProxyGenerator.php +++ b/src/Moka/Generator/ProxyGenerator.php @@ -3,27 +3,61 @@ namespace Moka\Generator; +use Moka\Exception\MockNotCreatedException; +use Moka\Generator\Template\ProxyClassTemplate; use Moka\Proxy\ProxyInterface; use Moka\Strategy\MockingStrategyInterface; +/** + * Class ProxyGenerator + * @package Moka\Generator + */ class ProxyGenerator { + /** + * @var MockingStrategyInterface + */ private $mockingStrategy; + /** + * ProxyGenerator constructor. + * @param MockingStrategyInterface $mockingStrategy + */ public function __construct(MockingStrategyInterface $mockingStrategy) { $this->mockingStrategy = $mockingStrategy; } - final public function generate($fqcn): ProxyInterface + /** + * @param string $fqcn + * @return ProxyInterface + * + * @throws MockNotCreatedException + */ + public function get(string $fqcn): ProxyInterface { - $object = $this->mockingStrategy->build($fqcn); - $codeWillBeEvaluated = ProxyClassGenerator::generateCode(get_class($object)); + $mock = $this->mockingStrategy->build($fqcn); + $mockFQCN = get_class($this->mockingStrategy->get($mock)); + $mockClass = new \ReflectionClass($mockFQCN); + + $proxyCode = ProxyClassTemplate::generate($mockClass); + $proxyFQCN = eval($proxyCode); + + return $this->getInstance($proxyFQCN) + ->_moka_setMock($mock) + ->_moka_setMockingStrategy($this->mockingStrategy); + } + + /** + * @param string $proxyFQCN + * @return ProxyInterface|ProxyTrait + */ + protected function getInstance(string $proxyFQCN): ProxyInterface + { + $proxyClass = new \ReflectionClass($proxyFQCN); /** @var ProxyInterface|ProxyTrait $proxy */ - $proxy = eval($codeWillBeEvaluated); - $proxy->_moka_setObject($object); - $proxy->_moka_setMockingStrategy($this->mockingStrategy); + $proxy = $proxyClass->newInstanceWithoutConstructor(); return $proxy; } diff --git a/src/Moka/Generator/ProxyMethodGenerator.php b/src/Moka/Generator/ProxyMethodGenerator.php deleted file mode 100644 index f064c59..0000000 --- a/src/Moka/Generator/ProxyMethodGenerator.php +++ /dev/null @@ -1,52 +0,0 @@ -__call("%s", func_get_args()); - } - '; - - public static function generateMethodString(\ReflectionMethod $method) - { - $static = $method->isStatic() ? 'static' : ''; - $originalReturnType = $method->getReturnType(); - - $returnType = !$originalReturnType ? '' : ProxyReturnGenerator::generateMethodReturnType($originalReturnType, $method); - - $parameters = $method->getParameters(); - $arguments = []; - if ($parameters) { - foreach ($method->getParameters() as $parameter) { - $arguments[] = ProxyArgumentGenerator::generateMethodParameter($parameter); - } - } - - $method->getReturnType(); - - $returnStatement = 'return '; - if (null !== $originalReturnType && self::getType($originalReturnType) === 'void') { - $returnStatement = ''; - } - - return sprintf( - self::$template, - $static, - $method->getName(), - implode(', ', $arguments), - $returnType, - $returnStatement, - $method->getName() - ); - } - - protected static function getType(\ReflectionType $type) - { - return (string)$type; - } -} diff --git a/src/Moka/Generator/ProxyReturnGenerator.php b/src/Moka/Generator/ProxyReturnGenerator.php deleted file mode 100644 index 1ffbc57..0000000 --- a/src/Moka/Generator/ProxyReturnGenerator.php +++ /dev/null @@ -1,31 +0,0 @@ -allowsNull()) { - $allowNull = '?'; - } - - $returnType = self::getType($type); - if ($returnType === 'self') { - $returnType = $method->getDeclaringClass()->getName(); - } - - return sprintf( - ':%s%s', - $allowNull, - $returnType - ); - } - - public static function getType(\ReflectionType $type) - { - return (string)$type; - } -} diff --git a/src/Moka/Generator/ProxyTrait.php b/src/Moka/Generator/ProxyTrait.php index 95e000d..71963f0 100644 --- a/src/Moka/Generator/ProxyTrait.php +++ b/src/Moka/Generator/ProxyTrait.php @@ -9,6 +9,10 @@ use Moka\Proxy\ProxyInterface; use Moka\Strategy\MockingStrategyInterface; +/** + * Trait ProxyTrait + * @package Moka\Generator + */ trait ProxyTrait { /** @@ -21,21 +25,33 @@ trait ProxyTrait */ private $mockingStrategy; + /** + * ProxyTrait constructor. + */ public function __construct() { } /** - * @param mixed $object + * @param $mock + * @return ProxyInterface|ProxyTrait */ - public function _moka_setObject($object) + public function _moka_setMock($mock): self { - $this->mock = $object; + $this->mock = $mock; + + return $this; } - public function _moka_setMockingStrategy(MockingStrategyInterface $mockingStrategy) + /** + * @param MockingStrategyInterface $mockingStrategy + * @return ProxyInterface|ProxyTrait + */ + public function _moka_setMockingStrategy(MockingStrategyInterface $mockingStrategy): self { $this->mockingStrategy = $mockingStrategy; + + return $this; } /** @@ -47,6 +63,7 @@ public function _moka_setMockingStrategy(MockingStrategyInterface $mockingStrate */ public function stub(array $methodsWithValues): ProxyInterface { + /** @var $this ProxyInterface */ $this->mockingStrategy->decorate($this->mock, $methodsWithValues); return $this; @@ -64,6 +81,11 @@ public function serve() return $this->mock; } + /** + * @param string $name + * @param array $arguments + * @return mixed + */ protected function doCall(string $name, array $arguments) { if ($this->mockingStrategy instanceof MockingStrategyInterface) { diff --git a/src/Moka/Generator/Template/ProxyClassTemplate.php b/src/Moka/Generator/Template/ProxyClassTemplate.php new file mode 100644 index 0000000..e5b39f2 --- /dev/null +++ b/src/Moka/Generator/Template/ProxyClassTemplate.php @@ -0,0 +1,91 @@ +doCall($name, $arguments); + } + }; + + return "%s"; + '; + + /** + * @param \ReflectionClass $class + * @return string + */ + public static function generate(\Reflector $class): string + { + return static::doGenerate($class); + } + + /** + * @param \ReflectionClass $class + * @return string + */ + protected static function doGenerate(\ReflectionClass $class): string + { + $methods = $class->getMethods(); + $methodsCode = []; + + $callParametersTypes = array_fill(0, 2, ''); + + foreach ($methods as $method) { + if ( + !$method->isFinal() && + !in_array($method->getName(), self::UNSAFE_METHODS, true) + ) { + $methodsCode[] = ProxyMethodTemplate::generate($method); + } + + if ('__call' === $method->getName()) { + $callParameters = $method->getParameters(); + foreach ($callParameters as $callParameter) { + $callParametersTypes[$callParameter->getPosition()] = (string)$callParameter->getType(); + } + } + } + + $mockClassName = $class->getName(); + $proxyClassName = sprintf( + self::TEMPLATE_FQCN, + preg_replace('/\\\/', '__', $mockClassName), + mt_rand() + ); + + list($callNameType, $callArgumentsType) = $callParametersTypes; + + return sprintf( + self::TEMPLATE, + $proxyClassName, + $mockClassName, + ProxyInterface::class, + ProxyTrait::class, + implode(PHP_EOL, $methodsCode), + $callNameType ?? '', + $callArgumentsType ?? '', + $proxyClassName + ); + } +} diff --git a/src/Moka/Generator/Template/ProxyMethodTemplate.php b/src/Moka/Generator/Template/ProxyMethodTemplate.php new file mode 100644 index 0000000..0de89fe --- /dev/null +++ b/src/Moka/Generator/Template/ProxyMethodTemplate.php @@ -0,0 +1,65 @@ +__call("%s", func_get_args()); + } + '; + + /** + * @param \ReflectionMethod $method + * @return string + */ + public static function generate(\Reflector $method): string + { + return static::doGenerate($method); + } + + /** + * @param \ReflectionMethod $method + * @return string + */ + protected static function doGenerate(\ReflectionMethod $method): string + { + $static = $method->isStatic() ? 'static' : ''; + + $parameters = $method->getParameters(); + $parametersCode = []; + if ($parameters) { + foreach ($parameters as $parameter) { + $parametersCode[] = ProxyParameterTemplate::generate($parameter); + } + } + + $originalReturnType = $method->getReturnType(); + $returnType = $originalReturnType + ? ProxyReturnTypeTemplate::generate($method) + : ''; + + $returnStatement = null === $originalReturnType || 'void' !== (string)$originalReturnType + ? 'return' + : ''; + + $methodName = $method->getName(); + + return sprintf( + self::TEMPLATE, + $static, + $methodName, + implode(',', $parametersCode), + $returnType, + $returnStatement, + $methodName + ); + } +} diff --git a/src/Moka/Generator/Template/ProxyParameterTemplate.php b/src/Moka/Generator/Template/ProxyParameterTemplate.php new file mode 100644 index 0000000..450b11f --- /dev/null +++ b/src/Moka/Generator/Template/ProxyParameterTemplate.php @@ -0,0 +1,65 @@ +allowsNull() + ? var_export($parameter->getDefaultValue(), true) + : 'null'; + + $defaultValue = '=' . $defaultValue; + } catch (\ReflectionException $exception) { + $defaultValue = ''; + } + + $type = $parameter->getType() + ? (string)$parameter->getType() + : ''; + + $isPassedByReference = $parameter->isPassedByReference() + ? '&' + : ''; + + $isVariadic = ''; + if ($parameter->isVariadic()) { + $isVariadic = '...'; + $isPassedByReference = ''; + $defaultValue = ''; + } + + $name = '$' . $parameter->getName(); + + return sprintf( + self::TEMPLATE, + $type, + $isVariadic, + $isPassedByReference, + $name, + $defaultValue + ); + } +} diff --git a/src/Moka/Generator/Template/ProxyReturnTypeTemplate.php b/src/Moka/Generator/Template/ProxyReturnTypeTemplate.php new file mode 100644 index 0000000..65b715d --- /dev/null +++ b/src/Moka/Generator/Template/ProxyReturnTypeTemplate.php @@ -0,0 +1,44 @@ +getReturnType(); + $allowsNull = $originalReturnType->allowsNull() + ? '?' + : ''; + + $returnType = 'self' === (string)$originalReturnType + ? $method->getDeclaringClass()->getName() + : (string)$originalReturnType; + + return sprintf( + self::TEMPLATE, + $allowsNull, + $returnType + ); + } +} diff --git a/src/Moka/Generator/Template/ProxyTemplateInterface.php b/src/Moka/Generator/Template/ProxyTemplateInterface.php new file mode 100644 index 0000000..9ba3cfe --- /dev/null +++ b/src/Moka/Generator/Template/ProxyTemplateInterface.php @@ -0,0 +1,17 @@ +reveal(), $name, $arguments); + $this->checkMockType($mock); + + $methodProphecies = $mock->getMethodProphecies($name); + if (count($methodProphecies) > 0) { + return parent::doCall($mock->reveal(), $name, $arguments); + } + + return parent::doCall($mock, $name, $arguments); } } diff --git a/src/Moka/Plugin/Prophecy/moka.php b/src/Moka/Plugin/Prophecy/moka.php new file mode 100644 index 0000000..d115dd0 --- /dev/null +++ b/src/Moka/Plugin/Prophecy/moka.php @@ -0,0 +1,18 @@ +checkMockType($mock); + + return $this->doGet($mock); + } + + /** + * @param object $mock + * @param string $name + * @param array $arguments + * @return mixed + */ + public function call($mock, string $name, array $arguments) + { + $this->checkMockType($mock); + + return $this->doCall($mock, $name, $arguments); + } + + /** + * @return string + * + * @throws NotImplementedException + */ + public function getMockType(): string + { + $this->verifyMockType(); + + return $this->mockType; + } + + /** + * @param string $fqcn + */ + final protected function setMockType(string $fqcn) + { + $this->mockType = $fqcn; + } + /** * @param object $mock * @@ -121,25 +162,17 @@ private function verifyMockType() } /** - * @param object $mock - * @param Stub $stub - * @return void + * @param string $fqcn + * @return object */ - abstract protected function doDecorate($mock, Stub $stub); + abstract protected function doBuild(string $fqcn); /** * @param object $mock - * @return object - * - * @throws NotImplementedException - * @throws InvalidArgumentException + * @param Stub $stub + * @return void */ - public function get($mock) - { - $this->checkMockType($mock); - - return $this->doGet($mock); - } + abstract protected function doDecorate($mock, Stub $stub); /** * @param object $mock @@ -148,27 +181,13 @@ public function get($mock) abstract protected function doGet($mock); /** - * @return string - * - * @throws NotImplementedException + * @param object $target + * @param string $name + * @param array $arguments + * @return mixed */ - public function getMockType(): string - { - $this->verifyMockType(); - - return $this->mockType; - } - - /** - * @param string $fqcn - */ - final protected function setMockType(string $fqcn) - { - $this->mockType = $fqcn; - } - - public function call($object, string $name, array $arguments) + protected function doCall($target, string $name, array $arguments) { - return $object->$name(...$arguments); + return $target->$name(...$arguments); } } diff --git a/src/Moka/Strategy/MockingStrategyInterface.php b/src/Moka/Strategy/MockingStrategyInterface.php index 386b701..1c25b15 100644 --- a/src/Moka/Strategy/MockingStrategyInterface.php +++ b/src/Moka/Strategy/MockingStrategyInterface.php @@ -37,12 +37,18 @@ public function decorate($mock, array $stubs); */ public function get($mock); + /** + * @param object $mock + * @param string $name + * @param array $arguments + * @return mixed + */ + public function call($mock, string $name, array $arguments); + /** * @return string * * @throws NotImplementedException */ public function getMockType(): string; - - public function call($object, string $name, array $arguments); } diff --git a/src/Moka/Traits/MokaMockeryTrait.php b/src/Moka/Traits/MokaMockeryTrait.php index 557338f..b42da63 100644 --- a/src/Moka/Traits/MokaMockeryTrait.php +++ b/src/Moka/Traits/MokaMockeryTrait.php @@ -10,6 +10,8 @@ /** * Trait MokaMockeryTrait * @package Moka\Traits + * + * @deprecated since v2.0.0 */ trait MokaMockeryTrait { @@ -17,6 +19,8 @@ trait MokaMockeryTrait * @param string $fqcnOrAlias * @param string|null $alias * @return ProxyInterface|MockInterface + * + * @deprecated since v2.0.0 */ protected function moka(string $fqcnOrAlias, string $alias = null): ProxyInterface { diff --git a/src/Moka/Traits/MokaPHPUnitTrait.php b/src/Moka/Traits/MokaPHPUnitTrait.php index 283744e..c6eaa88 100644 --- a/src/Moka/Traits/MokaPHPUnitTrait.php +++ b/src/Moka/Traits/MokaPHPUnitTrait.php @@ -10,6 +10,8 @@ /** * Trait MokaPHPUnitTrait * @package Moka\Traits + * + * @deprecated since v2.0.0 */ trait MokaPHPUnitTrait { @@ -17,6 +19,8 @@ trait MokaPHPUnitTrait * @param string $fqcnOrAlias * @param string|null $alias * @return ProxyInterface|MockObject + * + * @deprecated since v2.0.0 */ protected function moka(string $fqcnOrAlias, string $alias = null): ProxyInterface { diff --git a/src/Moka/Traits/MokaPhakeTrait.php b/src/Moka/Traits/MokaPhakeTrait.php index 321f13f..a9a9053 100644 --- a/src/Moka/Traits/MokaPhakeTrait.php +++ b/src/Moka/Traits/MokaPhakeTrait.php @@ -10,6 +10,8 @@ /** * Trait MokaPhakeTrait * @package Moka\Traits + * + * @deprecated since v2.0.0 */ trait MokaPhakeTrait { @@ -17,6 +19,8 @@ trait MokaPhakeTrait * @param string $fqcnOrAlias * @param string|null $alias * @return ProxyInterface|PhakeMock + * + * @deprecated since v2.0.0 */ protected function moka(string $fqcnOrAlias, string $alias = null): ProxyInterface { diff --git a/src/Moka/Traits/MokaProphecyTrait.php b/src/Moka/Traits/MokaProphecyTrait.php index 28c9092..63c3642 100644 --- a/src/Moka/Traits/MokaProphecyTrait.php +++ b/src/Moka/Traits/MokaProphecyTrait.php @@ -10,6 +10,8 @@ /** * Trait MokaProphecyTrait * @package Moka\Traits + * + * @deprecated since v2.0.0 */ trait MokaProphecyTrait { @@ -17,6 +19,8 @@ trait MokaProphecyTrait * @param string $fqcnOrAlias * @param string|null $alias * @return ProxyInterface|ObjectProphecy + * + * @deprecated since v2.0.0 */ protected function moka(string $fqcnOrAlias, string $alias = null): ProxyInterface { diff --git a/tests/GeneratorTest.php b/tests/GeneratorTest.php index eabedce..79ac11b 100644 --- a/tests/GeneratorTest.php +++ b/tests/GeneratorTest.php @@ -11,7 +11,7 @@ class GeneratorTest extends TestCase { /** - * @var \Moka\Generator\ProxyClassGenerator + * @var ProxyGenerator */ private $proxyGenerator; @@ -25,7 +25,7 @@ public function setUp() public function testCreation() { /** @var ProxyInterface|FooTestClass $proxy */ - $proxy = $this->proxyGenerator->generate(FooTestClass::class); + $proxy = $this->proxyGenerator->get(FooTestClass::class); $this->assertInstanceOf(ProxyInterface::class, $proxy); } @@ -34,7 +34,7 @@ public function testUseMockEngineMethod() { /** @var ProxyInterface|FooTestClass $proxy */ - $proxy = $this->proxyGenerator->generate(FooTestClass::class); + $proxy = $this->proxyGenerator->get(FooTestClass::class); $proxy->expects($this->any()) ->method('something') diff --git a/tests/Plugin/Prophecy/ProphecyMockingStrategyTest.php b/tests/Plugin/Prophecy/ProphecyMockingStrategyTest.php index d7ad65a..78e31c5 100644 --- a/tests/Plugin/Prophecy/ProphecyMockingStrategyTest.php +++ b/tests/Plugin/Prophecy/ProphecyMockingStrategyTest.php @@ -8,6 +8,7 @@ use Moka\Tests\MokaMockingStrategyTestCase; use Prophecy\Doubler\Doubler; use Prophecy\Doubler\LazyDouble; +use Prophecy\Prophecy\MethodProphecy; use Prophecy\Prophecy\ObjectProphecy; use Tests\FooTestClass; use Tests\TestInterface; @@ -91,4 +92,27 @@ public function testGetMultipleFakeFQCNFailure() $this->assertFalse(is_a($this->strategy->get($mock), $fqcn1)); $this->assertFalse(is_a($this->strategy->get($mock), $fqcn2)); } + + public function testCallObjectProphecy() + { + $mock = $this->strategy->build(FooTestClass::class); + + $this->assertInstanceOf( + MethodProphecy::class, + $this->strategy->call($mock, 'withArgument', []) + ); + } + + public function testCallMockedObject() + { + $mock = $this->strategy->build(FooTestClass::class); + $this->strategy->decorate($mock, [ + 'withArgument' => 1 + ]); + + $this->assertEquals( + 1, + $this->strategy->call($mock, 'withArgument', [1]) + ); + } } diff --git a/tests/Proxy/ProxyContainerTest.php b/tests/Proxy/ProxyContainerTest.php index 8d5b1ef..69a3e23 100644 --- a/tests/Proxy/ProxyContainerTest.php +++ b/tests/Proxy/ProxyContainerTest.php @@ -4,8 +4,8 @@ namespace Tests\Proxy; use Moka\Exception\InvalidIdentifierException; -use Moka\Proxy\ProxyInterface; use Moka\Proxy\ProxyContainer; +use Moka\Proxy\ProxyInterface; use PHPUnit\Framework\TestCase; class ProxyContainerTest extends TestCase From 94905c867894074bff7cb5e2135efe13ae96c928 Mon Sep 17 00:00:00 2001 From: Alberto Villa Date: Thu, 29 Jun 2017 16:10:35 +0200 Subject: [PATCH 14/46] Remove deprecated functionality --- src/Moka/Generator/ProxyTrait.php | 14 ++------- src/Moka/Moka.php | 25 +++------------- src/Moka/Proxy/ProxyInterface.php | 9 ------ src/Moka/Traits/MokaMockeryTrait.php | 41 --------------------------- src/Moka/Traits/MokaPHPUnitTrait.php | 41 --------------------------- src/Moka/Traits/MokaPhakeTrait.php | 41 --------------------------- src/Moka/Traits/MokaProphecyTrait.php | 41 --------------------------- src/Moka/Traits/MokaTrait.php | 28 ------------------ tests/MokaTest.php | 1 - 9 files changed, 6 insertions(+), 235 deletions(-) delete mode 100644 src/Moka/Traits/MokaMockeryTrait.php delete mode 100644 src/Moka/Traits/MokaPHPUnitTrait.php delete mode 100644 src/Moka/Traits/MokaPhakeTrait.php delete mode 100644 src/Moka/Traits/MokaProphecyTrait.php delete mode 100644 src/Moka/Traits/MokaTrait.php diff --git a/src/Moka/Generator/ProxyTrait.php b/src/Moka/Generator/ProxyTrait.php index 71963f0..6b4f934 100644 --- a/src/Moka/Generator/ProxyTrait.php +++ b/src/Moka/Generator/ProxyTrait.php @@ -69,18 +69,6 @@ public function stub(array $methodsWithValues): ProxyInterface return $this; } - /** - * @return object - * - * @throws MockNotServedException - * - * @deprecated since v2.0.0 - */ - public function serve() - { - return $this->mock; - } - /** * @param string $name * @param array $arguments @@ -91,5 +79,7 @@ protected function doCall(string $name, array $arguments) if ($this->mockingStrategy instanceof MockingStrategyInterface) { return $this->mockingStrategy->call($this->mock, $name, $arguments); } + + return null; } } diff --git a/src/Moka/Moka.php b/src/Moka/Moka.php index 9484ea5..c99050d 100644 --- a/src/Moka/Moka.php +++ b/src/Moka/Moka.php @@ -21,10 +21,10 @@ * Class Moka * @package Moka * - * @method static Proxy|MockInterface mockery(string $fqcnOrAlias, string $alias = null) - * @method static Proxy|PhakeMock phake(string $fqcnOrAlias, string $alias = null) - * @method static Proxy|MockObject phpunit(string $fqcnOrAlias, string $alias = null) - * @method static Proxy|ObjectProphecy prophecy(string $fqcnOrAlias, string $alias = null) + * @method static ProxyInterface|MockInterface mockery(string $fqcnOrAlias, string $alias = null) + * @method static ProxyInterface|PhakeMock phake(string $fqcnOrAlias, string $alias = null) + * @method static ProxyInterface|MockObject phpunit(string $fqcnOrAlias, string $alias = null) + * @method static ProxyInterface|ObjectProphecy prophecy(string $fqcnOrAlias, string $alias = null) */ class Moka { @@ -56,23 +56,6 @@ public static function __callStatic(string $name, array $arguments) return ProxyBuilderFactory::get($mockingStrategy)->getProxy($fqcnOrAlias, $alias); } - /** - * @param string $fqcnOrAlias - * @param string|null $alias - * @return ProxyInterface - * - * @throws NotImplementedException - * @throws InvalidIdentifierException - * @throws MockNotCreatedException - * @throws MissingDependencyException - * - * @deprecated since v1.2.0 - */ - public static function brew(string $fqcnOrAlias, string $alias = null): ProxyInterface - { - return self::phpunit($fqcnOrAlias, $alias); - } - /** * @return void */ diff --git a/src/Moka/Proxy/ProxyInterface.php b/src/Moka/Proxy/ProxyInterface.php index e929a57..d23488d 100644 --- a/src/Moka/Proxy/ProxyInterface.php +++ b/src/Moka/Proxy/ProxyInterface.php @@ -21,13 +21,4 @@ interface ProxyInterface * @throws MockNotCreatedException */ public function stub(array $methodsWithValues): ProxyInterface; - - /** - * @return object - * - * @throws MockNotServedException - * - * @deprecated since v2.0.0 - */ - public function serve(); } diff --git a/src/Moka/Traits/MokaMockeryTrait.php b/src/Moka/Traits/MokaMockeryTrait.php deleted file mode 100644 index b42da63..0000000 --- a/src/Moka/Traits/MokaMockeryTrait.php +++ /dev/null @@ -1,41 +0,0 @@ -moka($fqcnOrAlias, $alias); - } -} diff --git a/src/Moka/Traits/MokaPHPUnitTrait.php b/src/Moka/Traits/MokaPHPUnitTrait.php deleted file mode 100644 index c6eaa88..0000000 --- a/src/Moka/Traits/MokaPHPUnitTrait.php +++ /dev/null @@ -1,41 +0,0 @@ -moka($fqcnOrAlias, $alias); - } -} diff --git a/src/Moka/Traits/MokaPhakeTrait.php b/src/Moka/Traits/MokaPhakeTrait.php deleted file mode 100644 index a9a9053..0000000 --- a/src/Moka/Traits/MokaPhakeTrait.php +++ /dev/null @@ -1,41 +0,0 @@ -moka($fqcnOrAlias, $alias); - } -} diff --git a/src/Moka/Traits/MokaProphecyTrait.php b/src/Moka/Traits/MokaProphecyTrait.php deleted file mode 100644 index 63c3642..0000000 --- a/src/Moka/Traits/MokaProphecyTrait.php +++ /dev/null @@ -1,41 +0,0 @@ -moka($fqcnOrAlias, $alias); - } -} diff --git a/src/Moka/Traits/MokaTrait.php b/src/Moka/Traits/MokaTrait.php deleted file mode 100644 index b48dc99..0000000 --- a/src/Moka/Traits/MokaTrait.php +++ /dev/null @@ -1,28 +0,0 @@ - Date: Thu, 29 Jun 2017 17:07:52 +0200 Subject: [PATCH 15/46] Document and update method names --- src/Moka/Generator/ProxyGenerator.php | 6 ++++-- src/Moka/Generator/ProxyTrait.php | 5 ++--- src/Moka/Generator/Template/ProxyClassTemplate.php | 1 + 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/Moka/Generator/ProxyGenerator.php b/src/Moka/Generator/ProxyGenerator.php index 3532839..22df206 100644 --- a/src/Moka/Generator/ProxyGenerator.php +++ b/src/Moka/Generator/ProxyGenerator.php @@ -3,6 +3,7 @@ namespace Moka\Generator; +use Moka\Exception\InvalidArgumentException; use Moka\Exception\MockNotCreatedException; use Moka\Generator\Template\ProxyClassTemplate; use Moka\Proxy\ProxyInterface; @@ -33,6 +34,7 @@ public function __construct(MockingStrategyInterface $mockingStrategy) * @return ProxyInterface * * @throws MockNotCreatedException + * @throws InvalidArgumentException */ public function get(string $fqcn): ProxyInterface { @@ -44,8 +46,8 @@ public function get(string $fqcn): ProxyInterface $proxyFQCN = eval($proxyCode); return $this->getInstance($proxyFQCN) - ->_moka_setMock($mock) - ->_moka_setMockingStrategy($this->mockingStrategy); + ->__moka_setMock($mock) + ->__moka_setMockingStrategy($this->mockingStrategy); } /** diff --git a/src/Moka/Generator/ProxyTrait.php b/src/Moka/Generator/ProxyTrait.php index 6b4f934..55b36aa 100644 --- a/src/Moka/Generator/ProxyTrait.php +++ b/src/Moka/Generator/ProxyTrait.php @@ -5,7 +5,6 @@ use Moka\Exception\InvalidArgumentException; use Moka\Exception\MockNotCreatedException; -use Moka\Exception\MockNotServedException; use Moka\Proxy\ProxyInterface; use Moka\Strategy\MockingStrategyInterface; @@ -36,7 +35,7 @@ public function __construct() * @param $mock * @return ProxyInterface|ProxyTrait */ - public function _moka_setMock($mock): self + public function __moka_setMock($mock): self { $this->mock = $mock; @@ -47,7 +46,7 @@ public function _moka_setMock($mock): self * @param MockingStrategyInterface $mockingStrategy * @return ProxyInterface|ProxyTrait */ - public function _moka_setMockingStrategy(MockingStrategyInterface $mockingStrategy): self + public function __moka_setMockingStrategy(MockingStrategyInterface $mockingStrategy): self { $this->mockingStrategy = $mockingStrategy; diff --git a/src/Moka/Generator/Template/ProxyClassTemplate.php b/src/Moka/Generator/Template/ProxyClassTemplate.php index e5b39f2..0b94481 100644 --- a/src/Moka/Generator/Template/ProxyClassTemplate.php +++ b/src/Moka/Generator/Template/ProxyClassTemplate.php @@ -20,6 +20,7 @@ class ProxyClassTemplate implements ProxyTemplateInterface class %s extends %s implements %s { use %s; + %s public function __call(%s $name, %s $arguments) From 6e629193523d630e1b1693836e278822d09fc0f2 Mon Sep 17 00:00:00 2001 From: Alberto Villa Date: Thu, 29 Jun 2017 17:08:08 +0200 Subject: [PATCH 16/46] Ignore moka() files in coverage --- phpunit.xml.dist | 1 + 1 file changed, 1 insertion(+) diff --git a/phpunit.xml.dist b/phpunit.xml.dist index f4f409e..aa8d12a 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -25,6 +25,7 @@ src src/Moka/Exception + src/Moka/Plugin/* src/Moka/Tests src/Moka/Traits From a605aa7928feeec92dc5fcbee3fec21b786f7fef Mon Sep 17 00:00:00 2001 From: Alberto Villa Date: Thu, 29 Jun 2017 17:38:22 +0200 Subject: [PATCH 17/46] Complete tests --- .../Template/ProxyReturnTypeTemplate.php | 2 +- tests/AbstractTestClass.php | 19 +++-- tests/Generator/ProxyGeneratorTest.php | 67 +++++++++++++++ tests/Generator/ProxyTraitTest.php | 82 +++++++++++++++++++ .../Template/ProxyClassTemplateTests.php | 19 +++++ .../Template/ProxyMethodTemplateTest.php | 20 +++++ .../Template/ProxyParameterTemplateTest.php | 23 ++++++ .../Template/ProxyReturnTypeTemplateTest.php | 34 ++++++++ tests/GeneratorTest.php | 60 -------------- tests/NewTestClass.php | 12 +++ tests/ProxyTestClass.php | 17 ++++ 11 files changed, 289 insertions(+), 66 deletions(-) create mode 100644 tests/Generator/ProxyGeneratorTest.php create mode 100644 tests/Generator/ProxyTraitTest.php create mode 100644 tests/Generator/Template/ProxyClassTemplateTests.php create mode 100644 tests/Generator/Template/ProxyMethodTemplateTest.php create mode 100644 tests/Generator/Template/ProxyParameterTemplateTest.php create mode 100644 tests/Generator/Template/ProxyReturnTypeTemplateTest.php delete mode 100644 tests/GeneratorTest.php create mode 100644 tests/NewTestClass.php create mode 100644 tests/ProxyTestClass.php diff --git a/src/Moka/Generator/Template/ProxyReturnTypeTemplate.php b/src/Moka/Generator/Template/ProxyReturnTypeTemplate.php index 65b715d..136c0d7 100644 --- a/src/Moka/Generator/Template/ProxyReturnTypeTemplate.php +++ b/src/Moka/Generator/Template/ProxyReturnTypeTemplate.php @@ -9,7 +9,7 @@ */ class ProxyReturnTypeTemplate implements ProxyTemplateInterface { - const TEMPLATE = ':%s%s'; + const TEMPLATE = ': %s%s'; /** * @param \ReflectionMethod $method diff --git a/tests/AbstractTestClass.php b/tests/AbstractTestClass.php index b9d7f8d..f1c8093 100644 --- a/tests/AbstractTestClass.php +++ b/tests/AbstractTestClass.php @@ -12,7 +12,7 @@ public function isTrue(): bool public function getInt(): int { - return 1; + return 11; } public function getSelf(): TestInterface @@ -20,8 +20,10 @@ public function getSelf(): TestInterface return $this; } - public function something() + public function getCallable(): ?callable { + return function () { + }; } public function withArgument(int $argument): int @@ -29,9 +31,16 @@ public function withArgument(int $argument): int return $argument; } - public function withArguments(int $argument = 1, string &$aCapo = PHP_EOL, FooTestClass $fooTestClass = null, array $array = [1], ...$otherParameters): int - { - return $argument; + public function withArguments( + int $required, + $nullable = null, + string &$byReference = PHP_EOL, + FooTestClass $class = null, + array $array = [3], + callable $callable = null, + ...$variadic + ): int { + return $required; } public function throwException() diff --git a/tests/Generator/ProxyGeneratorTest.php b/tests/Generator/ProxyGeneratorTest.php new file mode 100644 index 0000000..6e27e27 --- /dev/null +++ b/tests/Generator/ProxyGeneratorTest.php @@ -0,0 +1,67 @@ +getMockBuilder(FooTestClass::class) + ->disableOriginalConstructor() + ->getMock(); + + /** @var MockingStrategyInterface|MockObject $mockingStrategy */ + $mockingStrategy = $this->getMockBuilder(MockingStrategyInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + $mockingStrategy + ->method('build') + ->willReturn($mock); + + $mockingStrategy + ->method('get') + ->willReturn($mock); + + $mockingStrategy + ->method('call') + ->willReturnCallback(function ($target, $name, $arguments) { + return $target->$name(...$arguments); + }); + + $this->proxyGenerator = new ProxyGenerator($mockingStrategy); + } + + public function testGet() + { + $proxy = $this->proxyGenerator->get(FooTestClass::class); + + $this->assertInstanceOf(ProxyInterface::class, $proxy); + $this->assertInstanceOf(FooTestClass::class, $proxy); + } + + public function testCall() + { + /** @var ProxyInterface|MockObject|FooTestClass $proxy */ + $proxy = $this->proxyGenerator->get(FooTestClass::class); + + $proxy->method('getInt') + ->willReturn(1138); + + $this->assertInstanceOf(ProxyInterface::class, $proxy); + $this->assertEquals(1138, $proxy->getInt()); + } +} diff --git a/tests/Generator/ProxyTraitTest.php b/tests/Generator/ProxyTraitTest.php new file mode 100644 index 0000000..484b1b0 --- /dev/null +++ b/tests/Generator/ProxyTraitTest.php @@ -0,0 +1,82 @@ +proxy = new ProxyTestClass(); + + $this->mockingStrategy = $this->getMockBuilder(MockingStrategyInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->mock = $this->getMockBuilder(FooTestClass::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->proxy->__moka_setMock($this->mock); + } + + public function testStub() + { + $this->mockingStrategy + ->expects($this->once()) + ->method('decorate') + ->with( + $this->equalTo($this->mock), + ['getInt' => 1138] + ); + + $this->proxy->__moka_setMockingStrategy($this->mockingStrategy); + + $this->proxy->stub([ + 'getInt' => 1138 + ]); + } + + public function testCallSuccess() + { + $this->mockingStrategy + ->expects($this->once()) + ->method('call') + ->with( + $this->equalTo($this->mock), + 'getSelf', + [] + ); + + $this->proxy->__moka_setMockingStrategy($this->mockingStrategy); + + $this->proxy->__call('getSelf', []); + } + + public function testCallFailure() + { + $this->assertNull($this->proxy->__call('getSelf', [])); + } +} diff --git a/tests/Generator/Template/ProxyClassTemplateTests.php b/tests/Generator/Template/ProxyClassTemplateTests.php new file mode 100644 index 0000000..cc40d2d --- /dev/null +++ b/tests/Generator/Template/ProxyClassTemplateTests.php @@ -0,0 +1,19 @@ +assertRegExp('/class *Moka_stdClass_\d/', $code); + } +} diff --git a/tests/Generator/Template/ProxyMethodTemplateTest.php b/tests/Generator/Template/ProxyMethodTemplateTest.php new file mode 100644 index 0000000..0212cd6 --- /dev/null +++ b/tests/Generator/Template/ProxyMethodTemplateTest.php @@ -0,0 +1,20 @@ +assertRegExp('/public +function getCallable\(/', $code); + } +} diff --git a/tests/Generator/Template/ProxyParameterTemplateTest.php b/tests/Generator/Template/ProxyParameterTemplateTest.php new file mode 100644 index 0000000..1e97197 --- /dev/null +++ b/tests/Generator/Template/ProxyParameterTemplateTest.php @@ -0,0 +1,23 @@ +getParameters(); + + $code = ProxyParameterTemplate::generate( + $parameters[2] + ); + + $this->assertRegExp('/string +&\$byReference *= */', $code); + } +} diff --git a/tests/Generator/Template/ProxyReturnTypeTemplateTest.php b/tests/Generator/Template/ProxyReturnTypeTemplateTest.php new file mode 100644 index 0000000..8088f23 --- /dev/null +++ b/tests/Generator/Template/ProxyReturnTypeTemplateTest.php @@ -0,0 +1,34 @@ +assertRegExp('/: *\? *callable/', $code); + } + + public function testGenerateWithSelf() + { + if (version_compare(phpversion(), '7.1', '<')) { + $this->markTestSkipped('Unsupported on PHP < 7.1'); + } + + $code = ProxyReturnTypeTemplate::generate( + new \ReflectionMethod(NewTestClass::class, 'getSelfNew') + ); + + $this->assertRegExp('/: *Tests\\\NewTestClass/', $code); + } +} diff --git a/tests/GeneratorTest.php b/tests/GeneratorTest.php deleted file mode 100644 index 79ac11b..0000000 --- a/tests/GeneratorTest.php +++ /dev/null @@ -1,60 +0,0 @@ -proxyGenerator = new ProxyGenerator( - new PHPUnitMockingStrategy() - ); - } - - public function testCreation() - { - /** @var ProxyInterface|FooTestClass $proxy */ - $proxy = $this->proxyGenerator->get(FooTestClass::class); - - $this->assertInstanceOf(ProxyInterface::class, $proxy); - } - - public function testUseMockEngineMethod() - { - - /** @var ProxyInterface|FooTestClass $proxy */ - $proxy = $this->proxyGenerator->get(FooTestClass::class); - - $proxy->expects($this->any()) - ->method('something') - ->willReturn(new \stdClass()); - - $this->assertInstanceOf(\stdClass::class, $proxy->something()); - - $this->assertInstanceOf(ProxyInterface::class, $proxy); - } - -// public function testUseMockEngineMethodProphecy() -// { -// $mock = $this->prophesize(FooTestClass::class); -// /** @var ProxyInterface|FooTestClass $proxy */ -// $proxy = $this->proxyGenerator->generate($mock); -// -// $proxy->something()->willReturn(new \stdClass()); -// -// $this->assertInstanceOf(\stdClass::class, $proxy->something()); -// -// $this->assertInstanceOf(ProxyInterface::class, $proxy); -// } -} diff --git a/tests/NewTestClass.php b/tests/NewTestClass.php new file mode 100644 index 0000000..5583d35 --- /dev/null +++ b/tests/NewTestClass.php @@ -0,0 +1,12 @@ +doCall($name, $arguments); + } +} From 87e6d2a928f46fd762c9529921ecbf541dc18728 Mon Sep 17 00:00:00 2001 From: Alberto Villa Date: Thu, 29 Jun 2017 17:41:06 +0200 Subject: [PATCH 18/46] Check for variable value as they cannot be unset --- src/Moka/Generator/Template/ProxyClassTemplate.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Moka/Generator/Template/ProxyClassTemplate.php b/src/Moka/Generator/Template/ProxyClassTemplate.php index 0b94481..85e1101 100644 --- a/src/Moka/Generator/Template/ProxyClassTemplate.php +++ b/src/Moka/Generator/Template/ProxyClassTemplate.php @@ -84,8 +84,8 @@ protected static function doGenerate(\ReflectionClass $class): string ProxyInterface::class, ProxyTrait::class, implode(PHP_EOL, $methodsCode), - $callNameType ?? '', - $callArgumentsType ?? '', + $callNameType ?: '', + $callArgumentsType ?: '', $proxyClassName ); } From 20459203ac04fb759b08b05ad9dcf647eafd1522 Mon Sep 17 00:00:00 2001 From: Alberto Villa Date: Thu, 29 Jun 2017 17:49:33 +0200 Subject: [PATCH 19/46] Update docblocks --- src/Moka/Plugin/Mockery/moka.php | 2 +- src/Moka/Plugin/PHPUnit/moka.php | 2 +- src/Moka/Plugin/Phake/moka.php | 2 +- src/Moka/Plugin/Prophecy/moka.php | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Moka/Plugin/Mockery/moka.php b/src/Moka/Plugin/Mockery/moka.php index 7e88749..70e8210 100644 --- a/src/Moka/Plugin/Mockery/moka.php +++ b/src/Moka/Plugin/Mockery/moka.php @@ -10,7 +10,7 @@ /** * @param string $fqcnOrAlias * @param string|null $alias - * @return ProxyInterface|MockInterface; + * @return MockInterface|ProxyInterface */ function moka(string $fqcnOrAlias, string $alias = null): ProxyInterface { diff --git a/src/Moka/Plugin/PHPUnit/moka.php b/src/Moka/Plugin/PHPUnit/moka.php index 53fec91..25fbe05 100644 --- a/src/Moka/Plugin/PHPUnit/moka.php +++ b/src/Moka/Plugin/PHPUnit/moka.php @@ -10,7 +10,7 @@ /** * @param string $fqcnOrAlias * @param string|null $alias - * @return ProxyInterface|MockObject; + * @return MockObject|ProxyInterface */ function moka(string $fqcnOrAlias, string $alias = null): ProxyInterface { diff --git a/src/Moka/Plugin/Phake/moka.php b/src/Moka/Plugin/Phake/moka.php index fde6bb8..736a0be 100644 --- a/src/Moka/Plugin/Phake/moka.php +++ b/src/Moka/Plugin/Phake/moka.php @@ -10,7 +10,7 @@ /** * @param string $fqcnOrAlias * @param string|null $alias - * @return ProxyInterface|PhakeMock; + * @return PhakeMock|ProxyInterface */ function moka(string $fqcnOrAlias, string $alias = null): ProxyInterface { diff --git a/src/Moka/Plugin/Prophecy/moka.php b/src/Moka/Plugin/Prophecy/moka.php index d115dd0..0c8e330 100644 --- a/src/Moka/Plugin/Prophecy/moka.php +++ b/src/Moka/Plugin/Prophecy/moka.php @@ -10,7 +10,7 @@ /** * @param string $fqcnOrAlias * @param string|null $alias - * @return ProxyInterface|ObjectProphecy; + * @return ObjectProphecy|ProxyInterface */ function moka(string $fqcnOrAlias, string $alias = null): ProxyInterface { From 6f4474f66a4d5fd6df69857674cb718e795bbf7c Mon Sep 17 00:00:00 2001 From: Alberto Villa Date: Thu, 29 Jun 2017 18:45:39 +0200 Subject: [PATCH 20/46] Update README --- README.md | 74 ++++++++++++++++++++++++++++++------------------------- 1 file changed, 40 insertions(+), 34 deletions(-) diff --git a/README.md b/README.md index 761b0c1..be0907b 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ composer require --dev facile-it/moka ## Usage -To use **Moka** in your tests simply `use` the `MokaPHPUnitTrait` (see generators section [below](#strategies)) and run `Moka::clean()` before every test. A simple interface will let you create *moka* (mock) objects, and decorate them with *stub* methods with a fluent interface. +To use **Moka** in your tests simply `use` function `Moka\Plugin\PHPUnit\moka()` (see generators section [below](#strategies)) and run `Moka::clean()` before every test. A simple interface will let you create *moka* (mock) objects and decorate them with *stub* methods with a fluent interface. A complete example follows: @@ -30,23 +30,21 @@ A complete example follows: namespace Foo\Tests; use Moka\Moka; -use Moka\Traits\MokaPHPUnitTrait; +use function Moka\Plugin\PHPUnit\moka; class FooTest extends \AnyTestCase { - use MokaPHPUnitTrait; - private $foo; - public function setUp() + protected function setUp() { Moka::clean(); // The subject of the test. $this->foo = new Foo( - $this->moka(BarInterface::class)->stub([ + moka(BarInterface::class)->stub([ // Method name => return value. - 'method1' => $this->moka(AcmeInterface::class), + 'method1' => moka(AcmeInterface::class), 'method2' => true // Any return value. ]) ); @@ -56,7 +54,7 @@ class FooTest extends \AnyTestCase } ``` -Alternatively, instead of using the trait and `$this->moka(/* ... */)`, you can call `Moka::phpunit(string $fqcnOrAlias, string $alias = null): ProxyInterface`. +Alternatively, instead of using `moka()`, you can call `Moka::phpunit(string $fqcnOrAlias, string $alias = null): ProxyInterface`. Being such a simple project, **Moka** can be integrated in an already existing test suite with no effort. @@ -68,15 +66,15 @@ Being such a simple project, **Moka** can be integrated in an already existing t namespace Foo\Tests; +use function Moka\Plugin\PHPUnit\moka; use Moka\Traits\MokaCleanerTrait; -use Moka\Traits\MokaPHPUnitTrait; use PHPUnit\Framework\TestCase; class FooTest extends TestCase { - use MokaPHPUnitTrait, MokaCleanerTrait; + use MokaCleanerTrait; - public function setUp() + protected function setUp() { // No call to Moka::clean() needed. @@ -90,20 +88,20 @@ class FooTest extends TestCase You can rely on the original mock object implementation to be accessible (in the example below, PHPUnit's): ```php -$this->moka(BarInterface::class, 'bar') +moka(BarInterface::class, 'bar') ->expects($this->at(0)) ->method('isValid') ->willReturn(true); -$this->moka('bar') +moka('bar') ->expects($this->at(1)) ->method('isValid') ->willThrowException(new \Exception()); -var_dump($this->moka('bar')->isValid()); +var_dump(moka('bar')->isValid()); // bool(true) -var_dump($this->moka('bar')->isValid()); +var_dump(moka('bar')->isValid()); // throws \Exception ``` @@ -114,8 +112,8 @@ var_dump($this->moka('bar')->isValid()); Creates a proxy containing a mock object (according to the selected strategy) for the provided *FQCN* and optionally assigns an `$alias` to it to be able to get it later: ```php -$mock1 = $this->moka(FooInterface::class); // Creates the mock for FooInterface. -$mock2 = $this->moka(FooInterface::class); // Gets a different mock. +$mock1 = moka(FooInterface::class); // Creates the mock for FooInterface. +$mock2 = moka(FooInterface::class); // Gets a different mock. var_dump($mock1 === $mock2); // bool(false) @@ -124,25 +122,25 @@ var_dump($mock1 === $mock2); The `$alias` allows you to store mock instances: ```php -$mock1 = $this->moka(FooInterface::class, 'foo'); // Creates a mock for FooInterface. -$mock2 = $this->moka('foo'); // Get the mock previously created. +$mock1 = moka(FooInterface::class, 'foo'); // Creates a mock for FooInterface. +$mock2 = moka('foo'); // Get the mock previously created. var_dump($mock1 === $mock2); // bool(true) ``` -### `stub(array $methodsWithValues): ProxyInterface` +### `ProxyInterface::stub(array $methodsWithValues): ProxyInterface` Accepts an array of method stubs with format `[$methodName => $methodValue]`, where `$methodName` **must** be a string and `$methodValue` can be of any type, including another mock object or an exception instance: ```php -$actualMock = $this->moka(BarInterface::class)->stub([ +$mock = moka(BarInterface::class)->stub([ 'isValid' => true, - 'getMock' => $this->moka(AcmeInterface::class), + 'getMock' => moka(AcmeInterface::class), 'throwException' => new \Exception() ]); -var_dump($actualMock->isValid()); +var_dump($mock->isValid()); // bool(true) ``` @@ -158,14 +156,12 @@ We support other generators as well, but you need to install the relevant packag - [Mockery](http://docs.mockery.io/en/latest/) -> [mockery/mockery](https://packagist.org/packages/mockery/mockery) - [Phake](http://phake.readthedocs.io/) -> [phake/phake](https://packagist.org/packages/phake/phake) -We provide a specific trait for each supported strategy, as well as a static method (self documented in the trait itself): - -- `MokaPHPUnitTrait` -- `MokaProphecyTrait` -- `MokaMockeryTrait` -- `MokaPhakeTrait` +We provide a specific `moka()` function for each supported strategy, as well as a static method (self documented in the function itself): -Every trait defines its own `moka(string $fqcnOrAlias, string $alias = null): ProxyInterface`, as described in the **[Reference](#reference)**. +- `Moka\Plugin\PHPUnit\moka` +- `Moka\Plugin\Prophecy\moka` +- `Moka\Plugin\Mockery\moka` +- `Moka\Plugin\Phake\moka` ## Plugin development @@ -200,21 +196,31 @@ use Moka\Stub\Stub; class YourOwnMockingStrategy extends AbstractMockingStrategy { - public function __construct() { + public function __construct() + { // TODO: Implement __construct() method. } - protected function doBuild(string $fqcn) { + protected function doBuild(string $fqcn) + { // TODO: Implement doBuild() method. } - protected function doDecorate($mock, Stub $stub) { + protected function doDecorate($mock, Stub $stub) + { // TODO: Implement doDecorate() method. } - protected function doGet($mock) { + protected function doGet($mock) + { // TODO: Implement doGet() method. } + + protected function doCall($target, string $name, array $arguments) + { + // Override doCall() if you need special behavior. + // See ProphecyMockingStrategy::doCall(). + } } ``` From 7a256746252c40ca942085359bf1dc95443e5392 Mon Sep 17 00:00:00 2001 From: Alberto Villa Date: Thu, 29 Jun 2017 18:51:44 +0200 Subject: [PATCH 21/46] Remove stale `use` --- src/Moka/Moka.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Moka/Moka.php b/src/Moka/Moka.php index c99050d..0754c50 100644 --- a/src/Moka/Moka.php +++ b/src/Moka/Moka.php @@ -10,7 +10,6 @@ use Moka\Exception\NotImplementedException; use Moka\Factory\ProxyBuilderFactory; use Moka\Plugin\PluginHelper; -use Moka\Proxy\Proxy; use Moka\Proxy\ProxyInterface; use Moka\Strategy\MockingStrategyInterface; use Phake_IMock as PhakeMock; From 1a261dbd4525e943f13437c3cbccfb2cda076a98 Mon Sep 17 00:00:00 2001 From: Alberto Villa Date: Fri, 30 Jun 2017 03:12:28 +0200 Subject: [PATCH 22/46] Cleanup README a little more --- README.md | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index be0907b..cfc5c3f 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ Tired of spending most of your testing time mocking objects like there's no tomo ## Installation -You can simply install the package via composer: +You can install the package via composer: ```bash composer require --dev facile-it/moka @@ -20,9 +20,7 @@ composer require --dev facile-it/moka ## Usage -To use **Moka** in your tests simply `use` function `Moka\Plugin\PHPUnit\moka()` (see generators section [below](#strategies)) and run `Moka::clean()` before every test. A simple interface will let you create *moka* (mock) objects and decorate them with *stub* methods with a fluent interface. - -A complete example follows: +To use **Moka** in your tests simply `use` function `Moka\Plugin\PHPUnit\moka()` (see generators section [below](#strategies)) and run `Moka::clean()` before every test. A simple interface will let you create *moka* (mock) objects and decorate them with *stub* methods via a fluent interface: ```php $methodValue]`, where `$methodName` **must** be a string and `$methodValue` can be of any type, including another mock object or an exception instance: +Accepts an array of method stubs with format `[$methodName => $methodValue]`, where `$methodName` **must** be a string and `$methodValue` can be of any type, including another mock object or an exception instance (which will be thrown): ```php $mock = moka(BarInterface::class)->stub([ @@ -144,7 +142,7 @@ var_dump($mock->isValid()); // bool(true) ``` -**Notice:** the stub is valid for **any** invocation of the method and it cannot be overridden. +**Notice:** the stub is valid for **any** invocation of the method and cannot be overridden. If you need more granular control over invocation strategies, you can get [access to the original mock object implementation](#original-mock). ## Supported mock object generators From b3f6d4929f1242278642c2b033921043e56436b4 Mon Sep 17 00:00:00 2001 From: Alberto Villa Date: Fri, 30 Jun 2017 03:24:55 +0200 Subject: [PATCH 23/46] Fix tests and improve code quality --- src/Moka/Generator/Template/ProxyClassTemplate.php | 6 +++--- src/Moka/Generator/Template/ProxyMethodTemplate.php | 4 ++-- src/Moka/Generator/Template/ProxyParameterTemplate.php | 2 +- src/Moka/Generator/Template/ProxyReturnTypeTemplate.php | 2 +- tests/AbstractTestClass.php | 2 +- tests/Generator/Template/ProxyReturnTypeTemplateTest.php | 4 ++-- tests/NewTestClass.php | 2 +- 7 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/Moka/Generator/Template/ProxyClassTemplate.php b/src/Moka/Generator/Template/ProxyClassTemplate.php index 85e1101..142507f 100644 --- a/src/Moka/Generator/Template/ProxyClassTemplate.php +++ b/src/Moka/Generator/Template/ProxyClassTemplate.php @@ -55,12 +55,12 @@ protected static function doGenerate(\ReflectionClass $class): string foreach ($methods as $method) { if ( !$method->isFinal() && - !in_array($method->getName(), self::UNSAFE_METHODS, true) + !in_array($method->name, self::UNSAFE_METHODS, true) ) { $methodsCode[] = ProxyMethodTemplate::generate($method); } - if ('__call' === $method->getName()) { + if ('__call' === $method->name) { $callParameters = $method->getParameters(); foreach ($callParameters as $callParameter) { $callParametersTypes[$callParameter->getPosition()] = (string)$callParameter->getType(); @@ -68,7 +68,7 @@ protected static function doGenerate(\ReflectionClass $class): string } } - $mockClassName = $class->getName(); + $mockClassName = $class->name; $proxyClassName = sprintf( self::TEMPLATE_FQCN, preg_replace('/\\\/', '__', $mockClassName), diff --git a/src/Moka/Generator/Template/ProxyMethodTemplate.php b/src/Moka/Generator/Template/ProxyMethodTemplate.php index 0de89fe..c1ee8e7 100644 --- a/src/Moka/Generator/Template/ProxyMethodTemplate.php +++ b/src/Moka/Generator/Template/ProxyMethodTemplate.php @@ -35,7 +35,7 @@ protected static function doGenerate(\ReflectionMethod $method): string $parameters = $method->getParameters(); $parametersCode = []; - if ($parameters) { + if (is_array($parameters)) { foreach ($parameters as $parameter) { $parametersCode[] = ProxyParameterTemplate::generate($parameter); } @@ -50,7 +50,7 @@ protected static function doGenerate(\ReflectionMethod $method): string ? 'return' : ''; - $methodName = $method->getName(); + $methodName = $method->name; return sprintf( self::TEMPLATE, diff --git a/src/Moka/Generator/Template/ProxyParameterTemplate.php b/src/Moka/Generator/Template/ProxyParameterTemplate.php index 450b11f..43eea29 100644 --- a/src/Moka/Generator/Template/ProxyParameterTemplate.php +++ b/src/Moka/Generator/Template/ProxyParameterTemplate.php @@ -51,7 +51,7 @@ protected static function doGenerate(\ReflectionParameter $parameter): string $defaultValue = ''; } - $name = '$' . $parameter->getName(); + $name = '$' . $parameter->name; return sprintf( self::TEMPLATE, diff --git a/src/Moka/Generator/Template/ProxyReturnTypeTemplate.php b/src/Moka/Generator/Template/ProxyReturnTypeTemplate.php index 136c0d7..739c2fb 100644 --- a/src/Moka/Generator/Template/ProxyReturnTypeTemplate.php +++ b/src/Moka/Generator/Template/ProxyReturnTypeTemplate.php @@ -32,7 +32,7 @@ protected static function doGenerate(\ReflectionMethod $method): string : ''; $returnType = 'self' === (string)$originalReturnType - ? $method->getDeclaringClass()->getName() + ? $method->getDeclaringClass()->name : (string)$originalReturnType; return sprintf( diff --git a/tests/AbstractTestClass.php b/tests/AbstractTestClass.php index f1c8093..bce3c0c 100644 --- a/tests/AbstractTestClass.php +++ b/tests/AbstractTestClass.php @@ -20,7 +20,7 @@ public function getSelf(): TestInterface return $this; } - public function getCallable(): ?callable + public function getCallable(): callable { return function () { }; diff --git a/tests/Generator/Template/ProxyReturnTypeTemplateTest.php b/tests/Generator/Template/ProxyReturnTypeTemplateTest.php index 8088f23..c11a040 100644 --- a/tests/Generator/Template/ProxyReturnTypeTemplateTest.php +++ b/tests/Generator/Template/ProxyReturnTypeTemplateTest.php @@ -16,7 +16,7 @@ public function testGenerate() new \ReflectionMethod(FooTestClass::class, 'getCallable') ); - $this->assertRegExp('/: *\? *callable/', $code); + $this->assertRegExp('/: *callable/', $code); } public function testGenerateWithSelf() @@ -29,6 +29,6 @@ public function testGenerateWithSelf() new \ReflectionMethod(NewTestClass::class, 'getSelfNew') ); - $this->assertRegExp('/: *Tests\\\NewTestClass/', $code); + $this->assertRegExp('/: *\? *Tests\\\NewTestClass/', $code); } } diff --git a/tests/NewTestClass.php b/tests/NewTestClass.php index 5583d35..3635ca5 100644 --- a/tests/NewTestClass.php +++ b/tests/NewTestClass.php @@ -5,7 +5,7 @@ class NewTestClass extends AbstractTestClass { - public function getSelfNew(): self + public function getSelfNew(): ?self { return $this; } From b6a9c851c750f82069847c5a88f8a19af2d6f8a8 Mon Sep 17 00:00:00 2001 From: Alberto Villa Date: Fri, 30 Jun 2017 14:35:20 +0200 Subject: [PATCH 24/46] Add getter for the actual mock object --- src/Moka/Generator/ProxyTrait.php | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/Moka/Generator/ProxyTrait.php b/src/Moka/Generator/ProxyTrait.php index 55b36aa..8ff52ec 100644 --- a/src/Moka/Generator/ProxyTrait.php +++ b/src/Moka/Generator/ProxyTrait.php @@ -32,7 +32,15 @@ public function __construct() } /** - * @param $mock + * @return object + */ + public function __moka_getMock() + { + return $this->mock; + } + + /** + * @param object $mock * @return ProxyInterface|ProxyTrait */ public function __moka_setMock($mock): self From 84ebf1a353d0557be0e8e1ae191a7278c98730b9 Mon Sep 17 00:00:00 2001 From: Alberto Villa Date: Fri, 30 Jun 2017 14:48:32 +0200 Subject: [PATCH 25/46] Register PHPUnit and Prophecy mocks within the test case --- src/Moka/Moka.php | 98 ++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 93 insertions(+), 5 deletions(-) diff --git a/src/Moka/Moka.php b/src/Moka/Moka.php index 0754c50..84a3236 100644 --- a/src/Moka/Moka.php +++ b/src/Moka/Moka.php @@ -9,21 +9,22 @@ use Moka\Exception\MockNotCreatedException; use Moka\Exception\NotImplementedException; use Moka\Factory\ProxyBuilderFactory; +use Moka\Generator\ProxyTrait; use Moka\Plugin\PluginHelper; use Moka\Proxy\ProxyInterface; use Moka\Strategy\MockingStrategyInterface; use Phake_IMock as PhakeMock; +use PHPUnit\Framework\TestCase; use PHPUnit_Framework_MockObject_MockObject as MockObject; use Prophecy\Prophecy\ObjectProphecy; +use Prophecy\Prophet; /** * Class Moka * @package Moka * - * @method static ProxyInterface|MockInterface mockery(string $fqcnOrAlias, string $alias = null) - * @method static ProxyInterface|PhakeMock phake(string $fqcnOrAlias, string $alias = null) - * @method static ProxyInterface|MockObject phpunit(string $fqcnOrAlias, string $alias = null) - * @method static ProxyInterface|ObjectProphecy prophecy(string $fqcnOrAlias, string $alias = null) + * @method static MockInterface|ProxyInterface mockery(string $fqcnOrAlias, string $alias = null) + * @method static PhakeMock|ProxyInterface phake(string $fqcnOrAlias, string $alias = null) */ class Moka { @@ -42,7 +43,7 @@ class Moka * @throws MockNotCreatedException * @throws MissingDependencyException */ - public static function __callStatic(string $name, array $arguments) + public static function __callStatic(string $name, array $arguments): ProxyInterface { if (!isset(self::$mockingStrategies[$name])) { self::$mockingStrategies[$name] = PluginHelper::load($name); @@ -55,6 +56,68 @@ public static function __callStatic(string $name, array $arguments) return ProxyBuilderFactory::get($mockingStrategy)->getProxy($fqcnOrAlias, $alias); } + /** + * @param string $fqcnOrAlias + * @param string|null $alias + * @return MockObject|ProxyInterface + */ + public static function phpunit(string $fqcnOrAlias, string $alias = null): ProxyInterface + { + /** @var ProxyInterface|ProxyTrait $proxy */ + $proxy = self::__callStatic('phpunit', [$fqcnOrAlias, $alias]); + + if (null !== $testCase = self::getCurrentTestCase()) { + $testCase->registerMockObject($proxy->__moka_getMock()); + } + + return $proxy; + } + + /** + * @param string $fqcnOrAlias + * @param string|null $alias + * @return ObjectProphecy|ProxyInterface + */ + public static function prophecy(string $fqcnOrAlias, string $alias = null): ProxyInterface + { + /** @var ProxyInterface|ProxyTrait $proxy */ + $proxy = self::__callStatic('prophecy', [$fqcnOrAlias, $alias]); + + if (null !== $testCase = self::getCurrentTestCase()) { + try { + $prophetProperty = new \ReflectionProperty( + TestCase::class, + 'prophet' + ); + } catch (\ReflectionException $exception) { + $prophetProperty = new \ReflectionProperty( + \PHPUnit_Framework_TestCase::class, + 'prophet' + ); + } + + $prophetProperty->setAccessible(true); + if (null === $prophet = $prophetProperty->getValue($testCase)) { + $prophet = new Prophet(); + $prophetProperty->setValue($testCase, $prophet); + } + + $propheciesProperty = new \ReflectionProperty( + Prophet::class, + 'prophecies' + ); + $propheciesProperty->setAccessible(true); + + /** @var ObjectProphecy[] $prophecies */ + $prophecies = $propheciesProperty->getValue($prophet); + $prophecies[] = $proxy->__moka_getMock(); + + $propheciesProperty->setValue($prophet, $prophecies); + } + + return $proxy; + } + /** * @return void */ @@ -62,4 +125,29 @@ public static function clean() { ProxyBuilderFactory::reset(); } + + /** + * @return TestCase|null + */ + private static function getCurrentTestCase() + { + $backtrace = debug_backtrace(DEBUG_BACKTRACE_PROVIDE_OBJECT); + foreach ($backtrace as $frame) { + if (!isset($frame['object'])) { + continue; + } + + $object = $frame['object']; + if ( + $object instanceof TestCase || + $object instanceof \PHPUnit_Framework_TestCase + ) { + return $object; + } + + return null; + } + + return null; + } } From 4c62ecaccd0530af711173ee6f4e8ce527077148 Mon Sep 17 00:00:00 2001 From: Alberto Villa Date: Fri, 30 Jun 2017 15:05:39 +0200 Subject: [PATCH 26/46] Tidy up structure --- src/Moka/Generator/ProxyGenerator.php | 5 +++-- .../{ProxyClassTemplate.php => ClassTemplate.php} | 8 ++++---- .../{ProxyMethodTemplate.php => MethodTemplate.php} | 8 ++++---- .../{ProxyParameterTemplate.php => ParameterTemplate.php} | 4 ++-- ...ProxyReturnTypeTemplate.php => ReturnTypeTemplate.php} | 4 ++-- .../{ProxyTemplateInterface.php => TemplateInterface.php} | 4 ++-- src/Moka/Moka.php | 2 +- src/Moka/{Generator => Proxy}/ProxyTrait.php | 5 ++--- ...{ProxyClassTemplateTests.php => ClassTemplateTest.php} | 6 +++--- ...ProxyMethodTemplateTest.php => MethodTemplateTest.php} | 6 +++--- ...arameterTemplateTest.php => ParameterTemplateTest.php} | 6 +++--- ...urnTypeTemplateTest.php => ReturnTypeTemplateTest.php} | 8 ++++---- tests/{ProxyTestClass.php => Proxy/FakeProxy.php} | 6 +++--- tests/{Generator => Proxy}/ProxyTraitTest.php | 7 +++---- 14 files changed, 39 insertions(+), 40 deletions(-) rename src/Moka/Generator/Template/{ProxyClassTemplate.php => ClassTemplate.php} (91%) rename src/Moka/Generator/Template/{ProxyMethodTemplate.php => MethodTemplate.php} (85%) rename src/Moka/Generator/Template/{ProxyParameterTemplate.php => ParameterTemplate.php} (93%) rename src/Moka/Generator/Template/{ProxyReturnTypeTemplate.php => ReturnTypeTemplate.php} (90%) rename src/Moka/Generator/Template/{ProxyTemplateInterface.php => TemplateInterface.php} (78%) rename src/Moka/{Generator => Proxy}/ProxyTrait.php (95%) rename tests/Generator/Template/{ProxyClassTemplateTests.php => ClassTemplateTest.php} (66%) rename tests/Generator/Template/{ProxyMethodTemplateTest.php => MethodTemplateTest.php} (69%) rename tests/Generator/Template/{ProxyParameterTemplateTest.php => ParameterTemplateTest.php} (73%) rename tests/Generator/Template/{ProxyReturnTypeTemplateTest.php => ReturnTypeTemplateTest.php} (76%) rename tests/{ProxyTestClass.php => Proxy/FakeProxy.php} (68%) rename tests/{Generator => Proxy}/ProxyTraitTest.php (92%) diff --git a/src/Moka/Generator/ProxyGenerator.php b/src/Moka/Generator/ProxyGenerator.php index 22df206..c110029 100644 --- a/src/Moka/Generator/ProxyGenerator.php +++ b/src/Moka/Generator/ProxyGenerator.php @@ -5,8 +5,9 @@ use Moka\Exception\InvalidArgumentException; use Moka\Exception\MockNotCreatedException; -use Moka\Generator\Template\ProxyClassTemplate; +use Moka\Generator\Template\ClassTemplate; use Moka\Proxy\ProxyInterface; +use Moka\Proxy\ProxyTrait; use Moka\Strategy\MockingStrategyInterface; /** @@ -42,7 +43,7 @@ public function get(string $fqcn): ProxyInterface $mockFQCN = get_class($this->mockingStrategy->get($mock)); $mockClass = new \ReflectionClass($mockFQCN); - $proxyCode = ProxyClassTemplate::generate($mockClass); + $proxyCode = ClassTemplate::generate($mockClass); $proxyFQCN = eval($proxyCode); return $this->getInstance($proxyFQCN) diff --git a/src/Moka/Generator/Template/ProxyClassTemplate.php b/src/Moka/Generator/Template/ClassTemplate.php similarity index 91% rename from src/Moka/Generator/Template/ProxyClassTemplate.php rename to src/Moka/Generator/Template/ClassTemplate.php index 142507f..833e16c 100644 --- a/src/Moka/Generator/Template/ProxyClassTemplate.php +++ b/src/Moka/Generator/Template/ClassTemplate.php @@ -3,14 +3,14 @@ namespace Moka\Generator\Template; -use Moka\Generator\ProxyTrait; use Moka\Proxy\ProxyInterface; +use Moka\Proxy\ProxyTrait; /** - * Class ProxyClassTemplate + * Class ClassTemplate * @package Moka\Generator\Template */ -class ProxyClassTemplate implements ProxyTemplateInterface +class ClassTemplate implements TemplateInterface { const UNSAFE_METHODS = ['__construct', '__destruct', '__call', '__clone']; @@ -57,7 +57,7 @@ protected static function doGenerate(\ReflectionClass $class): string !$method->isFinal() && !in_array($method->name, self::UNSAFE_METHODS, true) ) { - $methodsCode[] = ProxyMethodTemplate::generate($method); + $methodsCode[] = MethodTemplate::generate($method); } if ('__call' === $method->name) { diff --git a/src/Moka/Generator/Template/ProxyMethodTemplate.php b/src/Moka/Generator/Template/MethodTemplate.php similarity index 85% rename from src/Moka/Generator/Template/ProxyMethodTemplate.php rename to src/Moka/Generator/Template/MethodTemplate.php index c1ee8e7..6a85e77 100644 --- a/src/Moka/Generator/Template/ProxyMethodTemplate.php +++ b/src/Moka/Generator/Template/MethodTemplate.php @@ -4,10 +4,10 @@ namespace Moka\Generator\Template; /** - * Class ProxyMethodTemplate + * Class MethodTemplate * @package Moka\Generator\Template */ -class ProxyMethodTemplate implements ProxyTemplateInterface +class MethodTemplate implements TemplateInterface { const TEMPLATE = ' public %s function %s(%s)%s @@ -37,13 +37,13 @@ protected static function doGenerate(\ReflectionMethod $method): string $parametersCode = []; if (is_array($parameters)) { foreach ($parameters as $parameter) { - $parametersCode[] = ProxyParameterTemplate::generate($parameter); + $parametersCode[] = ParameterTemplate::generate($parameter); } } $originalReturnType = $method->getReturnType(); $returnType = $originalReturnType - ? ProxyReturnTypeTemplate::generate($method) + ? ReturnTypeTemplate::generate($method) : ''; $returnStatement = null === $originalReturnType || 'void' !== (string)$originalReturnType diff --git a/src/Moka/Generator/Template/ProxyParameterTemplate.php b/src/Moka/Generator/Template/ParameterTemplate.php similarity index 93% rename from src/Moka/Generator/Template/ProxyParameterTemplate.php rename to src/Moka/Generator/Template/ParameterTemplate.php index 43eea29..6d8afc8 100644 --- a/src/Moka/Generator/Template/ProxyParameterTemplate.php +++ b/src/Moka/Generator/Template/ParameterTemplate.php @@ -4,10 +4,10 @@ namespace Moka\Generator\Template; /** - * Class ProxyParameterTemplate + * Class ParameterTemplate * @package Moka\Generator\Template */ -class ProxyParameterTemplate implements ProxyTemplateInterface +class ParameterTemplate implements TemplateInterface { const TEMPLATE = '%s %s%s%s%s'; diff --git a/src/Moka/Generator/Template/ProxyReturnTypeTemplate.php b/src/Moka/Generator/Template/ReturnTypeTemplate.php similarity index 90% rename from src/Moka/Generator/Template/ProxyReturnTypeTemplate.php rename to src/Moka/Generator/Template/ReturnTypeTemplate.php index 739c2fb..6b0f521 100644 --- a/src/Moka/Generator/Template/ProxyReturnTypeTemplate.php +++ b/src/Moka/Generator/Template/ReturnTypeTemplate.php @@ -4,10 +4,10 @@ namespace Moka\Generator\Template; /** - * Class ProxyReturnTypeTemplate + * Class ReturnTypeTemplate * @package Moka\Generator\Template */ -class ProxyReturnTypeTemplate implements ProxyTemplateInterface +class ReturnTypeTemplate implements TemplateInterface { const TEMPLATE = ': %s%s'; diff --git a/src/Moka/Generator/Template/ProxyTemplateInterface.php b/src/Moka/Generator/Template/TemplateInterface.php similarity index 78% rename from src/Moka/Generator/Template/ProxyTemplateInterface.php rename to src/Moka/Generator/Template/TemplateInterface.php index 9ba3cfe..2399df6 100644 --- a/src/Moka/Generator/Template/ProxyTemplateInterface.php +++ b/src/Moka/Generator/Template/TemplateInterface.php @@ -4,10 +4,10 @@ namespace Moka\Generator\Template; /** - * Interface ProxyTemplateInterface + * Interface TemplateInterface * @package Moka\Generator\Template */ -interface ProxyTemplateInterface +interface TemplateInterface { /** * @param \Reflector $reflector diff --git a/src/Moka/Moka.php b/src/Moka/Moka.php index 84a3236..9a687dd 100644 --- a/src/Moka/Moka.php +++ b/src/Moka/Moka.php @@ -9,9 +9,9 @@ use Moka\Exception\MockNotCreatedException; use Moka\Exception\NotImplementedException; use Moka\Factory\ProxyBuilderFactory; -use Moka\Generator\ProxyTrait; use Moka\Plugin\PluginHelper; use Moka\Proxy\ProxyInterface; +use Moka\Proxy\ProxyTrait; use Moka\Strategy\MockingStrategyInterface; use Phake_IMock as PhakeMock; use PHPUnit\Framework\TestCase; diff --git a/src/Moka/Generator/ProxyTrait.php b/src/Moka/Proxy/ProxyTrait.php similarity index 95% rename from src/Moka/Generator/ProxyTrait.php rename to src/Moka/Proxy/ProxyTrait.php index 8ff52ec..f9576a1 100644 --- a/src/Moka/Generator/ProxyTrait.php +++ b/src/Moka/Proxy/ProxyTrait.php @@ -1,16 +1,15 @@ getParameters(); - $code = ProxyParameterTemplate::generate( + $code = ParameterTemplate::generate( $parameters[2] ); diff --git a/tests/Generator/Template/ProxyReturnTypeTemplateTest.php b/tests/Generator/Template/ReturnTypeTemplateTest.php similarity index 76% rename from tests/Generator/Template/ProxyReturnTypeTemplateTest.php rename to tests/Generator/Template/ReturnTypeTemplateTest.php index c11a040..9941901 100644 --- a/tests/Generator/Template/ProxyReturnTypeTemplateTest.php +++ b/tests/Generator/Template/ReturnTypeTemplateTest.php @@ -3,16 +3,16 @@ namespace Tests\Generator\Template; -use Moka\Generator\Template\ProxyReturnTypeTemplate; +use Moka\Generator\Template\ReturnTypeTemplate; use PHPUnit\Framework\TestCase; use Tests\FooTestClass; use Tests\NewTestClass; -class ProxyReturnTypeTemplateTest extends TestCase +class ReturnTypeTemplateTest extends TestCase { public function testGenerate() { - $code = ProxyReturnTypeTemplate::generate( + $code = ReturnTypeTemplate::generate( new \ReflectionMethod(FooTestClass::class, 'getCallable') ); @@ -25,7 +25,7 @@ public function testGenerateWithSelf() $this->markTestSkipped('Unsupported on PHP < 7.1'); } - $code = ProxyReturnTypeTemplate::generate( + $code = ReturnTypeTemplate::generate( new \ReflectionMethod(NewTestClass::class, 'getSelfNew') ); diff --git a/tests/ProxyTestClass.php b/tests/Proxy/FakeProxy.php similarity index 68% rename from tests/ProxyTestClass.php rename to tests/Proxy/FakeProxy.php index 4dc93da..4f1548f 100644 --- a/tests/ProxyTestClass.php +++ b/tests/Proxy/FakeProxy.php @@ -1,12 +1,12 @@ proxy = new ProxyTestClass(); + $this->proxy = new FakeProxy(); $this->mockingStrategy = $this->getMockBuilder(MockingStrategyInterface::class) ->disableOriginalConstructor() From 42e14dfcb84679221f3941977a7d0f6022110a57 Mon Sep 17 00:00:00 2001 From: Alberto Villa Date: Fri, 30 Jun 2017 15:16:32 +0200 Subject: [PATCH 27/46] Ensure $prophecies is an array --- src/Moka/Moka.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Moka/Moka.php b/src/Moka/Moka.php index 9a687dd..51b1307 100644 --- a/src/Moka/Moka.php +++ b/src/Moka/Moka.php @@ -109,7 +109,7 @@ public static function prophecy(string $fqcnOrAlias, string $alias = null): Prox $propheciesProperty->setAccessible(true); /** @var ObjectProphecy[] $prophecies */ - $prophecies = $propheciesProperty->getValue($prophet); + $prophecies = $propheciesProperty->getValue($prophet) ?: []; $prophecies[] = $proxy->__moka_getMock(); $propheciesProperty->setValue($prophet, $prophecies); From 21c02261630404ade75ea5bb10e2696096ceed0b Mon Sep 17 00:00:00 2001 From: Alberto Villa Date: Thu, 6 Jul 2017 14:08:39 +0200 Subject: [PATCH 28/46] Update to PHPUnit 6 and Paraunit 0.9 --- composer.json | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/composer.json b/composer.json index 5dfc7d9..954262c 100644 --- a/composer.json +++ b/composer.json @@ -49,14 +49,14 @@ "php": ">=7.0", "phpcollection/phpcollection": "^0.5.0", "psr/container": "^1.0", - "phpunit/phpunit-mock-objects": "^3.4||^4.0" + "phpunit/phpunit-mock-objects": "^4.0" }, "require-dev": { "friendsofphp/php-cs-fixer": "^2.3", - "phpunit/phpunit": "^5.6||^6.0", - "phpspec/prophecy": "^1.6", - "mockery/mockery": "^0.9.9", - "phake/phake": "^2.3" + "phpunit/phpunit": "^6.2", + "phpspec/prophecy": "^1.7", + "phake/phake": "^3.0", + "mockery/mockery": "^0.9.9" }, "suggest": { "phpspec/prophecy": "To allow loading of ProphecyPlugin", From 61f3fbb785ed84c4d4fa6920615b70e8889c70de Mon Sep 17 00:00:00 2001 From: Alberto Villa Date: Thu, 6 Jul 2017 14:09:05 +0200 Subject: [PATCH 29/46] Complete and test proxy generator --- src/Moka/Generator/ProxyGenerator.php | 2 +- src/Moka/Generator/Template/ClassTemplate.php | 44 +++++++++++++- .../Generator/Template/MethodTemplate.php | 7 ++- .../PropertyInitializationTemplate.php | 44 ++++++++++++++ .../Generator/Template/PropertyTemplate.php | 46 +++++++++++++++ .../Generator/Template/TemplateInterface.php | 4 +- .../Generator/Template/VisibilityTrait.php | 47 +++++++++++++++ src/Moka/Moka.php | 24 +++----- .../Plugin/Prophecy/MethodProphecyHelper.php | 44 ++++++++++++++ .../Prophecy/ProphecyMockingStrategy.php | 16 ++--- src/Moka/Proxy/ProxyTrait.php | 40 ++++++++----- src/Moka/Strategy/AbstractMockingStrategy.php | 26 +++++--- .../Strategy/MockingStrategyInterface.php | 5 +- tests/AbstractTestClass.php | 4 ++ tests/Generator/Template/FakeTemplate.php | 16 +++++ tests/Generator/Template/FakeTemplateTest.php | 59 +++++++++++++++++++ tests/MokaTest.php | 43 ++++++++++++-- .../Prophecy/ProphecyMockingStrategyTest.php | 15 +---- tests/Proxy/FakeProxy.php | 17 ------ tests/Proxy/ProxyTraitTest.php | 54 +++++++++++++---- tests/Proxy/TestProxy.php | 37 ++++++++++++ tests/Strategy/BareMockingStrategy.php | 12 ++++ tests/Strategy/FakeMockingStrategyTest.php | 18 ------ .../IncompleteMockingStrategyTest.php | 18 ------ tests/Strategy/MockingStrategyTest.php | 35 +++++++++++ 25 files changed, 533 insertions(+), 144 deletions(-) create mode 100644 src/Moka/Generator/Template/PropertyInitializationTemplate.php create mode 100644 src/Moka/Generator/Template/PropertyTemplate.php create mode 100644 src/Moka/Generator/Template/VisibilityTrait.php create mode 100644 src/Moka/Plugin/Prophecy/MethodProphecyHelper.php create mode 100644 tests/Generator/Template/FakeTemplate.php create mode 100644 tests/Generator/Template/FakeTemplateTest.php delete mode 100644 tests/Proxy/FakeProxy.php create mode 100644 tests/Proxy/TestProxy.php create mode 100644 tests/Strategy/BareMockingStrategy.php delete mode 100644 tests/Strategy/FakeMockingStrategyTest.php delete mode 100644 tests/Strategy/IncompleteMockingStrategyTest.php create mode 100644 tests/Strategy/MockingStrategyTest.php diff --git a/src/Moka/Generator/ProxyGenerator.php b/src/Moka/Generator/ProxyGenerator.php index c110029..2588919 100644 --- a/src/Moka/Generator/ProxyGenerator.php +++ b/src/Moka/Generator/ProxyGenerator.php @@ -60,7 +60,7 @@ protected function getInstance(string $proxyFQCN): ProxyInterface $proxyClass = new \ReflectionClass($proxyFQCN); /** @var ProxyInterface|ProxyTrait $proxy */ - $proxy = $proxyClass->newInstanceWithoutConstructor(); + $proxy = $proxyClass->newInstance(); return $proxy; } diff --git a/src/Moka/Generator/Template/ClassTemplate.php b/src/Moka/Generator/Template/ClassTemplate.php index 833e16c..81434d9 100644 --- a/src/Moka/Generator/Template/ClassTemplate.php +++ b/src/Moka/Generator/Template/ClassTemplate.php @@ -16,17 +16,29 @@ class ClassTemplate implements TemplateInterface const TEMPLATE_FQCN = 'Moka_%s_%s'; - const TEMPLATE = ' + const TEMPLATE_CLASS = ' class %s extends %s implements %s { use %s; + + %s + public function __construct() + { + %s + } + %s public function __call(%s $name, %s $arguments) { return $this->doCall($name, $arguments); } + + public function __get(%s $name) + { + return $this->doGet($name); + } }; return "%s"; @@ -47,10 +59,29 @@ public static function generate(\Reflector $class): string */ protected static function doGenerate(\ReflectionClass $class): string { - $methods = $class->getMethods(); + $properties = $class->getProperties(\ReflectionProperty::IS_PUBLIC); + $propertiesCode = []; + + $constructorCode = []; + + $methods = $class->getMethods(\ReflectionMethod::IS_PUBLIC); $methodsCode = []; + $methodNames = array_map(function (\ReflectionMethod $method) { + return $method->getName(); + }, $methods); $callParametersTypes = array_fill(0, 2, ''); + $getNameType = ''; + + foreach ($properties as $property) { + if (!in_array($property->getName(), $methodNames)) { + continue; + } + + $propertiesCode[] = PropertyTemplate::generate($property); + + $constructorCode[] = PropertyInitializationTemplate::generate($property); + } foreach ($methods as $method) { if ( @@ -66,6 +97,10 @@ protected static function doGenerate(\ReflectionClass $class): string $callParametersTypes[$callParameter->getPosition()] = (string)$callParameter->getType(); } } + + if ('__get' === $method->name) { + $getNameType = (string)$method->getParameters()[0]->getType(); + } } $mockClassName = $class->name; @@ -78,14 +113,17 @@ protected static function doGenerate(\ReflectionClass $class): string list($callNameType, $callArgumentsType) = $callParametersTypes; return sprintf( - self::TEMPLATE, + self::TEMPLATE_CLASS, $proxyClassName, $mockClassName, ProxyInterface::class, ProxyTrait::class, + implode(PHP_EOL, $propertiesCode), + implode(PHP_EOL, $constructorCode), implode(PHP_EOL, $methodsCode), $callNameType ?: '', $callArgumentsType ?: '', + $getNameType, $proxyClassName ); } diff --git a/src/Moka/Generator/Template/MethodTemplate.php b/src/Moka/Generator/Template/MethodTemplate.php index 6a85e77..6dfd90f 100644 --- a/src/Moka/Generator/Template/MethodTemplate.php +++ b/src/Moka/Generator/Template/MethodTemplate.php @@ -9,8 +9,10 @@ */ class MethodTemplate implements TemplateInterface { + use VisibilityTrait; + const TEMPLATE = ' - public %s function %s(%s)%s + %s %s function %s(%s)%s { %s $this->__call("%s", func_get_args()); } @@ -31,6 +33,8 @@ public static function generate(\Reflector $method): string */ protected static function doGenerate(\ReflectionMethod $method): string { + $visibility = static::getVisibility($method); + $static = $method->isStatic() ? 'static' : ''; $parameters = $method->getParameters(); @@ -54,6 +58,7 @@ protected static function doGenerate(\ReflectionMethod $method): string return sprintf( self::TEMPLATE, + $visibility, $static, $methodName, implode(',', $parametersCode), diff --git a/src/Moka/Generator/Template/PropertyInitializationTemplate.php b/src/Moka/Generator/Template/PropertyInitializationTemplate.php new file mode 100644 index 0000000..9f12182 --- /dev/null +++ b/src/Moka/Generator/Template/PropertyInitializationTemplate.php @@ -0,0 +1,44 @@ +doGet("%s"); + }; + '; + + /** + * @param \ReflectionProperty $property + * @return string + */ + public static function generate(\Reflector $property): string + { + return self::doGenerate($property); + } + + /** + * @param \ReflectionProperty $property + * @return string + */ + protected static function doGenerate(\ReflectionProperty $property): string + { + $scope = $property->isStatic() ? 'self::$' : '$this->'; + + $name = $property->getName(); + + return sprintf( + self::TEMPLATE, + $scope, + $name, + $name + ); + } +} diff --git a/src/Moka/Generator/Template/PropertyTemplate.php b/src/Moka/Generator/Template/PropertyTemplate.php new file mode 100644 index 0000000..3ca43d8 --- /dev/null +++ b/src/Moka/Generator/Template/PropertyTemplate.php @@ -0,0 +1,46 @@ +isStatic() ? 'static' : ''; + + $name = $property->getName(); + + return sprintf( + self::TEMPLATE, + $visibility, + $static, + $name + ); + } +} diff --git a/src/Moka/Generator/Template/TemplateInterface.php b/src/Moka/Generator/Template/TemplateInterface.php index 2399df6..f9f93d2 100644 --- a/src/Moka/Generator/Template/TemplateInterface.php +++ b/src/Moka/Generator/Template/TemplateInterface.php @@ -10,8 +10,8 @@ interface TemplateInterface { /** - * @param \Reflector $reflector + * @param \Reflector $property * @return string */ - public static function generate(\Reflector $reflector): string; + public static function generate(\Reflector $property): string; } diff --git a/src/Moka/Generator/Template/VisibilityTrait.php b/src/Moka/Generator/Template/VisibilityTrait.php new file mode 100644 index 0000000..fe19724 --- /dev/null +++ b/src/Moka/Generator/Template/VisibilityTrait.php @@ -0,0 +1,47 @@ +isPublic()) { + return 'public'; + } + + if ($reflector->isProtected()) { + return 'protected'; + } + + if ($reflector->isPrivate()) { + return 'private'; + } + + throw new \RuntimeException('Witness me!'); + } +} diff --git a/src/Moka/Moka.php b/src/Moka/Moka.php index 51b1307..b4e0962 100644 --- a/src/Moka/Moka.php +++ b/src/Moka/Moka.php @@ -84,17 +84,10 @@ public static function prophecy(string $fqcnOrAlias, string $alias = null): Prox $proxy = self::__callStatic('prophecy', [$fqcnOrAlias, $alias]); if (null !== $testCase = self::getCurrentTestCase()) { - try { - $prophetProperty = new \ReflectionProperty( - TestCase::class, - 'prophet' - ); - } catch (\ReflectionException $exception) { - $prophetProperty = new \ReflectionProperty( - \PHPUnit_Framework_TestCase::class, - 'prophet' - ); - } + $prophetProperty = new \ReflectionProperty( + TestCase::class, + 'prophet' + ); $prophetProperty->setAccessible(true); if (null === $prophet = $prophetProperty->getValue($testCase)) { @@ -138,16 +131,17 @@ private static function getCurrentTestCase() } $object = $frame['object']; - if ( - $object instanceof TestCase || - $object instanceof \PHPUnit_Framework_TestCase - ) { + if ($object instanceof TestCase) { return $object; } + // @codeCoverageIgnoreStart return null; + // @codeCoverageIgnoreEnd } + // @codeCoverageIgnoreStart return null; + // @codeCoverageIgnoreEnd } } diff --git a/src/Moka/Plugin/Prophecy/MethodProphecyHelper.php b/src/Moka/Plugin/Prophecy/MethodProphecyHelper.php new file mode 100644 index 0000000..08b3413 --- /dev/null +++ b/src/Moka/Plugin/Prophecy/MethodProphecyHelper.php @@ -0,0 +1,44 @@ +mock = $mock; + $this->methodName = $methodName; + } + + /** + * @param TokenInterface|null $token + * @return MethodProphecy + */ + public function set(TokenInterface $token = null): MethodProphecy + { + return $this->mock->{$this->methodName}($token); + } +} diff --git a/src/Moka/Plugin/Prophecy/ProphecyMockingStrategy.php b/src/Moka/Plugin/Prophecy/ProphecyMockingStrategy.php index 246d2d4..3308217 100644 --- a/src/Moka/Plugin/Prophecy/ProphecyMockingStrategy.php +++ b/src/Moka/Plugin/Prophecy/ProphecyMockingStrategy.php @@ -88,19 +88,11 @@ protected function doGet($mock) /** * @param ObjectProphecy $mock - * @param string $name - * @param array $arguments - * @return mixed + * @param string $methodName + * @return object */ - protected function doCall($mock, string $name, array $arguments) + protected function doCall($mock, string $methodName) { - $this->checkMockType($mock); - - $methodProphecies = $mock->getMethodProphecies($name); - if (count($methodProphecies) > 0) { - return parent::doCall($mock->reveal(), $name, $arguments); - } - - return parent::doCall($mock, $name, $arguments); + return new MethodProphecyHelper($mock, $methodName); } } diff --git a/src/Moka/Proxy/ProxyTrait.php b/src/Moka/Proxy/ProxyTrait.php index f9576a1..943fcf5 100644 --- a/src/Moka/Proxy/ProxyTrait.php +++ b/src/Moka/Proxy/ProxyTrait.php @@ -16,26 +16,19 @@ trait ProxyTrait /** * @var object */ - private $mock; + private $__moka_mock; /** * @var MockingStrategyInterface */ - private $mockingStrategy; - - /** - * ProxyTrait constructor. - */ - public function __construct() - { - } + private $__moka_mockingStrategy; /** * @return object */ public function __moka_getMock() { - return $this->mock; + return $this->__moka_mock; } /** @@ -44,7 +37,7 @@ public function __moka_getMock() */ public function __moka_setMock($mock): self { - $this->mock = $mock; + $this->__moka_mock = $mock; return $this; } @@ -55,7 +48,7 @@ public function __moka_setMock($mock): self */ public function __moka_setMockingStrategy(MockingStrategyInterface $mockingStrategy): self { - $this->mockingStrategy = $mockingStrategy; + $this->__moka_mockingStrategy = $mockingStrategy; return $this; } @@ -70,7 +63,7 @@ public function __moka_setMockingStrategy(MockingStrategyInterface $mockingStrat public function stub(array $methodsWithValues): ProxyInterface { /** @var $this ProxyInterface */ - $this->mockingStrategy->decorate($this->mock, $methodsWithValues); + $this->__moka_mockingStrategy->decorate($this->__moka_mock, $methodsWithValues); return $this; } @@ -82,10 +75,25 @@ public function stub(array $methodsWithValues): ProxyInterface */ protected function doCall(string $name, array $arguments) { - if ($this->mockingStrategy instanceof MockingStrategyInterface) { - return $this->mockingStrategy->call($this->mock, $name, $arguments); + if (!$this->__moka_mockingStrategy instanceof MockingStrategyInterface) { + return null; + } + + $target = $this->__moka_mockingStrategy->get($this->__moka_mock); + + return $target->$name(...$arguments); + } + + /** + * @param string $name + * @return mixed + */ + protected function doGet(string $name) + { + if (!$this->__moka_mockingStrategy instanceof MockingStrategyInterface) { + return null; } - return null; + return $this->__moka_mockingStrategy->call($this->__moka_mock, $name); } } diff --git a/src/Moka/Strategy/AbstractMockingStrategy.php b/src/Moka/Strategy/AbstractMockingStrategy.php index c2a6ed6..673c0d2 100644 --- a/src/Moka/Strategy/AbstractMockingStrategy.php +++ b/src/Moka/Strategy/AbstractMockingStrategy.php @@ -97,15 +97,16 @@ public function get($mock) /** * @param object $mock - * @param string $name - * @param array $arguments + * @param string $methodName * @return mixed + * + * @throws NotImplementedException */ - public function call($mock, string $name, array $arguments) + public function call($mock, string $methodName) { $this->checkMockType($mock); - return $this->doCall($mock, $name, $arguments); + return $this->doCall($mock, $methodName); } /** @@ -181,13 +182,20 @@ abstract protected function doDecorate($mock, Stub $stub); abstract protected function doGet($mock); /** - * @param object $target - * @param string $name - * @param array $arguments + * @param object $mock + * @param string $methodName * @return mixed + * + * @throws \Error */ - protected function doCall($target, string $name, array $arguments) + protected function doCall($mock, string $methodName) { - return $target->$name(...$arguments); + throw new \Error( + sprintf( + 'Undefined property: %s::$%s', + get_class($this), + $methodName + ) + ); } } diff --git a/src/Moka/Strategy/MockingStrategyInterface.php b/src/Moka/Strategy/MockingStrategyInterface.php index 1c25b15..888c754 100644 --- a/src/Moka/Strategy/MockingStrategyInterface.php +++ b/src/Moka/Strategy/MockingStrategyInterface.php @@ -39,11 +39,10 @@ public function get($mock); /** * @param object $mock - * @param string $name - * @param array $arguments + * @param string $methodName * @return mixed */ - public function call($mock, string $name, array $arguments); + public function call($mock, string $methodName); /** * @return string diff --git a/tests/AbstractTestClass.php b/tests/AbstractTestClass.php index bce3c0c..98cdc9d 100644 --- a/tests/AbstractTestClass.php +++ b/tests/AbstractTestClass.php @@ -5,6 +5,10 @@ abstract class AbstractTestClass implements TestInterface { + public $isTrue; + + public static $getInt; + public function isTrue(): bool { return true; diff --git a/tests/Generator/Template/FakeTemplate.php b/tests/Generator/Template/FakeTemplate.php new file mode 100644 index 0000000..296f303 --- /dev/null +++ b/tests/Generator/Template/FakeTemplate.php @@ -0,0 +1,16 @@ +getProperties(); + + foreach ($properties as $property) { + $this->assertEquals( + $property->getName(), + FakeTemplate::checkVisibility($property) + ); + } + } + + public function testGetVisibilityFailure() + { + /** @var \Reflector $reflector */ + $reflector = $this->getMockBuilder(\Reflector::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->expectException(InvalidArgumentException::class); + + FakeTemplate::checkVisibility($reflector); + } + + public function testGetVisibilityImpossibleFailure() + { + /** @var \ReflectionProperty|MockObject $reflector */ + $reflector = $this->getMockBuilder(\ReflectionProperty::class) + ->disableOriginalConstructor() + ->getMock(); + + $reflector->method('isPublic')->willReturn(false); + $reflector->method('isProtected')->willReturn(false); + $reflector->method('isPrivate')->willReturn(false); + + $this->expectException(\RuntimeException::class); + + FakeTemplate::checkVisibility($reflector); + } +} diff --git a/tests/MokaTest.php b/tests/MokaTest.php index 5543db8..c53c4fd 100644 --- a/tests/MokaTest.php +++ b/tests/MokaTest.php @@ -7,12 +7,10 @@ use Moka\Moka; use Moka\Proxy\ProxyInterface; use PHPUnit\Framework\TestCase; +use Prophecy\Argument\Token\AnyValuesToken; class MokaTest extends TestCase { - /** - * Moka::brew() is deprecated, but it still needs to be tested. - */ const METHODS = [ 'mockery', 'phake', @@ -20,7 +18,7 @@ class MokaTest extends TestCase 'prophecy' ]; - public function testBrewSuccess() + public function testCallStaticSuccess() { foreach (self::METHODS as $method) { $this->assertInstanceOf( @@ -30,13 +28,48 @@ public function testBrewSuccess() } } - public function testBrewFailure() + public function testCallStaticFailure() { $this->expectException(NotImplementedException::class); Moka::foo(\stdClass::class); } + public function testPHPUnitExpectation() + { + $proxy = Moka::phpunit(FooTestClass::class, 'foo'); + + $proxy->expects($this->once()) + ->method('getInt'); + + try { + $this->verifyMockObjects(); + } catch (\Exception $e) { + $proxy->getInt(); + return; + } + + $this->fail('Mock object was not registered within test case'); + } + + public function testProphecyExpectation() + { + $proxy = Moka::prophecy(FooTestClass::class, 'foo'); + + $proxy->getInt->set(new AnyValuesToken()) + ->willReturn(1138) + ->shouldBeCalledTimes(1); + + try { + $this->verifyMockObjects(); + } catch (\Exception $e) { + $proxy->getInt(); + return; + } + + $this->fail('Mock object was not registered within test case'); + } + public function testClean() { $proxy1 = Moka::phpunit(\stdClass::class); diff --git a/tests/Plugin/Prophecy/ProphecyMockingStrategyTest.php b/tests/Plugin/Prophecy/ProphecyMockingStrategyTest.php index 78e31c5..8095f13 100644 --- a/tests/Plugin/Prophecy/ProphecyMockingStrategyTest.php +++ b/tests/Plugin/Prophecy/ProphecyMockingStrategyTest.php @@ -99,20 +99,7 @@ public function testCallObjectProphecy() $this->assertInstanceOf( MethodProphecy::class, - $this->strategy->call($mock, 'withArgument', []) - ); - } - - public function testCallMockedObject() - { - $mock = $this->strategy->build(FooTestClass::class); - $this->strategy->decorate($mock, [ - 'withArgument' => 1 - ]); - - $this->assertEquals( - 1, - $this->strategy->call($mock, 'withArgument', [1]) + $this->strategy->call($mock, 'withArgument')->set() ); } } diff --git a/tests/Proxy/FakeProxy.php b/tests/Proxy/FakeProxy.php deleted file mode 100644 index 4f1548f..0000000 --- a/tests/Proxy/FakeProxy.php +++ /dev/null @@ -1,17 +0,0 @@ -doCall($name, $arguments); - } -} diff --git a/tests/Proxy/ProxyTraitTest.php b/tests/Proxy/ProxyTraitTest.php index 4349b8d..9225d98 100644 --- a/tests/Proxy/ProxyTraitTest.php +++ b/tests/Proxy/ProxyTraitTest.php @@ -12,7 +12,7 @@ class ProxyTraitTest extends TestCase { /** - * @var ProxyInterface|FakeProxy + * @var ProxyInterface|TestProxy */ private $proxy; @@ -28,7 +28,7 @@ class ProxyTraitTest extends TestCase protected function setUp() { - $this->proxy = new FakeProxy(); + $this->proxy = new TestProxy(); $this->mockingStrategy = $this->getMockBuilder(MockingStrategyInterface::class) ->disableOriginalConstructor() @@ -60,22 +60,56 @@ public function testStub() public function testCallSuccess() { + $this->mock + ->expects($this->once()) + ->method('getSelf') + ->willReturn($this->mock); + $this->mockingStrategy ->expects($this->once()) - ->method('call') - ->with( - $this->equalTo($this->mock), - 'getSelf', - [] - ); + ->method('get') + ->willReturn($this->mock); $this->proxy->__moka_setMockingStrategy($this->mockingStrategy); - $this->proxy->__call('getSelf', []); + $this->assertSame($this->mock, $this->proxy->getSelf()); } public function testCallFailure() { - $this->assertNull($this->proxy->__call('getSelf', [])); + $this->mockingStrategy + ->expects($this->once()) + ->method('get') + ->willReturn($this->mock); + + $this->proxy->__moka_setMockingStrategy($this->mockingStrategy); + + $this->expectException(\Error::class); + + $this->proxy->fakeMethod(); + } + + public function testCallWithoutStrategyFailure() + { + $this->assertNull($this->proxy->getSelf()); + } + + public function testGetFailure() + { + $this->mockingStrategy + ->expects($this->once()) + ->method('call') + ->willThrowException(new \Exception()); + + $this->proxy->__moka_setMockingStrategy($this->mockingStrategy); + + $this->expectException(\Exception::class); + + $this->proxy->getSelf; + } + + public function testGetWithoutStrategyFailure() + { + $this->assertNull($this->proxy->getSelf); } } diff --git a/tests/Proxy/TestProxy.php b/tests/Proxy/TestProxy.php new file mode 100644 index 0000000..01d2dbe --- /dev/null +++ b/tests/Proxy/TestProxy.php @@ -0,0 +1,37 @@ +isTrue = function () { + return $this->doGet('isTrue'); + }; + + self::$getInt = function () { + return $this->doGet('getInt'); + }; + } + + public function __call(string $name, array $arguments) + { + return $this->doCall($name, $arguments); + } + + public function __get(string $name) + { + return $this->doGet($name); + } +} diff --git a/tests/Strategy/BareMockingStrategy.php b/tests/Strategy/BareMockingStrategy.php new file mode 100644 index 0000000..7579fa6 --- /dev/null +++ b/tests/Strategy/BareMockingStrategy.php @@ -0,0 +1,12 @@ +setMockType(\stdClass::class); + } +} diff --git a/tests/Strategy/FakeMockingStrategyTest.php b/tests/Strategy/FakeMockingStrategyTest.php deleted file mode 100644 index 0da9bbb..0000000 --- a/tests/Strategy/FakeMockingStrategyTest.php +++ /dev/null @@ -1,18 +0,0 @@ -expectException(MissingDependencyException::class); - - new FakeMockingStrategy(); - } -} diff --git a/tests/Strategy/IncompleteMockingStrategyTest.php b/tests/Strategy/IncompleteMockingStrategyTest.php deleted file mode 100644 index d72e6b3..0000000 --- a/tests/Strategy/IncompleteMockingStrategyTest.php +++ /dev/null @@ -1,18 +0,0 @@ -expectException(NotImplementedException::class); - $strategy->getMockType(); - } -} diff --git a/tests/Strategy/MockingStrategyTest.php b/tests/Strategy/MockingStrategyTest.php new file mode 100644 index 0000000..4832cf2 --- /dev/null +++ b/tests/Strategy/MockingStrategyTest.php @@ -0,0 +1,35 @@ +expectException(MissingDependencyException::class); + + new FakeMockingStrategy(); + } + + public function testGetMockTypeFailure() + { + $strategy = new IncompleteMockingStrategy(); + + $this->expectException(NotImplementedException::class); + $strategy->getMockType(); + } + + public function testCallFailure() + { + $strategy = new BareMockingStrategy(); + + $this->expectException(\Error::class); + + $strategy->call(new \stdClass(), 'foo'); + } +} From ef14107f9b8426d5cffc142264a7002ee8c45b65 Mon Sep 17 00:00:00 2001 From: Alberto Villa Date: Thu, 6 Jul 2017 14:25:29 +0200 Subject: [PATCH 30/46] Use 'name' instead of getName() --- src/Moka/Generator/Template/ClassTemplate.php | 4 ++-- .../Generator/Template/PropertyInitializationTemplate.php | 2 +- src/Moka/Generator/Template/PropertyTemplate.php | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Moka/Generator/Template/ClassTemplate.php b/src/Moka/Generator/Template/ClassTemplate.php index 81434d9..db02516 100644 --- a/src/Moka/Generator/Template/ClassTemplate.php +++ b/src/Moka/Generator/Template/ClassTemplate.php @@ -67,14 +67,14 @@ protected static function doGenerate(\ReflectionClass $class): string $methods = $class->getMethods(\ReflectionMethod::IS_PUBLIC); $methodsCode = []; $methodNames = array_map(function (\ReflectionMethod $method) { - return $method->getName(); + return $method->name; }, $methods); $callParametersTypes = array_fill(0, 2, ''); $getNameType = ''; foreach ($properties as $property) { - if (!in_array($property->getName(), $methodNames)) { + if (!in_array($property->name, $methodNames)) { continue; } diff --git a/src/Moka/Generator/Template/PropertyInitializationTemplate.php b/src/Moka/Generator/Template/PropertyInitializationTemplate.php index 9f12182..44217c6 100644 --- a/src/Moka/Generator/Template/PropertyInitializationTemplate.php +++ b/src/Moka/Generator/Template/PropertyInitializationTemplate.php @@ -32,7 +32,7 @@ protected static function doGenerate(\ReflectionProperty $property): string { $scope = $property->isStatic() ? 'self::$' : '$this->'; - $name = $property->getName(); + $name = $property->name; return sprintf( self::TEMPLATE, diff --git a/src/Moka/Generator/Template/PropertyTemplate.php b/src/Moka/Generator/Template/PropertyTemplate.php index 3ca43d8..336b3c8 100644 --- a/src/Moka/Generator/Template/PropertyTemplate.php +++ b/src/Moka/Generator/Template/PropertyTemplate.php @@ -34,7 +34,7 @@ protected static function doGenerate(\ReflectionProperty $property): string $static = $property->isStatic() ? 'static' : ''; - $name = $property->getName(); + $name = $property->name; return sprintf( self::TEMPLATE, From 4732d91701184a833974a90c3940c61c41c2fc7f Mon Sep 17 00:00:00 2001 From: Alberto Villa Date: Thu, 6 Jul 2017 14:31:04 +0200 Subject: [PATCH 31/46] Simplify conditions --- src/Moka/Generator/Template/VisibilityTrait.php | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/src/Moka/Generator/Template/VisibilityTrait.php b/src/Moka/Generator/Template/VisibilityTrait.php index fe19724..fa4f991 100644 --- a/src/Moka/Generator/Template/VisibilityTrait.php +++ b/src/Moka/Generator/Template/VisibilityTrait.php @@ -30,16 +30,10 @@ protected static function getVisibility(\Reflector $reflector): string ); } - if ($reflector->isPublic()) { - return 'public'; - } - - if ($reflector->isProtected()) { - return 'protected'; - } - - if ($reflector->isPrivate()) { - return 'private'; + foreach (['Public', 'Protected', 'Private'] as $visibility) { + if ($reflector->{'is' . $visibility}()) { + return strtolower($visibility); + } } throw new \RuntimeException('Witness me!'); From 2a1f4000eaaa176d82ab14cef68d71527033f880 Mon Sep 17 00:00:00 2001 From: Angelo Giuffredi Date: Thu, 6 Jul 2017 09:59:58 +0200 Subject: [PATCH 32/46] Format code --- composer.json | 1 + src/Moka/Builder/ProxyBuilder.php | 4 ++++ .../Framework/MokaCleanerTestListener.php | 24 +++++++++++++++++++ src/Moka/Traits/MokaCleanerTrait.php | 21 ---------------- 4 files changed, 29 insertions(+), 21 deletions(-) create mode 100644 src/Moka/PHPUnit/Framework/MokaCleanerTestListener.php delete mode 100644 src/Moka/Traits/MokaCleanerTrait.php diff --git a/composer.json b/composer.json index 954262c..001883e 100644 --- a/composer.json +++ b/composer.json @@ -57,6 +57,7 @@ "phpspec/prophecy": "^1.7", "phake/phake": "^3.0", "mockery/mockery": "^0.9.9" + }, "suggest": { "phpspec/prophecy": "To allow loading of ProphecyPlugin", diff --git a/src/Moka/Builder/ProxyBuilder.php b/src/Moka/Builder/ProxyBuilder.php index 173ab4d..af17d3c 100644 --- a/src/Moka/Builder/ProxyBuilder.php +++ b/src/Moka/Builder/ProxyBuilder.php @@ -3,6 +3,7 @@ namespace Moka\Builder; +use Moka\Exception\InvalidArgumentException; use Moka\Exception\InvalidIdentifierException; use Moka\Exception\MockNotCreatedException; use Moka\Factory\ProxyGeneratorFactory; @@ -72,6 +73,9 @@ public function getProxy(string $fqcnOrAlias, string $alias = null): ProxyInterf /** * @param string $fqcn * @return ProxyInterface + * + * @throws InvalidArgumentException + * @throws MockNotCreatedException */ protected function buildProxy(string $fqcn): ProxyInterface { diff --git a/src/Moka/PHPUnit/Framework/MokaCleanerTestListener.php b/src/Moka/PHPUnit/Framework/MokaCleanerTestListener.php new file mode 100644 index 0000000..787cb4a --- /dev/null +++ b/src/Moka/PHPUnit/Framework/MokaCleanerTestListener.php @@ -0,0 +1,24 @@ + Date: Thu, 6 Jul 2017 14:48:24 +0200 Subject: [PATCH 33/46] Fix mockery lowest supported version --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 001883e..0474eff 100644 --- a/composer.json +++ b/composer.json @@ -56,7 +56,7 @@ "phpunit/phpunit": "^6.2", "phpspec/prophecy": "^1.7", "phake/phake": "^3.0", - "mockery/mockery": "^0.9.9" + "mockery/mockery": "^0.9" }, "suggest": { From be9d18f993778cce31bf13601963da1ca475409d Mon Sep 17 00:00:00 2001 From: Alberto Villa Date: Thu, 6 Jul 2017 15:33:53 +0200 Subject: [PATCH 34/46] Revert "Format code" This reverts commit 2a1f4000eaaa176d82ab14cef68d71527033f880. --- composer.json | 1 - .../Framework/MokaCleanerTestListener.php | 24 ------------------- src/Moka/Traits/MokaCleanerTrait.php | 21 ++++++++++++++++ 3 files changed, 21 insertions(+), 25 deletions(-) delete mode 100644 src/Moka/PHPUnit/Framework/MokaCleanerTestListener.php create mode 100644 src/Moka/Traits/MokaCleanerTrait.php diff --git a/composer.json b/composer.json index 0474eff..2c9a199 100644 --- a/composer.json +++ b/composer.json @@ -57,7 +57,6 @@ "phpspec/prophecy": "^1.7", "phake/phake": "^3.0", "mockery/mockery": "^0.9" - }, "suggest": { "phpspec/prophecy": "To allow loading of ProphecyPlugin", diff --git a/src/Moka/PHPUnit/Framework/MokaCleanerTestListener.php b/src/Moka/PHPUnit/Framework/MokaCleanerTestListener.php deleted file mode 100644 index 787cb4a..0000000 --- a/src/Moka/PHPUnit/Framework/MokaCleanerTestListener.php +++ /dev/null @@ -1,24 +0,0 @@ - Date: Thu, 6 Jul 2017 15:34:57 +0200 Subject: [PATCH 35/46] Improve MokaCleanerTrait Avoid overriding tearDown(). --- src/Moka/Traits/MokaCleanerTrait.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Moka/Traits/MokaCleanerTrait.php b/src/Moka/Traits/MokaCleanerTrait.php index 5dca93a..c4bc0c2 100644 --- a/src/Moka/Traits/MokaCleanerTrait.php +++ b/src/Moka/Traits/MokaCleanerTrait.php @@ -13,8 +13,10 @@ trait MokaCleanerTrait { /** * @return void + * + * @after */ - protected function tearDown() + protected function __moka_tearDown() { Moka::clean(); } From fb9c62a42c1f8684e03f7b224a997fd2866daa6a Mon Sep 17 00:00:00 2001 From: Alberto Villa Date: Thu, 6 Jul 2017 15:48:38 +0200 Subject: [PATCH 36/46] Document trait and Prophecy workaround --- README.md | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index cfc5c3f..fc4b7cd 100644 --- a/README.md +++ b/README.md @@ -56,17 +56,16 @@ Alternatively, instead of using `moka()`, you can call `Moka::phpunit(string $fq Being such a simple project, **Moka** can be integrated in an already existing test suite with no effort. -**Notice:** if you are extending PHPUnit `TestCase`, to simplify the cleaning phase we provide a `MokaCleanerTrait` which automatically runs `Moka::clean()` in `tearDown()`. -**Warning:** if you are defining your own `tearDown()`, you cannot use the trait! +**Notice:** if you are extending PHPUnit `TestCase`, to simplify the cleaning phase we provide a `MokaCleanerTrait` which automatically runs `Moka::clean()` after each test. ```php You can rely on the original mock object implementation to be accessible (in the example below, PHPUnit's): +You can rely on the original mock object implementation to be accessible (in the example below, PHPUnit's - for Prophecy see below): ```php moka(BarInterface::class, 'bar') @@ -161,6 +160,22 @@ We provide a specific `moka()` function for each supported strategy, as well as - `Moka\Plugin\Mockery\moka` - `Moka\Plugin\Phake\moka` +### Prophecy native behavior + +Prophecy lets you stub methods by calling them directly on the `ObjectProphecy`. **Moka** doesn't support such a behavior, but we provide an easy workaround: + +```php +// Native Prophecy behavior... +$this->prophesize(FooInterface::class) + ->someMethod(new AnyValuesToken()) + ->willReturn($something); + +// ...translates to... +Moka::prophecy(FooInterface::class) + ->someMethod->set(new AnyValuesToken()) + ->willReturn($something); +``` + ## Plugin development If you feel a genius and want to create your own mock generator (or add support for an existing one), just implement `Moka\Plugin\PluginInterface` and the relative `Moka\Strategy\MockingStrategyInterface`: From f4d05db7b51576d9271a227c9e58dbda497fd90d Mon Sep 17 00:00:00 2001 From: Angelo Giuffredi Date: Thu, 6 Jul 2017 19:48:48 +0200 Subject: [PATCH 37/46] Fix phpcollection version costraint --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 2c9a199..c553e8d 100644 --- a/composer.json +++ b/composer.json @@ -47,7 +47,7 @@ }, "require": { "php": ">=7.0", - "phpcollection/phpcollection": "^0.5.0", + "phpcollection/phpcollection": "^0.5", "psr/container": "^1.0", "phpunit/phpunit-mock-objects": "^4.0" }, From 608f3ec8ba121610fe9d3775b8e9f301c0c0d37b Mon Sep 17 00:00:00 2001 From: Angelo Giuffredi Date: Fri, 7 Jul 2017 00:01:51 +0200 Subject: [PATCH 38/46] Fix lower bound version constraint of mockery --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index c553e8d..4b98d33 100644 --- a/composer.json +++ b/composer.json @@ -56,7 +56,7 @@ "phpunit/phpunit": "^6.2", "phpspec/prophecy": "^1.7", "phake/phake": "^3.0", - "mockery/mockery": "^0.9" + "mockery/mockery": "^0.9.9" }, "suggest": { "phpspec/prophecy": "To allow loading of ProphecyPlugin", From 1f9b0d961e00d469bf0813e7fc3166eb99d1385c Mon Sep 17 00:00:00 2001 From: Angelo Giuffredi Date: Fri, 7 Jul 2017 10:01:09 +0200 Subject: [PATCH 39/46] Support phpunit from ^6.0 --- composer.json | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 4b98d33..92f1737 100644 --- a/composer.json +++ b/composer.json @@ -53,7 +53,7 @@ }, "require-dev": { "friendsofphp/php-cs-fixer": "^2.3", - "phpunit/phpunit": "^6.2", + "phpunit/phpunit": "^6.0", "phpspec/prophecy": "^1.7", "phake/phake": "^3.0", "mockery/mockery": "^0.9.9" @@ -63,5 +63,10 @@ "mockery/mockery": "To allow loading of MockeryPlugin", "phake/phake": "To allow loading of PhakePlugin", "facile-it/paraunit": "For parallel test running; it's faster!" + }, + "config": { + "platform": { + "php": "7.0" + } } } From f9d327d2b6b02789e367d04506e83d5b20f88083 Mon Sep 17 00:00:00 2001 From: Angelo Giuffredi Date: Fri, 7 Jul 2017 20:12:26 +0200 Subject: [PATCH 40/46] Remove 'config' --- composer.json | 5 ----- 1 file changed, 5 deletions(-) diff --git a/composer.json b/composer.json index 92f1737..b3a9c5b 100644 --- a/composer.json +++ b/composer.json @@ -63,10 +63,5 @@ "mockery/mockery": "To allow loading of MockeryPlugin", "phake/phake": "To allow loading of PhakePlugin", "facile-it/paraunit": "For parallel test running; it's faster!" - }, - "config": { - "platform": { - "php": "7.0" - } } } From e6d12e4b6a58270a41150ab5a63fdcdac30d7752 Mon Sep 17 00:00:00 2001 From: Alberto Villa Date: Wed, 12 Jul 2017 10:19:47 +0200 Subject: [PATCH 41/46] Document exceptions --- src/Moka/Generator/Template/VisibilityTrait.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Moka/Generator/Template/VisibilityTrait.php b/src/Moka/Generator/Template/VisibilityTrait.php index fa4f991..2da5356 100644 --- a/src/Moka/Generator/Template/VisibilityTrait.php +++ b/src/Moka/Generator/Template/VisibilityTrait.php @@ -14,6 +14,9 @@ trait VisibilityTrait /** * @param \Reflector $reflector * @return string + * + * @throws InvalidArgumentException + * @throws \RuntimeException */ protected static function getVisibility(\Reflector $reflector): string { From 6d738a9fb2a82897479f6781074ba7f17aa65037 Mon Sep 17 00:00:00 2001 From: Alberto Villa Date: Wed, 12 Jul 2017 11:33:15 +0200 Subject: [PATCH 42/46] Use PHPUnit annotation --- tests/Generator/Template/ReturnTypeTemplateTest.php | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/tests/Generator/Template/ReturnTypeTemplateTest.php b/tests/Generator/Template/ReturnTypeTemplateTest.php index 9941901..fc3328e 100644 --- a/tests/Generator/Template/ReturnTypeTemplateTest.php +++ b/tests/Generator/Template/ReturnTypeTemplateTest.php @@ -19,12 +19,11 @@ public function testGenerate() $this->assertRegExp('/: *callable/', $code); } + /** + * @requires PHP 7.1 + */ public function testGenerateWithSelf() { - if (version_compare(phpversion(), '7.1', '<')) { - $this->markTestSkipped('Unsupported on PHP < 7.1'); - } - $code = ReturnTypeTemplate::generate( new \ReflectionMethod(NewTestClass::class, 'getSelfNew') ); From 32182865e354882610444f1ec310d91c697e5ed8 Mon Sep 17 00:00:00 2001 From: Alberto Villa Date: Wed, 12 Jul 2017 12:55:11 +0200 Subject: [PATCH 43/46] Support stubbing of properties --- .../Plugin/Mockery/MockeryMockingStrategy.php | 4 +- .../Plugin/PHPUnit/PHPUnitMockingStrategy.php | 4 +- .../Plugin/Phake/PhakeMockingStrategy.php | 4 +- .../Prophecy/ProphecyMockingStrategy.php | 4 +- src/Moka/Stub/Stub.php | 38 +++++++++++++++---- 5 files changed, 38 insertions(+), 16 deletions(-) diff --git a/src/Moka/Plugin/Mockery/MockeryMockingStrategy.php b/src/Moka/Plugin/Mockery/MockeryMockingStrategy.php index eff1ddc..f52c715 100644 --- a/src/Moka/Plugin/Mockery/MockeryMockingStrategy.php +++ b/src/Moka/Plugin/Mockery/MockeryMockingStrategy.php @@ -46,8 +46,8 @@ protected function doBuild(string $fqcn) */ protected function doDecorate($mock, Stub $stub) { - $methodName = $stub->getMethodName(); - $methodValue = $stub->getMethodValue(); + $methodName = $stub->getName(); + $methodValue = $stub->getValue(); /** @noinspection PhpMethodParametersCountMismatchInspection */ $partial = $mock->shouldReceive($methodName)->zeroOrMoreTimes(); diff --git a/src/Moka/Plugin/PHPUnit/PHPUnitMockingStrategy.php b/src/Moka/Plugin/PHPUnit/PHPUnitMockingStrategy.php index 6d5e61c..7884db1 100644 --- a/src/Moka/Plugin/PHPUnit/PHPUnitMockingStrategy.php +++ b/src/Moka/Plugin/PHPUnit/PHPUnitMockingStrategy.php @@ -62,8 +62,8 @@ protected function doBuild(string $fqcn) */ protected function doDecorate($mock, Stub $stub) { - $methodName = $stub->getMethodName(); - $methodValue = $stub->getMethodValue(); + $methodName = $stub->getName(); + $methodValue = $stub->getValue(); $partial = $mock->expects(new AnyInvokedCountMatcher())->method($methodName); $methodValue instanceof \Throwable diff --git a/src/Moka/Plugin/Phake/PhakeMockingStrategy.php b/src/Moka/Plugin/Phake/PhakeMockingStrategy.php index 5b3d14b..64ce2fa 100644 --- a/src/Moka/Plugin/Phake/PhakeMockingStrategy.php +++ b/src/Moka/Plugin/Phake/PhakeMockingStrategy.php @@ -48,8 +48,8 @@ protected function doBuild(string $fqcn) */ protected function doDecorate($mock, Stub $stub) { - $methodName = $stub->getMethodName(); - $methodValue = $stub->getMethodValue(); + $methodName = $stub->getName(); + $methodValue = $stub->getValue(); /** @var AnswerBinderProxy $partial */ $partial = Phake::when($mock)->$methodName(new FirstStubMatcher($mock, $methodName)); diff --git a/src/Moka/Plugin/Prophecy/ProphecyMockingStrategy.php b/src/Moka/Plugin/Prophecy/ProphecyMockingStrategy.php index 3308217..c26a73b 100644 --- a/src/Moka/Plugin/Prophecy/ProphecyMockingStrategy.php +++ b/src/Moka/Plugin/Prophecy/ProphecyMockingStrategy.php @@ -56,8 +56,8 @@ protected function doBuild(string $fqcn) */ protected function doDecorate($mock, Stub $stub) { - $methodName = $stub->getMethodName(); - $methodValue = $stub->getMethodValue(); + $methodName = $stub->getName(); + $methodValue = $stub->getValue(); /** @var MethodProphecy $partial */ $partial = $mock->$methodName(new MaxPriorityToken()); diff --git a/src/Moka/Stub/Stub.php b/src/Moka/Stub/Stub.php index c4ba978..1cced73 100644 --- a/src/Moka/Stub/Stub.php +++ b/src/Moka/Stub/Stub.php @@ -3,17 +3,23 @@ namespace Moka\Stub; +/** + * Class Stub + * @package Moka\Stub + */ class Stub { + const PREFIX_PROPERTY = '$'; + /** * @var string */ - private $methodName; + private $name; /** * @var mixed */ - private $methodValue; + private $value; /** * Stub constructor. @@ -22,23 +28,39 @@ class Stub */ public function __construct(string $methodName, $methodValue) { - $this->methodName = $methodName; - $this->methodValue = $methodValue; + $this->name = $methodName; + $this->value = $methodValue; + } + + /** + * @return bool + */ + public function isProperty(): bool + { + return self::PREFIX_PROPERTY === $this->getName()[0]; + } + + /** + * @return bool + */ + public function isMethod(): bool + { + return !$this->isProperty(); } /** * @return string */ - public function getMethodName(): string + public function getName(): string { - return $this->methodName; + return $this->name; } /** * @return mixed */ - public function getMethodValue() + public function getValue() { - return $this->methodValue; + return $this->value; } } From abe7a837a69ed2971d883649b5a2d3e111e89275 Mon Sep 17 00:00:00 2001 From: Alberto Villa Date: Wed, 12 Jul 2017 16:08:17 +0200 Subject: [PATCH 44/46] Add StubInterface --- README.md | 6 +- src/Moka/Factory/StubFactory.php | 18 +++-- .../Generator/Template/VisibilityTrait.php | 5 +- .../Plugin/Mockery/MockeryMockingStrategy.php | 6 +- .../Plugin/PHPUnit/PHPUnitMockingStrategy.php | 6 +- .../Plugin/Phake/PhakeMockingStrategy.php | 6 +- .../Prophecy/ProphecyMockingStrategy.php | 6 +- src/Moka/Proxy/ProxyTrait.php | 6 +- src/Moka/Strategy/AbstractMockingStrategy.php | 31 ++++++-- src/Moka/Stub/AbstractStub.php | 56 ++++++++++++++ src/Moka/Stub/MethodStub.php | 29 +++++++ src/Moka/Stub/PropertyStub.php | 29 +++++++ src/Moka/Stub/Stub.php | 66 ---------------- src/Moka/Stub/StubInterface.php | 24 ++++++ src/Moka/Stub/StubSet.php | 8 +- .../Tests/MokaMockingStrategyTestCase.php | 24 ++++-- tests/Factory/StubFactoryTest.php | 7 +- tests/Strategy/IncompleteMockingStrategy.php | 4 +- tests/Stub/MethodStubTest.php | 63 +++++++++++++++ tests/Stub/PropertyStubTest.php | 76 +++++++++++++++++++ tests/Stub/StubSetTest.php | 5 +- tests/Stub/StubTestCase.php | 29 +++++++ 22 files changed, 394 insertions(+), 116 deletions(-) create mode 100644 src/Moka/Stub/AbstractStub.php create mode 100644 src/Moka/Stub/MethodStub.php create mode 100644 src/Moka/Stub/PropertyStub.php delete mode 100644 src/Moka/Stub/Stub.php create mode 100644 src/Moka/Stub/StubInterface.php create mode 100644 tests/Stub/MethodStubTest.php create mode 100644 tests/Stub/PropertyStubTest.php create mode 100644 tests/Stub/StubTestCase.php diff --git a/README.md b/README.md index fc4b7cd..d76d2e3 100644 --- a/README.md +++ b/README.md @@ -205,7 +205,7 @@ Extend `AbstractMockingStrategy` for an easier (and stricter) implementation of namespace Moka\Plugin\YourOwn; use Moka\Strategy\AbstractMockingStrategy; -use Moka\Stub\Stub; +use Moka\Stub\MethodStub; class YourOwnMockingStrategy extends AbstractMockingStrategy { @@ -219,7 +219,7 @@ class YourOwnMockingStrategy extends AbstractMockingStrategy // TODO: Implement doBuild() method. } - protected function doDecorate($mock, Stub $stub) + protected function doDecorateWithMethod($mock, MethodStub $stub) { // TODO: Implement doDecorate() method. } @@ -229,7 +229,7 @@ class YourOwnMockingStrategy extends AbstractMockingStrategy // TODO: Implement doGet() method. } - protected function doCall($target, string $name, array $arguments) + protected function doCall($mock, string $methodName) { // Override doCall() if you need special behavior. // See ProphecyMockingStrategy::doCall(). diff --git a/src/Moka/Factory/StubFactory.php b/src/Moka/Factory/StubFactory.php index eb84c47..d970524 100644 --- a/src/Moka/Factory/StubFactory.php +++ b/src/Moka/Factory/StubFactory.php @@ -4,7 +4,9 @@ namespace Moka\Factory; use Moka\Exception\InvalidArgumentException; -use Moka\Stub\Stub; +use Moka\Stub\MethodStub; +use Moka\Stub\PropertyStub; +use Moka\Stub\StubInterface; use Moka\Stub\StubSet; /** @@ -14,17 +16,21 @@ class StubFactory { /** - * @param array $methodsWithValues - * @return StubSet|Stub[] + * @param array $namesWithValues + * @return StubSet|StubInterface[] * * @throws InvalidArgumentException */ - public static function fromArray(array $methodsWithValues): StubSet + public static function fromArray(array $namesWithValues): StubSet { $stubSet = new StubSet(); - foreach ($methodsWithValues as $methodName => $methodValue) { + foreach ($namesWithValues as $name => $value) { try { - $stubSet->add(new Stub($methodName, $methodValue)); + $stub = StubInterface::PREFIX_PROPERTY === $name[0] + ? new PropertyStub($name, $value) + : new MethodStub($name, $value); + + $stubSet->add($stub); } catch (\Error $error) { throw new InvalidArgumentException($error->getMessage()); } diff --git a/src/Moka/Generator/Template/VisibilityTrait.php b/src/Moka/Generator/Template/VisibilityTrait.php index 2da5356..7afb8b1 100644 --- a/src/Moka/Generator/Template/VisibilityTrait.php +++ b/src/Moka/Generator/Template/VisibilityTrait.php @@ -26,9 +26,10 @@ protected static function getVisibility(\Reflector $reflector): string ) { throw new InvalidArgumentException( sprintf( - 'Reflector must be an instance of "%s" or "%s"', + 'Reflector must be an instance of "%s" or "%s", "%s" given', \ReflectionMethod::class, - \ReflectionProperty::class + \ReflectionProperty::class, + get_class($reflector) ) ); } diff --git a/src/Moka/Plugin/Mockery/MockeryMockingStrategy.php b/src/Moka/Plugin/Mockery/MockeryMockingStrategy.php index f52c715..4c0a36c 100644 --- a/src/Moka/Plugin/Mockery/MockeryMockingStrategy.php +++ b/src/Moka/Plugin/Mockery/MockeryMockingStrategy.php @@ -7,7 +7,7 @@ use Mockery\MockInterface; use Moka\Exception\MissingDependencyException; use Moka\Strategy\AbstractMockingStrategy; -use Moka\Stub\Stub; +use Moka\Stub\MethodStub; /** * Class MockeryMockingStrategy @@ -41,10 +41,10 @@ protected function doBuild(string $fqcn) /** * @param MockInterface $mock - * @param Stub $stub + * @param MethodStub $stub * @return void */ - protected function doDecorate($mock, Stub $stub) + protected function doDecorateWithMethod($mock, MethodStub $stub) { $methodName = $stub->getName(); $methodValue = $stub->getValue(); diff --git a/src/Moka/Plugin/PHPUnit/PHPUnitMockingStrategy.php b/src/Moka/Plugin/PHPUnit/PHPUnitMockingStrategy.php index 7884db1..5f88cd8 100644 --- a/src/Moka/Plugin/PHPUnit/PHPUnitMockingStrategy.php +++ b/src/Moka/Plugin/PHPUnit/PHPUnitMockingStrategy.php @@ -5,7 +5,7 @@ use Moka\Exception\MissingDependencyException; use Moka\Strategy\AbstractMockingStrategy; -use Moka\Stub\Stub; +use Moka\Stub\MethodStub; use PHPUnit_Framework_MockObject_Generator as MockGenerator; use PHPUnit_Framework_MockObject_Matcher_AnyInvokedCount as AnyInvokedCountMatcher; use PHPUnit_Framework_MockObject_MockObject as MockObject; @@ -57,10 +57,10 @@ protected function doBuild(string $fqcn) /** * @param MockObject $mock - * @param Stub $stub + * @param MethodStub $stub * @return void */ - protected function doDecorate($mock, Stub $stub) + protected function doDecorateWithMethod($mock, MethodStub $stub) { $methodName = $stub->getName(); $methodValue = $stub->getValue(); diff --git a/src/Moka/Plugin/Phake/PhakeMockingStrategy.php b/src/Moka/Plugin/Phake/PhakeMockingStrategy.php index 64ce2fa..f07fb9d 100644 --- a/src/Moka/Plugin/Phake/PhakeMockingStrategy.php +++ b/src/Moka/Plugin/Phake/PhakeMockingStrategy.php @@ -6,7 +6,7 @@ use Moka\Exception\MissingDependencyException; use Moka\Plugin\Phake\Matcher\FirstStubMatcher; use Moka\Strategy\AbstractMockingStrategy; -use Moka\Stub\Stub; +use Moka\Stub\MethodStub; use Phake; use Phake_IMock as PhakeMock; use Phake_Proxies_AnswerBinderProxy as AnswerBinderProxy; @@ -43,10 +43,10 @@ protected function doBuild(string $fqcn) /** * @param PhakeMock $mock - * @param Stub $stub + * @param MethodStub $stub * @return void */ - protected function doDecorate($mock, Stub $stub) + protected function doDecorateWithMethod($mock, MethodStub $stub) { $methodName = $stub->getName(); $methodValue = $stub->getValue(); diff --git a/src/Moka/Plugin/Prophecy/ProphecyMockingStrategy.php b/src/Moka/Plugin/Prophecy/ProphecyMockingStrategy.php index c26a73b..4b32fcf 100644 --- a/src/Moka/Plugin/Prophecy/ProphecyMockingStrategy.php +++ b/src/Moka/Plugin/Prophecy/ProphecyMockingStrategy.php @@ -7,7 +7,7 @@ use Moka\Exception\MockNotCreatedException; use Moka\Plugin\Prophecy\Token\MaxPriorityToken; use Moka\Strategy\AbstractMockingStrategy; -use Moka\Stub\Stub; +use Moka\Stub\MethodStub; use Prophecy\Exception\Prophecy\ObjectProphecyException; use Prophecy\Prophecy\MethodProphecy; use Prophecy\Prophecy\ObjectProphecy; @@ -51,10 +51,10 @@ protected function doBuild(string $fqcn) /** * @param ObjectProphecy $mock - * @param Stub $stub + * @param MethodStub $stub * @return void */ - protected function doDecorate($mock, Stub $stub) + protected function doDecorateWithMethod($mock, MethodStub $stub) { $methodName = $stub->getName(); $methodValue = $stub->getValue(); diff --git a/src/Moka/Proxy/ProxyTrait.php b/src/Moka/Proxy/ProxyTrait.php index 943fcf5..26a3c0d 100644 --- a/src/Moka/Proxy/ProxyTrait.php +++ b/src/Moka/Proxy/ProxyTrait.php @@ -54,16 +54,16 @@ public function __moka_setMockingStrategy(MockingStrategyInterface $mockingStrat } /** - * @param array $methodsWithValues + * @param array $namesWithValues * @return ProxyInterface * * @throws InvalidArgumentException * @throws MockNotCreatedException */ - public function stub(array $methodsWithValues): ProxyInterface + public function stub(array $namesWithValues): ProxyInterface { /** @var $this ProxyInterface */ - $this->__moka_mockingStrategy->decorate($this->__moka_mock, $methodsWithValues); + $this->__moka_mockingStrategy->decorate($this->__moka_mock, $namesWithValues); return $this; } diff --git a/src/Moka/Strategy/AbstractMockingStrategy.php b/src/Moka/Strategy/AbstractMockingStrategy.php index 673c0d2..a852018 100644 --- a/src/Moka/Strategy/AbstractMockingStrategy.php +++ b/src/Moka/Strategy/AbstractMockingStrategy.php @@ -8,7 +8,9 @@ use Moka\Exception\MockNotCreatedException; use Moka\Exception\NotImplementedException; use Moka\Factory\StubFactory; -use Moka\Stub\Stub; +use Moka\Stub\MethodStub; +use Moka\Stub\PropertyStub; +use Moka\Stub\StubInterface; /** * Class AbstractMockingStrategy @@ -63,7 +65,7 @@ public function build(string $fqcn) /** * @param object $mock - * @param array $stubs + * @param StubInterface[] $stubs * @return void * * @throws InvalidArgumentException @@ -75,9 +77,14 @@ public function decorate($mock, array $stubs) $stubs = StubFactory::fromArray($stubs); - /** @var Stub $stub */ foreach ($stubs as $stub) { - $this->doDecorate($mock, $stub); + if ($stub instanceof PropertyStub) { + $this->doDecorateWithProperty($mock, $stub); + } + + if ($stub instanceof MethodStub) { + $this->doDecorateWithMethod($mock, $stub); + } } } @@ -142,7 +149,7 @@ final protected function checkMockType($mock) if (!is_a($mock, $this->mockType)) { throw new InvalidArgumentException( sprintf( - 'Mock object must be of type "%s", "%s" given', + 'Mock object must be an instance of "%s", "%s" given', $this->mockType, gettype($mock) ) @@ -170,10 +177,20 @@ abstract protected function doBuild(string $fqcn); /** * @param object $mock - * @param Stub $stub + * @param PropertyStub $stub + * @return void + */ + protected function doDecorateWithProperty($mock, PropertyStub $stub) + { + $mock->{$stub->getName()} = $stub->getValue(); + } + + /** + * @param object $mock + * @param MethodStub $stub * @return void */ - abstract protected function doDecorate($mock, Stub $stub); + abstract protected function doDecorateWithMethod($mock, MethodStub $stub); /** * @param object $mock diff --git a/src/Moka/Stub/AbstractStub.php b/src/Moka/Stub/AbstractStub.php new file mode 100644 index 0000000..b314c85 --- /dev/null +++ b/src/Moka/Stub/AbstractStub.php @@ -0,0 +1,56 @@ +name = $name; + $this->value = $value; + } + + /** + * @return string + */ + public function getName(): string + { + return $this->name; + } + + /** + * @return mixed + */ + public function getValue() + { + return $this->value; + } +} diff --git a/src/Moka/Stub/MethodStub.php b/src/Moka/Stub/MethodStub.php new file mode 100644 index 0000000..3425c0f --- /dev/null +++ b/src/Moka/Stub/MethodStub.php @@ -0,0 +1,29 @@ +name = $methodName; - $this->value = $methodValue; - } - - /** - * @return bool - */ - public function isProperty(): bool - { - return self::PREFIX_PROPERTY === $this->getName()[0]; - } - - /** - * @return bool - */ - public function isMethod(): bool - { - return !$this->isProperty(); - } - - /** - * @return string - */ - public function getName(): string - { - return $this->name; - } - - /** - * @return mixed - */ - public function getValue() - { - return $this->value; - } -} diff --git a/src/Moka/Stub/StubInterface.php b/src/Moka/Stub/StubInterface.php new file mode 100644 index 0000000..b22024f --- /dev/null +++ b/src/Moka/Stub/StubInterface.php @@ -0,0 +1,24 @@ +strategy->get($this->mock)->getSelf(); } - final public function testDecorateSingleCallSuccess() + final public function testDecorateWithPropertySuccess() + { + $this->strategy->decorate($this->mock, [ + '$property' => 1138 + ]); + + $this->assertEquals( + 1138, + $this->strategy->get($this->mock)->property + ); + } + + final public function testDecorateWithMethodSingleCallSuccess() { $this->assertSame($this->methodsWithValues['isTrue'], $this->strategy->get($this->mock)->isTrue()); @@ -83,13 +95,13 @@ final public function testDecorateSingleCallSuccess() $this->strategy->get($this->mock)->throwException(); } - final public function testDecorateMultipleCallsSuccess() + final public function testDecorateWithMethodMultipleCallsSuccess() { $this->assertSame($this->methodsWithValues['getInt'], $this->strategy->get($this->mock)->getInt()); $this->assertSame($this->methodsWithValues['getInt'], $this->strategy->get($this->mock)->getInt()); } - final public function testDecorateOverriddenCallsFailure() + final public function testDecorateWithMethodOverriddenCallsFailure() { $this->strategy->decorate($this->mock, [ 'getInt' => mt_rand(), @@ -104,19 +116,19 @@ final public function testDecorateOverriddenCallsFailure() $this->strategy->get($this->mock)->throwException(); } - final public function testDecorateCallWithArgumentSuccess() + final public function testDecorateWithMethodCallWithArgumentSuccess() { $this->assertSame($this->methodsWithValues['withArgument'], $this->strategy->get($this->mock)->withArgument(mt_rand())); } - final public function testDecorateCallWithMissingArgumentFailure() + final public function testDecorateWithMethodCallWithMissingArgumentFailure() { $this->expectException(\Error::class); $this->strategy->get($this->mock)->withArgument(); } - final public function testDecorateCallWithWrongArgumentFailure() + final public function testDecorateWithMethodCallWithWrongArgumentFailure() { $this->expectException(\TypeError::class); diff --git a/tests/Factory/StubFactoryTest.php b/tests/Factory/StubFactoryTest.php index 0b521b2..42014a3 100644 --- a/tests/Factory/StubFactoryTest.php +++ b/tests/Factory/StubFactoryTest.php @@ -5,7 +5,7 @@ use Moka\Exception\InvalidArgumentException; use Moka\Factory\StubFactory; -use Moka\Stub\Stub; +use Moka\Stub\StubInterface; use PHPUnit\Framework\TestCase; class StubFactoryTest extends TestCase @@ -13,13 +13,14 @@ class StubFactoryTest extends TestCase public function testSuccess() { $array = [ - 'methodName' => true + 'methodName' => true, + '$propertyName' => false ]; $stubs = StubFactory::fromArray($array); $this->assertNotEmpty($stubs); - $this->containsOnlyInstancesOf(Stub::class); + $this->containsOnlyInstancesOf(StubInterface::class); $this->assertCount(count($array), $stubs); } diff --git a/tests/Strategy/IncompleteMockingStrategy.php b/tests/Strategy/IncompleteMockingStrategy.php index 3339b06..2fc6a03 100644 --- a/tests/Strategy/IncompleteMockingStrategy.php +++ b/tests/Strategy/IncompleteMockingStrategy.php @@ -4,7 +4,7 @@ namespace Tests\Strategy; use Moka\Strategy\AbstractMockingStrategy; -use Moka\Stub\Stub; +use Moka\Stub\MethodStub; class IncompleteMockingStrategy extends AbstractMockingStrategy { @@ -16,7 +16,7 @@ protected function doBuild(string $fqcn) { } - protected function doDecorate($mock, Stub $stub) + protected function doDecorateWithMethod($mock, MethodStub $stub) { } diff --git a/tests/Stub/MethodStubTest.php b/tests/Stub/MethodStubTest.php new file mode 100644 index 0000000..0ea258f --- /dev/null +++ b/tests/Stub/MethodStubTest.php @@ -0,0 +1,63 @@ +setStubType(MethodStub::class); + } + + public function testConstructMethodSuccess() + { + $fqcn = $this->fqcn; + + $stub = new $fqcn('name', 1138); + + $this->assertInstanceOf(StubInterface::class, $stub); + } + + public function testConstructMethodFailure() + { + $fqcn = $this->fqcn; + + $this->expectException(InvalidArgumentException::class); + + new $fqcn( + sprintf( + '%s%s', + StubInterface::PREFIX_PROPERTY, + 'name' + ), + true + ); + } + + public function testGetName() + { + $fqcn = $this->fqcn; + + /** @var StubInterface $stub */ + $stub = new $fqcn('name', 1138); + + $this->assertEquals('name', $stub->getName()); + } + + public function testGetValue() + { + $fqcn = $this->fqcn; + + /** @var StubInterface $stub */ + $stub = new $fqcn('name', 1138); + + $this->assertEquals(1138, $stub->getValue()); + } +} diff --git a/tests/Stub/PropertyStubTest.php b/tests/Stub/PropertyStubTest.php new file mode 100644 index 0000000..99a2b1b --- /dev/null +++ b/tests/Stub/PropertyStubTest.php @@ -0,0 +1,76 @@ +setStubType(PropertyStub::class); + } + + public function testConstructPropertySuccess() + { + $fqcn = $this->fqcn; + + $stub = new $fqcn( + sprintf( + '%s%s', + StubInterface::PREFIX_PROPERTY, + 'name' + ), + 1138); + + $this->assertInstanceOf(StubInterface::class, $stub); + } + + public function testConstructPropertyFailure() + { + $fqcn = $this->fqcn; + + $this->expectException(InvalidArgumentException::class); + + new $fqcn('name', true); + } + + public function testGetName() + { + $fqcn = $this->fqcn; + + /** @var StubInterface $stub */ + $stub = new $fqcn( + sprintf( + '%s%s', + StubInterface::PREFIX_PROPERTY, + 'name' + ), + 1138 + ); + + $this->assertEquals('name', $stub->getName()); + } + + public function testGetValue() + { + $fqcn = $this->fqcn; + + /** @var StubInterface $stub */ + $stub = new $fqcn( + sprintf( + '%s%s', + StubInterface::PREFIX_PROPERTY, + 'name' + ), + 1138 + ); + + $this->assertEquals(1138, $stub->getValue()); + } +} diff --git a/tests/Stub/StubSetTest.php b/tests/Stub/StubSetTest.php index 061d211..92f80a7 100644 --- a/tests/Stub/StubSetTest.php +++ b/tests/Stub/StubSetTest.php @@ -4,7 +4,7 @@ namespace Tests\Stub; use Moka\Exception\InvalidArgumentException; -use Moka\Stub\Stub; +use Moka\Stub\StubInterface; use Moka\Stub\StubSet; use PHPUnit\Framework\TestCase; @@ -22,7 +22,8 @@ protected function setUp() public function testAddSuccess() { - $stub = $this->getMockBuilder(Stub::class) + /** @var StubInterface $stub */ + $stub = $this->getMockBuilder(StubInterface::class) ->disableOriginalConstructor() ->getMock(); diff --git a/tests/Stub/StubTestCase.php b/tests/Stub/StubTestCase.php new file mode 100644 index 0000000..6d43905 --- /dev/null +++ b/tests/Stub/StubTestCase.php @@ -0,0 +1,29 @@ +fqcn; + + $this->expectException(InvalidArgumentException::class); + + new $fqcn('0a', true); + } + + protected function setStubType(string $fqcn) + { + $this->fqcn = $fqcn; + } +} From 94897c3cfcfa8f848ea1b7f3a670f466ecacc521 Mon Sep 17 00:00:00 2001 From: Alberto Villa Date: Wed, 12 Jul 2017 16:57:26 +0200 Subject: [PATCH 45/46] Update README --- README.md | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index d76d2e3..286a933 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ composer require --dev facile-it/moka ## Usage -To use **Moka** in your tests simply `use` function `Moka\Plugin\PHPUnit\moka()` (see generators section [below](#strategies)) and run `Moka::clean()` before every test. A simple interface will let you create *moka* (mock) objects and decorate them with *stub* methods via a fluent interface: +To use **Moka** in your tests simply `use` function `Moka\Plugin\PHPUnit\moka()` (see generators section [below](#strategies)) and run `Moka::clean()` before every test. A simple interface will let you create *moka* (mock) objects and decorate them with *stub* methods and properties via a fluent interface: ```php foo = new Foo( moka(BarInterface::class)->stub([ + // Property name => value. + '$property' => 3, // Method name => return value. 'method1' => moka(AcmeInterface::class), - 'method2' => true // Any return value. + 'method2' => true ]) ); } @@ -126,22 +128,30 @@ var_dump($mock1 === $mock2); // bool(true) ``` -### `ProxyInterface::stub(array $methodsWithValues): ProxyInterface` +### `ProxyInterface::stub(array $namesWithValues): ProxyInterface` -Accepts an array of method stubs with format `[$methodName => $methodValue]`, where `$methodName` **must** be a string and `$methodValue` can be of any type, including another mock object or an exception instance (which will be thrown): +Accepts an array of method or property stubs with format `[$name => $value]`, where `$name` **must** be a string and `$value` can be of any type, including another mock object. + +**Caution**: +- Properties are identified by symbol `$` prepended to their names +- An exception instance set as a method value will be thrown when the method is called ```php $mock = moka(BarInterface::class)->stub([ + '$property' => 1, 'isValid' => true, 'getMock' => moka(AcmeInterface::class), 'throwException' => new \Exception() ]); +var_dump($mock->property); +// int(1) + var_dump($mock->isValid()); // bool(true) ``` -**Notice:** the stub is valid for **any** invocation of the method and cannot be overridden. +**Notice:** method stubs are valid for **any** invocation of the defined methods and cannot be overridden. If you need more granular control over invocation strategies, you can get [access to the original mock object implementation](#original-mock). ## Supported mock object generators @@ -221,7 +231,7 @@ class YourOwnMockingStrategy extends AbstractMockingStrategy protected function doDecorateWithMethod($mock, MethodStub $stub) { - // TODO: Implement doDecorate() method. + // TODO: Implement doDecorateWithMethod() method. } protected function doGet($mock) From f4c4c0c49c51ac008a303687b5e1aea2f63eccf4 Mon Sep 17 00:00:00 2001 From: Alberto Villa Date: Wed, 12 Jul 2017 17:03:28 +0200 Subject: [PATCH 46/46] Improve stub name validation --- src/Moka/Stub/AbstractStub.php | 11 +++++++++-- src/Moka/Stub/MethodStub.php | 17 ----------------- src/Moka/Stub/PropertyStub.php | 10 ++++++++-- 3 files changed, 17 insertions(+), 21 deletions(-) diff --git a/src/Moka/Stub/AbstractStub.php b/src/Moka/Stub/AbstractStub.php index b314c85..7a1cf20 100644 --- a/src/Moka/Stub/AbstractStub.php +++ b/src/Moka/Stub/AbstractStub.php @@ -11,6 +11,8 @@ */ abstract class AbstractStub implements StubInterface { + const REGEX_NAME = '/^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$/'; + /** * @var string */ @@ -30,8 +32,13 @@ abstract class AbstractStub implements StubInterface */ public function __construct(string $name, $value) { - if (!preg_match('/^[a-z_][a-z0-9_]*$/i', $name)) { - throw new InvalidArgumentException(); + if (!preg_match(self::REGEX_NAME, $name)) { + throw new InvalidArgumentException( + sprintf( + 'Name must be a valid variable or method name, "%s" given', + $name + ) + ); } $this->name = $name; diff --git a/src/Moka/Stub/MethodStub.php b/src/Moka/Stub/MethodStub.php index 3425c0f..05df795 100644 --- a/src/Moka/Stub/MethodStub.php +++ b/src/Moka/Stub/MethodStub.php @@ -3,27 +3,10 @@ namespace Moka\Stub; -use Moka\Exception\InvalidArgumentException; - /** * Class MethodStub * @package Moka\Stub */ class MethodStub extends AbstractStub { - /** - * PropertyStub constructor. - * @param string $name - * @param mixed $value - * - * @throws InvalidArgumentException - */ - public function __construct($name, $value) - { - if (static::PREFIX_PROPERTY === $name[0]) { - throw new InvalidArgumentException(); - } - - parent::__construct($name, $value); - } } diff --git a/src/Moka/Stub/PropertyStub.php b/src/Moka/Stub/PropertyStub.php index fc731fc..096dd2c 100644 --- a/src/Moka/Stub/PropertyStub.php +++ b/src/Moka/Stub/PropertyStub.php @@ -18,10 +18,16 @@ class PropertyStub extends AbstractStub * * @throws InvalidArgumentException */ - public function __construct($name, $value) + public function __construct(string $name, $value) { if (static::PREFIX_PROPERTY !== $name[0]) { - throw new InvalidArgumentException(); + throw new InvalidArgumentException( + sprintf( + 'Name must be prefixed by "%s", "%s" given', + StubInterface::PREFIX_PROPERTY, + $name + ) + ); } parent::__construct(substr($name, 1), $value);