diff options
author | Andrew Dolgov <[email protected]> | 2022-03-22 12:24:31 +0300 |
---|---|---|
committer | Andrew Dolgov <[email protected]> | 2022-03-22 12:24:31 +0300 |
commit | 1c4f7ab3b838b23afb2ee4dab14acbf75956e952 (patch) | |
tree | 0a19274107d717efe92d2c0376cd3105fead5a11 /vendor/phpspec/prophecy/src/Prophecy/Call/CallCenter.php | |
parent | 711662948768492e8d05b778a7d80eacaec368d2 (diff) |
* add phpunit as a dev dependency
* add some basic tests for UrlHelper::rewrite_relative()
* fix UrlHelper::rewrite_relative() to work better on non-absolute
relative URL paths
Diffstat (limited to 'vendor/phpspec/prophecy/src/Prophecy/Call/CallCenter.php')
-rw-r--r-- | vendor/phpspec/prophecy/src/Prophecy/Call/CallCenter.php | 240 |
1 files changed, 240 insertions, 0 deletions
diff --git a/vendor/phpspec/prophecy/src/Prophecy/Call/CallCenter.php b/vendor/phpspec/prophecy/src/Prophecy/Call/CallCenter.php new file mode 100644 index 000000000..00c526d7e --- /dev/null +++ b/vendor/phpspec/prophecy/src/Prophecy/Call/CallCenter.php @@ -0,0 +1,240 @@ +<?php + +/* + * This file is part of the Prophecy. + * (c) Konstantin Kudryashov <[email protected]> + * Marcello Duarte <[email protected]> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Prophecy\Call; + +use Prophecy\Exception\Prophecy\MethodProphecyException; +use Prophecy\Prophecy\ObjectProphecy; +use Prophecy\Argument\ArgumentsWildcard; +use Prophecy\Util\StringUtil; +use Prophecy\Exception\Call\UnexpectedCallException; +use SplObjectStorage; + +/** + * Calls receiver & manager. + * + * @author Konstantin Kudryashov <[email protected]> + */ +class CallCenter +{ + private $util; + + /** + * @var Call[] + */ + private $recordedCalls = array(); + + /** + * @var SplObjectStorage + */ + private $unexpectedCalls; + + /** + * Initializes call center. + * + * @param StringUtil $util + */ + public function __construct(StringUtil $util = null) + { + $this->util = $util ?: new StringUtil; + $this->unexpectedCalls = new SplObjectStorage(); + } + + /** + * Makes and records specific method call for object prophecy. + * + * @param ObjectProphecy $prophecy + * @param string $methodName + * @param array $arguments + * + * @return mixed Returns null if no promise for prophecy found or promise return value. + * + * @throws \Prophecy\Exception\Call\UnexpectedCallException If no appropriate method prophecy found + */ + public function makeCall(ObjectProphecy $prophecy, $methodName, array $arguments) + { + // For efficiency exclude 'args' from the generated backtrace + // Limit backtrace to last 3 calls as we don't use the rest + $backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 3); + + $file = $line = null; + if (isset($backtrace[2]) && isset($backtrace[2]['file'])) { + $file = $backtrace[2]['file']; + $line = $backtrace[2]['line']; + } + + // If no method prophecies defined, then it's a dummy, so we'll just return null + if ('__destruct' === strtolower($methodName) || 0 == count($prophecy->getMethodProphecies())) { + $this->recordedCalls[] = new Call($methodName, $arguments, null, null, $file, $line); + + return null; + } + + // There are method prophecies, so it's a fake/stub. Searching prophecy for this call + $matches = $this->findMethodProphecies($prophecy, $methodName, $arguments); + + // If fake/stub doesn't have method prophecy for this call - throw exception + if (!count($matches)) { + $this->unexpectedCalls->attach(new Call($methodName, $arguments, null, null, $file, $line), $prophecy); + $this->recordedCalls[] = new Call($methodName, $arguments, null, null, $file, $line); + + return null; + } + + // Sort matches by their score value + @usort($matches, function ($match1, $match2) { return $match2[0] - $match1[0]; }); + + $score = $matches[0][0]; + // If Highest rated method prophecy has a promise - execute it or return null instead + $methodProphecy = $matches[0][1]; + $returnValue = null; + $exception = null; + if ($promise = $methodProphecy->getPromise()) { + try { + $returnValue = $promise->execute($arguments, $prophecy, $methodProphecy); + } catch (\Exception $e) { + $exception = $e; + } + } + + if ($methodProphecy->hasReturnVoid() && $returnValue !== null) { + throw new MethodProphecyException( + "The method \"$methodName\" has a void return type, but the promise returned a value", + $methodProphecy + ); + } + + $this->recordedCalls[] = $call = new Call( + $methodName, $arguments, $returnValue, $exception, $file, $line + ); + $call->addScore($methodProphecy->getArgumentsWildcard(), $score); + + if (null !== $exception) { + throw $exception; + } + + return $returnValue; + } + + /** + * Searches for calls by method name & arguments wildcard. + * + * @param string $methodName + * @param ArgumentsWildcard $wildcard + * + * @return Call[] + */ + public function findCalls($methodName, ArgumentsWildcard $wildcard) + { + $methodName = strtolower($methodName); + + return array_values( + array_filter($this->recordedCalls, function (Call $call) use ($methodName, $wildcard) { + return $methodName === strtolower($call->getMethodName()) + && 0 < $call->getScore($wildcard) + ; + }) + ); + } + + /** + * @throws UnexpectedCallException + */ + public function checkUnexpectedCalls() + { + /** @var Call $call */ + foreach ($this->unexpectedCalls as $call) { + $prophecy = $this->unexpectedCalls[$call]; + + // If fake/stub doesn't have method prophecy for this call - throw exception + if (!count($this->findMethodProphecies($prophecy, $call->getMethodName(), $call->getArguments()))) { + throw $this->createUnexpectedCallException($prophecy, $call->getMethodName(), $call->getArguments()); + } + } + } + + private function createUnexpectedCallException(ObjectProphecy $prophecy, $methodName, + array $arguments) + { + $classname = get_class($prophecy->reveal()); + $indentationLength = 8; // looks good + $argstring = implode( + ",\n", + $this->indentArguments( + array_map(array($this->util, 'stringify'), $arguments), + $indentationLength + ) + ); + + $expected = array(); + + foreach (array_merge(...array_values($prophecy->getMethodProphecies())) as $methodProphecy) { + $expected[] = sprintf( + " - %s(\n" . + "%s\n" . + " )", + $methodProphecy->getMethodName(), + implode( + ",\n", + $this->indentArguments( + array_map('strval', $methodProphecy->getArgumentsWildcard()->getTokens()), + $indentationLength + ) + ) + ); + } + + return new UnexpectedCallException( + sprintf( + "Unexpected method call on %s:\n". + " - %s(\n". + "%s\n". + " )\n". + "expected calls were:\n". + "%s", + + $classname, $methodName, $argstring, implode("\n", $expected) + ), + $prophecy, $methodName, $arguments + + ); + } + + private function indentArguments(array $arguments, $indentationLength) + { + return preg_replace_callback( + '/^/m', + function () use ($indentationLength) { + return str_repeat(' ', $indentationLength); + }, + $arguments + ); + } + + /** + * @param ObjectProphecy $prophecy + * @param string $methodName + * @param array $arguments + * + * @return array + */ + private function findMethodProphecies(ObjectProphecy $prophecy, $methodName, array $arguments) + { + $matches = array(); + foreach ($prophecy->getMethodProphecies($methodName) as $methodProphecy) { + if (0 < $score = $methodProphecy->getArgumentsWildcard()->scoreArguments($arguments)) { + $matches[] = array($score, $methodProphecy); + } + } + + return $matches; + } +} |