diff --git a/spec/Prophecy/Argument/ArgumentsWildcardSpec.php b/spec/Prophecy/Argument/ArgumentsWildcardSpec.php index b82f1b893..4daa0b0b3 100644 --- a/spec/Prophecy/Argument/ArgumentsWildcardSpec.php +++ b/spec/Prophecy/Argument/ArgumentsWildcardSpec.php @@ -14,7 +14,10 @@ function it_wraps_non_token_arguments_into_ExactValueToken(\stdClass $object) $class = get_class($object->getWrappedObject()); $hash = spl_object_hash($object->getWrappedObject()); - $this->__toString()->shouldReturn("exact(42), exact(\"zet\"), exact($class:$hash Object (\n 'objectProphecy' => Prophecy\Prophecy\ObjectProphecy Object (*Prophecy*)\n))"); + $objHash = "exact(42), exact(\"zet\"), exact($class:$hash Object (\n 'objectProphecyClosure' => Closure:%s Object (\n 0 => Closure:%s Object\n )\n))"; + + $hashRegexExpr = '[a-f0-9]{32}'; + $this->__toString()->shouldMatch(sprintf('/^%s$/', sprintf(preg_quote("$objHash"), $hashRegexExpr, $hashRegexExpr))); } function it_generates_string_representation_from_all_tokens_imploded( diff --git a/spec/Prophecy/Argument/Token/ExactValueTokenSpec.php b/spec/Prophecy/Argument/Token/ExactValueTokenSpec.php index 14322f829..357c05b7f 100644 --- a/spec/Prophecy/Argument/Token/ExactValueTokenSpec.php +++ b/spec/Prophecy/Argument/Token/ExactValueTokenSpec.php @@ -125,13 +125,15 @@ function it_generates_proper_string_representation_for_resource() function it_generates_proper_string_representation_for_object(\stdClass $object) { - $objHash = sprintf('%s:%s', + $objHash = sprintf('exact(%s:%s', get_class($object->getWrappedObject()), spl_object_hash($object->getWrappedObject()) - ); + ) . " Object (\n 'objectProphecyClosure' => Closure:%s Object (\n 0 => Closure:%s Object\n )\n))"; $this->beConstructedWith($object); - $this->__toString()->shouldReturn("exact($objHash Object (\n 'objectProphecy' => Prophecy\Prophecy\ObjectProphecy Object (*Prophecy*)\n))"); + + $hashRegexExpr = '[a-f0-9]{32}'; + $this->__toString()->shouldMatch(sprintf('/^%s$/', sprintf(preg_quote("$objHash"), $hashRegexExpr, $hashRegexExpr))); } } diff --git a/spec/Prophecy/Argument/Token/IdenticalValueTokenSpec.php b/spec/Prophecy/Argument/Token/IdenticalValueTokenSpec.php index 00c3a2157..42625b695 100644 --- a/spec/Prophecy/Argument/Token/IdenticalValueTokenSpec.php +++ b/spec/Prophecy/Argument/Token/IdenticalValueTokenSpec.php @@ -141,12 +141,14 @@ function it_generates_proper_string_representation_for_resource() function it_generates_proper_string_representation_for_object($object) { - $objHash = sprintf('%s:%s', + $objHash = sprintf('identical(%s:%s', get_class($object->getWrappedObject()), spl_object_hash($object->getWrappedObject()) - ); + ) . " Object (\n 'objectProphecyClosure' => Closure:%s Object (\n 0 => Closure:%s Object\n )\n))"; $this->beConstructedWith($object); - $this->__toString()->shouldReturn("identical($objHash Object (\n 'objectProphecy' => Prophecy\Prophecy\ObjectProphecy Object (*Prophecy*)\n))"); + + $hashRegexExpr = '[a-f0-9]{32}'; + $this->__toString()->shouldMatch(sprintf('/^%s$/', sprintf(preg_quote("$objHash"), $hashRegexExpr, $hashRegexExpr))); } } diff --git a/spec/Prophecy/Doubler/CachedDoublerSpec.php b/spec/Prophecy/Doubler/CachedDoublerSpec.php new file mode 100644 index 000000000..8cf9a0cbd --- /dev/null +++ b/spec/Prophecy/Doubler/CachedDoublerSpec.php @@ -0,0 +1,414 @@ +beConstructedWith($mirror, $creator, $namer); + $this->resetCache(); + } + + /** + * @todo implement + * T - T + * T - F + * F - T + * F - F + * F T F + * F T T + */ + + // T - - + function it_creates_only_one_class_definition_for_the_same_class_without_interfaces_and_patches( + ClassMirror $mirror, + ClassCreator $creator, + NameGenerator $namer, + \ReflectionClass $class, + ClassNode $node + ) { + $mirror->reflect($class, array())->willReturn($node); + $namer->name($class, array())->willReturn('SplStack'); + $class->getName()->willReturn('stdClass'); + + $creator->create('SplStack', $node)->shouldBeCalledTimes(1); + + $this->double($class, array()); + $this->double($class, array()); + } + + // F - - + function it_creates_two_class_definitions_for_different_classes_without_interfaces_and_patches( + ClassMirror $mirror, + ClassCreator $creator, + NameGenerator $namer, + \ReflectionClass $class1, + \ReflectionClass $class2, + ClassNode $node1, + ClassNode $node2 + ) { + $mirror->reflect($class1, array())->willReturn($node1); + $mirror->reflect($class2, array())->willReturn($node2); + $namer->name($class1, array())->willReturn('SplStack'); + $namer->name($class2, array())->willReturn('spec\Prophecy\Doubler\aClass'); + $class1->getName()->willReturn('stdClass'); + $class2->getName()->willReturn('aClass'); + + $creator->create('SplStack', $node1)->shouldBeCalledTimes(1); + $creator->create('spec\Prophecy\Doubler\aClass', $node2)->shouldBeCalledTimes(1); + + $this->double($class1, array()); + $this->double($class2, array()); + } + + // T F T + function it_creates_two_different_class_definitions_for_the_same_class_with_different_interfaces_and_same_patches( + ClassMirror $mirror, + ClassCreator $creator, + NameGenerator $namer, + ClassPatchInterface $alt1, + ClassPatchInterface $alt2, + \ReflectionClass $class, + \ReflectionClass $interface1, + \ReflectionClass $interface2, + ClassNode $node1, + ClassNode $node2 + ) { + $mirror->reflect($class, array($interface1))->willReturn($node1); + $mirror->reflect($class, array($interface2))->willReturn($node2); + $alt1->supports($node1)->willReturn(true); + $alt1->supports($node2)->willReturn(true); + $alt2->supports($node1)->willReturn(false); + $alt2->supports($node2)->willReturn(false); + $alt1->getPriority()->willReturn(1); + $alt2->getPriority()->willReturn(2); + $namer->name($class, array($interface1))->willReturn('SplStack'); + $namer->name($class, array($interface2))->willReturn('SplStack'); + $class->getName()->willReturn('stdClass'); + $interface1->getName()->willReturn('ArrayAccess'); + $interface2->getName()->willReturn('Iterator'); + + $alt1->apply($node1)->shouldBeCalled(); + $alt1->apply($node2)->shouldBeCalled(); + $alt2->apply($node1)->shouldNotBeCalled(); + $alt2->apply($node2)->shouldNotBeCalled(); + $creator->create('SplStack', $node1)->shouldBeCalledTimes(1); + $creator->create('SplStack', $node2)->shouldBeCalledTimes(1); + + $this->registerClassPatch($alt1); + $this->registerClassPatch($alt2); + + $this->double($class, array($interface1)); + $this->double($class, array($interface2)); + } + + // F F T + function it_creates_two_different_class_definitions_for_different_classes_with_different_interfaces_and_same_patches( + ClassMirror $mirror, + ClassCreator $creator, + NameGenerator $namer, + ClassPatchInterface $alt1, + ClassPatchInterface $alt2, + \ReflectionClass $class1, + \ReflectionClass $class2, + \ReflectionClass $interface1, + \ReflectionClass $interface2, + ClassNode $node1, + ClassNode $node2 + ) { + $mirror->reflect($class1, array($interface1))->willReturn($node1); + $mirror->reflect($class2, array($interface2))->willReturn($node2); + $alt1->supports($node1)->willReturn(true); + $alt1->supports($node2)->willReturn(true); + $alt2->supports($node1)->willReturn(false); + $alt2->supports($node2)->willReturn(false); + $alt1->getPriority()->willReturn(1); + $alt2->getPriority()->willReturn(2); + $namer->name($class1, array($interface1))->willReturn('SplStack'); + $namer->name($class2, array($interface2))->willReturn('spec\Prophecy\Doubler\aClass'); + $class1->getName()->willReturn('stdClass'); + $class2->getName()->willReturn('aClass'); + $interface1->getName()->willReturn('ArrayAccess'); + $interface2->getName()->willReturn('Iterator'); + + $alt1->apply($node1)->shouldBeCalled(); + $alt1->apply($node2)->shouldBeCalled(); + $alt2->apply($node1)->shouldNotBeCalled(); + $alt2->apply($node2)->shouldNotBeCalled(); + $creator->create('SplStack', $node1)->shouldBeCalledTimes(1); + $creator->create('spec\Prophecy\Doubler\aClass', $node2)->shouldBeCalledTimes(1); + + $this->registerClassPatch($alt1); + $this->registerClassPatch($alt2); + + $this->double($class1, array($interface1)); + $this->double($class2, array($interface2)); + } + + // T T - + function it_creates_only_one_class_definition_for_the_same_class_with_same_interfaces_and_without_patches( + ClassMirror $mirror, + ClassCreator $creator, + NameGenerator $namer, + \ReflectionClass $class, + \ReflectionClass $interface1, + \ReflectionClass $interface2, + ClassNode $node + ) { + $mirror->reflect($class, array($interface1, $interface2))->willReturn($node); + $namer->name($class, array($interface1, $interface2))->willReturn('SplStack'); + $class->getName()->willReturn('stdClass'); + $interface1->getName()->willReturn('ArrayAccess'); + $interface2->getName()->willReturn('Iterator'); + + $creator->create('SplStack', $node)->shouldBeCalledTimes(1); + + $this->double($class, array($interface1, $interface2)); + $this->double($class, array($interface1, $interface2)); + } + + // F T - + function it_creates_only_one_class_definition_for_different_classes_with_same_interfaces_and_without_patches( + ClassMirror $mirror, + ClassCreator $creator, + NameGenerator $namer, + \ReflectionClass $class1, + \ReflectionClass $class2, + \ReflectionClass $interface1, + \ReflectionClass $interface2, + ClassNode $node1, + ClassNode $node2 + ) { + $mirror->reflect($class1, array($interface1, $interface2))->willReturn($node1); + $mirror->reflect($class2, array($interface1, $interface2))->willReturn($node2); + $namer->name($class1, array($interface1, $interface2))->willReturn('SplStack'); + $namer->name($class2, array($interface1, $interface2))->willReturn('spec\Prophecy\Doubler\aClass'); + $class1->getName()->willReturn('stdClass'); + $class2->getName()->willReturn('aClass'); + $interface1->getName()->willReturn('ArrayAccess'); + $interface2->getName()->willReturn('Iterator'); + + $creator->create('SplStack', $node1)->shouldBeCalledTimes(1); + $creator->create('spec\Prophecy\Doubler\aClass', $node2)->shouldBeCalledTimes(1); + + $this->double($class1, array($interface1, $interface2)); + $this->double($class2, array($interface1, $interface2)); + } + + // T F - + function it_creates_two_different_class_definitions_for_the_same_class_with_different_interfaces_and_without_patches( + ClassMirror $mirror, + ClassCreator $creator, + NameGenerator $namer, + \ReflectionClass $class, + \ReflectionClass $interface1, + \ReflectionClass $interface2, + ClassNode $node1, + ClassNode $node2 + ) { + $mirror->reflect($class, array($interface1))->willReturn($node1); + $mirror->reflect($class, array($interface2))->willReturn($node2); + $namer->name($class, array($interface1))->willReturn('SplStack'); + $namer->name($class, array($interface2))->willReturn('SplStack'); + $class->getName()->willReturn('stdClass'); + $interface1->getName()->willReturn('ArrayAccess'); + $interface2->getName()->willReturn('Iterator'); + + $creator->create('SplStack', $node1)->shouldBeCalledTimes(1); + $creator->create('SplStack', $node2)->shouldBeCalledTimes(1); + + $this->double($class, array($interface1)); + $this->double($class, array($interface2)); + } + + // F F - + function it_creates_two_different_class_definitions_for_different_classes_with_different_interfaces_and_without_patches( + ClassMirror $mirror, + ClassCreator $creator, + NameGenerator $namer, + \ReflectionClass $class1, + \ReflectionClass $class2, + \ReflectionClass $interface1, + \ReflectionClass $interface2, + ClassNode $node1, + ClassNode $node2 + ) { + $mirror->reflect($class1, array($interface1))->willReturn($node1); + $mirror->reflect($class2, array($interface2))->willReturn($node2); + $namer->name($class1, array($interface1))->willReturn('SplStack'); + $namer->name($class2, array($interface2))->willReturn('spec\Prophecy\Doubler\aClass'); + $class1->getName()->willReturn('stdClass'); + $class2->getName()->willReturn('aClass'); + $interface1->getName()->willReturn('ArrayAccess'); + $interface2->getName()->willReturn('Iterator'); + + $creator->create('SplStack', $node1)->shouldBeCalledTimes(1); + $creator->create('spec\Prophecy\Doubler\aClass', $node2)->shouldBeCalledTimes(1); + + $this->double($class1, array($interface1)); + $this->double($class2, array($interface2)); + } + + // T T T + function it_creates_only_one_class_definition_for_the_same_class_with_same_interfaces_and_same_patches( + ClassMirror $mirror, + ClassCreator $creator, + NameGenerator $namer, + ClassPatchInterface $alt1, + ClassPatchInterface $alt2, + \ReflectionClass $class, + \ReflectionClass $interface1, + \ReflectionClass $interface2, + ClassNode $node + ) { + $mirror->reflect($class, array($interface1, $interface2))->willReturn($node); + $alt1->supports($node)->willReturn(true); + $alt2->supports($node)->willReturn(false); + $alt1->getPriority()->willReturn(1); + $alt2->getPriority()->willReturn(2); + $namer->name($class, array($interface1, $interface2))->willReturn('SplStack'); + $class->getName()->willReturn('stdClass'); + $interface1->getName()->willReturn('ArrayAccess'); + $interface2->getName()->willReturn('Iterator'); + + $alt1->apply($node)->shouldBeCalled(); + $alt2->apply($node)->shouldNotBeCalled(); + $creator->create('SplStack', $node)->shouldBeCalledTimes(1); + + $this->registerClassPatch($alt1); + $this->registerClassPatch($alt2); + + $this->double($class, array($interface1, $interface2)); + $this->double($class, array($interface1, $interface2)); + } + + // F F F + function it_creates_two_class_definitions_for_different_classes_with_different_interfaces_and_patches( + ClassMirror $mirror, + ClassCreator $creator, + NameGenerator $namer, + ClassPatchInterface $alt1, + ClassPatchInterface $alt2, + \ReflectionClass $class1, + \ReflectionClass $class2, + \ReflectionClass $interface1, + \ReflectionClass $interface2, + ClassNode $node1, + ClassNode $node2 + ) { + $mirror->reflect($class1, array($interface1))->willReturn($node1); + $mirror->reflect($class2, array($interface2))->willReturn($node2); + $alt1->supports($node1)->willReturn(true); + $alt1->supports($node2)->willReturn(true); + $alt2->supports($node2)->willReturn(false); + $alt1->getPriority()->willReturn(1); + $alt2->getPriority()->willReturn(2); + $namer->name($class1, array($interface1))->willReturn('SplStack'); + $namer->name($class2, array($interface2))->willReturn('spec\Prophecy\Doubler\aClass'); + $class1->getName()->willReturn('stdClass'); + $class2->getName()->willReturn('aClass'); + $interface1->getName()->willReturn('ArrayAccess'); + $interface2->getName()->willReturn('Iterator'); + + $alt1->apply($node1)->shouldBeCalled(); + $alt1->apply($node2)->shouldBeCalled(); + $alt2->apply($node2)->shouldNotBeCalled(); + $creator->create('SplStack', $node1)->shouldBeCalledTimes(1); + $creator->create('spec\Prophecy\Doubler\aClass', $node2)->shouldBeCalledTimes(1); + + $this->registerClassPatch($alt1); + $this->double($class1, array($interface1)); + + $this->registerClassPatch($alt2); + $this->double($class2, array($interface2)); + } + + // T F F + function it_creates_two_class_definitions_for_the_same_class_with_different_interfaces_and_patches( + ClassMirror $mirror, + ClassCreator $creator, + NameGenerator $namer, + ClassPatchInterface $alt1, + ClassPatchInterface $alt2, + \ReflectionClass $class, + \ReflectionClass $interface1, + \ReflectionClass $interface2, + ClassNode $node1, + ClassNode $node2 + ) { + $mirror->reflect($class, array($interface1))->willReturn($node1); + $mirror->reflect($class, array($interface2))->willReturn($node2); + $alt1->supports($node1)->willReturn(true); + $alt1->supports($node2)->willReturn(true); + $alt2->supports($node2)->willReturn(false); + $alt1->getPriority()->willReturn(1); + $alt2->getPriority()->willReturn(2); + $namer->name($class, array($interface1))->willReturn('SplStack'); + $namer->name($class, array($interface2))->willReturn('SplStack'); + $class->getName()->willReturn('stdClass'); + $interface1->getName()->willReturn('ArrayAccess'); + $interface2->getName()->willReturn('Iterator'); + + $alt1->apply($node1)->shouldBeCalled(); + $alt1->apply($node2)->shouldBeCalled(); + $alt2->apply($node2)->shouldNotBeCalled(); + $creator->create('SplStack', $node1)->shouldBeCalledTimes(1); + $creator->create('SplStack', $node2)->shouldBeCalledTimes(1); + + $this->registerClassPatch($alt1); + $this->double($class, array($interface1)); + + $this->registerClassPatch($alt2); + $this->double($class, array($interface2)); + } + + // T T F + function it_creates_two_different_class_definitions_for_the_same_class_with_same_interfaces_and_different_patches( + ClassMirror $mirror, + ClassCreator $creator, + NameGenerator $namer, + ClassPatchInterface $alt1, + ClassPatchInterface $alt2, + \ReflectionClass $class, + \ReflectionClass $interface1, + \ReflectionClass $interface2, + ClassNode $node1, + ClassNode $node2 + ) { + $mirror->reflect($class, array($interface1, $interface2))->willReturn($node1, $node2); + $alt1->supports($node1)->willReturn(true); + $alt1->supports($node2)->willReturn(true); + $alt2->supports($node2)->willReturn(false); + $alt1->getPriority()->willReturn(1); + $alt2->getPriority()->willReturn(2); + $namer->name($class, array($interface1, $interface2))->willReturn('SplStack'); + $class->getName()->willReturn('stdClass'); + $interface1->getName()->willReturn('ArrayAccess'); + $interface2->getName()->willReturn('Iterator'); + + $alt1->apply($node1)->shouldBeCalled(); + $creator->create('SplStack', $node1)->shouldBeCalledTimes(1); + + $this->registerClassPatch($alt1); + $this->double($class, array($interface1, $interface2)); + + $alt1->apply($node2)->shouldBeCalled(); + $alt2->apply($node2)->shouldNotBeCalled(); + $creator->create('SplStack', $node2)->shouldBeCalledTimes(1); + + $this->registerClassPatch($alt2); + $this->double($class, array($interface1, $interface2)); + } +} + +class aClass +{ +} \ No newline at end of file diff --git a/spec/Prophecy/Doubler/ClassPatch/ProphecySubjectPatchSpec.php b/spec/Prophecy/Doubler/ClassPatch/ProphecySubjectPatchSpec.php index ef1c254ed..87e4fd099 100644 --- a/spec/Prophecy/Doubler/ClassPatch/ProphecySubjectPatchSpec.php +++ b/spec/Prophecy/Doubler/ClassPatch/ProphecySubjectPatchSpec.php @@ -28,7 +28,7 @@ function it_forces_class_to_implement_ProphecySubjectInterface(ClassNode $node) { $node->addInterface('Prophecy\Prophecy\ProphecySubjectInterface')->shouldBeCalled(); - $node->addProperty('objectProphecy', 'private')->willReturn(null); + $node->addProperty('objectProphecyClosure', 'private')->willReturn(null); $node->getMethods()->willReturn(array()); $node->hasMethod(Argument::any())->willReturn(false); $node->addMethod(Argument::type('Prophecy\Doubler\Generator\Node\MethodNode'), true)->willReturn(null); @@ -45,7 +45,7 @@ function it_forces_all_class_methods_except_constructor_to_proxy_calls_into_prop MethodNode $method3 ) { $node->addInterface('Prophecy\Prophecy\ProphecySubjectInterface')->willReturn(null); - $node->addProperty('objectProphecy', 'private')->willReturn(null); + $node->addProperty('objectProphecyClosure', 'private')->willReturn(null); $node->hasMethod(Argument::any())->willReturn(false); $node->addMethod(Argument::type('Prophecy\Doubler\Generator\Node\MethodNode'), true)->willReturn(null); $node->addMethod(Argument::type('Prophecy\Doubler\Generator\Node\MethodNode'), true)->willReturn(null); diff --git a/spec/Prophecy/Util/StringUtilSpec.php b/spec/Prophecy/Util/StringUtilSpec.php index 80573cffb..923f09af1 100644 --- a/spec/Prophecy/Util/StringUtilSpec.php +++ b/spec/Prophecy/Util/StringUtilSpec.php @@ -74,9 +74,10 @@ function it_generates_proper_string_representation_for_object(\stdClass $object) $objHash = sprintf('%s:%s', get_class($object->getWrappedObject()), spl_object_hash($object->getWrappedObject()) - ) . " Object (\n 'objectProphecy' => Prophecy\Prophecy\ObjectProphecy Object (*Prophecy*)\n)"; + ) . " Object (\n 'objectProphecyClosure' => Closure:%s Object (\n 0 => Closure:%s Object\n )\n)"; - $this->stringify($object)->shouldReturn("$objHash"); + $hashRegexExpr = '[a-f0-9]{32}'; + $this->stringify($object)->shouldMatch(sprintf('/^%s$/', sprintf(preg_quote("$objHash"), $hashRegexExpr, $hashRegexExpr))); } function it_generates_proper_string_representation_for_object_without_exporting(\stdClass $object) diff --git a/src/Prophecy/Doubler/CachedDoubler.php b/src/Prophecy/Doubler/CachedDoubler.php index d6b6b1a9e..2b875211a 100644 --- a/src/Prophecy/Doubler/CachedDoubler.php +++ b/src/Prophecy/Doubler/CachedDoubler.php @@ -21,17 +21,7 @@ */ class CachedDoubler extends Doubler { - private $classes = array(); - - /** - * {@inheritdoc} - */ - public function registerClassPatch(ClassPatch\ClassPatchInterface $patch) - { - $this->classes[] = array(); - - parent::registerClassPatch($patch); - } + private static $classes = array(); /** * {@inheritdoc} @@ -39,11 +29,11 @@ public function registerClassPatch(ClassPatch\ClassPatchInterface $patch) protected function createDoubleClass(ReflectionClass $class = null, array $interfaces) { $classId = $this->generateClassId($class, $interfaces); - if (isset($this->classes[$classId])) { - return $this->classes[$classId]; + if (isset(self::$classes[$classId])) { + return self::$classes[$classId]; } - return $this->classes[$classId] = parent::createDoubleClass($class, $interfaces); + return self::$classes[$classId] = parent::createDoubleClass($class, $interfaces); } /** @@ -61,8 +51,16 @@ private function generateClassId(ReflectionClass $class = null, array $interface foreach ($interfaces as $interface) { $parts[] = $interface->getName(); } + foreach ($this->getClassPatches() as $patch) { + $parts[] = get_class($patch); + } sort($parts); return md5(implode('', $parts)); } + + public function resetCache() + { + self::$classes = array(); + } } diff --git a/src/Prophecy/Doubler/ClassPatch/ProphecySubjectPatch.php b/src/Prophecy/Doubler/ClassPatch/ProphecySubjectPatch.php index 081dea82a..ef4036667 100644 --- a/src/Prophecy/Doubler/ClassPatch/ProphecySubjectPatch.php +++ b/src/Prophecy/Doubler/ClassPatch/ProphecySubjectPatch.php @@ -43,7 +43,7 @@ public function supports(ClassNode $node) public function apply(ClassNode $node) { $node->addInterface('Prophecy\Prophecy\ProphecySubjectInterface'); - $node->addProperty('objectProphecy', 'private'); + $node->addProperty('objectProphecyClosure', 'private'); foreach ($node->getMethods() as $name => $method) { if ('__construct' === strtolower($name)) { @@ -65,10 +65,10 @@ public function apply(ClassNode $node) $prophecyArgument = new ArgumentNode('prophecy'); $prophecyArgument->setTypeHint('Prophecy\Prophecy\ProphecyInterface'); $prophecySetter->addArgument($prophecyArgument); - $prophecySetter->setCode('$this->objectProphecy = $prophecy;'); + $prophecySetter->setCode('$this->objectProphecyClosure = function () use ($prophecy) { return $prophecy; };'); $prophecyGetter = new MethodNode('getProphecy'); - $prophecyGetter->setCode('return $this->objectProphecy;'); + $prophecyGetter->setCode('return call_user_func($this->objectProphecyClosure);'); if ($node->hasMethod('__call')) { $__call = $node->getMethod('__call'); diff --git a/src/Prophecy/Prophet.php b/src/Prophecy/Prophet.php index a4fe4b0d2..d37c92a34 100644 --- a/src/Prophecy/Prophet.php +++ b/src/Prophecy/Prophet.php @@ -11,6 +11,7 @@ namespace Prophecy; +use Prophecy\Doubler\CachedDoubler; use Prophecy\Doubler\Doubler; use Prophecy\Doubler\LazyDouble; use Prophecy\Doubler\ClassPatch; @@ -45,11 +46,13 @@ class Prophet * @param null|RevealerInterface $revealer * @param null|StringUtil $util */ - public function __construct(Doubler $doubler = null, RevealerInterface $revealer = null, - StringUtil $util = null) - { + public function __construct( + Doubler $doubler = null, + RevealerInterface $revealer = null, + StringUtil $util = null + ) { if (null === $doubler) { - $doubler = new Doubler; + $doubler = new CachedDoubler(); $doubler->registerClassPatch(new ClassPatch\SplFileInfoPatch); $doubler->registerClassPatch(new ClassPatch\TraversablePatch); $doubler->registerClassPatch(new ClassPatch\ThrowablePatch); diff --git a/src/Prophecy/Util/ExportUtil.php b/src/Prophecy/Util/ExportUtil.php index 50dd3f325..1090a801e 100644 --- a/src/Prophecy/Util/ExportUtil.php +++ b/src/Prophecy/Util/ExportUtil.php @@ -181,9 +181,7 @@ protected static function recursiveExport(&$value, $indentation, $processed = nu if (is_object($value)) { $class = get_class($value); - if ($value instanceof ProphecyInterface) { - return sprintf('%s Object (*Prophecy*)', $class); - } elseif ($hash = $processed->contains($value)) { + if ($hash = $processed->contains($value)) { return sprintf('%s:%s Object', $class, $hash); }