summaryrefslogtreecommitdiff
path: root/vendor/phpspec/prophecy/src/Prophecy/Doubler
diff options
context:
space:
mode:
authorAndrew Dolgov <[email protected]>2022-03-22 12:24:31 +0300
committerAndrew Dolgov <[email protected]>2022-03-22 12:24:31 +0300
commit1c4f7ab3b838b23afb2ee4dab14acbf75956e952 (patch)
tree0a19274107d717efe92d2c0376cd3105fead5a11 /vendor/phpspec/prophecy/src/Prophecy/Doubler
parent711662948768492e8d05b778a7d80eacaec368d2 (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/Doubler')
-rw-r--r--vendor/phpspec/prophecy/src/Prophecy/Doubler/CachedDoubler.php66
-rw-r--r--vendor/phpspec/prophecy/src/Prophecy/Doubler/ClassPatch/ClassPatchInterface.php48
-rw-r--r--vendor/phpspec/prophecy/src/Prophecy/Doubler/ClassPatch/DisableConstructorPatch.php76
-rw-r--r--vendor/phpspec/prophecy/src/Prophecy/Doubler/ClassPatch/HhvmExceptionPatch.php63
-rw-r--r--vendor/phpspec/prophecy/src/Prophecy/Doubler/ClassPatch/KeywordPatch.php68
-rw-r--r--vendor/phpspec/prophecy/src/Prophecy/Doubler/ClassPatch/MagicCallPatch.php105
-rw-r--r--vendor/phpspec/prophecy/src/Prophecy/Doubler/ClassPatch/ProphecySubjectPatch.php113
-rw-r--r--vendor/phpspec/prophecy/src/Prophecy/Doubler/ClassPatch/ReflectionClassNewInstancePatch.php57
-rw-r--r--vendor/phpspec/prophecy/src/Prophecy/Doubler/ClassPatch/SplFileInfoPatch.php123
-rw-r--r--vendor/phpspec/prophecy/src/Prophecy/Doubler/ClassPatch/ThrowablePatch.php95
-rw-r--r--vendor/phpspec/prophecy/src/Prophecy/Doubler/ClassPatch/TraversablePatch.php98
-rw-r--r--vendor/phpspec/prophecy/src/Prophecy/Doubler/DoubleInterface.php22
-rw-r--r--vendor/phpspec/prophecy/src/Prophecy/Doubler/Doubler.php146
-rw-r--r--vendor/phpspec/prophecy/src/Prophecy/Doubler/Generator/ClassCodeGenerator.php110
-rw-r--r--vendor/phpspec/prophecy/src/Prophecy/Doubler/Generator/ClassCreator.php67
-rw-r--r--vendor/phpspec/prophecy/src/Prophecy/Doubler/Generator/ClassMirror.php254
-rw-r--r--vendor/phpspec/prophecy/src/Prophecy/Doubler/Generator/Node/ArgumentNode.php133
-rw-r--r--vendor/phpspec/prophecy/src/Prophecy/Doubler/Generator/Node/ArgumentTypeNode.php10
-rw-r--r--vendor/phpspec/prophecy/src/Prophecy/Doubler/Generator/Node/ClassNode.php169
-rw-r--r--vendor/phpspec/prophecy/src/Prophecy/Doubler/Generator/Node/MethodNode.php210
-rw-r--r--vendor/phpspec/prophecy/src/Prophecy/Doubler/Generator/Node/ReturnTypeNode.php45
-rw-r--r--vendor/phpspec/prophecy/src/Prophecy/Doubler/Generator/Node/TypeNodeAbstract.php97
-rw-r--r--vendor/phpspec/prophecy/src/Prophecy/Doubler/Generator/ReflectionInterface.php22
-rw-r--r--vendor/phpspec/prophecy/src/Prophecy/Doubler/Generator/TypeHintReference.php43
-rw-r--r--vendor/phpspec/prophecy/src/Prophecy/Doubler/LazyDouble.php127
-rw-r--r--vendor/phpspec/prophecy/src/Prophecy/Doubler/NameGenerator.php52
26 files changed, 2419 insertions, 0 deletions
diff --git a/vendor/phpspec/prophecy/src/Prophecy/Doubler/CachedDoubler.php b/vendor/phpspec/prophecy/src/Prophecy/Doubler/CachedDoubler.php
new file mode 100644
index 000000000..2b875211a
--- /dev/null
+++ b/vendor/phpspec/prophecy/src/Prophecy/Doubler/CachedDoubler.php
@@ -0,0 +1,66 @@
+<?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\Doubler;
+
+use ReflectionClass;
+
+/**
+ * Cached class doubler.
+ * Prevents mirroring/creation of the same structure twice.
+ *
+ * @author Konstantin Kudryashov <[email protected]>
+ */
+class CachedDoubler extends Doubler
+{
+ private static $classes = array();
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function createDoubleClass(ReflectionClass $class = null, array $interfaces)
+ {
+ $classId = $this->generateClassId($class, $interfaces);
+ if (isset(self::$classes[$classId])) {
+ return self::$classes[$classId];
+ }
+
+ return self::$classes[$classId] = parent::createDoubleClass($class, $interfaces);
+ }
+
+ /**
+ * @param ReflectionClass $class
+ * @param ReflectionClass[] $interfaces
+ *
+ * @return string
+ */
+ private function generateClassId(ReflectionClass $class = null, array $interfaces)
+ {
+ $parts = array();
+ if (null !== $class) {
+ $parts[] = $class->getName();
+ }
+ 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/vendor/phpspec/prophecy/src/Prophecy/Doubler/ClassPatch/ClassPatchInterface.php b/vendor/phpspec/prophecy/src/Prophecy/Doubler/ClassPatch/ClassPatchInterface.php
new file mode 100644
index 000000000..d6d196850
--- /dev/null
+++ b/vendor/phpspec/prophecy/src/Prophecy/Doubler/ClassPatch/ClassPatchInterface.php
@@ -0,0 +1,48 @@
+<?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\Doubler\ClassPatch;
+
+use Prophecy\Doubler\Generator\Node\ClassNode;
+
+/**
+ * Class patch interface.
+ * Class patches extend doubles functionality or help
+ * Prophecy to avoid some internal PHP bugs.
+ *
+ * @author Konstantin Kudryashov <[email protected]>
+ */
+interface ClassPatchInterface
+{
+ /**
+ * Checks if patch supports specific class node.
+ *
+ * @param ClassNode $node
+ *
+ * @return bool
+ */
+ public function supports(ClassNode $node);
+
+ /**
+ * Applies patch to the specific class node.
+ *
+ * @param ClassNode $node
+ * @return void
+ */
+ public function apply(ClassNode $node);
+
+ /**
+ * Returns patch priority, which determines when patch will be applied.
+ *
+ * @return int Priority number (higher - earlier)
+ */
+ public function getPriority();
+}
diff --git a/vendor/phpspec/prophecy/src/Prophecy/Doubler/ClassPatch/DisableConstructorPatch.php b/vendor/phpspec/prophecy/src/Prophecy/Doubler/ClassPatch/DisableConstructorPatch.php
new file mode 100644
index 000000000..9d843099d
--- /dev/null
+++ b/vendor/phpspec/prophecy/src/Prophecy/Doubler/ClassPatch/DisableConstructorPatch.php
@@ -0,0 +1,76 @@
+<?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\Doubler\ClassPatch;
+
+use Prophecy\Doubler\Generator\Node\ClassNode;
+use Prophecy\Doubler\Generator\Node\MethodNode;
+
+/**
+ * Disable constructor.
+ * Makes all constructor arguments optional.
+ *
+ * @author Konstantin Kudryashov <[email protected]>
+ */
+class DisableConstructorPatch implements ClassPatchInterface
+{
+ /**
+ * Checks if class has `__construct` method.
+ *
+ * @param ClassNode $node
+ *
+ * @return bool
+ */
+ public function supports(ClassNode $node)
+ {
+ return true;
+ }
+
+ /**
+ * Makes all class constructor arguments optional.
+ *
+ * @param ClassNode $node
+ */
+ public function apply(ClassNode $node)
+ {
+ if (!$node->isExtendable('__construct')) {
+ return;
+ }
+
+ if (!$node->hasMethod('__construct')) {
+ $node->addMethod(new MethodNode('__construct', ''));
+
+ return;
+ }
+
+ $constructor = $node->getMethod('__construct');
+ foreach ($constructor->getArguments() as $argument) {
+ $argument->setDefault(null);
+ }
+
+ $constructor->setCode(<<<PHP
+if (0 < func_num_args()) {
+ call_user_func_array(array('parent', '__construct'), func_get_args());
+}
+PHP
+ );
+ }
+
+ /**
+ * Returns patch priority, which determines when patch will be applied.
+ *
+ * @return int Priority number (higher - earlier)
+ */
+ public function getPriority()
+ {
+ return 100;
+ }
+}
diff --git a/vendor/phpspec/prophecy/src/Prophecy/Doubler/ClassPatch/HhvmExceptionPatch.php b/vendor/phpspec/prophecy/src/Prophecy/Doubler/ClassPatch/HhvmExceptionPatch.php
new file mode 100644
index 000000000..fa38fc0d1
--- /dev/null
+++ b/vendor/phpspec/prophecy/src/Prophecy/Doubler/ClassPatch/HhvmExceptionPatch.php
@@ -0,0 +1,63 @@
+<?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\Doubler\ClassPatch;
+
+use Prophecy\Doubler\Generator\Node\ClassNode;
+
+/**
+ * Exception patch for HHVM to remove the stubs from special methods
+ *
+ * @author Christophe Coevoet <[email protected]>
+ */
+class HhvmExceptionPatch implements ClassPatchInterface
+{
+ /**
+ * Supports exceptions on HHVM.
+ *
+ * @param ClassNode $node
+ *
+ * @return bool
+ */
+ public function supports(ClassNode $node)
+ {
+ if (!defined('HHVM_VERSION')) {
+ return false;
+ }
+
+ return 'Exception' === $node->getParentClass() || is_subclass_of($node->getParentClass(), 'Exception');
+ }
+
+ /**
+ * Removes special exception static methods from the doubled methods.
+ *
+ * @param ClassNode $node
+ *
+ * @return void
+ */
+ public function apply(ClassNode $node)
+ {
+ if ($node->hasMethod('setTraceOptions')) {
+ $node->getMethod('setTraceOptions')->useParentCode();
+ }
+ if ($node->hasMethod('getTraceOptions')) {
+ $node->getMethod('getTraceOptions')->useParentCode();
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getPriority()
+ {
+ return -50;
+ }
+}
diff --git a/vendor/phpspec/prophecy/src/Prophecy/Doubler/ClassPatch/KeywordPatch.php b/vendor/phpspec/prophecy/src/Prophecy/Doubler/ClassPatch/KeywordPatch.php
new file mode 100644
index 000000000..ab99f74be
--- /dev/null
+++ b/vendor/phpspec/prophecy/src/Prophecy/Doubler/ClassPatch/KeywordPatch.php
@@ -0,0 +1,68 @@
+<?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\Doubler\ClassPatch;
+
+use Prophecy\Doubler\Generator\Node\ClassNode;
+
+/**
+ * Remove method functionality from the double which will clash with php keywords.
+ *
+ * @author Milan Magudia <[email protected]>
+ */
+class KeywordPatch implements ClassPatchInterface
+{
+ /**
+ * Support any class
+ *
+ * @param ClassNode $node
+ *
+ * @return boolean
+ */
+ public function supports(ClassNode $node)
+ {
+ return true;
+ }
+
+ /**
+ * Remove methods that clash with php keywords
+ *
+ * @param ClassNode $node
+ */
+ public function apply(ClassNode $node)
+ {
+ $methodNames = array_keys($node->getMethods());
+ $methodsToRemove = array_intersect($methodNames, $this->getKeywords());
+ foreach ($methodsToRemove as $methodName) {
+ $node->removeMethod($methodName);
+ }
+ }
+
+ /**
+ * Returns patch priority, which determines when patch will be applied.
+ *
+ * @return int Priority number (higher - earlier)
+ */
+ public function getPriority()
+ {
+ return 49;
+ }
+
+ /**
+ * Returns array of php keywords.
+ *
+ * @return array
+ */
+ private function getKeywords()
+ {
+ return ['__halt_compiler'];
+ }
+}
diff --git a/vendor/phpspec/prophecy/src/Prophecy/Doubler/ClassPatch/MagicCallPatch.php b/vendor/phpspec/prophecy/src/Prophecy/Doubler/ClassPatch/MagicCallPatch.php
new file mode 100644
index 000000000..a545eeff5
--- /dev/null
+++ b/vendor/phpspec/prophecy/src/Prophecy/Doubler/ClassPatch/MagicCallPatch.php
@@ -0,0 +1,105 @@
+<?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\Doubler\ClassPatch;
+
+use Prophecy\Doubler\Generator\Node\ArgumentNode;
+use Prophecy\Doubler\Generator\Node\ClassNode;
+use Prophecy\Doubler\Generator\Node\MethodNode;
+use Prophecy\PhpDocumentor\ClassAndInterfaceTagRetriever;
+use Prophecy\PhpDocumentor\MethodTagRetrieverInterface;
+
+/**
+ * Discover Magical API using "@method" PHPDoc format.
+ *
+ * @author Thomas Tourlourat <[email protected]>
+ * @author Kévin Dunglas <[email protected]>
+ * @author Théo FIDRY <[email protected]>
+ */
+class MagicCallPatch implements ClassPatchInterface
+{
+ const MAGIC_METHODS_WITH_ARGUMENTS = ['__call', '__callStatic', '__get', '__isset', '__set', '__set_state', '__unserialize', '__unset'];
+
+ private $tagRetriever;
+
+ public function __construct(MethodTagRetrieverInterface $tagRetriever = null)
+ {
+ $this->tagRetriever = null === $tagRetriever ? new ClassAndInterfaceTagRetriever() : $tagRetriever;
+ }
+
+ /**
+ * Support any class
+ *
+ * @param ClassNode $node
+ *
+ * @return boolean
+ */
+ public function supports(ClassNode $node)
+ {
+ return true;
+ }
+
+ /**
+ * Discover Magical API
+ *
+ * @param ClassNode $node
+ */
+ public function apply(ClassNode $node)
+ {
+ $types = array_filter($node->getInterfaces(), function ($interface) {
+ return 0 !== strpos($interface, 'Prophecy\\');
+ });
+ $types[] = $node->getParentClass();
+
+ foreach ($types as $type) {
+ $reflectionClass = new \ReflectionClass($type);
+
+ while ($reflectionClass) {
+ $tagList = $this->tagRetriever->getTagList($reflectionClass);
+
+ foreach ($tagList as $tag) {
+ $methodName = $tag->getMethodName();
+
+ if (empty($methodName)) {
+ continue;
+ }
+
+ if (!$reflectionClass->hasMethod($methodName)) {
+ $methodNode = new MethodNode($methodName);
+
+ // only magic methods can have a contract that needs to be enforced
+ if (in_array($methodName, self::MAGIC_METHODS_WITH_ARGUMENTS)) {
+ foreach($tag->getArguments() as $argument) {
+ $argumentNode = new ArgumentNode($argument['name']);
+ $methodNode->addArgument($argumentNode);
+ }
+ }
+
+ $methodNode->setStatic($tag->isStatic());
+ $node->addMethod($methodNode);
+ }
+ }
+
+ $reflectionClass = $reflectionClass->getParentClass();
+ }
+ }
+ }
+
+ /**
+ * Returns patch priority, which determines when patch will be applied.
+ *
+ * @return integer Priority number (higher - earlier)
+ */
+ public function getPriority()
+ {
+ return 50;
+ }
+}
diff --git a/vendor/phpspec/prophecy/src/Prophecy/Doubler/ClassPatch/ProphecySubjectPatch.php b/vendor/phpspec/prophecy/src/Prophecy/Doubler/ClassPatch/ProphecySubjectPatch.php
new file mode 100644
index 000000000..7573ca50e
--- /dev/null
+++ b/vendor/phpspec/prophecy/src/Prophecy/Doubler/ClassPatch/ProphecySubjectPatch.php
@@ -0,0 +1,113 @@
+<?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\Doubler\ClassPatch;
+
+use Prophecy\Doubler\Generator\Node\ArgumentTypeNode;
+use Prophecy\Doubler\Generator\Node\ClassNode;
+use Prophecy\Doubler\Generator\Node\MethodNode;
+use Prophecy\Doubler\Generator\Node\ArgumentNode;
+use Prophecy\Doubler\Generator\Node\ReturnTypeNode;
+
+/**
+ * Add Prophecy functionality to the double.
+ * This is a core class patch for Prophecy.
+ *
+ * @author Konstantin Kudryashov <[email protected]>
+ */
+class ProphecySubjectPatch implements ClassPatchInterface
+{
+ /**
+ * Always returns true.
+ *
+ * @param ClassNode $node
+ *
+ * @return bool
+ */
+ public function supports(ClassNode $node)
+ {
+ return true;
+ }
+
+ /**
+ * Apply Prophecy functionality to class node.
+ *
+ * @param ClassNode $node
+ */
+ public function apply(ClassNode $node)
+ {
+ $node->addInterface('Prophecy\Prophecy\ProphecySubjectInterface');
+ $node->addProperty('objectProphecyClosure', 'private');
+
+ foreach ($node->getMethods() as $name => $method) {
+ if ('__construct' === strtolower($name)) {
+ continue;
+ }
+
+ if (!$method->getReturnTypeNode()->hasReturnStatement()) {
+ $method->setCode(
+ '$this->getProphecy()->makeProphecyMethodCall(__FUNCTION__, func_get_args());'
+ );
+ } else {
+ $method->setCode(
+ 'return $this->getProphecy()->makeProphecyMethodCall(__FUNCTION__, func_get_args());'
+ );
+ }
+ }
+
+ $prophecySetter = new MethodNode('setProphecy');
+ $prophecyArgument = new ArgumentNode('prophecy');
+ $prophecyArgument->setTypeNode(new ArgumentTypeNode('Prophecy\Prophecy\ProphecyInterface'));
+ $prophecySetter->addArgument($prophecyArgument);
+ $prophecySetter->setCode(<<<PHP
+if (null === \$this->objectProphecyClosure) {
+ \$this->objectProphecyClosure = static function () use (\$prophecy) {
+ return \$prophecy;
+ };
+}
+PHP
+ );
+
+ $prophecyGetter = new MethodNode('getProphecy');
+ $prophecyGetter->setCode('return \call_user_func($this->objectProphecyClosure);');
+
+ if ($node->hasMethod('__call')) {
+ $__call = $node->getMethod('__call');
+ } else {
+ $__call = new MethodNode('__call');
+ $__call->addArgument(new ArgumentNode('name'));
+ $__call->addArgument(new ArgumentNode('arguments'));
+
+ $node->addMethod($__call, true);
+ }
+
+ $__call->setCode(<<<PHP
+throw new \Prophecy\Exception\Doubler\MethodNotFoundException(
+ sprintf('Method `%s::%s()` not found.', get_class(\$this), func_get_arg(0)),
+ get_class(\$this), func_get_arg(0)
+);
+PHP
+ );
+
+ $node->addMethod($prophecySetter, true);
+ $node->addMethod($prophecyGetter, true);
+ }
+
+ /**
+ * Returns patch priority, which determines when patch will be applied.
+ *
+ * @return int Priority number (higher - earlier)
+ */
+ public function getPriority()
+ {
+ return 0;
+ }
+}
diff --git a/vendor/phpspec/prophecy/src/Prophecy/Doubler/ClassPatch/ReflectionClassNewInstancePatch.php b/vendor/phpspec/prophecy/src/Prophecy/Doubler/ClassPatch/ReflectionClassNewInstancePatch.php
new file mode 100644
index 000000000..9166aeefa
--- /dev/null
+++ b/vendor/phpspec/prophecy/src/Prophecy/Doubler/ClassPatch/ReflectionClassNewInstancePatch.php
@@ -0,0 +1,57 @@
+<?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\Doubler\ClassPatch;
+
+use Prophecy\Doubler\Generator\Node\ClassNode;
+
+/**
+ * ReflectionClass::newInstance patch.
+ * Makes first argument of newInstance optional, since it works but signature is misleading
+ *
+ * @author Florian Klein <[email protected]>
+ */
+class ReflectionClassNewInstancePatch implements ClassPatchInterface
+{
+ /**
+ * Supports ReflectionClass
+ *
+ * @param ClassNode $node
+ *
+ * @return bool
+ */
+ public function supports(ClassNode $node)
+ {
+ return 'ReflectionClass' === $node->getParentClass();
+ }
+
+ /**
+ * Updates newInstance's first argument to make it optional
+ *
+ * @param ClassNode $node
+ */
+ public function apply(ClassNode $node)
+ {
+ foreach ($node->getMethod('newInstance')->getArguments() as $argument) {
+ $argument->setDefault(null);
+ }
+ }
+
+ /**
+ * Returns patch priority, which determines when patch will be applied.
+ *
+ * @return int Priority number (higher = earlier)
+ */
+ public function getPriority()
+ {
+ return 50;
+ }
+}
diff --git a/vendor/phpspec/prophecy/src/Prophecy/Doubler/ClassPatch/SplFileInfoPatch.php b/vendor/phpspec/prophecy/src/Prophecy/Doubler/ClassPatch/SplFileInfoPatch.php
new file mode 100644
index 000000000..ceee94a2e
--- /dev/null
+++ b/vendor/phpspec/prophecy/src/Prophecy/Doubler/ClassPatch/SplFileInfoPatch.php
@@ -0,0 +1,123 @@
+<?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\Doubler\ClassPatch;
+
+use Prophecy\Doubler\Generator\Node\ClassNode;
+use Prophecy\Doubler\Generator\Node\MethodNode;
+
+/**
+ * SplFileInfo patch.
+ * Makes SplFileInfo and derivative classes usable with Prophecy.
+ *
+ * @author Konstantin Kudryashov <[email protected]>
+ */
+class SplFileInfoPatch implements ClassPatchInterface
+{
+ /**
+ * Supports everything that extends SplFileInfo.
+ *
+ * @param ClassNode $node
+ *
+ * @return bool
+ */
+ public function supports(ClassNode $node)
+ {
+ if (null === $node->getParentClass()) {
+ return false;
+ }
+ return 'SplFileInfo' === $node->getParentClass()
+ || is_subclass_of($node->getParentClass(), 'SplFileInfo')
+ ;
+ }
+
+ /**
+ * Updated constructor code to call parent one with dummy file argument.
+ *
+ * @param ClassNode $node
+ */
+ public function apply(ClassNode $node)
+ {
+ if ($node->hasMethod('__construct')) {
+ $constructor = $node->getMethod('__construct');
+ } else {
+ $constructor = new MethodNode('__construct');
+ $node->addMethod($constructor);
+ }
+
+ if ($this->nodeIsDirectoryIterator($node)) {
+ $constructor->setCode('return parent::__construct("' . __DIR__ . '");');
+
+ return;
+ }
+
+ if ($this->nodeIsSplFileObject($node)) {
+ $filePath = str_replace('\\','\\\\',__FILE__);
+ $constructor->setCode('return parent::__construct("' . $filePath .'");');
+
+ return;
+ }
+
+ if ($this->nodeIsSymfonySplFileInfo($node)) {
+ $filePath = str_replace('\\','\\\\',__FILE__);
+ $constructor->setCode('return parent::__construct("' . $filePath .'", "", "");');
+
+ return;
+ }
+
+ $constructor->useParentCode();
+ }
+
+ /**
+ * Returns patch priority, which determines when patch will be applied.
+ *
+ * @return int Priority number (higher - earlier)
+ */
+ public function getPriority()
+ {
+ return 50;
+ }
+
+ /**
+ * @param ClassNode $node
+ * @return boolean
+ */
+ private function nodeIsDirectoryIterator(ClassNode $node)
+ {
+ $parent = $node->getParentClass();
+
+ return 'DirectoryIterator' === $parent
+ || is_subclass_of($parent, 'DirectoryIterator');
+ }
+
+ /**
+ * @param ClassNode $node
+ * @return boolean
+ */
+ private function nodeIsSplFileObject(ClassNode $node)
+ {
+ $parent = $node->getParentClass();
+
+ return 'SplFileObject' === $parent
+ || is_subclass_of($parent, 'SplFileObject');
+ }
+
+ /**
+ * @param ClassNode $node
+ * @return boolean
+ */
+ private function nodeIsSymfonySplFileInfo(ClassNode $node)
+ {
+ $parent = $node->getParentClass();
+
+ return 'Symfony\\Component\\Finder\\SplFileInfo' === $parent;
+ }
+}
diff --git a/vendor/phpspec/prophecy/src/Prophecy/Doubler/ClassPatch/ThrowablePatch.php b/vendor/phpspec/prophecy/src/Prophecy/Doubler/ClassPatch/ThrowablePatch.php
new file mode 100644
index 000000000..b98e94327
--- /dev/null
+++ b/vendor/phpspec/prophecy/src/Prophecy/Doubler/ClassPatch/ThrowablePatch.php
@@ -0,0 +1,95 @@
+<?php
+
+namespace Prophecy\Doubler\ClassPatch;
+
+use Prophecy\Doubler\Generator\Node\ClassNode;
+use Prophecy\Exception\Doubler\ClassCreatorException;
+
+class ThrowablePatch implements ClassPatchInterface
+{
+ /**
+ * Checks if patch supports specific class node.
+ *
+ * @param ClassNode $node
+ * @return bool
+ */
+ public function supports(ClassNode $node)
+ {
+ return $this->implementsAThrowableInterface($node) && $this->doesNotExtendAThrowableClass($node);
+ }
+
+ /**
+ * @param ClassNode $node
+ * @return bool
+ */
+ private function implementsAThrowableInterface(ClassNode $node)
+ {
+ foreach ($node->getInterfaces() as $type) {
+ if (is_a($type, 'Throwable', true)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * @param ClassNode $node
+ * @return bool
+ */
+ private function doesNotExtendAThrowableClass(ClassNode $node)
+ {
+ return !is_a($node->getParentClass(), 'Throwable', true);
+ }
+
+ /**
+ * Applies patch to the specific class node.
+ *
+ * @param ClassNode $node
+ *
+ * @return void
+ */
+ public function apply(ClassNode $node)
+ {
+ $this->checkItCanBeDoubled($node);
+ $this->setParentClassToException($node);
+ }
+
+ private function checkItCanBeDoubled(ClassNode $node)
+ {
+ $className = $node->getParentClass();
+ if ($className !== 'stdClass') {
+ throw new ClassCreatorException(
+ sprintf(
+ 'Cannot double concrete class %s as well as implement Traversable',
+ $className
+ ),
+ $node
+ );
+ }
+ }
+
+ private function setParentClassToException(ClassNode $node)
+ {
+ $node->setParentClass('Exception');
+
+ $node->removeMethod('getMessage');
+ $node->removeMethod('getCode');
+ $node->removeMethod('getFile');
+ $node->removeMethod('getLine');
+ $node->removeMethod('getTrace');
+ $node->removeMethod('getPrevious');
+ $node->removeMethod('getNext');
+ $node->removeMethod('getTraceAsString');
+ }
+
+ /**
+ * Returns patch priority, which determines when patch will be applied.
+ *
+ * @return int Priority number (higher - earlier)
+ */
+ public function getPriority()
+ {
+ return 100;
+ }
+}
diff --git a/vendor/phpspec/prophecy/src/Prophecy/Doubler/ClassPatch/TraversablePatch.php b/vendor/phpspec/prophecy/src/Prophecy/Doubler/ClassPatch/TraversablePatch.php
new file mode 100644
index 000000000..0e2e04700
--- /dev/null
+++ b/vendor/phpspec/prophecy/src/Prophecy/Doubler/ClassPatch/TraversablePatch.php
@@ -0,0 +1,98 @@
+<?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\Doubler\ClassPatch;
+
+use Prophecy\Doubler\Generator\Node\ClassNode;
+use Prophecy\Doubler\Generator\Node\MethodNode;
+use Prophecy\Doubler\Generator\Node\ReturnTypeNode;
+
+/**
+ * Traversable interface patch.
+ * Forces classes that implement interfaces, that extend Traversable to also implement Iterator.
+ *
+ * @author Konstantin Kudryashov <[email protected]>
+ */
+class TraversablePatch implements ClassPatchInterface
+{
+ /**
+ * Supports nodetree, that implement Traversable, but not Iterator or IteratorAggregate.
+ *
+ * @param ClassNode $node
+ *
+ * @return bool
+ */
+ public function supports(ClassNode $node)
+ {
+ if (in_array('Iterator', $node->getInterfaces())) {
+ return false;
+ }
+ if (in_array('IteratorAggregate', $node->getInterfaces())) {
+ return false;
+ }
+
+ foreach ($node->getInterfaces() as $interface) {
+ if ('Traversable' !== $interface && !is_subclass_of($interface, 'Traversable')) {
+ continue;
+ }
+ if ('Iterator' === $interface || is_subclass_of($interface, 'Iterator')) {
+ continue;
+ }
+ if ('IteratorAggregate' === $interface || is_subclass_of($interface, 'IteratorAggregate')) {
+ continue;
+ }
+
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Forces class to implement Iterator interface.
+ *
+ * @param ClassNode $node
+ */
+ public function apply(ClassNode $node)
+ {
+ $node->addInterface('Iterator');
+
+ $currentMethod = new MethodNode('current');
+ (\PHP_VERSION_ID >= 80100) && $currentMethod->setReturnTypeNode(new ReturnTypeNode('mixed'));
+ $node->addMethod($currentMethod);
+
+ $keyMethod = new MethodNode('key');
+ (\PHP_VERSION_ID >= 80100) && $keyMethod->setReturnTypeNode(new ReturnTypeNode('mixed'));
+ $node->addMethod($keyMethod);
+
+ $nextMethod = new MethodNode('next');
+ (\PHP_VERSION_ID >= 80100) && $nextMethod->setReturnTypeNode(new ReturnTypeNode('void'));
+ $node->addMethod($nextMethod);
+
+ $rewindMethod = new MethodNode('rewind');
+ (\PHP_VERSION_ID >= 80100) && $rewindMethod->setReturnTypeNode(new ReturnTypeNode('void'));
+ $node->addMethod($rewindMethod);
+
+ $validMethod = new MethodNode('valid');
+ (\PHP_VERSION_ID >= 80100) && $validMethod->setReturnTypeNode(new ReturnTypeNode('bool'));
+ $node->addMethod($validMethod);
+ }
+
+ /**
+ * Returns patch priority, which determines when patch will be applied.
+ *
+ * @return int Priority number (higher - earlier)
+ */
+ public function getPriority()
+ {
+ return 100;
+ }
+}
diff --git a/vendor/phpspec/prophecy/src/Prophecy/Doubler/DoubleInterface.php b/vendor/phpspec/prophecy/src/Prophecy/Doubler/DoubleInterface.php
new file mode 100644
index 000000000..699be3a2a
--- /dev/null
+++ b/vendor/phpspec/prophecy/src/Prophecy/Doubler/DoubleInterface.php
@@ -0,0 +1,22 @@
+<?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\Doubler;
+
+/**
+ * Core double interface.
+ * All doubled classes will implement this one.
+ *
+ * @author Konstantin Kudryashov <[email protected]>
+ */
+interface DoubleInterface
+{
+}
diff --git a/vendor/phpspec/prophecy/src/Prophecy/Doubler/Doubler.php b/vendor/phpspec/prophecy/src/Prophecy/Doubler/Doubler.php
new file mode 100644
index 000000000..a378ae279
--- /dev/null
+++ b/vendor/phpspec/prophecy/src/Prophecy/Doubler/Doubler.php
@@ -0,0 +1,146 @@
+<?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\Doubler;
+
+use Doctrine\Instantiator\Instantiator;
+use Prophecy\Doubler\ClassPatch\ClassPatchInterface;
+use Prophecy\Doubler\Generator\ClassMirror;
+use Prophecy\Doubler\Generator\ClassCreator;
+use Prophecy\Exception\InvalidArgumentException;
+use ReflectionClass;
+
+/**
+ * Cached class doubler.
+ * Prevents mirroring/creation of the same structure twice.
+ *
+ * @author Konstantin Kudryashov <[email protected]>
+ */
+class Doubler
+{
+ private $mirror;
+ private $creator;
+ private $namer;
+
+ /**
+ * @var ClassPatchInterface[]
+ */
+ private $patches = array();
+
+ /**
+ * @var \Doctrine\Instantiator\Instantiator
+ */
+ private $instantiator;
+
+ /**
+ * Initializes doubler.
+ *
+ * @param ClassMirror $mirror
+ * @param ClassCreator $creator
+ * @param NameGenerator $namer
+ */
+ public function __construct(ClassMirror $mirror = null, ClassCreator $creator = null,
+ NameGenerator $namer = null)
+ {
+ $this->mirror = $mirror ?: new ClassMirror;
+ $this->creator = $creator ?: new ClassCreator;
+ $this->namer = $namer ?: new NameGenerator;
+ }
+
+ /**
+ * Returns list of registered class patches.
+ *
+ * @return ClassPatchInterface[]
+ */
+ public function getClassPatches()
+ {
+ return $this->patches;
+ }
+
+ /**
+ * Registers new class patch.
+ *
+ * @param ClassPatchInterface $patch
+ */
+ public function registerClassPatch(ClassPatchInterface $patch)
+ {
+ $this->patches[] = $patch;
+
+ @usort($this->patches, function (ClassPatchInterface $patch1, ClassPatchInterface $patch2) {
+ return $patch2->getPriority() - $patch1->getPriority();
+ });
+ }
+
+ /**
+ * Creates double from specific class or/and list of interfaces.
+ *
+ * @param ReflectionClass $class
+ * @param ReflectionClass[] $interfaces Array of ReflectionClass instances
+ * @param array $args Constructor arguments
+ *
+ * @return DoubleInterface
+ *
+ * @throws \Prophecy\Exception\InvalidArgumentException
+ */
+ public function double(ReflectionClass $class = null, array $interfaces, array $args = null)
+ {
+ foreach ($interfaces as $interface) {
+ if (!$interface instanceof ReflectionClass) {
+ throw new InvalidArgumentException(sprintf(
+ "[ReflectionClass \$interface1 [, ReflectionClass \$interface2]] array expected as\n".
+ "a second argument to `Doubler::double(...)`, but got %s.",
+ is_object($interface) ? get_class($interface).' class' : gettype($interface)
+ ));
+ }
+ }
+
+ $classname = $this->createDoubleClass($class, $interfaces);
+ $reflection = new ReflectionClass($classname);
+
+ if (null !== $args) {
+ return $reflection->newInstanceArgs($args);
+ }
+ if ((null === $constructor = $reflection->getConstructor())
+ || ($constructor->isPublic() && !$constructor->isFinal())) {
+ return $reflection->newInstance();
+ }
+
+ if (!$this->instantiator) {
+ $this->instantiator = new Instantiator();
+ }
+
+ return $this->instantiator->instantiate($classname);
+ }
+
+ /**
+ * Creates double class and returns its FQN.
+ *
+ * @param ReflectionClass $class
+ * @param ReflectionClass[] $interfaces
+ *
+ * @return string
+ */
+ protected function createDoubleClass(ReflectionClass $class = null, array $interfaces)
+ {
+ $name = $this->namer->name($class, $interfaces);
+ $node = $this->mirror->reflect($class, $interfaces);
+
+ foreach ($this->patches as $patch) {
+ if ($patch->supports($node)) {
+ $patch->apply($node);
+ }
+ }
+
+ $this->creator->create($name, $node);
+
+ return $name;
+ }
+}
diff --git a/vendor/phpspec/prophecy/src/Prophecy/Doubler/Generator/ClassCodeGenerator.php b/vendor/phpspec/prophecy/src/Prophecy/Doubler/Generator/ClassCodeGenerator.php
new file mode 100644
index 000000000..52e5e0455
--- /dev/null
+++ b/vendor/phpspec/prophecy/src/Prophecy/Doubler/Generator/ClassCodeGenerator.php
@@ -0,0 +1,110 @@
+<?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\Doubler\Generator;
+
+use Prophecy\Doubler\Generator\Node\ReturnTypeNode;
+use Prophecy\Doubler\Generator\Node\TypeNodeAbstract;
+
+/**
+ * Class code creator.
+ * Generates PHP code for specific class node tree.
+ *
+ * @author Konstantin Kudryashov <[email protected]>
+ */
+class ClassCodeGenerator
+{
+ public function __construct(TypeHintReference $typeHintReference = null)
+ {
+ }
+
+ /**
+ * Generates PHP code for class node.
+ *
+ * @param string $classname
+ * @param Node\ClassNode $class
+ *
+ * @return string
+ */
+ public function generate($classname, Node\ClassNode $class)
+ {
+ $parts = explode('\\', $classname);
+ $classname = array_pop($parts);
+ $namespace = implode('\\', $parts);
+
+ $code = sprintf("class %s extends \%s implements %s {\n",
+ $classname, $class->getParentClass(), implode(', ',
+ array_map(function ($interface) {return '\\'.$interface;}, $class->getInterfaces())
+ )
+ );
+
+ foreach ($class->getProperties() as $name => $visibility) {
+ $code .= sprintf("%s \$%s;\n", $visibility, $name);
+ }
+ $code .= "\n";
+
+ foreach ($class->getMethods() as $method) {
+ $code .= $this->generateMethod($method)."\n";
+ }
+ $code .= "\n}";
+
+ return sprintf("namespace %s {\n%s\n}", $namespace, $code);
+ }
+
+ private function generateMethod(Node\MethodNode $method)
+ {
+ $php = sprintf("%s %s function %s%s(%s)%s {\n",
+ $method->getVisibility(),
+ $method->isStatic() ? 'static' : '',
+ $method->returnsReference() ? '&':'',
+ $method->getName(),
+ implode(', ', $this->generateArguments($method->getArguments())),
+ ($ret = $this->generateTypes($method->getReturnTypeNode())) ? ': '.$ret : ''
+ );
+ $php .= $method->getCode()."\n";
+
+ return $php.'}';
+ }
+
+ private function generateTypes(TypeNodeAbstract $typeNode): string
+ {
+ if (!$typeNode->getTypes()) {
+ return '';
+ }
+
+ // When we require PHP 8 we can stop generating ?foo nullables and remove this first block
+ if ($typeNode->canUseNullShorthand()) {
+ return sprintf( '?%s', $typeNode->getNonNullTypes()[0]);
+ } else {
+ return join('|', $typeNode->getTypes());
+ }
+ }
+
+ private function generateArguments(array $arguments)
+ {
+ return array_map(function (Node\ArgumentNode $argument){
+
+ $php = $this->generateTypes($argument->getTypeNode());
+
+ $php .= ' '.($argument->isPassedByReference() ? '&' : '');
+
+ $php .= $argument->isVariadic() ? '...' : '';
+
+ $php .= '$'.$argument->getName();
+
+ if ($argument->isOptional() && !$argument->isVariadic()) {
+ $php .= ' = '.var_export($argument->getDefault(), true);
+ }
+
+ return $php;
+ }, $arguments);
+ }
+}
diff --git a/vendor/phpspec/prophecy/src/Prophecy/Doubler/Generator/ClassCreator.php b/vendor/phpspec/prophecy/src/Prophecy/Doubler/Generator/ClassCreator.php
new file mode 100644
index 000000000..882a4a4b7
--- /dev/null
+++ b/vendor/phpspec/prophecy/src/Prophecy/Doubler/Generator/ClassCreator.php
@@ -0,0 +1,67 @@
+<?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\Doubler\Generator;
+
+use Prophecy\Exception\Doubler\ClassCreatorException;
+
+/**
+ * Class creator.
+ * Creates specific class in current environment.
+ *
+ * @author Konstantin Kudryashov <[email protected]>
+ */
+class ClassCreator
+{
+ private $generator;
+
+ /**
+ * Initializes creator.
+ *
+ * @param ClassCodeGenerator $generator
+ */
+ public function __construct(ClassCodeGenerator $generator = null)
+ {
+ $this->generator = $generator ?: new ClassCodeGenerator;
+ }
+
+ /**
+ * Creates class.
+ *
+ * @param string $classname
+ * @param Node\ClassNode $class
+ *
+ * @return mixed
+ *
+ * @throws \Prophecy\Exception\Doubler\ClassCreatorException
+ */
+ public function create($classname, Node\ClassNode $class)
+ {
+ $code = $this->generator->generate($classname, $class);
+ $return = eval($code);
+
+ if (!class_exists($classname, false)) {
+ if (count($class->getInterfaces())) {
+ throw new ClassCreatorException(sprintf(
+ 'Could not double `%s` and implement interfaces: [%s].',
+ $class->getParentClass(), implode(', ', $class->getInterfaces())
+ ), $class);
+ }
+
+ throw new ClassCreatorException(
+ sprintf('Could not double `%s`.', $class->getParentClass()),
+ $class
+ );
+ }
+
+ return $return;
+ }
+}
diff --git a/vendor/phpspec/prophecy/src/Prophecy/Doubler/Generator/ClassMirror.php b/vendor/phpspec/prophecy/src/Prophecy/Doubler/Generator/ClassMirror.php
new file mode 100644
index 000000000..5d9cd2d20
--- /dev/null
+++ b/vendor/phpspec/prophecy/src/Prophecy/Doubler/Generator/ClassMirror.php
@@ -0,0 +1,254 @@
+<?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\Doubler\Generator;
+
+use Prophecy\Doubler\Generator\Node\ArgumentTypeNode;
+use Prophecy\Doubler\Generator\Node\ReturnTypeNode;
+use Prophecy\Exception\InvalidArgumentException;
+use Prophecy\Exception\Doubler\ClassMirrorException;
+use ReflectionClass;
+use ReflectionIntersectionType;
+use ReflectionMethod;
+use ReflectionNamedType;
+use ReflectionParameter;
+use ReflectionType;
+use ReflectionUnionType;
+
+/**
+ * Class mirror.
+ * Core doubler class. Mirrors specific class and/or interfaces into class node tree.
+ *
+ * @author Konstantin Kudryashov <[email protected]>
+ */
+class ClassMirror
+{
+ private static $reflectableMethods = array(
+ '__construct',
+ '__destruct',
+ '__sleep',
+ '__wakeup',
+ '__toString',
+ '__call',
+ '__invoke'
+ );
+
+ /**
+ * Reflects provided arguments into class node.
+ *
+ * @param ReflectionClass|null $class
+ * @param ReflectionClass[] $interfaces
+ *
+ * @return Node\ClassNode
+ *
+ */
+ public function reflect(?ReflectionClass $class, array $interfaces)
+ {
+ $node = new Node\ClassNode;
+
+ if (null !== $class) {
+ if (true === $class->isInterface()) {
+ throw new InvalidArgumentException(sprintf(
+ "Could not reflect %s as a class, because it\n".
+ "is interface - use the second argument instead.",
+ $class->getName()
+ ));
+ }
+
+ $this->reflectClassToNode($class, $node);
+ }
+
+ foreach ($interfaces as $interface) {
+ if (!$interface instanceof ReflectionClass) {
+ throw new InvalidArgumentException(sprintf(
+ "[ReflectionClass \$interface1 [, ReflectionClass \$interface2]] array expected as\n".
+ "a second argument to `ClassMirror::reflect(...)`, but got %s.",
+ is_object($interface) ? get_class($interface).' class' : gettype($interface)
+ ));
+ }
+ if (false === $interface->isInterface()) {
+ throw new InvalidArgumentException(sprintf(
+ "Could not reflect %s as an interface, because it\n".
+ "is class - use the first argument instead.",
+ $interface->getName()
+ ));
+ }
+
+ $this->reflectInterfaceToNode($interface, $node);
+ }
+
+ $node->addInterface('Prophecy\Doubler\Generator\ReflectionInterface');
+
+ return $node;
+ }
+
+ private function reflectClassToNode(ReflectionClass $class, Node\ClassNode $node)
+ {
+ if (true === $class->isFinal()) {
+ throw new ClassMirrorException(sprintf(
+ 'Could not reflect class %s as it is marked final.', $class->getName()
+ ), $class);
+ }
+
+ $node->setParentClass($class->getName());
+
+ foreach ($class->getMethods(ReflectionMethod::IS_ABSTRACT) as $method) {
+ if (false === $method->isProtected()) {
+ continue;
+ }
+
+ $this->reflectMethodToNode($method, $node);
+ }
+
+ foreach ($class->getMethods(ReflectionMethod::IS_PUBLIC) as $method) {
+ if (0 === strpos($method->getName(), '_')
+ && !in_array($method->getName(), self::$reflectableMethods)) {
+ continue;
+ }
+
+ if (true === $method->isFinal()) {
+ $node->addUnextendableMethod($method->getName());
+ continue;
+ }
+
+ $this->reflectMethodToNode($method, $node);
+ }
+ }
+
+ private function reflectInterfaceToNode(ReflectionClass $interface, Node\ClassNode $node)
+ {
+ $node->addInterface($interface->getName());
+
+ foreach ($interface->getMethods() as $method) {
+ $this->reflectMethodToNode($method, $node);
+ }
+ }
+
+ private function reflectMethodToNode(ReflectionMethod $method, Node\ClassNode $classNode)
+ {
+ $node = new Node\MethodNode($method->getName());
+
+ if (true === $method->isProtected()) {
+ $node->setVisibility('protected');
+ }
+
+ if (true === $method->isStatic()) {
+ $node->setStatic();
+ }
+
+ if (true === $method->returnsReference()) {
+ $node->setReturnsReference();
+ }
+
+ if ($method->hasReturnType()) {
+ $returnTypes = $this->getTypeHints($method->getReturnType(), $method->getDeclaringClass(), $method->getReturnType()->allowsNull());
+ $node->setReturnTypeNode(new ReturnTypeNode(...$returnTypes));
+ }
+ elseif (method_exists($method, 'hasTentativeReturnType') && $method->hasTentativeReturnType()) {
+ $returnTypes = $this->getTypeHints($method->getTentativeReturnType(), $method->getDeclaringClass(), $method->getTentativeReturnType()->allowsNull());
+ $node->setReturnTypeNode(new ReturnTypeNode(...$returnTypes));
+ }
+
+ if (is_array($params = $method->getParameters()) && count($params)) {
+ foreach ($params as $param) {
+ $this->reflectArgumentToNode($param, $node);
+ }
+ }
+
+ $classNode->addMethod($node);
+ }
+
+ private function reflectArgumentToNode(ReflectionParameter $parameter, Node\MethodNode $methodNode)
+ {
+ $name = $parameter->getName() == '...' ? '__dot_dot_dot__' : $parameter->getName();
+ $node = new Node\ArgumentNode($name);
+
+ $typeHints = $this->getTypeHints($parameter->getType(), $parameter->getDeclaringClass(), $parameter->allowsNull());
+
+ $node->setTypeNode(new ArgumentTypeNode(...$typeHints));
+
+ if ($parameter->isVariadic()) {
+ $node->setAsVariadic();
+ }
+
+ if ($this->hasDefaultValue($parameter)) {
+ $node->setDefault($this->getDefaultValue($parameter));
+ }
+
+ if ($parameter->isPassedByReference()) {
+ $node->setAsPassedByReference();
+ }
+
+
+ $methodNode->addArgument($node);
+ }
+
+ private function hasDefaultValue(ReflectionParameter $parameter)
+ {
+ if ($parameter->isVariadic()) {
+ return false;
+ }
+
+ if ($parameter->isDefaultValueAvailable()) {
+ return true;
+ }
+
+ return $parameter->isOptional() || ($parameter->allowsNull() && $parameter->getType() && \PHP_VERSION_ID < 80100);
+ }
+
+ private function getDefaultValue(ReflectionParameter $parameter)
+ {
+ if (!$parameter->isDefaultValueAvailable()) {
+ return null;
+ }
+
+ return $parameter->getDefaultValue();
+ }
+
+ private function getTypeHints(?ReflectionType $type, ?ReflectionClass $class, bool $allowsNull) : array
+ {
+ $types = [];
+
+ if ($type instanceof ReflectionNamedType) {
+ $types = [$type->getName()];
+
+ }
+ elseif ($type instanceof ReflectionUnionType) {
+ $types = $type->getTypes();
+ }
+ elseif ($type instanceof ReflectionIntersectionType) {
+ throw new ClassMirrorException('Doubling intersection types is not supported', $class);
+ }
+ elseif(is_object($type)) {
+ throw new ClassMirrorException('Unknown reflection type ' . get_class($type), $class);
+ }
+
+ $types = array_map(
+ function(string $type) use ($class) {
+ if ($type === 'self') {
+ return $class->getName();
+ }
+ if ($type === 'parent') {
+ return $class->getParentClass()->getName();
+ }
+
+ return $type;
+ },
+ $types
+ );
+
+ if ($types && $types != ['mixed'] && $allowsNull) {
+ $types[] = 'null';
+ }
+
+ return $types;
+ }
+}
diff --git a/vendor/phpspec/prophecy/src/Prophecy/Doubler/Generator/Node/ArgumentNode.php b/vendor/phpspec/prophecy/src/Prophecy/Doubler/Generator/Node/ArgumentNode.php
new file mode 100644
index 000000000..da7fed4e1
--- /dev/null
+++ b/vendor/phpspec/prophecy/src/Prophecy/Doubler/Generator/Node/ArgumentNode.php
@@ -0,0 +1,133 @@
+<?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\Doubler\Generator\Node;
+
+/**
+ * Argument node.
+ *
+ * @author Konstantin Kudryashov <[email protected]>
+ */
+class ArgumentNode
+{
+ private $name;
+ private $default;
+ private $optional = false;
+ private $byReference = false;
+ private $isVariadic = false;
+
+ /** @var ArgumentTypeNode */
+ private $typeNode;
+
+ /**
+ * @param string $name
+ */
+ public function __construct($name)
+ {
+ $this->name = $name;
+ $this->typeNode = new ArgumentTypeNode();
+ }
+
+ public function getName()
+ {
+ return $this->name;
+ }
+
+ public function setTypeNode(ArgumentTypeNode $typeNode)
+ {
+ $this->typeNode = $typeNode;
+ }
+
+ public function getTypeNode() : ArgumentTypeNode
+ {
+ return $this->typeNode;
+ }
+
+ public function hasDefault()
+ {
+ return $this->isOptional() && !$this->isVariadic();
+ }
+
+ public function getDefault()
+ {
+ return $this->default;
+ }
+
+ public function setDefault($default = null)
+ {
+ $this->optional = true;
+ $this->default = $default;
+ }
+
+ public function isOptional()
+ {
+ return $this->optional;
+ }
+
+ public function setAsPassedByReference($byReference = true)
+ {
+ $this->byReference = $byReference;
+ }
+
+ public function isPassedByReference()
+ {
+ return $this->byReference;
+ }
+
+ public function setAsVariadic($isVariadic = true)
+ {
+ $this->isVariadic = $isVariadic;
+ }
+
+ public function isVariadic()
+ {
+ return $this->isVariadic;
+ }
+
+ /**
+ * @deprecated use getArgumentTypeNode instead
+ * @return string|null
+ */
+ public function getTypeHint()
+ {
+ $type = $this->typeNode->getNonNullTypes() ? $this->typeNode->getNonNullTypes()[0] : null;
+
+ return $type ? ltrim($type, '\\') : null;
+ }
+
+ /**
+ * @deprecated use setArgumentTypeNode instead
+ * @param string|null $typeHint
+ */
+ public function setTypeHint($typeHint = null)
+ {
+ $this->typeNode = ($typeHint === null) ? new ArgumentTypeNode() : new ArgumentTypeNode($typeHint);
+ }
+
+ /**
+ * @deprecated use getArgumentTypeNode instead
+ * @return bool
+ */
+ public function isNullable()
+ {
+ return $this->typeNode->canUseNullShorthand();
+ }
+
+ /**
+ * @deprecated use getArgumentTypeNode instead
+ * @param bool $isNullable
+ */
+ public function setAsNullable($isNullable = true)
+ {
+ $nonNullTypes = $this->typeNode->getNonNullTypes();
+ $this->typeNode = $isNullable ? new ArgumentTypeNode('null', ...$nonNullTypes) : new ArgumentTypeNode(...$nonNullTypes);
+ }
+}
diff --git a/vendor/phpspec/prophecy/src/Prophecy/Doubler/Generator/Node/ArgumentTypeNode.php b/vendor/phpspec/prophecy/src/Prophecy/Doubler/Generator/Node/ArgumentTypeNode.php
new file mode 100644
index 000000000..0a18b91e1
--- /dev/null
+++ b/vendor/phpspec/prophecy/src/Prophecy/Doubler/Generator/Node/ArgumentTypeNode.php
@@ -0,0 +1,10 @@
+<?php
+
+namespace Prophecy\Doubler\Generator\Node;
+
+use Prophecy\Exception\Doubler\DoubleException;
+
+class ArgumentTypeNode extends TypeNodeAbstract
+{
+
+}
diff --git a/vendor/phpspec/prophecy/src/Prophecy/Doubler/Generator/Node/ClassNode.php b/vendor/phpspec/prophecy/src/Prophecy/Doubler/Generator/Node/ClassNode.php
new file mode 100644
index 000000000..f7bd2857a
--- /dev/null
+++ b/vendor/phpspec/prophecy/src/Prophecy/Doubler/Generator/Node/ClassNode.php
@@ -0,0 +1,169 @@
+<?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\Doubler\Generator\Node;
+
+use Prophecy\Exception\Doubler\MethodNotExtendableException;
+use Prophecy\Exception\InvalidArgumentException;
+
+/**
+ * Class node.
+ *
+ * @author Konstantin Kudryashov <[email protected]>
+ */
+class ClassNode
+{
+ private $parentClass = 'stdClass';
+ private $interfaces = array();
+ private $properties = array();
+ private $unextendableMethods = array();
+
+ /**
+ * @var MethodNode[]
+ */
+ private $methods = array();
+
+ public function getParentClass()
+ {
+ return $this->parentClass;
+ }
+
+ /**
+ * @param string $class
+ */
+ public function setParentClass($class)
+ {
+ $this->parentClass = $class ?: 'stdClass';
+ }
+
+ /**
+ * @return string[]
+ */
+ public function getInterfaces()
+ {
+ return $this->interfaces;
+ }
+
+ /**
+ * @param string $interface
+ */
+ public function addInterface($interface)
+ {
+ if ($this->hasInterface($interface)) {
+ return;
+ }
+
+ array_unshift($this->interfaces, $interface);
+ }
+
+ /**
+ * @param string $interface
+ *
+ * @return bool
+ */
+ public function hasInterface($interface)
+ {
+ return in_array($interface, $this->interfaces);
+ }
+
+ public function getProperties()
+ {
+ return $this->properties;
+ }
+
+ public function addProperty($name, $visibility = 'public')
+ {
+ $visibility = strtolower($visibility);
+
+ if (!in_array($visibility, array('public', 'private', 'protected'))) {
+ throw new InvalidArgumentException(sprintf(
+ '`%s` property visibility is not supported.', $visibility
+ ));
+ }
+
+ $this->properties[$name] = $visibility;
+ }
+
+ /**
+ * @return MethodNode[]
+ */
+ public function getMethods()
+ {
+ return $this->methods;
+ }
+
+ public function addMethod(MethodNode $method, $force = false)
+ {
+ if (!$this->isExtendable($method->getName())){
+ $message = sprintf(
+ 'Method `%s` is not extendable, so can not be added.', $method->getName()
+ );
+ throw new MethodNotExtendableException($message, $this->getParentClass(), $method->getName());
+ }
+
+ if ($force || !isset($this->methods[$method->getName()])) {
+ $this->methods[$method->getName()] = $method;
+ }
+ }
+
+ public function removeMethod($name)
+ {
+ unset($this->methods[$name]);
+ }
+
+ /**
+ * @param string $name
+ *
+ * @return MethodNode|null
+ */
+ public function getMethod($name)
+ {
+ return $this->hasMethod($name) ? $this->methods[$name] : null;
+ }
+
+ /**
+ * @param string $name
+ *
+ * @return bool
+ */
+ public function hasMethod($name)
+ {
+ return isset($this->methods[$name]);
+ }
+
+ /**
+ * @return string[]
+ */
+ public function getUnextendableMethods()
+ {
+ return $this->unextendableMethods;
+ }
+
+ /**
+ * @param string $unextendableMethod
+ */
+ public function addUnextendableMethod($unextendableMethod)
+ {
+ if (!$this->isExtendable($unextendableMethod)){
+ return;
+ }
+ $this->unextendableMethods[] = $unextendableMethod;
+ }
+
+ /**
+ * @param string $method
+ * @return bool
+ */
+ public function isExtendable($method)
+ {
+ return !in_array($method, $this->unextendableMethods);
+ }
+}
diff --git a/vendor/phpspec/prophecy/src/Prophecy/Doubler/Generator/Node/MethodNode.php b/vendor/phpspec/prophecy/src/Prophecy/Doubler/Generator/Node/MethodNode.php
new file mode 100644
index 000000000..ece652f9f
--- /dev/null
+++ b/vendor/phpspec/prophecy/src/Prophecy/Doubler/Generator/Node/MethodNode.php
@@ -0,0 +1,210 @@
+<?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\Doubler\Generator\Node;
+
+use Prophecy\Doubler\Generator\TypeHintReference;
+use Prophecy\Exception\InvalidArgumentException;
+
+/**
+ * Method node.
+ *
+ * @author Konstantin Kudryashov <[email protected]>
+ */
+class MethodNode
+{
+ private $name;
+ private $code;
+ private $visibility = 'public';
+ private $static = false;
+ private $returnsReference = false;
+
+ /** @var ReturnTypeNode */
+ private $returnTypeNode;
+
+ /**
+ * @var ArgumentNode[]
+ */
+ private $arguments = array();
+
+ /**
+ * @param string $name
+ * @param string $code
+ */
+ public function __construct($name, $code = null, TypeHintReference $typeHintReference = null)
+ {
+ $this->name = $name;
+ $this->code = $code;
+ $this->returnTypeNode = new ReturnTypeNode();
+ }
+
+ public function getVisibility()
+ {
+ return $this->visibility;
+ }
+
+ /**
+ * @param string $visibility
+ */
+ public function setVisibility($visibility)
+ {
+ $visibility = strtolower($visibility);
+
+ if (!in_array($visibility, array('public', 'private', 'protected'))) {
+ throw new InvalidArgumentException(sprintf(
+ '`%s` method visibility is not supported.', $visibility
+ ));
+ }
+
+ $this->visibility = $visibility;
+ }
+
+ public function isStatic()
+ {
+ return $this->static;
+ }
+
+ public function setStatic($static = true)
+ {
+ $this->static = (bool) $static;
+ }
+
+ public function returnsReference()
+ {
+ return $this->returnsReference;
+ }
+
+ public function setReturnsReference()
+ {
+ $this->returnsReference = true;
+ }
+
+ public function getName()
+ {
+ return $this->name;
+ }
+
+ public function addArgument(ArgumentNode $argument)
+ {
+ $this->arguments[] = $argument;
+ }
+
+ /**
+ * @return ArgumentNode[]
+ */
+ public function getArguments()
+ {
+ return $this->arguments;
+ }
+
+ /**
+ * @deprecated use getReturnTypeNode instead
+ * @return bool
+ */
+ public function hasReturnType()
+ {
+ return (bool) $this->returnTypeNode->getNonNullTypes();
+ }
+
+ public function setReturnTypeNode(ReturnTypeNode $returnTypeNode): void
+ {
+ $this->returnTypeNode = $returnTypeNode;
+ }
+
+ /**
+ * @deprecated use setReturnTypeNode instead
+ * @param string $type
+ */
+ public function setReturnType($type = null)
+ {
+ $this->returnTypeNode = ($type === '' || $type === null) ? new ReturnTypeNode() : new ReturnTypeNode($type);
+ }
+
+ /**
+ * @deprecated use setReturnTypeNode instead
+ * @param bool $bool
+ */
+ public function setNullableReturnType($bool = true)
+ {
+ if ($bool) {
+ $this->returnTypeNode = new ReturnTypeNode('null', ...$this->returnTypeNode->getTypes());
+ }
+ else {
+ $this->returnTypeNode = new ReturnTypeNode(...$this->returnTypeNode->getNonNullTypes());
+ }
+ }
+
+ /**
+ * @deprecated use getReturnTypeNode instead
+ * @return string|null
+ */
+ public function getReturnType()
+ {
+ if ($types = $this->returnTypeNode->getNonNullTypes())
+ {
+ return $types[0];
+ }
+
+ return null;
+ }
+
+ public function getReturnTypeNode() : ReturnTypeNode
+ {
+ return $this->returnTypeNode;
+ }
+
+ /**
+ * @deprecated use getReturnTypeNode instead
+ * @return bool
+ */
+ public function hasNullableReturnType()
+ {
+ return $this->returnTypeNode->canUseNullShorthand();
+ }
+
+ /**
+ * @param string $code
+ */
+ public function setCode($code)
+ {
+ $this->code = $code;
+ }
+
+ public function getCode()
+ {
+ if ($this->returnsReference)
+ {
+ return "throw new \Prophecy\Exception\Doubler\ReturnByReferenceException('Returning by reference not supported', get_class(\$this), '{$this->name}');";
+ }
+
+ return (string) $this->code;
+ }
+
+ public function useParentCode()
+ {
+ $this->code = sprintf(
+ 'return parent::%s(%s);', $this->getName(), implode(', ',
+ array_map(array($this, 'generateArgument'), $this->arguments)
+ )
+ );
+ }
+
+ private function generateArgument(ArgumentNode $arg)
+ {
+ $argument = '$'.$arg->getName();
+
+ if ($arg->isVariadic()) {
+ $argument = '...'.$argument;
+ }
+
+ return $argument;
+ }
+}
diff --git a/vendor/phpspec/prophecy/src/Prophecy/Doubler/Generator/Node/ReturnTypeNode.php b/vendor/phpspec/prophecy/src/Prophecy/Doubler/Generator/Node/ReturnTypeNode.php
new file mode 100644
index 000000000..5b5824988
--- /dev/null
+++ b/vendor/phpspec/prophecy/src/Prophecy/Doubler/Generator/Node/ReturnTypeNode.php
@@ -0,0 +1,45 @@
+<?php
+
+namespace Prophecy\Doubler\Generator\Node;
+
+use Prophecy\Exception\Doubler\DoubleException;
+
+final class ReturnTypeNode extends TypeNodeAbstract
+{
+ protected function getRealType(string $type): string
+ {
+ switch ($type) {
+ case 'void':
+ case 'never':
+ return $type;
+ default:
+ return parent::getRealType($type);
+ }
+ }
+
+ protected function guardIsValidType()
+ {
+ if (isset($this->types['void']) && count($this->types) !== 1) {
+ throw new DoubleException('void cannot be part of a union');
+ }
+ if (isset($this->types['never']) && count($this->types) !== 1) {
+ throw new DoubleException('never cannot be part of a union');
+ }
+
+ parent::guardIsValidType();
+ }
+
+ /**
+ * @deprecated use hasReturnStatement
+ */
+ public function isVoid()
+ {
+ return $this->types == ['void' => 'void'];
+ }
+
+ public function hasReturnStatement(): bool
+ {
+ return $this->types !== ['void' => 'void']
+ && $this->types !== ['never' => 'never'];
+ }
+}
diff --git a/vendor/phpspec/prophecy/src/Prophecy/Doubler/Generator/Node/TypeNodeAbstract.php b/vendor/phpspec/prophecy/src/Prophecy/Doubler/Generator/Node/TypeNodeAbstract.php
new file mode 100644
index 000000000..97fc54978
--- /dev/null
+++ b/vendor/phpspec/prophecy/src/Prophecy/Doubler/Generator/Node/TypeNodeAbstract.php
@@ -0,0 +1,97 @@
+<?php
+
+namespace Prophecy\Doubler\Generator\Node;
+
+use Prophecy\Exception\Doubler\DoubleException;
+
+abstract class TypeNodeAbstract
+{
+ /** @var string[] */
+ protected $types = [];
+
+ public function __construct(string ...$types)
+ {
+ foreach ($types as $type) {
+ $type = $this->getRealType($type);
+ $this->types[$type] = $type;
+ }
+
+ $this->guardIsValidType();
+ }
+
+ public function canUseNullShorthand(): bool
+ {
+ return isset($this->types['null']) && count($this->types) <= 2;
+ }
+
+ public function getTypes(): array
+ {
+ return array_values($this->types);
+ }
+
+ public function getNonNullTypes(): array
+ {
+ $nonNullTypes = $this->types;
+ unset($nonNullTypes['null']);
+
+ return array_values($nonNullTypes);
+ }
+
+ protected function prefixWithNsSeparator(string $type): string
+ {
+ return '\\' . ltrim($type, '\\');
+ }
+
+ protected function getRealType(string $type): string
+ {
+ switch ($type) {
+ // type aliases
+ case 'double':
+ case 'real':
+ return 'float';
+ case 'boolean':
+ return 'bool';
+ case 'integer':
+ return 'int';
+
+ // built in types
+ case 'self':
+ case 'static':
+ case 'array':
+ case 'callable':
+ case 'bool':
+ case 'false':
+ case 'float':
+ case 'int':
+ case 'string':
+ case 'iterable':
+ case 'object':
+ case 'null':
+ return $type;
+ case 'mixed':
+ return \PHP_VERSION_ID < 80000 ? $this->prefixWithNsSeparator($type) : $type;
+
+ default:
+ return $this->prefixWithNsSeparator($type);
+ }
+ }
+
+ protected function guardIsValidType()
+ {
+ if ($this->types == ['null' => 'null']) {
+ throw new DoubleException('Type cannot be standalone null');
+ }
+
+ if ($this->types == ['false' => 'false']) {
+ throw new DoubleException('Type cannot be standalone false');
+ }
+
+ if ($this->types == ['false' => 'false', 'null' => 'null']) {
+ throw new DoubleException('Type cannot be nullable false');
+ }
+
+ if (\PHP_VERSION_ID >= 80000 && isset($this->types['mixed']) && count($this->types) !== 1) {
+ throw new DoubleException('mixed cannot be part of a union');
+ }
+ }
+}
diff --git a/vendor/phpspec/prophecy/src/Prophecy/Doubler/Generator/ReflectionInterface.php b/vendor/phpspec/prophecy/src/Prophecy/Doubler/Generator/ReflectionInterface.php
new file mode 100644
index 000000000..d720b1515
--- /dev/null
+++ b/vendor/phpspec/prophecy/src/Prophecy/Doubler/Generator/ReflectionInterface.php
@@ -0,0 +1,22 @@
+<?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\Doubler\Generator;
+
+/**
+ * Reflection interface.
+ * All reflected classes implement this interface.
+ *
+ * @author Konstantin Kudryashov <[email protected]>
+ */
+interface ReflectionInterface
+{
+}
diff --git a/vendor/phpspec/prophecy/src/Prophecy/Doubler/Generator/TypeHintReference.php b/vendor/phpspec/prophecy/src/Prophecy/Doubler/Generator/TypeHintReference.php
new file mode 100644
index 000000000..5e8aa303d
--- /dev/null
+++ b/vendor/phpspec/prophecy/src/Prophecy/Doubler/Generator/TypeHintReference.php
@@ -0,0 +1,43 @@
+<?php
+
+namespace Prophecy\Doubler\Generator;
+
+/**
+ * Tells whether a keyword refers to a class or to a built-in type for the
+ * current version of php
+ *
+ * @deprecated in favour of Node\TypeNodeAbstract
+ */
+final class TypeHintReference
+{
+ public function isBuiltInParamTypeHint($type)
+ {
+ switch ($type) {
+ case 'self':
+ case 'array':
+ case 'callable':
+ case 'bool':
+ case 'float':
+ case 'int':
+ case 'string':
+ case 'iterable':
+ case 'object':
+ return true;
+
+ case 'mixed':
+ return PHP_VERSION_ID >= 80000;
+
+ default:
+ return false;
+ }
+ }
+
+ public function isBuiltInReturnTypeHint($type)
+ {
+ if ($type === 'void') {
+ return true;
+ }
+
+ return $this->isBuiltInParamTypeHint($type);
+ }
+}
diff --git a/vendor/phpspec/prophecy/src/Prophecy/Doubler/LazyDouble.php b/vendor/phpspec/prophecy/src/Prophecy/Doubler/LazyDouble.php
new file mode 100644
index 000000000..8a99c4ce8
--- /dev/null
+++ b/vendor/phpspec/prophecy/src/Prophecy/Doubler/LazyDouble.php
@@ -0,0 +1,127 @@
+<?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\Doubler;
+
+use Prophecy\Exception\Doubler\DoubleException;
+use Prophecy\Exception\Doubler\ClassNotFoundException;
+use Prophecy\Exception\Doubler\InterfaceNotFoundException;
+use ReflectionClass;
+
+/**
+ * Lazy double.
+ * Gives simple interface to describe double before creating it.
+ *
+ * @author Konstantin Kudryashov <[email protected]>
+ */
+class LazyDouble
+{
+ private $doubler;
+ private $class;
+ private $interfaces = array();
+ private $arguments = null;
+ private $double;
+
+ /**
+ * Initializes lazy double.
+ *
+ * @param Doubler $doubler
+ */
+ public function __construct(Doubler $doubler)
+ {
+ $this->doubler = $doubler;
+ }
+
+ /**
+ * Tells doubler to use specific class as parent one for double.
+ *
+ * @param string|ReflectionClass $class
+ *
+ * @throws \Prophecy\Exception\Doubler\ClassNotFoundException
+ * @throws \Prophecy\Exception\Doubler\DoubleException
+ */
+ public function setParentClass($class)
+ {
+ if (null !== $this->double) {
+ throw new DoubleException('Can not extend class with already instantiated double.');
+ }
+
+ if (!$class instanceof ReflectionClass) {
+ if (!class_exists($class)) {
+ throw new ClassNotFoundException(sprintf('Class %s not found.', $class), $class);
+ }
+
+ $class = new ReflectionClass($class);
+ }
+
+ $this->class = $class;
+ }
+
+ /**
+ * Tells doubler to implement specific interface with double.
+ *
+ * @param string|ReflectionClass $interface
+ *
+ * @throws \Prophecy\Exception\Doubler\InterfaceNotFoundException
+ * @throws \Prophecy\Exception\Doubler\DoubleException
+ */
+ public function addInterface($interface)
+ {
+ if (null !== $this->double) {
+ throw new DoubleException(
+ 'Can not implement interface with already instantiated double.'
+ );
+ }
+
+ if (!$interface instanceof ReflectionClass) {
+ if (!interface_exists($interface)) {
+ throw new InterfaceNotFoundException(
+ sprintf('Interface %s not found.', $interface),
+ $interface
+ );
+ }
+
+ $interface = new ReflectionClass($interface);
+ }
+
+ $this->interfaces[] = $interface;
+ }
+
+ /**
+ * Sets constructor arguments.
+ *
+ * @param array $arguments
+ */
+ public function setArguments(array $arguments = null)
+ {
+ $this->arguments = $arguments;
+ }
+
+ /**
+ * Creates double instance or returns already created one.
+ *
+ * @return DoubleInterface
+ */
+ public function getInstance()
+ {
+ if (null === $this->double) {
+ if (null !== $this->arguments) {
+ return $this->double = $this->doubler->double(
+ $this->class, $this->interfaces, $this->arguments
+ );
+ }
+
+ $this->double = $this->doubler->double($this->class, $this->interfaces);
+ }
+
+ return $this->double;
+ }
+}
diff --git a/vendor/phpspec/prophecy/src/Prophecy/Doubler/NameGenerator.php b/vendor/phpspec/prophecy/src/Prophecy/Doubler/NameGenerator.php
new file mode 100644
index 000000000..d67ec6a4d
--- /dev/null
+++ b/vendor/phpspec/prophecy/src/Prophecy/Doubler/NameGenerator.php
@@ -0,0 +1,52 @@
+<?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\Doubler;
+
+use ReflectionClass;
+
+/**
+ * Name generator.
+ * Generates classname for double.
+ *
+ * @author Konstantin Kudryashov <[email protected]>
+ */
+class NameGenerator
+{
+ private static $counter = 1;
+
+ /**
+ * Generates name.
+ *
+ * @param ReflectionClass $class
+ * @param ReflectionClass[] $interfaces
+ *
+ * @return string
+ */
+ public function name(ReflectionClass $class = null, array $interfaces)
+ {
+ $parts = array();
+
+ if (null !== $class) {
+ $parts[] = $class->getName();
+ } else {
+ foreach ($interfaces as $interface) {
+ $parts[] = $interface->getShortName();
+ }
+ }
+
+ if (!count($parts)) {
+ $parts[] = 'stdClass';
+ }
+
+ return sprintf('Double\%s\P%d', implode('\\', $parts), self::$counter++);
+ }
+}