EVOLUTION-MANAGER
Edit File: ObjectProphecy.php
<?php /* * This file is part of the Prophecy. * (c) Konstantin Kudryashov <ever.zet@gmail.com> * Marcello Duarte <marcello.duarte@gmail.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Prophecy\Prophecy; use Prophecy\Comparator\FactoryProvider; use SebastianBergmann\Comparator\ComparisonFailure; use SebastianBergmann\Comparator\Factory as ComparatorFactory; use Prophecy\Call\Call; use Prophecy\Doubler\LazyDouble; use Prophecy\Argument\ArgumentsWildcard; use Prophecy\Call\CallCenter; use Prophecy\Exception\Prophecy\ObjectProphecyException; use Prophecy\Exception\Prophecy\MethodProphecyException; use Prophecy\Exception\Prediction\AggregateException; use Prophecy\Exception\Prediction\PredictionException; /** * @author Konstantin Kudryashov <ever.zet@gmail.com> * * @template-covariant T of object * @template-implements ProphecyInterface<T> */ class ObjectProphecy implements ProphecyInterface { /** * @var LazyDouble<T> */ private $lazyDouble; private $callCenter; private $revealer; private $comparatorFactory; /** * @var array<string, list<MethodProphecy>> */ private $methodProphecies = array(); /** * @param LazyDouble<T> $lazyDouble */ public function __construct( LazyDouble $lazyDouble, CallCenter $callCenter = null, RevealerInterface $revealer = null, ComparatorFactory $comparatorFactory = null ) { $this->lazyDouble = $lazyDouble; $this->callCenter = $callCenter ?: new CallCenter; $this->revealer = $revealer ?: new Revealer; $this->comparatorFactory = $comparatorFactory ?: FactoryProvider::getInstance(); } /** * Forces double to extend specific class. * * @param string $class * * @return $this * * @template U of object * @phpstan-param class-string<U> $class * @phpstan-this-out static<T&U> */ public function willExtend($class) { $this->lazyDouble->setParentClass($class); return $this; } /** * Forces double to implement specific interface. * * @param string $interface * * @return $this * * @template U of object * @phpstan-param class-string<U> $interface * @phpstan-this-out static<T&U> */ public function willImplement($interface) { $this->lazyDouble->addInterface($interface); return $this; } /** * Sets constructor arguments. * * @param array<mixed> $arguments * * @return $this */ public function willBeConstructedWith(array $arguments = null) { $this->lazyDouble->setArguments($arguments); return $this; } /** * Reveals double. * * @return object * * @throws \Prophecy\Exception\Prophecy\ObjectProphecyException If double doesn't implement needed interface * * @phpstan-return T */ public function reveal() { $double = $this->lazyDouble->getInstance(); if (!$double instanceof ProphecySubjectInterface) { throw new ObjectProphecyException( "Generated double must implement ProphecySubjectInterface, but it does not.\n". 'It seems you have wrongly configured doubler without required ClassPatch.', $this ); } $double->setProphecy($this); return $double; } /** * Adds method prophecy to object prophecy. * * @param MethodProphecy $methodProphecy * * @return void */ public function addMethodProphecy(MethodProphecy $methodProphecy) { $methodName = strtolower($methodProphecy->getMethodName()); if (!isset($this->methodProphecies[$methodName])) { $this->methodProphecies[$methodName] = array(); } $this->methodProphecies[$methodName][] = $methodProphecy; } /** * Returns either all or related to single method prophecies. * * @param null|string $methodName * * @return MethodProphecy[]|array<string, MethodProphecy[]> * * @phpstan-return ($methodName is string ? list<MethodProphecy> : array<string, list<MethodProphecy>>) */ public function getMethodProphecies($methodName = null) { if (null === $methodName) { return $this->methodProphecies; } $methodName = strtolower($methodName); if (!isset($this->methodProphecies[$methodName])) { return array(); } return $this->methodProphecies[$methodName]; } /** * Makes specific method call. * * @param string $methodName * @param array<mixed> $arguments * * @return mixed */ public function makeProphecyMethodCall($methodName, array $arguments) { $arguments = $this->revealer->reveal($arguments); \assert(\is_array($arguments)); $return = $this->callCenter->makeCall($this, $methodName, $arguments); return $this->revealer->reveal($return); } /** * Finds calls by method name & arguments wildcard. * * @param string $methodName * @param ArgumentsWildcard $wildcard * * @return list<Call> */ public function findProphecyMethodCalls($methodName, ArgumentsWildcard $wildcard) { return $this->callCenter->findCalls($methodName, $wildcard); } /** * Checks that registered method predictions do not fail. * * @return void * * @throws \Prophecy\Exception\Prediction\AggregateException If any of registered predictions fail * @throws \Prophecy\Exception\Call\UnexpectedCallException */ public function checkProphecyMethodsPredictions() { $exception = new AggregateException(sprintf("%s:\n", get_class($this->reveal()))); $exception->setObjectProphecy($this); $this->callCenter->checkUnexpectedCalls(); foreach ($this->methodProphecies as $prophecies) { foreach ($prophecies as $prophecy) { try { $prophecy->checkPrediction(); } catch (PredictionException $e) { $exception->append($e); } } } if (count($exception->getExceptions())) { throw $exception; } } /** * Creates new method prophecy using specified method name and arguments. * * @param string $methodName * @param array<mixed> $arguments * * @return MethodProphecy */ public function __call($methodName, array $arguments) { $arguments = $this->revealer->reveal($arguments); \assert(\is_array($arguments)); $arguments = new ArgumentsWildcard($arguments); foreach ($this->getMethodProphecies($methodName) as $prophecy) { $argumentsWildcard = $prophecy->getArgumentsWildcard(); $comparator = $this->comparatorFactory->getComparatorFor( $argumentsWildcard, $arguments ); try { $comparator->assertEquals($argumentsWildcard, $arguments); return $prophecy; } catch (ComparisonFailure $failure) {} } return new MethodProphecy($this, $methodName, $arguments); } /** * Tries to get property value from double. * * @param string $name * * @return mixed */ public function __get($name) { return $this->reveal()->$name; } /** * Tries to set property value to double. * * @param string $name * @param mixed $value * * @return void */ public function __set($name, $value) { $this->reveal()->$name = $this->revealer->reveal($value); } }