[
  {
    "path": ".editorconfig",
    "content": "root = true\n\n[*]\ncharset = utf-8\nend_of_line = lf\nindent_size = 4\nindent_style = space\ninsert_final_newline = true\ntab_width = 4\ntrim_trailing_whitespace = true\n\n[.github/workflows/*.yml]\nindent_size = 2\n"
  },
  {
    "path": ".gitattributes",
    "content": "/.editorconfig    export-ignore\n/.gitattributes   export-ignore\n/.gitignore       export-ignore\n/CONTRIBUTING.md  export-ignore\n/.github/         export-ignore\n/fixtures/        export-ignore\n/phpunit.xml.dist export-ignore\n/phpstan*.neon    export-ignore\n/spec/            export-ignore\n/tests/           export-ignore\n"
  },
  {
    "path": ".github/workflows/build.yml",
    "content": "name: Build\n\non:\n  push:\n    branches: [master]\n  pull_request:\n  release:\n    types: [created]\n\njobs:\n  tests:\n    runs-on: ubuntu-latest\n    name: Build and test\n    continue-on-error: ${{ matrix.experimental || false }}\n    strategy:\n      fail-fast: false\n      matrix:\n        php: [\"8.2\", \"8.3\", \"8.4\"]\n        composer-flags: [ \"\" ]\n        experimental: [ false ]\n        include:\n          - php: 8.2\n            composer-flags: \"--prefer-lowest\"\n          - php: \"8.5\" # TODO move that to a normal job once phpspec supports PHP 8.5\n            composer-flags: \"--ignore-platform-req=php+\"\n          - php: nightly\n            composer-flags: \"--ignore-platform-req=php+\"\n            experimental: true\n\n    steps:\n      -   uses: actions/checkout@v5\n\n      -   name: Set up PHP\n          uses: shivammathur/setup-php@v2\n          with:\n            php-version: \"${{ matrix.php }}\"\n            coverage: none\n\n      -   name: Install dependencies\n          run: COMPOSER_ROOT_VERSION=dev-master composer update ${{ matrix.composer-flags }} --no-scripts\n          id: end-of-setup\n\n      -   name: Run tests (phpspec)\n          run: ./vendor/bin/phpspec run --format=dot\n          if: always() && steps.end-of-setup.outcome == 'success'\n\n      -   name: Run tests (phpunit)\n          run: ./vendor/bin/phpunit\n          if: always() && steps.end-of-setup.outcome == 'success'\n\n  phpstan:\n    runs-on: ubuntu-latest\n    name: Static analysis\n    steps:\n      - uses: actions/checkout@v5\n      - name: Set up PHP\n        uses: shivammathur/setup-php@v2\n        with:\n          php-version: \"8.3\"\n          coverage: none\n      - name: Install dependencies\n        run: COMPOSER_ROOT_VERSION=dev-master composer update --no-scripts\n      - run: ./vendor/bin/phpstan\n\n  coding-standards:\n    runs-on: ubuntu-latest\n    name: Coding standards\n    steps:\n      - uses: actions/checkout@v5\n      - name: Set up PHP\n        uses: shivammathur/setup-php@v2\n        with:\n          php-version: \"8.3\"\n          coverage: none\n      - name: Install dependencies\n        run: COMPOSER_ROOT_VERSION=dev-master composer update --no-scripts\n      - run: composer cs:check -- --ansi\n"
  },
  {
    "path": ".gitignore",
    "content": "*.tgz\n*.phar\n/.php-cs-fixer.cache\n/composer.lock\n/dev-tools/vendor/\n/vendor\n/phpstan.neon\n/phpunit.xml\n/.phpunit.result.cache\n/.phpunit.cache/\n"
  },
  {
    "path": ".php-cs-fixer.dist.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nreturn (new PhpCsFixer\\Config())\n    ->setRiskyAllowed(false)\n    ->setRules([\n        '@PER-CS' => true,\n        'array_syntax' => false,\n        'braces_position' => [\n            'control_structures_opening_brace' => 'same_line',\n        ],\n        'no_unused_imports' => true,\n        'concat_space' => ['spacing' => 'none'],\n        'method_argument_space' => ['on_multiline' => 'ignore'],\n        // Since PHP 7.2 is supported we can't add trailing commas in arguments, parameters and match\n        'trailing_comma_in_multiline' => ['elements' => ['arrays']],\n        'modifier_keywords' => false,\n    ])\n    ->setFinder(\n        (new PhpCsFixer\\Finder())\n            ->ignoreDotFiles(false)\n            ->ignoreVCSIgnored(true)\n            ->exclude(['fixtures'])\n            ->notPath(['phpstan-baseline.php'])\n            ->in(__DIR__)\n    )\n;\n"
  },
  {
    "path": "CHANGES.md",
    "content": "Unreleased\n==========\n\n1.26.0\n======\n\n**Added:**\n\n* Add support for `phpdocumentor/reflection-docblock` v6 (@mspirkov)\n\n1.25.0\n======\n\n**Added:**\n\n* Add support for PHPUnit 13 (@Jean85)\n\n1.24.0\n======\n\n**Added:**\n\n* Add support for PHP 8.5 (@andypost)\n\n1.23.1\n======\n\n**Changed:**\n\n* Refactor the ProphecyComparator to use composition instead of extending internal comparator classes (@stof)\n\n1.23.0\n======\n\n**Removed:**\n\n* Remove support for PHP lower than 8.2 (@Nek-)\n\n**Added:**\n\n* Add support for doubling classes using intersection types and DNF types (@Nek-)\n\n**Fixed:**\n\n* Fix deprecation for `SplObjectStorage` changes in PHP 8.5 (@Nek-)\n\n**Changed:**\n\n* Improve error message for unsupported default return values (@stof)\n\n1.22.0\n======\n\n**Removed:**\n\n* Support for PHP 7.2 and 7.3 (@jean85)\n\n1.21.0\n======\n\n**Added:**\n\n* Add support for PHPUnit 12 (@jean85)\n\n1.20.0\n======\n\n**Added:**\n\n* Add support for PHP 8.4 (@andypost)\n\n**Fixed:**\n\n* Fix support for doubling methods using an enum case as default value of a parameter (@jdreesen)\n* Fix deprecation when doubling a class with constructor parameters (@singinwhale, @W0rma)\n* Fix deprecation warning when using phpdocumentor/reflection-docblock 5.4+ (@jrfnl)\n\n1.19.0\n======\n\n**Added:**\n\n* Allow sebastian/comparator and sebastian/recursion-context 6\n\n1.18.0 / 2023-12-07\n===================\n\n* [added] Add support for PHP 8.3 [@rajeshreeputra]\n* [changed] Improve the error when using return types that Prophecy does not support for mocking [@stof]\n* [changed] Add more precise type for static analysis [@stof]\n* [fixed] Error when comparing object arguments with integers [@lucassabreu]\n* [changed] Add PHP 8.2 to test matrix [@Jean85]\n* [Added] Allow sebastian/comparator and sebastian/recursion-context 5, and phpunit/phpunit 10 [@Jean85]\n* [docs] Switch travis status badge to GHA one [@michalbundyra]\n\n1.17.0 / 2023-02-02\n===================\n\n* [added] Add generic types for ProphecyInterface and ObjectProphecy [@stof]\n* [added] Add the conditional return type for `ObjectProphecy::getMethodProphecies` [@stof]\n* [added] Add support for doctrine/instantiator 2.0 [@stof]\n* [added] Add the ability to customize the __toString representation of a CallbackToken [@ian-zunderdorp]\n* [changed] Remove support for instantiating a MethodProphecy without its arguments [@stof]\n* [deprecated] Deprecate `\\Prophecy\\Comparator\\Factory` as `sebastian/comparator` v5 makes it parent class final [@stof]\n\n1.16.0 / 2022/11/29\n===================\n\n* [added] Allow installing with PHP 8.2 [@gquemener]\n* [added] Use shorter object IDs for object comparison [@TysonAndre]\n* [added] Support standalone false,true and null types [@kschatzle]\n* [added] Support doubling readonly classes [@gquemener]\n* [fixed] Remove workarounds for unsupported HHVM [@TysonAndre]\n* [fixed] Clear error message when doubling DNF types [@kschatzle]\n\n\n1.15.0 / 2021/12/08\n===================\n\n* [added] Support for the `static` return type [@denis-rolling-scopes]\n* [fixed] Add return types for Comparator implementations to avoid deprecation warnings from Symfony's DebugClassLoader [@stof]\n\n1.14.0 / 2021/09/16\n===================\n\n* [added] Support for static closures in will and should [@ntzm]\n* [added] Allow install on PHP 8.1 (with test suite fixes) [@javer]\n* [added] Support for the 'never' return type [@ciaranmcnulty]\n* [fixed] Better error message when doubling intersection return types [@ciaranmcnulty]\n\n1.13.0 / 2021/03/17\n===================\n\n* [added] willYield can now specify a return value [@camilledejoye]\n* [added] Prophecy exception interfaces are explicitly Throwable [@ciaranmcnulty]\n* [fixed] Argument::in() and notIn() now marked as static [@tyteen4a03]\n* [fixed] Can now double unions containing false [@ciaranmcnulty]\n* [fixed] Virtual magic methods with arguments are now doublable in PHP 8 [@ciaranmcnulty]\n\n1.12.2 / 2020/12/19\n===================\n\n* [fixed] MethodNotFoundException sometimes thrown with wrong class attached [@ciaranmcnulty]\n\n1.12.1 / 2020/10/29\n===================\n\n* [fixed] Incorrect handling of inherited 'self' return types [@ciaranmcnulty]\n\n1.12.0 / 2020/10/28\n===================\n\n* [added] PHP 8 support [@ciaranmcnulty]\n* [added] Argument::in() and Argument::notIn() [@viniciusalonso]\n* [added] Support for union and mixed types [@ciaranmcnulty]\n* [fixed] Issues caused by introduction of named parameters [@ciaranmcnulty]\n* [fixed] Issues caused by stricter rounding [@ciaranmcnulty]\n\n1.11.1 / 2020/07/08\n===================\n\n* [fixed] can't double objects with `self` type hints (@greg0ire)\n* [fixed] cloned doubes were not loosely comparable (@tkulka)\n\n1.11.0 / 2020/07/07\n===================\n\n* [changed] dropped support for PHP versions earlier than 7.2 (@ciaranmcnulty)\n* [fixed] removed use of Reflection APIs deprecated in PHP 8.0 (@Ayesh)\n\n1.10.3 / 2020/03/05\n===================\n\n* [fixed] removed fatal error when phpdocumentor/reflection-docblock 5 parses an invalid `@method` tag (@stof)\n\n1.10.2 / 2020/01/20\n===================\n\n* [added] support for new versions of `sebastian/comparator` and `sebastian/recursion-context` (@sebastianbergmann)\n\n1.10.1 / 2019/12/22\n===================\n\n* [fixed] identical callables no longer match as arguments (@ciaranmcnulty)\n\n1.10.0 / 2019/12/17\n===================\n\n* [added] shouldHaveBeenCalled evaluation happens later so un-stubbed calls don't throw (@elvetemedve)\n* [added] methods can now be doubled case-insensitively to match PHP semantics (@michalbundyra)\n* [fixed] reduced memory usage by optimising CachedDoubler (@DonCallisto)\n* [fixed] removed fatal error nesting level when comparing large objects (@scroach)\n\n1.9.0 / 2019/10/03\n==================\n\n* [added] Add willYield feature to Method Prophecy(@tkotosz)\n* [fixed] Allow `MethodProphecy::willThrow()` to accept Throwable as string (@timoschinkel )\n* [fixed] Allow new version of phpdocumentor/reflection-docblock (@ricpelo)\n\n1.8.1 / 2019/06/13\n==================\n\n* [fixed] Don't try to patch final constructors (@NiR)\n\n1.8.0 / 2018/08/05\n==================\n\n* Support for void return types without explicit will (@crellbar)\n* Clearer error message for unexpected method calls (@meridius)\n* Clearer error message for aggregate exceptions (@meridius)\n* More verbose `shouldBeCalledOnce` expectation (@olvlvl)\n* Ability to double Throwable, or methods that extend it (@ciaranmcnulty)\n* [fixed] Doubling methods where class has additional arguments to interface (@webimpress)\n* [fixed] Doubling methods where arguments are nullable but default is not null (@webimpress)\n* [fixed] Doubling magic methods on parent class (@dsnopek)\n* [fixed] Check method predictions only once (@dontub)\n* [fixed] Argument::containingString throwing error when called with non-string (@dcabrejas)\n\n1.7.6 / 2018/04/18\n==================\n\n* Allow sebastian/comparator ^3.0 (@sebastianbergmann)\n\n1.7.5 / 2018/02/11\n==================\n\n* Support for object return type hints (thanks @greg0ire)\n\n1.7.4 / 2018/02/11\n==================\n\n* Fix issues with PHP 7.2 (thanks @greg0ire)\n* Support object type hints in PHP 7.2 (thanks @@jansvoboda11)\n\n1.7.3 / 2017/11/24\n==================\n\n* Fix SplInfo ClassPatch to work with Symfony 4 (Thanks @gnugat)\n\n1.7.2 / 2017-10-04\n==================\n\n* Reverted \"check method predictions only once\" due to it breaking Spies\n\n1.7.1 / 2017-10-03\n==================\n\n* Allow PHP5 keywords methods generation on PHP7 (thanks @bycosta)\n* Allow reflection-docblock v4 (thanks @GrahamCampbell)\n* Check method predictions only once (thanks @dontub)\n* Escape file path sent to \\SplFileObjectConstructor when running on Windows (thanks @danmartin-epiphany)\n\n1.7.0 / 2017-03-02\n==================\n\n* Add full PHP 7.1 Support (thanks @prolic)\n* Allow `sebastian/comparator ^2.0` (thanks @sebastianbergmann)\n* Allow `sebastian/recursion-context ^3.0` (thanks @sebastianbergmann)\n* Allow `\\Error` instances in `ThrowPromise` (thanks @jameshalsall)\n* Support `phpspec/phpspect ^3.2` (thanks @Sam-Burns)\n* Fix failing builds (thanks @Sam-Burns)\n\n1.6.2 / 2016-11-21\n==================\n\n* Added support for detecting @method on interfaces that the class itself implements, or when the stubbed class is an interface itself (thanks @Seldaek)\n* Added support for sebastian/recursion-context 2 (thanks @sebastianbergmann)\n* Added testing on PHP 7.1 on Travis (thanks @danizord)\n* Fixed the usage of the phpunit comparator (thanks @Anyqax)\n\n1.6.1 / 2016-06-07\n==================\n\n  * Ignored empty method names in invalid `@method` phpdoc\n  * Fixed the mocking of SplFileObject\n  * Added compatibility with phpdocumentor/reflection-docblock 3\n\n1.6.0 / 2016-02-15\n==================\n\n  * Add Variadics support (thanks @pamil)\n  * Add ProphecyComparator for comparing objects that need revealing (thanks @jon-acker)\n  * Add ApproximateValueToken (thanks @dantleech)\n  * Add support for 'self' and 'parent' return type (thanks @bendavies)\n  * Add __invoke to allowed reflectable methods list (thanks @ftrrtf)\n  * Updated ExportUtil to reflect the latest changes by Sebastian (thanks @jakari)\n  * Specify the required php version for composer (thanks @jakzal)\n  * Exclude 'args' in the generated backtrace (thanks @oradwell)\n  * Fix code generation for scalar parameters (thanks @trowski)\n  * Fix missing sprintf in InvalidArgumentException __construct call (thanks @emmanuelballery)\n  * Fix phpdoc for magic methods (thanks @Tobion)\n  * Fix PhpDoc for interfaces usage (thanks @ImmRanneft)\n  * Prevent final methods from being manually extended (thanks @kamioftea)\n  * Enhance exception for invalid argument to ThrowPromise (thanks @Tobion)\n\n1.5.0 / 2015-04-27\n==================\n\n  * Add support for PHP7 scalar type hints (thanks @trowski)\n  * Add support for PHP7 return types (thanks @trowski)\n  * Update internal test suite to support PHP7\n\n1.4.1 / 2015-04-27\n==================\n\n  * Fixed bug in closure-based argument tokens (#181)\n\n1.4.0 / 2015-03-27\n==================\n\n  * Fixed errors in return type phpdocs (thanks @sobit)\n  * Fixed stringifying of hash containing one value (thanks @avant1)\n  * Improved clarity of method call expectation exception (thanks @dantleech)\n  * Add ability to specify which argument is returned in willReturnArgument (thanks @coderbyheart)\n  * Add more information to MethodNotFound exceptions (thanks @ciaranmcnulty)\n  * Support for mocking classes with methods that return references (thanks @edsonmedina)\n  * Improved object comparison (thanks @whatthejeff)\n  * Adopted '^' in composer dependencies (thanks @GrahamCampbell)\n  * Fixed non-typehinted arguments being treated as optional (thanks @whatthejeff)\n  * Magic methods are now filtered for keywords (thanks @seagoj)\n  * More readable errors for failure when expecting single calls (thanks @dantleech)\n\n1.3.1 / 2014-11-17\n==================\n\n  * Fix the edge case when failed predictions weren't recorded for `getCheckedPredictions()`\n\n1.3.0 / 2014-11-14\n==================\n\n  * Add a way to get checked predictions with `MethodProphecy::getCheckedPredictions()`\n  * Fix HHVM compatibility\n  * Remove dead code (thanks @stof)\n  * Add support for DirectoryIterators (thanks @shanethehat)\n\n1.2.0 / 2014-07-18\n==================\n\n  * Added support for doubling magic methods documented in the class phpdoc (thanks @armetiz)\n  * Fixed a segfault appearing in some cases (thanks @dmoreaulf)\n  * Fixed the doubling of methods with typehints on non-existent classes (thanks @gquemener)\n  * Added support for internal classes using keywords as method names (thanks @milan)\n  * Added IdenticalValueToken and Argument::is (thanks @florianv)\n  * Removed the usage of scalar typehints in HHVM as HHVM 3 does not support them anymore in PHP code (thanks @whatthejeff)\n\n1.1.2 / 2014-01-24\n==================\n\n  * Spy automatically promotes spied method call to an expected one\n\n1.1.1 / 2014-01-15\n==================\n\n  * Added support for HHVM\n\n1.1.0 / 2014-01-01\n==================\n\n  * Changed the generated class names to use a static counter instead of a random number\n  * Added a clss patch for ReflectionClass::newInstance to make its argument optional consistently (thanks @docteurklein)\n  * Fixed mirroring of classes with typehints on non-existent classes (thanks @docteurklein)\n  * Fixed the support of array callables in CallbackPromise and CallbackPrediction (thanks @ciaranmcnulty)\n  * Added support for properties in ObjectStateToken (thanks @adrienbrault)\n  * Added support for mocking classes with a final constructor (thanks @ciaranmcnulty)\n  * Added ArrayEveryEntryToken and Argument::withEveryEntry() (thanks @adrienbrault)\n  * Added an exception when trying to prophesize on a final method instead of ignoring silently (thanks @docteurklein)\n  * Added StringContainToken and Argument::containingString() (thanks @peterjmit)\n  * Added ``shouldNotHaveBeenCalled`` on the MethodProphecy (thanks @ciaranmcnulty)\n  * Fixed the comparison of objects in ExactValuetoken (thanks @sstok)\n  * Deprecated ``shouldNotBeenCalled`` in favor of ``shouldNotHaveBeenCalled``\n\n1.0.4 / 2013-08-10\n==================\n\n  * Better randomness for generated class names (thanks @sstok)\n  * Add support for interfaces into TypeToken and Argument::type() (thanks @sstok)\n  * Add support for old-style (method name === class name) constructors (thanks @l310 for report)\n\n1.0.3 / 2013-07-04\n==================\n\n  * Support callable typehints (thanks @stof)\n  * Do not attempt to autoload arrays when generating code (thanks @MarcoDeBortoli)\n  * New ArrayEntryToken (thanks @kagux)\n\n1.0.2 / 2013-05-19\n==================\n\n  * Logical `AND` token added (thanks @kagux)\n  * Logical `NOT` token added (thanks @kagux)\n  * Add support for setting custom constructor arguments\n  * Properly stringify hashes\n  * Record calls that throw exceptions\n  * Migrate spec suite to PhpSpec 2.0\n\n1.0.1 / 2013-04-30\n==================\n\n  * Fix broken UnexpectedCallException message\n  * Trim AggregateException message\n\n1.0.0 / 2013-04-29\n==================\n\n  * Improve exception messages\n\n1.0.0-BETA2 / 2013-04-03\n========================\n\n  * Add more debug information to CallTimes and Call prediction exception messages\n  * Fix MethodNotFoundException wrong namespace (thanks @gunnarlium)\n  * Fix some typos in the exception messages (thanks @pborreli)\n\n1.0.0-BETA1 / 2013-03-25\n========================\n\n  * Initial release\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "Contributing\n------------\n\nProphecy is an open source, community-driven project. If you'd like to contribute,\nfeel free to do this, but remember to follow these few simple rules:\n\n- Make your feature addition or bug fix,\n- Add either specs or examples for any changes you're making (bugfixes or additions)\n  (please look into `spec/` folder for some examples). This is important so we don't break\n  it in a future version unintentionally,\n- Commit your code, but do not mess with `CHANGES.md`,\n\nRunning tests\n-------------\n\nMake sure that you don't break anything with your changes by running:\n\n```bash\n$> composer install --prefer-dist\n$> vendor/bin/phpspec run\n$> vendor/bin/phpunit\n```\n"
  },
  {
    "path": "LICENSE",
    "content": "Copyright (c) 2013 Konstantin Kudryashov <ever.zet@gmail.com>\nCopyright (c) 2013 Marcello Duarte <marcello.duarte@gmail.com>\n\nPermission is hereby granted, free of charge, to any person\nobtaining a copy of this software and associated documentation\nfiles (the \"Software\"), to deal in the Software without\nrestriction, including without limitation the rights to use,\ncopy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the\nSoftware is furnished to do so, subject to the following\nconditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES\nOF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\nNONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT\nHOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\nWHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\nFROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR\nOTHER DEALINGS IN THE SOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "# Prophecy\n\n[![Stable release](https://poser.pugx.org/phpspec/prophecy/version.svg)](https://packagist.org/packages/phpspec/prophecy)\n[![Build](https://github.com/phpspec/prophecy/actions/workflows/build.yml/badge.svg)](https://github.com/phpspec/prophecy/actions/workflows/build.yml)\n\nProphecy is a highly opinionated yet very powerful and flexible PHP object mocking\nframework. Though initially it was created to fulfil phpspec2 needs, it is flexible\nenough to be used inside any testing framework out there with minimal effort.\n\n## A simple example\n\n```php\n<?php\n\nclass UserTest extends PHPUnit\\Framework\\TestCase\n{\n    private $prophet;\n\n    public function testPasswordHashing()\n    {\n        $hasher = $this->prophet->prophesize('App\\Security\\Hasher');\n        $user   = new App\\Entity\\User($hasher->reveal());\n\n        $hasher->generateHash($user, 'qwerty')->willReturn('hashed_pass');\n\n        $user->setPassword('qwerty');\n\n        $this->assertEquals('hashed_pass', $user->getPassword());\n    }\n\n    protected function setUp()\n    {\n        $this->prophet = new \\Prophecy\\Prophet;\n    }\n\n    protected function tearDown()\n    {\n        $this->prophet->checkPredictions();\n    }\n}\n```\n\n## Installation\n\n### Prerequisites\n\nProphecy requires PHP 7.2.0 or greater.\n\n### Setup through composer\n\nFirst, add Prophecy to the list of dependencies inside your `composer.json`:\n\n```json\n{\n    \"require-dev\": {\n        \"phpspec/prophecy\": \"~1.0\"\n    }\n}\n```\n\nThen simply install it with composer:\n\n```bash\n$> composer install --prefer-dist\n```\n\nYou can read more about Composer on its [official webpage](http://getcomposer.org).\n\n## How to use it\n\nFirst of all, in Prophecy every word has a logical meaning, even the name of the library\nitself (Prophecy). When you start feeling that, you'll become very fluid with this\ntool.\n\nFor example, Prophecy has been named that way because it concentrates on describing the future\nbehavior of objects with very limited knowledge about them. But as with any other prophecy,\nthose object prophecies can't create themselves - there should be a Prophet:\n\n```php\n$prophet = new Prophecy\\Prophet;\n```\n\nThe Prophet creates prophecies by *prophesizing* them:\n\n```php\n$prophecy = $prophet->prophesize();\n```\n\nThe result of the `prophesize()` method call is a new object of class `ObjectProphecy`. Yes,\nthat's your specific object prophecy, which describes how your object would behave\nin the near future. But first, you need to specify which object you're talking about,\nright?\n\n```php\n$prophecy->willExtend('stdClass');\n$prophecy->willImplement('SessionHandlerInterface');\n```\n\nThere are 2 interesting calls - `willExtend` and `willImplement`. The first one tells\nobject prophecy that our object should extend a specific class. The second one says that\nit should implement some interface. Obviously, objects in PHP can implement multiple\ninterfaces, but extend only one parent class.\n\n### Dummies\n\nOk, now we have our object prophecy. What can we do with it? First of all, we can get\nour object *dummy* by revealing its prophecy:\n\n```php\n$dummy = $prophecy->reveal();\n```\n\nThe `$dummy` variable now holds a special dummy object. Dummy objects are objects that extend\nand/or implement preset classes/interfaces by overriding all their public methods. The key\npoint about dummies is that they do not hold any logic - they just do nothing. Any method\nof the dummy will always return `null` and the dummy will never throw any exceptions.\nDummy is your friend if you don't care about the actual behavior of this double and just need\na token object to satisfy a method typehint.\n\nYou need to understand one thing - a dummy is not a prophecy. Your object prophecy is still\nassigned to `$prophecy` variable and in order to manipulate with your expectations, you\nshould work with it. `$dummy` is a dummy - a simple php object that tries to fulfil your\nprophecy.\n\n### Stubs\n\nOk, now we know how to create basic prophecies and reveal dummies from them. That's\nawesome if we don't care about our _doubles_ (objects that reflect originals)\ninteractions. If we do, we need to use *stubs* or *mocks*.\n\nA stub is an object double, which doesn't have any expectations about the object behavior,\nbut when put in specific environment, behaves in specific way. Ok, I know, it's cryptic,\nbut bear with me for a minute. Simply put, a stub is a dummy, which depending on the called\nmethod signature does different things (has logic). To create stubs in Prophecy:\n\n```php\n$prophecy->read('123')->willReturn('value');\n```\n\nOh wow. We've just made an arbitrary call on the object prophecy? Yes, we did. And this\ncall returned us a new object instance of class `MethodProphecy`. Yep, that's a specific\nmethod with arguments prophecy. Method prophecies give you the ability to create method\npromises or predictions. We'll talk about method predictions later in the _Mocks_ section.\n\n#### Promises\n\nPromises are logical blocks, that represent your fictional methods in prophecy terms\nand they are handled by the `MethodProphecy::will(PromiseInterface $promise)` method.\nAs a matter of fact, the call that we made earlier (`willReturn('value')`) is a simple\nshortcut to:\n\n```php\n$prophecy->read('123')->will(new Prophecy\\Promise\\ReturnPromise(array('value')));\n```\n\nThis promise will cause any call to our double's `read()` method with exactly one\nargument - `'123'` to always return `'value'`. But that's only for this\npromise, there's plenty others you can use:\n\n- `ReturnPromise` or `->willReturn(1)` - returns a value from a method call\n- `ReturnArgumentPromise` or `->willReturnArgument($index)` - returns the nth method argument from call\n- `ThrowPromise` or `->willThrow($exception)` - causes the method to throw specific exception\n- `CallbackPromise` or `->will($callback)` - gives you a quick way to define your own custom logic\n\nKeep in mind, that you can always add even more promises by implementing\n`Prophecy\\Promise\\PromiseInterface`.\n\n#### Method prophecies idempotency\n\nProphecy enforces same method prophecies and, as a consequence, same promises and\npredictions for the same method calls with the same arguments. This means:\n\n```php\n$methodProphecy1 = $prophecy->read('123');\n$methodProphecy2 = $prophecy->read('123');\n$methodProphecy3 = $prophecy->read('321');\n\n$methodProphecy1 === $methodProphecy2;\n$methodProphecy1 !== $methodProphecy3;\n```\n\nThat's interesting, right? Now you might ask me how would you define more complex\nbehaviors where some method call changes behavior of others. In PHPUnit or Mockery\nyou do that by predicting how many times your method will be called. In Prophecy,\nyou'll use promises for that:\n\n```php\n$user->getName()->willReturn(null);\n\n// For PHP 5.4\n$user->setName('everzet')->will(function () {\n    $this->getName()->willReturn('everzet');\n});\n\n// For PHP 5.3\n$user->setName('everzet')->will(function ($args, $user) {\n    $user->getName()->willReturn('everzet');\n});\n\n// Or\n$user->setName('everzet')->will(function ($args) use ($user) {\n    $user->getName()->willReturn('everzet');\n});\n```\n\nAnd now it doesn't matter how many times or in which order your methods are called.\nWhat matters is their behaviors and how well you faked it.\n\nNote: If the method is called several times, you can use the following syntax to return different\nvalues for each call:\n\n```php\n$prophecy->read('123')->willReturn(1, 2, 3);\n```\n\nThis feature is actually not recommended for most cases. Relying on the order of\ncalls for the same arguments tends to make test fragile, as adding one more call\ncan break everything.\n\n#### Arguments wildcarding\n\nThe previous example is awesome (at least I hope it is for you), but that's not\noptimal enough. We hardcoded `'everzet'` in our expectation. Isn't there a better\nway? In fact there is, but it involves understanding what this `'everzet'`\nactually is.\n\nYou see, even if method arguments used during method prophecy creation look\nlike simple method arguments, in reality they are not. They are argument token\nwildcards.  As a matter of fact, `->setName('everzet')` looks like a simple call just\nbecause Prophecy automatically transforms it under the hood into:\n\n```php\n$user->setName(new Prophecy\\Argument\\Token\\ExactValueToken('everzet'));\n```\n\nThose argument tokens are simple PHP classes, that implement\n`Prophecy\\Argument\\Token\\TokenInterface` and tell Prophecy how to compare real arguments\nwith your expectations. And yes, those classnames are damn big. That's why there's a\nshortcut class `Prophecy\\Argument`, which you can use to create tokens like that:\n\n```php\nuse Prophecy\\Argument;\n\n$user->setName(Argument::exact('everzet'));\n```\n\n`ExactValueToken` is not very useful in our case as it forced us to hardcode the username.\nThat's why Prophecy comes bundled with a bunch of other tokens:\n\n- `IdenticalValueToken` or `Argument::is($value)` - checks that the argument is identical to a specific value\n- `ExactValueToken` or `Argument::exact($value)` - checks that the argument matches a specific value\n- `TypeToken` or `Argument::type($typeOrClass)` - checks that the argument matches a specific type or\n  classname\n- `ObjectStateToken` or `Argument::which($method, $value)` - checks that the argument method returns\n  a specific value\n- `CallbackToken` or `Argument::that(callback)` - checks that the argument matches a custom callback\n- `AnyValueToken` or `Argument::any()` - matches any argument\n- `AnyValuesToken` or `Argument::cetera()` - matches any arguments to the rest of the signature\n- `StringContainsToken` or `Argument::containingString($value)` - checks that the argument contains a specific string value\n- `InArrayToken` or `Argument::in($array)` - checks if value is in array\n- `NotInArrayToken` or `Argument::notIn($array)` - checks if value is not in array\n\nAnd you can add even more by implementing `TokenInterface` with your own custom classes.\n\nSo, let's refactor our initial `{set,get}Name()` logic with argument tokens:\n\n```php\nuse Prophecy\\Argument;\n\n$user->getName()->willReturn(null);\n\n// For PHP 5.4\n$user->setName(Argument::type('string'))->will(function ($args) {\n    $this->getName()->willReturn($args[0]);\n});\n\n// For PHP 5.3\n$user->setName(Argument::type('string'))->will(function ($args, $user) {\n    $user->getName()->willReturn($args[0]);\n});\n\n// Or\n$user->setName(Argument::type('string'))->will(function ($args) use ($user) {\n    $user->getName()->willReturn($args[0]);\n});\n```\n\nThat's it. Now our `{set,get}Name()` prophecy will work with any string argument provided to it.\nWe've just described how our stub object should behave, even though the original object could have\nno behavior whatsoever.\n\nOne last bit about arguments now. You might ask, what happens in case of:\n\n```php\nuse Prophecy\\Argument;\n\n$user->getName()->willReturn(null);\n\n// For PHP 5.4\n$user->setName(Argument::type('string'))->will(function ($args) {\n    $this->getName()->willReturn($args[0]);\n});\n\n// For PHP 5.3\n$user->setName(Argument::type('string'))->will(function ($args, $user) {\n    $user->getName()->willReturn($args[0]);\n});\n\n// Or\n$user->setName(Argument::type('string'))->will(function ($args) use ($user) {\n    $user->getName()->willReturn($args[0]);\n});\n\n$user->setName(Argument::any())->will(function () {\n});\n```\n\nNothing. Your stub will continue behaving the way it did before. That's because of how\narguments wildcarding works. Every argument token type has a different score level, which\nwildcard then uses to calculate the final arguments match score and use the method prophecy\npromise that has the highest score. In this case, `Argument::type()` in case of success\nscores `5` and `Argument::any()` scores `3`. So the type token wins, as does the first\n`setName()` method prophecy and its promise. The simple rule of thumb - more precise token\nalways wins.\n\n#### Getting stub objects\n\nOk, now we know how to define our prophecy method promises, let's get our stub from\nit:\n\n```php\n$stub = $prophecy->reveal();\n```\n\nAs you might see, the only difference between how we get dummies and stubs is that with\nstubs we describe every object conversation instead of just agreeing with `null` returns\n(object being *dummy*). As a matter of fact, after you define your first promise\n(method call), Prophecy will force you to define all the communications - it throws\nthe `UnexpectedCallException` for any call you didn't describe with object prophecy before\ncalling it on a stub.\n\n### Mocks\n\nNow we know how to define doubles without behavior (dummies) and doubles with behavior, but\nno expectations (stubs). What's left is doubles for which we have some expectations. These\nare called mocks and in Prophecy they look almost exactly the same as stubs, except that\nthey define *predictions* instead of *promises* on method prophecies:\n\n```php\n$entityManager->flush()->shouldBeCalled();\n```\n\n#### Predictions\n\nThe `shouldBeCalled()` method here assigns `CallPrediction` to our method prophecy.\nPredictions are a delayed behavior check for your prophecies. You see, during the entire lifetime\nof your doubles, Prophecy records every single call you're making against it inside your\ncode. After that, Prophecy can use this collected information to check if it matches defined\npredictions. You can assign predictions to method prophecies using the\n`MethodProphecy::should(PredictionInterface $prediction)` method. As a matter of fact,\nthe `shouldBeCalled()` method we used earlier is just a shortcut to:\n\n```php\n$entityManager->flush()->should(new Prophecy\\Prediction\\CallPrediction());\n```\n\nIt checks if your method of interest (that matches both the method name and the arguments wildcard)\nwas called 1 or more times. If the prediction failed then it throws an exception. When does this\ncheck happen? Whenever you call `checkPredictions()` on the main Prophet object:\n\n```php\n$prophet->checkPredictions();\n```\n\nIn PHPUnit, you would want to put this call into the `tearDown()` method. If no predictions\nare defined, it would do nothing. So it won't harm to call it after every test.\n\nThere are plenty more predictions you can play with:\n\n- `CallPrediction` or `shouldBeCalled()` - checks that the method has been called 1 or more times\n- `NoCallsPrediction` or `shouldNotBeCalled()` - checks that the method has not been called\n- `CallTimesPrediction` or `shouldBeCalledTimes($count)` - checks that the method has been called\n  `$count` times\n- `CallbackPrediction` or `should($callback)` - checks the method against your own custom callback\n\nOf course, you can always create your own custom prediction any time by implementing\n`PredictionInterface`.\n\n### Spies\n\nThe last bit of awesomeness in Prophecy is out-of-the-box spies support. As I said in the previous\nsection, Prophecy records every call made during the double's entire lifetime. This means\nyou don't need to record predictions in order to check them. You can also do it\nmanually by using the `MethodProphecy::shouldHave(PredictionInterface $prediction)` method:\n\n```php\n$em = $prophet->prophesize('Doctrine\\ORM\\EntityManager');\n\n$controller->createUser($em->reveal());\n\n$em->flush()->shouldHaveBeenCalled();\n```\n\nSuch manipulation with doubles is called spying. And with Prophecy it just works.\n\n\n## FAQ\n\n### Can I call the original methods on a prophesized class?\n\nProphecy does not support calling the original methods on a phrophesized class. If you find yourself needing to mock some methods of a class while calling the original version of other methods, it's likely a sign that your class violates the [single-responsibility principle](https://en.wikipedia.org/wiki/Single-responsibility_principle) and should be refactored.\n"
  },
  {
    "path": "composer.json",
    "content": "{\n    \"name\":         \"phpspec/prophecy\",\n    \"description\":  \"Highly opinionated mocking framework for PHP 5.3+\",\n    \"keywords\":     [\"Mock\", \"Stub\", \"Dummy\", \"Double\", \"Fake\", \"Spy\", \"dev\"],\n    \"homepage\":     \"https://github.com/phpspec/prophecy\",\n    \"type\":         \"library\",\n    \"license\":      \"MIT\",\n    \"authors\":      [\n        {\n            \"name\":      \"Konstantin Kudryashov\",\n            \"email\":     \"ever.zet@gmail.com\",\n            \"homepage\":  \"http://everzet.com\"\n        },\n        {\n            \"name\":      \"Marcello Duarte\",\n            \"email\":     \"marcello.duarte@gmail.com\"\n        }\n    ],\n\n    \"require\": {\n        \"php\":                               \"8.2.* || 8.3.* || 8.4.* || 8.5.*\",\n        \"phpdocumentor/reflection-docblock\": \"^5.2 || ^6.0\",\n        \"sebastian/comparator\":              \"^3.0 || ^4.0 || ^5.0 || ^6.0 || ^7.0 || ^8.0\",\n        \"doctrine/instantiator\":             \"^1.2 || ^2.0\",\n        \"sebastian/recursion-context\":       \"^3.0 || ^4.0 || ^5.0 || ^6.0 || ^7.0 || ^8.0\",\n        \"symfony/deprecation-contracts\":     \"^2.5 || ^3.1\"\n    },\n\n    \"require-dev\": {\n        \"php-cs-fixer/shim\": \"^3.93.1\",\n        \"phpspec/phpspec\": \"^6.0 || ^7.0 || ^8.0\",\n        \"phpstan/phpstan\": \"^2.1.13, <2.1.34 || ^2.1.39\",\n        \"phpunit/phpunit\": \"^11.0 || ^12.0 || ^13.0\"\n    },\n\n    \"autoload\": {\n        \"psr-4\": {\n            \"Prophecy\\\\\": \"src/Prophecy\"\n        }\n    },\n\n    \"autoload-dev\": {\n        \"psr-4\": {\n            \"Fixtures\\\\Prophecy\\\\\": \"fixtures\",\n            \"Tests\\\\Prophecy\\\\\": \"tests\"\n        }\n    },\n\n    \"scripts\": {\n        \"cs:check\": \"@php php-cs-fixer check --verbose --diff\",\n        \"cs:fix\": \"@php php-cs-fixer fix\",\n        \"phpstan\": \"phpstan analyse\",\n        \"phpstan:baseline\": \"phpstan analyse --generate-baseline\"\n    },\n\n    \"scripts-descriptions\": {\n        \"cs:check\": \"Check coding standards\",\n        \"cs:fix\": \"Fix coding standards\",\n        \"phpstan\": \"Run PHPStan analysis\",\n        \"phpstan:baseline\": \"Dump PHPStan baseline file - use only for updating, do not add new errors when possible\"\n    },\n\n    \"extra\": {\n        \"branch-alias\": {\n            \"dev-master\": \"1.x-dev\"\n        }\n    }\n}\n"
  },
  {
    "path": "fixtures/AbstractBaseClassWithMethodWithReturnType.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Fixtures\\Prophecy;\n\nabstract class AbstractBaseClassWithMethodWithReturnType\n{\n    public function returnSelf(?\\DateTimeInterface $test): self\n    {\n    }\n}\n"
  },
  {
    "path": "fixtures/ClassExtendAbstractWithMethodWithReturnType.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Fixtures\\Prophecy;\n\nclass ClassExtendAbstractWithMethodWithReturnType extends AbstractBaseClassWithMethodWithReturnType\n{\n}\n"
  },
  {
    "path": "fixtures/DnfArgumentType.php",
    "content": "<?php\n\nnamespace Fixtures\\Prophecy;\n\nclass DnfArgumentType\n{\n    public function doSomething ((A&B)|C $foo)\n    {\n\n    }\n}\n"
  },
  {
    "path": "fixtures/DnfReturnType.php",
    "content": "<?php\n\nnamespace Fixtures\\Prophecy;\n\nclass DnfReturnType\n{\n    public function doSomething () : (A&B)|C\n    {\n\n    }\n}\n"
  },
  {
    "path": "fixtures/EmptyClass.php",
    "content": "<?php\n\nnamespace Fixtures\\Prophecy;\n\nclass EmptyClass\n{\n}\n"
  },
  {
    "path": "fixtures/EmptyInterface.php",
    "content": "<?php\n\nnamespace Fixtures\\Prophecy;\n\ninterface EmptyInterface\n{\n}\n"
  },
  {
    "path": "fixtures/Enum.php",
    "content": "<?php\n\nnamespace Fixtures\\Prophecy;\n\nenum Enum {\n    case Clubs;\n    case Diamonds;\n    case Hearts;\n    case Spades;\n}\n"
  },
  {
    "path": "fixtures/FinalClass.php",
    "content": "<?php\n\nnamespace Fixtures\\Prophecy;\n\nfinal class FinalClass\n{\n}\n"
  },
  {
    "path": "fixtures/IntersectionArgumentType.php",
    "content": "<?php\n\nnamespace Fixtures\\Prophecy;\n\nclass IntersectionArgumentType\n{\n    public function doSomething (Bar&Baz $foo)\n    {\n\n    }\n}\n"
  },
  {
    "path": "fixtures/IntersectionReturnType.php",
    "content": "<?php\n\nnamespace Fixtures\\Prophecy;\n\nclass IntersectionReturnType\n{\n    public function doSomething () : Bar&Baz\n    {\n\n    }\n}\n"
  },
  {
    "path": "fixtures/MethodWithAdditionalParam.php",
    "content": "<?php\n\nnamespace Fixtures\\Prophecy;\n\nabstract class MethodWithAdditionalParam extends WithArguments implements Named\n{\n    abstract public function getName($name = null);\n\n    public function methodWithoutTypeHints($arg, $arg2 = null)\n    {\n    }\n}\n"
  },
  {
    "path": "fixtures/MixedTypes.php",
    "content": "<?php\n\nnamespace Fixtures\\Prophecy;\n\nclass MixedTypes\n{\n    public function doSomething(mixed $arg1): mixed\n    {\n\n    }\n}\n"
  },
  {
    "path": "fixtures/ModifierInterface.php",
    "content": "<?php\n\nnamespace Fixtures\\Prophecy;\n\ninterface ModifierInterface\n{\n    public function isAbstract();\n\n    public function getVisibility();\n}\n"
  },
  {
    "path": "fixtures/Named.php",
    "content": "<?php\n\nnamespace Fixtures\\Prophecy;\n\ninterface Named\n{\n    public function getName();\n}\n"
  },
  {
    "path": "fixtures/NeverType.php",
    "content": "<?php\n\nnamespace Fixtures\\Prophecy;\n\nclass NeverType\n{\n    public function doSomething(): never\n    {\n        throw new \\RuntimeException();\n    }\n}\n"
  },
  {
    "path": "fixtures/NullableArrayParameter.php",
    "content": "<?php\n\nnamespace Fixtures\\Prophecy;\n\nclass NullableArrayParameter\n{\n    public function iHaveNullableArrayParameterWithNotNullDefaultValue(?array $arr = array())\n    {\n    }\n}\n"
  },
  {
    "path": "fixtures/NullableParameterTypeFalse.php",
    "content": "<?php\n\nnamespace Fixtures\\Prophecy;\n\nclass NullableParameterTypeFalse\n{\n    public function method(?false $arg)\n    {\n        return $arg;\n    }\n}\n"
  },
  {
    "path": "fixtures/NullableParameterTypeTrue.php",
    "content": "<?php\n\nnamespace Fixtures\\Prophecy;\n\nclass NullableParameterTypeTrue\n{\n    public function method(?true $arg)\n    {\n        return $arg;\n    }\n}\n"
  },
  {
    "path": "fixtures/NullableReturnTypeFalse.php",
    "content": "<?php\n\nnamespace Fixtures\\Prophecy;\n\nclass NullableReturnTypeFalse\n{\n    public function method(): ?false\n    {\n        return false;\n    }\n}\n"
  },
  {
    "path": "fixtures/NullableReturnTypeTrue.php",
    "content": "<?php\n\nnamespace Fixtures\\Prophecy;\n\nclass NullableReturnTypeTrue\n{\n    public function method(): ?true\n    {\n        return true;\n    }\n}\n"
  },
  {
    "path": "fixtures/OptionalDepsClass.php",
    "content": "<?php\n\nnamespace Fixtures\\Prophecy;\n\nuse I\\Simply;\n\nclass OptionalDepsClass\n{\n    public function iHaveAStrangeTypeHintedArg(\\I\\Simply\\Am\\Nonexistent $class)\n    {\n    }\n\n    public function iHaveAnEvenStrangerTypeHintedArg(Simply\\Am\\Not $class)\n    {\n    }\n}\n"
  },
  {
    "path": "fixtures/ReadOnlyClass.php",
    "content": "<?php\n\nnamespace Fixtures\\Prophecy;\n\nreadonly class ReadOnlyClass\n{\n}\n"
  },
  {
    "path": "fixtures/ReturningFinalClass.php",
    "content": "<?php\n\nnamespace Fixtures\\Prophecy;\n\ninterface ReturningFinalClass\n{\n    public function doSomething(): FinalClass;\n}\n"
  },
  {
    "path": "fixtures/SelfReferencing.php",
    "content": "<?php\n\nnamespace Fixtures\\Prophecy;\n\ninterface SelfReferencing\n{\n    public function __invoke(self $self): self;\n}\n"
  },
  {
    "path": "fixtures/SpecialMethods.php",
    "content": "<?php\n\nnamespace Fixtures\\Prophecy;\n\nclass SpecialMethods\n{\n    public function __construct()\n    {\n    }\n\n    function __destruct()\n    {\n    }\n\n    function __call($name, $arguments)\n    {\n    }\n\n    function __sleep()\n    {\n    }\n\n    function __wakeup()\n    {\n    }\n\n    function __toString()\n    {\n        return '';\n    }\n\n    function __invoke()\n    {\n    }\n\n}\n"
  },
  {
    "path": "fixtures/StandaloneParameterTypeFalse.php",
    "content": "<?php\n\nnamespace Fixtures\\Prophecy;\n\nclass StandaloneParameterTypeFalse\n{\n    public function method(false $arg)\n    {\n        return $arg;\n    }\n}\n"
  },
  {
    "path": "fixtures/StandaloneParameterTypeNull.php",
    "content": "<?php\n\nnamespace Fixtures\\Prophecy;\n\nclass StandaloneParameterTypeNull\n{\n    public function method(null $arg)\n    {\n        return $arg;\n    }\n}\n"
  },
  {
    "path": "fixtures/StandaloneParameterTypeTrue.php",
    "content": "<?php\n\nnamespace Fixtures\\Prophecy;\n\nclass StandaloneParameterTypeTrue\n{\n    public function method(true $arg)\n    {\n        return $arg;\n    }\n}\n"
  },
  {
    "path": "fixtures/StandaloneReturnTypeFalse.php",
    "content": "<?php\n\nnamespace Fixtures\\Prophecy;\n\nclass StandaloneReturnTypeFalse\n{\n    public function method(): false\n    {\n        return false;\n    }\n}\n"
  },
  {
    "path": "fixtures/StandaloneReturnTypeNull.php",
    "content": "<?php\n\nnamespace Fixtures\\Prophecy;\n\nclass StandaloneReturnTypeNull\n{\n    public function method(): null\n    {\n        return null;\n    }\n}\n"
  },
  {
    "path": "fixtures/StandaloneReturnTypeTrue.php",
    "content": "<?php\n\nnamespace Fixtures\\Prophecy;\n\nclass StandaloneReturnTypeTrue\n{\n    public function method(): true\n    {\n        return true;\n    }\n}\n"
  },
  {
    "path": "fixtures/TentativeReturnTypeNull.php",
    "content": "<?php\n\nnamespace Fixtures\\Prophecy;\n\nclass TentativeReturnTypeNull\n{\n    #[\\ReturnTypeWillChange()]\n    public function method(): ?string\n    {\n        return null;\n    }\n}\n"
  },
  {
    "path": "fixtures/ThrowableInterface.php",
    "content": "<?php\n\nnamespace Fixtures\\Prophecy;\n\ninterface ThrowableInterface extends \\Throwable\n{\n}\n"
  },
  {
    "path": "fixtures/UnionArgumentTypeFalse.php",
    "content": "<?php\n\nnamespace Fixtures\\Prophecy;\n\nclass UnionArgumentTypeFalse\n{\n    public function method(false|\\stdClass $arg)\n    {\n\n    }\n}\n"
  },
  {
    "path": "fixtures/UnionArgumentTypes.php",
    "content": "<?php\n\nnamespace Fixtures\\Prophecy;\n\nclass UnionArgumentTypes\n{\n    public function doSomething(bool|\\stdClass $arg)\n    {\n\n    }\n}\n"
  },
  {
    "path": "fixtures/UnionReturnTypeFalse.php",
    "content": "<?php\n\nnamespace Fixtures\\Prophecy;\n\nclass UnionReturnTypeFalse\n{\n    public function method(): false|\\stdClass\n    {\n\n    }\n}\n"
  },
  {
    "path": "fixtures/UnionReturnTypes.php",
    "content": "<?php\n\nnamespace Fixtures\\Prophecy;\n\nclass UnionReturnTypes\n{\n    public function doSomething(): bool|\\stdClass\n    {\n\n    }\n}\n"
  },
  {
    "path": "fixtures/WithArguments.php",
    "content": "<?php\n\nnamespace Fixtures\\Prophecy;\n\nclass WithArguments\n{\n    public function methodWithArgs(\\ArrayAccess $arg_1, array $arg_2 = [], ?\\ArrayAccess $arg_3 = null)\n    {\n    }\n    \n    public function methodWithoutTypeHints($arg)\n    {\n    }\n}\n"
  },
  {
    "path": "fixtures/WithCallableArgument.php",
    "content": "<?php\n\nnamespace Fixtures\\Prophecy;\n\nclass WithCallableArgument\n{\n    public function methodWithArgs(callable $arg_1, ?callable $arg_2 = null)\n    {\n    }\n}\n"
  },
  {
    "path": "fixtures/WithFinalMethod.php",
    "content": "<?php\n\nnamespace Fixtures\\Prophecy;\n\nclass WithFinalMethod\n{\n    final public function finalImplementation()\n    {\n    }\n}\n"
  },
  {
    "path": "fixtures/WithFinalVirtuallyPrivateMethod.php",
    "content": "<?php\n\nnamespace Fixtures\\Prophecy;\n\nclass WithFinalVirtuallyPrivateMethod\n{\n    final public function __toString()\n    {\n        return '';\n    }\n\n    final public function _getName()\n    {\n    }\n}\n"
  },
  {
    "path": "fixtures/WithPhpdocClass.php",
    "content": "<?php\n\nnamespace Fixtures\\Prophecy;\n\n/**\n * @method string name(string $gender = null)\n * @method mixed randomElement(array $array = array('a', 'b', 'c'))\n * @method mixed __unserialize($data)\n */\nclass WithPhpdocClass\n{\n    public function __call($name, $arguments)\n    {\n        // TODO: Implement __call() method.\n    }\n}\n"
  },
  {
    "path": "fixtures/WithProtectedAbstractMethod.php",
    "content": "<?php\n\nnamespace Fixtures\\Prophecy;\n\nabstract class WithProtectedAbstractMethod\n{\n    abstract protected function innerDetail();\n}\n"
  },
  {
    "path": "fixtures/WithReferences.php",
    "content": "<?php\n\nnamespace Fixtures\\Prophecy;\n\nclass WithReferences\n{\n    public function methodWithReferenceArgument(&$arg_1, \\ArrayAccess &$arg_2)\n    {\n    }\n}\n"
  },
  {
    "path": "fixtures/WithReturnTypehints.php",
    "content": "<?php\n\nnamespace Fixtures\\Prophecy;\n\nclass WithReturnTypehints extends EmptyClass\n{\n    public function getSelf(): self {\n        return $this;\n    }\n\n    public function getName(): string {\n        return __CLASS__;\n    }\n    \n    public function getParent(): parent {\n        return $this;\n    }\n}\n"
  },
  {
    "path": "fixtures/WithStaticMethod.php",
    "content": "<?php\n\nnamespace Fixtures\\Prophecy;\n\nclass WithStaticMethod\n{\n    public static function innerDetail()\n    {\n    }\n}\n"
  },
  {
    "path": "fixtures/WithTypehintedVariadicArgument.php",
    "content": "<?php\n\nnamespace Fixtures\\Prophecy;\n\nclass WithTypehintedVariadicArgument\n{\n    function methodWithTypeHintedArgs(array ...$args)\n    {\n    }\n}\n"
  },
  {
    "path": "fixtures/WithVariadicArgument.php",
    "content": "<?php\n\nnamespace Fixtures\\Prophecy;\n\nclass WithVariadicArgument\n{\n    function methodWithArgs(...$args)\n    {\n    }\n}\n"
  },
  {
    "path": "fixtures/WithVirtuallyPrivateMethod.php",
    "content": "<?php\n\nnamespace Fixtures\\Prophecy;\n\nclass WithVirtuallyPrivateMethod\n{\n    public function __toString()\n    {\n        return '';\n    }\n\n    public function _getName()\n    {\n    }\n\n    public function isAbstract()\n    {\n    }\n}\n"
  },
  {
    "path": "phpstan-baseline.neon",
    "content": "parameters:\n\tignoreErrors:\n\t\t-\n\t\t\tmessage: '#^Parameter \\#1 \\$value of function strval expects bool\\|float\\|int\\|resource\\|string\\|null, mixed given\\.$#'\n\t\t\tidentifier: argument.type\n\t\t\tcount: 2\n\t\t\tpath: src/Prophecy/Argument/Token/ExactValueToken.php\n\n\t\t-\n\t\t\tmessage: '#^Method Prophecy\\\\Doubler\\\\CachedDoubler\\:\\:createDoubleClass\\(\\) should return class\\-string\\<Prophecy\\\\Doubler\\\\DoubleInterface&T of object\\> but returns class\\-string\\.$#'\n\t\t\tidentifier: return.type\n\t\t\tcount: 1\n\t\t\tpath: src/Prophecy/Doubler/CachedDoubler.php\n\n\t\t-\n\t\t\tmessage: '#^Parameter \\#1 \\$types of class Prophecy\\\\Doubler\\\\Generator\\\\Node\\\\Type\\\\UnionType constructor expects list\\<Prophecy\\\\Doubler\\\\Generator\\\\Node\\\\Type\\\\IntersectionType\\|Prophecy\\\\Doubler\\\\Generator\\\\Node\\\\Type\\\\SimpleType\\>, array\\{Prophecy\\\\Doubler\\\\Generator\\\\Node\\\\Type\\\\BuiltinType, Prophecy\\\\Doubler\\\\Generator\\\\Node\\\\Type\\\\TypeInterface\\} given\\.$#'\n\t\t\tidentifier: argument.type\n\t\t\tcount: 1\n\t\t\tpath: src/Prophecy/Doubler/ClassPatch/DisableConstructorPatch.php\n\n\t\t-\n\t\t\tmessage: '#^Method Prophecy\\\\Doubler\\\\Doubler\\:\\:createDoubleClass\\(\\) should return class\\-string\\<Prophecy\\\\Doubler\\\\DoubleInterface&T of object\\> but returns class\\-string\\.$#'\n\t\t\tidentifier: return.type\n\t\t\tcount: 1\n\t\t\tpath: src/Prophecy/Doubler/Doubler.php\n\n\t\t-\n\t\t\tmessage: '#^Call to function method_exists\\(\\) with ''ReflectionClass'' and ''isReadOnly'' will always evaluate to true\\.$#'\n\t\t\tidentifier: function.alreadyNarrowedType\n\t\t\tcount: 1\n\t\t\tpath: src/Prophecy/Doubler/Generator/ClassMirror.php\n\n\t\t-\n\t\t\tmessage: '#^Call to function method_exists\\(\\) with ReflectionMethod and ''hasTentativeReturnT…'' will always evaluate to true\\.$#'\n\t\t\tidentifier: function.alreadyNarrowedType\n\t\t\tcount: 1\n\t\t\tpath: src/Prophecy/Doubler/Generator/ClassMirror.php\n\n\t\t-\n\t\t\tmessage: '#^PHPDoc tag @var with type static\\(Prophecy\\\\Doubler\\\\LazyDouble\\<U of object\\>\\) is not subtype of native type \\$this\\(Prophecy\\\\Doubler\\\\LazyDouble\\<T of object\\>\\)\\.$#'\n\t\t\tidentifier: varTag.nativeType\n\t\t\tcount: 1\n\t\t\tpath: src/Prophecy/Doubler/LazyDouble.php\n\n\t\t-\n\t\t\tmessage: '#^Property Prophecy\\\\Doubler\\\\LazyDouble\\:\\:\\$class \\(ReflectionClass\\<T of object\\>\\|null\\) does not accept ReflectionClass\\<U of object\\>\\.$#'\n\t\t\tidentifier: assign.propertyType\n\t\t\tcount: 1\n\t\t\tpath: src/Prophecy/Doubler/LazyDouble.php\n\n\t\t-\n\t\t\tmessage: '#^Call to function method_exists\\(\\) with ReflectionMethod and ''hasTentativeReturnT…'' will always evaluate to true\\.$#'\n\t\t\tidentifier: function.alreadyNarrowedType\n\t\t\tcount: 1\n\t\t\tpath: src/Prophecy/Prophecy/MethodProphecy.php\n\n\t\t-\n\t\t\tmessage: '#^Parameter \\#1 \\$callback of function array_map expects \\(callable\\(ReflectionIntersectionType\\|ReflectionNamedType\\)\\: mixed\\)\\|null, Closure\\(ReflectionNamedType\\)\\: string given\\.$#'\n\t\t\tidentifier: argument.type\n\t\t\tcount: 1\n\t\t\tpath: src/Prophecy/Prophecy/MethodProphecy.php\n\n\t\t-\n\t\t\tmessage: '#^Possibly invalid array key type mixed\\.$#'\n\t\t\tidentifier: offsetAccess.invalidOffset\n\t\t\tcount: 1\n\t\t\tpath: src/Prophecy/Util/ExportUtil.php\n\n\t\t-\n\t\t\tmessage: '#^Call to an undefined method phpDocumentor\\\\Reflection\\\\DocBlock\\\\Tags\\\\Method\\:\\:getArguments\\(\\)\\.$#'\n\t\t\tidentifier: method.notFound\n\t\t\tcount: 1\n\t\t\tpath: src/Prophecy/Doubler/ClassPatch/MagicCallPatch.php\n"
  },
  {
    "path": "phpstan.dist.neon",
    "content": "parameters:\n    level: 9\n    inferPrivatePropertyTypeFromConstructor: true\n    treatPhpDocTypesAsCertain: false\n    paths:\n        - ./src/\n    excludePaths:\n        - src/Prophecy/Comparator/Factory.php\nincludes:\n    - phpstan-baseline.neon\n"
  },
  {
    "path": "phpunit.xml.dist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<phpunit xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:noNamespaceSchemaLocation=\"https://schema.phpunit.de/12.1/phpunit.xsd\" backupGlobals=\"false\" colors=\"true\" bootstrap=\"vendor/autoload.php\" cacheDirectory=\".phpunit.cache\">\n  <php>\n    <ini name=\"error_reporting\" value=\"-1\"/>\n  </php>\n  <testsuites>\n    <testsuite name=\"PhpSpec Test Suite\">\n      <directory>tests</directory>\n    </testsuite>\n  </testsuites>\n  <source>\n    <include>\n      <directory>./src/</directory>\n    </include>\n  </source>\n</phpunit>\n"
  },
  {
    "path": "spec/Prophecy/Argument/ArgumentsWildcardSpec.php",
    "content": "<?php\n\nnamespace spec\\Prophecy\\Argument;\n\nuse PhpSpec\\ObjectBehavior;\nuse Prophecy\\Argument\\Token\\TokenInterface;\n\nclass ArgumentsWildcardSpec extends ObjectBehavior\n{\n    function it_wraps_non_token_arguments_into_ExactValueToken(\\stdClass $object)\n    {\n        $this->beConstructedWith(array(42, 'zet', $object));\n\n        $class = get_class($object->getWrappedObject());\n        $id  = spl_object_id($object->getWrappedObject());\n\n        $objHash = \"exact(42), exact(\\\"zet\\\"), exact($class#$id Object (\\n    'objectProphecyClosure' => Closure#%s Object (\\n        0 => Closure#%s Object\\n    )\\n))\";\n\n        $idRegexExpr = '[0-9]+';\n        $this->__toString()->shouldMatch(sprintf('/^%s$/', sprintf(preg_quote(\"$objHash\"), $idRegexExpr, $idRegexExpr)));\n    }\n\n    function it_generates_string_representation_from_all_tokens_imploded(\n        TokenInterface $token1,\n        TokenInterface $token2,\n        TokenInterface $token3\n    ) {\n        $token1->__toString()->willReturn('token_1');\n        $token2->__toString()->willReturn('token_2');\n        $token3->__toString()->willReturn('token_3');\n\n        $this->beConstructedWith(array($token1, $token2, $token3));\n        $this->__toString()->shouldReturn('token_1, token_2, token_3');\n    }\n\n    function it_exposes_list_of_tokens(TokenInterface $token)\n    {\n        $this->beConstructedWith(array($token));\n\n        $this->getTokens()->shouldReturn(array($token));\n    }\n\n    function it_returns_score_of_1_if_there_are_no_tokens_and_arguments()\n    {\n        $this->beConstructedWith(array());\n\n        $this->scoreArguments(array())->shouldReturn(1);\n    }\n\n    function it_should_return_match_score_based_on_all_tokens_score(\n        TokenInterface $token1,\n        TokenInterface $token2,\n        TokenInterface $token3\n    ) {\n        $token1->scoreArgument('one')->willReturn(3);\n        $token1->isLast()->willReturn(false);\n        $token2->scoreArgument(2)->willReturn(5);\n        $token2->isLast()->willReturn(false);\n        $token3->scoreArgument($obj = new \\stdClass())->willReturn(10);\n        $token3->isLast()->willReturn(false);\n\n        $this->beConstructedWith(array($token1, $token2, $token3));\n        $this->scoreArguments(array('one', 2, $obj))->shouldReturn(18);\n    }\n\n    function it_returns_false_if_there_is_less_arguments_than_tokens(\n        TokenInterface $token1,\n        TokenInterface $token2,\n        TokenInterface $token3\n    ) {\n        $token1->scoreArgument('one')->willReturn(3);\n        $token1->isLast()->willReturn(false);\n        $token2->scoreArgument(2)->willReturn(5);\n        $token2->isLast()->willReturn(false);\n        $token3->scoreArgument(null)->willReturn(false);\n        $token3->isLast()->willReturn(false);\n\n        $this->beConstructedWith(array($token1, $token2, $token3));\n        $this->scoreArguments(array('one', 2))->shouldReturn(false);\n    }\n\n    function it_returns_false_if_there_is_less_tokens_than_arguments(\n        TokenInterface $token1,\n        TokenInterface $token2,\n        TokenInterface $token3\n    ) {\n        $token1->scoreArgument('one')->willReturn(3);\n        $token1->isLast()->willReturn(false);\n        $token2->scoreArgument(2)->willReturn(5);\n        $token2->isLast()->willReturn(false);\n        $token3->scoreArgument($obj = new \\stdClass())->willReturn(10);\n        $token3->isLast()->willReturn(false);\n\n        $this->beConstructedWith(array($token1, $token2, $token3));\n        $this->scoreArguments(array('one', 2, $obj, 4))->shouldReturn(false);\n    }\n\n    function it_should_return_false_if_one_of_the_tokens_returns_false(\n        TokenInterface $token1,\n        TokenInterface $token2,\n        TokenInterface $token3\n    ) {\n        $token1->scoreArgument('one')->willReturn(3);\n        $token1->isLast()->willReturn(false);\n        $token2->scoreArgument(2)->willReturn(false);\n        $token2->isLast()->willReturn(false);\n        $token3->scoreArgument($obj = new \\stdClass())->willReturn(10);\n        $token3->isLast()->willReturn(false);\n\n        $this->beConstructedWith(array($token1, $token2, $token3));\n        $this->scoreArguments(array('one', 2, $obj))->shouldReturn(false);\n    }\n\n    function it_should_calculate_score_until_last_token(\n        TokenInterface $token1,\n        TokenInterface $token2,\n        TokenInterface $token3\n    ) {\n        $token1->scoreArgument('one')->willReturn(3);\n        $token1->isLast()->willReturn(false);\n\n        $token2->scoreArgument(2)->willReturn(7);\n        $token2->isLast()->willReturn(true);\n\n        $token3->scoreArgument($obj = new \\stdClass())->willReturn(10);\n        $token3->isLast()->willReturn(false);\n\n        $this->beConstructedWith(array($token1, $token2, $token3));\n        $this->scoreArguments(array('one', 2, $obj))->shouldReturn(10);\n    }\n}\n"
  },
  {
    "path": "spec/Prophecy/Argument/Token/AnyValueTokenSpec.php",
    "content": "<?php\n\nnamespace spec\\Prophecy\\Argument\\Token;\n\nuse PhpSpec\\ObjectBehavior;\n\nclass AnyValueTokenSpec extends ObjectBehavior\n{\n    function it_implements_TokenInterface()\n    {\n        $this->shouldBeAnInstanceOf('Prophecy\\Argument\\Token\\TokenInterface');\n    }\n\n    function it_is_not_last()\n    {\n        $this->shouldNotBeLast();\n    }\n\n    function its_string_representation_is_star()\n    {\n        $this->__toString()->shouldReturn('*');\n    }\n\n    function it_scores_any_argument_as_3()\n    {\n        $this->scoreArgument(42)->shouldReturn(3);\n    }\n}\n"
  },
  {
    "path": "spec/Prophecy/Argument/Token/AnyValuesTokenSpec.php",
    "content": "<?php\n\nnamespace spec\\Prophecy\\Argument\\Token;\n\nuse PhpSpec\\ObjectBehavior;\n\nclass AnyValuesTokenSpec extends ObjectBehavior\n{\n    function it_implements_TokenInterface()\n    {\n        $this->shouldBeAnInstanceOf('Prophecy\\Argument\\Token\\TokenInterface');\n    }\n\n    function it_is_last()\n    {\n        $this->shouldBeLast();\n    }\n\n    function its_string_representation_is_star_with_followup()\n    {\n        $this->__toString()->shouldReturn('* [, ...]');\n    }\n\n    function it_scores_any_argument_as_2()\n    {\n        $this->scoreArgument(42)->shouldReturn(2);\n    }\n}\n"
  },
  {
    "path": "spec/Prophecy/Argument/Token/ApproximateValueTokenSpec.php",
    "content": "<?php\n\nnamespace spec\\Prophecy\\Argument\\Token;\n\nuse PhpSpec\\ObjectBehavior;\n\nclass ApproximateValueTokenSpec extends ObjectBehavior\n{\n    function let()\n    {\n        $this->beConstructedWith(10.12345678, 4);\n    }\n\n    function it_is_initializable()\n    {\n        $this->shouldHaveType('Prophecy\\Argument\\Token\\ApproximateValueToken');\n    }\n\n    function it_implements_TokenInterface()\n    {\n        $this->shouldBeAnInstanceOf('Prophecy\\Argument\\Token\\TokenInterface');\n    }\n\n    function it_is_not_last()\n    {\n        $this->shouldNotBeLast();\n    }\n\n    function it_scores_10_if_rounded_argument_matches_rounded_value()\n    {\n        $this->scoreArgument(10.12345)->shouldReturn(10);\n    }\n\n    function it_does_not_score_if_rounded_argument_does_not_match_rounded_value()\n    {\n        $this->scoreArgument(10.1234)->shouldReturn(false);\n    }\n\n    function it_uses_a_default_precision_of_zero()\n    {\n        $this->beConstructedWith(10.7);\n        $this->scoreArgument(11.4)->shouldReturn(10);\n    }\n\n    function it_does_not_score_if_rounded_argument_is_not_numeric()\n    {\n        $this->scoreArgument('hello')->shouldReturn(false);\n        $this->scoreArgument(new \\stdClass())->shouldReturn(false);\n        $this->scoreArgument(false)->shouldReturn(false);\n    }\n\n    function it_has_simple_string_representation()\n    {\n        $this->__toString()->shouldBe('≅10.1235');\n    }\n}\n"
  },
  {
    "path": "spec/Prophecy/Argument/Token/ArrayCountTokenSpec.php",
    "content": "<?php\n\nnamespace spec\\Prophecy\\Argument\\Token;\n\nuse PhpSpec\\ObjectBehavior;\n\nclass ArrayCountTokenSpec extends ObjectBehavior\n{\n    function let()\n    {\n        $this->beConstructedWith(2);\n    }\n\n    function it_implements_TokenInterface()\n    {\n        $this->shouldBeAnInstanceOf('Prophecy\\Argument\\Token\\TokenInterface');\n    }\n\n    function it_is_not_last()\n    {\n        $this->shouldNotBeLast();\n    }\n\n    function it_scores_6_if_argument_array_has_proper_count()\n    {\n        $this->scoreArgument(array(1,2))->shouldReturn(6);\n    }\n\n    function it_scores_6_if_argument_countable_object_has_proper_count(\\Countable $countable)\n    {\n        $countable->count()->willReturn(2);\n        $this->scoreArgument($countable)->shouldReturn(6);\n    }\n\n    function it_does_not_score_if_argument_is_neither_array_nor_countable_object()\n    {\n        $this->scoreArgument('string')->shouldBe(false);\n        $this->scoreArgument(5)->shouldBe(false);\n        $this->scoreArgument(new \\stdClass())->shouldBe(false);\n    }\n\n    function it_does_not_score_if_argument_array_has_wrong_count()\n    {\n        $this->scoreArgument(array(1))->shouldReturn(false);\n    }\n\n    function it_does_not_score_if_argument_countable_object_has_wrong_count(\\Countable $countable)\n    {\n        $countable->count()->willReturn(3);\n        $this->scoreArgument($countable)->shouldReturn(false);\n    }\n\n    function it_has_simple_string_representation()\n    {\n        $this->__toString()->shouldBe('count(2)');\n    }\n\n}\n"
  },
  {
    "path": "spec/Prophecy/Argument/Token/ArrayEntryTokenSpec.php",
    "content": "<?php\n\nnamespace spec\\Prophecy\\Argument\\Token;\n\nuse PhpSpec\\ObjectBehavior;\nuse Prophecy\\Argument\\Token\\ExactValueToken;\nuse Prophecy\\Argument\\Token\\TokenInterface;\nuse Prophecy\\Exception\\InvalidArgumentException;\n\nclass ArrayEntryTokenSpec extends ObjectBehavior\n{\n    function let(TokenInterface $key, TokenInterface $value)\n    {\n        $this->beConstructedWith($key, $value);\n    }\n\n    function it_implements_TokenInterface()\n    {\n        $this->shouldBeAnInstanceOf('Prophecy\\Argument\\Token\\TokenInterface');\n    }\n\n    function it_is_not_last()\n    {\n        $this->shouldNotBeLast();\n    }\n\n    function it_holds_key_and_value($key, $value)\n    {\n        $this->getKey()->shouldBe($key);\n        $this->getValue()->shouldBe($value);\n    }\n\n    function its_string_representation_tells_that_its_an_array_containing_the_key_value_pair($key, $value)\n    {\n        $key->__toString()->willReturn('key');\n        $value->__toString()->willReturn('value');\n        $this->__toString()->shouldBe('[..., key => value, ...]');\n    }\n\n    function it_wraps_non_token_value_into_ExactValueToken(TokenInterface $key, \\stdClass $object)\n    {\n        $this->beConstructedWith($key, $object);\n        $this->getValue()->shouldHaveType('\\Prophecy\\Argument\\Token\\ExactValueToken');\n    }\n\n    function it_wraps_non_token_key_into_ExactValueToken(\\stdClass $object, TokenInterface $value)\n    {\n        $this->beConstructedWith($object, $value);\n        $this->getKey()->shouldHaveType('\\Prophecy\\Argument\\Token\\ExactValueToken');\n    }\n\n    function it_scores_array_half_of_combined_scores_from_key_and_value_tokens($key, $value)\n    {\n        $key->scoreArgument('key')->willReturn(4);\n        $value->scoreArgument('value')->willReturn(6);\n        $this->scoreArgument(array('key' => 'value'))->shouldBe(5);\n    }\n\n    function it_scores_traversable_object_half_of_combined_scores_from_key_and_value_tokens(\n        TokenInterface $key,\n        TokenInterface $value,\n        \\Iterator $object\n    ) {\n        $object->current()->will(function () use ($object) {\n            $object->valid()->willReturn(false);\n\n            return 'value';\n        });\n        $object->key()->willReturn('key');\n        (\\PHP_VERSION_ID < 80100) ? $object->rewind()->willReturn(null) : $object->rewind()->shouldBeCalled();\n        (\\PHP_VERSION_ID < 80100) ? $object->next()->willReturn(null) : $object->next()->shouldBeCalled();\n        $object->valid()->willReturn(true);\n        $key->scoreArgument('key')->willReturn(6);\n        $value->scoreArgument('value')->willReturn(2);\n        $this->scoreArgument($object)->shouldBe(4);\n    }\n\n    function it_throws_exception_during_scoring_of_array_accessible_object_if_key_is_not_ExactValueToken(\n        TokenInterface $key,\n        TokenInterface $value,\n        \\ArrayAccess $object\n    ) {\n        $key->__toString()->willReturn('any_token');\n        $this->beConstructedWith($key, $value);\n        $errorMessage = 'You can only use exact value tokens to match key of ArrayAccess object'.PHP_EOL\n                        .'But you used `any_token`.';\n        $this->shouldThrow(new InvalidArgumentException($errorMessage))->duringScoreArgument($object);\n    }\n\n    function it_scores_array_accessible_object_half_of_combined_scores_from_key_and_value_tokens(\n        ExactValueToken $key,\n        TokenInterface $value,\n        \\ArrayAccess $object\n    ) {\n        $object->offsetExists('key')->willReturn(true);\n        $object->offsetGet('key')->willReturn('value');\n        $key->getValue()->willReturn('key');\n        $key->scoreArgument('key')->willReturn(3);\n        $value->scoreArgument('value')->willReturn(1);\n        $this->scoreArgument($object)->shouldBe(2);\n    }\n\n    function it_accepts_any_key_token_type_to_score_object_that_is_both_traversable_and_array_accessible(\n        TokenInterface $key,\n        TokenInterface $value,\n        \\ArrayIterator $object\n    ) {\n        $this->beConstructedWith($key, $value);\n        $object->current()->will(function () use ($object) {\n            $object->valid()->willReturn(false);\n\n            return 'value';\n        });\n        $object->key()->willReturn('key');\n        (\\PHP_VERSION_ID < 80100) ? $object->rewind()->willReturn(null) : $object->rewind()->shouldBeCalled();\n        (\\PHP_VERSION_ID < 80100) ? $object->next()->willReturn(null) : $object->next()->shouldBeCalled();\n        $object->valid()->willReturn(true);\n        $this->shouldNotThrow(new InvalidArgumentException())->duringScoreArgument($object);\n    }\n\n    function it_does_not_score_if_argument_is_neither_array_nor_traversable_nor_array_accessible()\n    {\n        $this->scoreArgument('string')->shouldBe(false);\n        $this->scoreArgument(new \\stdClass())->shouldBe(false);\n    }\n\n    function it_does_not_score_empty_array()\n    {\n        $this->scoreArgument(array())->shouldBe(false);\n    }\n\n    function it_does_not_score_array_if_key_and_value_tokens_do_not_score_same_entry($key, $value)\n    {\n        $argument = array(1 => 'foo', 2 => 'bar');\n        $key->scoreArgument(1)->willReturn(true);\n        $key->scoreArgument(2)->willReturn(false);\n        $value->scoreArgument('foo')->willReturn(false);\n        $value->scoreArgument('bar')->willReturn(true);\n        $this->scoreArgument($argument)->shouldBe(false);\n    }\n\n    function it_does_not_score_traversable_object_without_entries(\\Iterator $object)\n    {\n        (\\PHP_VERSION_ID < 80100) ? $object->rewind()->willReturn(null) : $object->rewind()->shouldBeCalled();\n        (\\PHP_VERSION_ID < 80100) && $object->next()->willReturn(null);\n        $object->valid()->willReturn(false);\n        $this->scoreArgument($object)->shouldBe(false);\n    }\n\n    function it_does_not_score_traversable_object_if_key_and_value_tokens_do_not_score_same_entry(\n        TokenInterface $key,\n        TokenInterface $value,\n        \\Iterator $object\n    ) {\n        $object->current()->willReturn('foo');\n        $object->current()->will(static function () use ($object) {\n            $object->valid()->willReturn(false);\n\n            return 'bar';\n        });\n        $object->key()->willReturn(1);\n        $object->key()->willReturn(2);\n        (\\PHP_VERSION_ID < 80100) ? $object->rewind()->willReturn(null) : $object->rewind()->shouldBeCalled();\n        (\\PHP_VERSION_ID < 80100) ? $object->next()->willReturn(null) : $object->next()->shouldBeCalled();\n        $object->valid()->willReturn(true);\n        $key->scoreArgument(1)->willReturn(true);\n        $key->scoreArgument(2)->willReturn(false);\n        $value->scoreArgument('foo')->willReturn(false);\n        $value->scoreArgument('bar')->willReturn(true);\n        $this->scoreArgument($object)->shouldBe(false);\n    }\n\n    function it_does_not_score_array_accessible_object_if_it_has_no_offset_with_key_token_value(\n        ExactValueToken $key,\n        \\ArrayAccess $object\n    ) {\n        $object->offsetExists('key')->willReturn(false);\n        $key->getValue()->willReturn('key');\n        $this->scoreArgument($object)->shouldBe(false);\n    }\n\n    function it_does_not_score_array_accessible_object_if_key_and_value_tokens_do_not_score_same_entry(\n        ExactValueToken $key,\n        TokenInterface $value,\n        \\ArrayAccess $object\n    ) {\n        $object->offsetExists('key')->willReturn(true);\n        $object->offsetGet('key')->willReturn('value');\n        $key->getValue()->willReturn('key');\n        $value->scoreArgument('value')->willReturn(false);\n        $key->scoreArgument('key')->willReturn(true);\n        $this->scoreArgument($object)->shouldBe(false);\n    }\n\n    function its_score_is_capped_at_8($key, $value)\n    {\n        $key->scoreArgument('key')->willReturn(10);\n        $value->scoreArgument('value')->willReturn(10);\n        $this->scoreArgument(array('key' => 'value'))->shouldBe(8);\n    }\n}\n"
  },
  {
    "path": "spec/Prophecy/Argument/Token/ArrayEveryEntryTokenSpec.php",
    "content": "<?php\n\nnamespace spec\\Prophecy\\Argument\\Token;\n\nuse PhpSpec\\ObjectBehavior;\nuse Prophecy\\Argument\\Token\\TokenInterface;\n\nclass ArrayEveryEntryTokenSpec extends ObjectBehavior\n{\n    function let(TokenInterface $value)\n    {\n        $this->beConstructedWith($value);\n    }\n\n    function it_implements_TokenInterface()\n    {\n        $this->shouldBeAnInstanceOf('Prophecy\\Argument\\Token\\TokenInterface');\n    }\n\n    function it_is_not_last()\n    {\n        $this->shouldNotBeLast();\n    }\n\n    function it_holds_value($value)\n    {\n        $this->getValue()->shouldBe($value);\n    }\n\n    function its_string_representation_tells_that_its_an_array_containing_only_value($value)\n    {\n        $value->__toString()->willReturn('value');\n        $this->__toString()->shouldBe('[value, ..., value]');\n    }\n\n    function it_wraps_non_token_value_into_ExactValueToken(\\stdClass $stdClass)\n    {\n        $this->beConstructedWith($stdClass);\n        $this->getValue()->shouldHaveType('Prophecy\\Argument\\Token\\ExactValueToken');\n    }\n\n    function it_does_not_score_if_argument_is_neither_array_nor_traversable()\n    {\n        $this->scoreArgument('string')->shouldBe(false);\n        $this->scoreArgument(new \\stdClass())->shouldBe(false);\n    }\n\n    function it_does_not_score_empty_array()\n    {\n        $this->scoreArgument(array())->shouldBe(false);\n    }\n\n    function it_does_not_score_traversable_object_without_entries(\\Iterator $object)\n    {\n        (\\PHP_VERSION_ID < 80100) ? $object->rewind()->willReturn(null) : $object->rewind()->shouldBeCalled();\n        (\\PHP_VERSION_ID < 80100) && $object->next()->willReturn(null);\n        $object->valid()->willReturn(false);\n        $this->scoreArgument($object)->shouldBe(false);\n    }\n\n    function it_scores_avg_of_scores_from_value_tokens($value)\n    {\n        $value->scoreArgument('value1')->willReturn(6);\n        $value->scoreArgument('value2')->willReturn(3);\n        $this->scoreArgument(array('value1', 'value2'))->shouldBe(4.5);\n    }\n\n    function it_scores_false_if_entry_scores_false($value)\n    {\n        $value->scoreArgument('value1')->willReturn(6);\n        $value->scoreArgument('value2')->willReturn(false);\n        $this->scoreArgument(array('value1', 'value2'))->shouldBe(false);\n    }\n\n    function it_does_not_score_array_keys($value)\n    {\n        $value->scoreArgument('value')->willReturn(6);\n        $value->scoreArgument('key')->shouldNotBeCalled(0);\n        $this->scoreArgument(array('key' => 'value'))->shouldBe(6);\n    }\n\n    function it_scores_traversable_object_from_value_token(TokenInterface $value, \\Iterator $object)\n    {\n        $object->current()->will(function ($args, $object) {\n            $object->valid()->willReturn(false);\n\n            return 'value';\n        });\n        $object->key()->willReturn('key');\n        (\\PHP_VERSION_ID < 80100) ? $object->rewind()->willReturn(null) : $object->rewind()->shouldBeCalled();\n        (\\PHP_VERSION_ID < 80100) ? $object->next()->willReturn(null) : $object->next()->shouldBeCalled();\n        $object->valid()->willReturn(true);\n        $value->scoreArgument('value')->willReturn(2);\n        $this->scoreArgument($object)->shouldBe(2);\n    }\n}\n"
  },
  {
    "path": "spec/Prophecy/Argument/Token/CallbackTokenSpec.php",
    "content": "<?php\n\nnamespace spec\\Prophecy\\Argument\\Token;\n\nuse PhpSpec\\ObjectBehavior;\n\nclass CallbackTokenSpec extends ObjectBehavior\n{\n    function let()\n    {\n        $this->beConstructedWith('get_class');\n    }\n\n    function it_implements_TokenInterface()\n    {\n        $this->shouldBeAnInstanceOf('Prophecy\\Argument\\Token\\TokenInterface');\n    }\n\n    function it_is_not_last()\n    {\n        $this->shouldNotBeLast();\n    }\n\n    function it_scores_7_if_argument_matches_callback()\n    {\n        $this->beConstructedWith(function ($argument) { return 2 === $argument; });\n\n        $this->scoreArgument(2)->shouldReturn(7);\n    }\n\n    function it_does_not_scores_if_argument_does_not_match_callback()\n    {\n        $this->beConstructedWith(function ($argument) { return 2 === $argument; });\n\n        $this->scoreArgument(5)->shouldReturn(false);\n    }\n\n    function its_string_representation_should_tell_that_its_callback()\n    {\n        $this->__toString()->shouldReturn('callback()');\n    }\n\n    function its_string_representation_can_be_customized()\n    {\n        $this->beConstructedWith('get_class', 'MyCustomTestCase');\n\n        $this->__toString()->shouldReturn('MyCustomTestCase');\n    }\n}\n"
  },
  {
    "path": "spec/Prophecy/Argument/Token/ExactValueTokenSpec.php",
    "content": "<?php\n\nnamespace spec\\Prophecy\\Argument\\Token;\n\nuse PhpSpec\\ObjectBehavior;\n\nclass ExactValueTokenSpec extends ObjectBehavior\n{\n    function let()\n    {\n        $this->beConstructedWith(42);\n    }\n\n    function it_implements_TokenInterface()\n    {\n        $this->shouldBeAnInstanceOf('Prophecy\\Argument\\Token\\TokenInterface');\n    }\n\n    function it_is_not_last()\n    {\n        $this->shouldNotBeLast();\n    }\n\n    function it_holds_value()\n    {\n        $this->getValue()->shouldReturn(42);\n    }\n\n    function it_scores_10_if_value_is_equal_to_argument()\n    {\n        $this->scoreArgument(42)->shouldReturn(10);\n        $this->scoreArgument('42')->shouldReturn(10);\n    }\n\n    function it_scores_10_if_value_is_an_object_and_equal_to_argument()\n    {\n        $value = new \\DateTime();\n        $value2 = clone $value;\n\n        $this->beConstructedWith($value);\n        $this->scoreArgument($value2)->shouldReturn(10);\n    }\n\n    function it_scores_10_if_value_is_a_double_object_and_equal_to_argument(\\stdClass $value)\n    {\n        $value2 = clone $value->getWrappedObject();\n\n        $this->beConstructedWith($value);\n        $this->scoreArgument($value2)->shouldReturn(10);\n    }\n\n    function it_does_not_scores_if_value_is_not_equal_to_argument()\n    {\n        $this->scoreArgument(50)->shouldReturn(false);\n        $this->scoreArgument(new \\stdClass())->shouldReturn(false);\n    }\n\n    function it_does_not_scores_if_value_an_object_and_is_not_equal_to_argument()\n    {\n        $value = new ExactValueTokenFixtureB('ABC');\n        $value2 = new ExactValueTokenFixtureB('CBA');\n\n        $this->beConstructedWith($value);\n        $this->scoreArgument($value2)->shouldReturn(false);\n    }\n\n    function it_does_not_scores_if_value_type_and_is_not_equal_to_argument()\n    {\n        $this->beConstructedWith(false);\n        $this->scoreArgument(0)->shouldReturn(false);\n    }\n\n    function it_generates_proper_string_representation_for_integer()\n    {\n        $this->beConstructedWith(42);\n        $this->__toString()->shouldReturn('exact(42)');\n    }\n\n    function it_generates_proper_string_representation_for_string()\n    {\n        $this->beConstructedWith('some string');\n        $this->__toString()->shouldReturn('exact(\"some string\")');\n    }\n\n    function it_generates_single_line_representation_for_multiline_string()\n    {\n        $this->beConstructedWith(\"some\\nstring\");\n        $this->__toString()->shouldReturn('exact(\"some\\\\nstring\")');\n    }\n\n    function it_generates_proper_string_representation_for_double()\n    {\n        $this->beConstructedWith(42.3);\n        $this->__toString()->shouldReturn('exact(42.3)');\n    }\n\n    function it_generates_proper_string_representation_for_boolean_true()\n    {\n        $this->beConstructedWith(true);\n        $this->__toString()->shouldReturn('exact(true)');\n    }\n\n    function it_generates_proper_string_representation_for_boolean_false()\n    {\n        $this->beConstructedWith(false);\n        $this->__toString()->shouldReturn('exact(false)');\n    }\n\n    function it_generates_proper_string_representation_for_null()\n    {\n        $this->beConstructedWith(null);\n        $this->__toString()->shouldReturn('exact(null)');\n    }\n\n    function it_generates_proper_string_representation_for_empty_array()\n    {\n        $this->beConstructedWith(array());\n        $this->__toString()->shouldReturn('exact([])');\n    }\n\n    function it_generates_proper_string_representation_for_array()\n    {\n        $this->beConstructedWith(array('zet', 42));\n        $this->__toString()->shouldReturn('exact([\"zet\", 42])');\n    }\n\n    function it_generates_proper_string_representation_for_resource()\n    {\n        $resource = fopen(__FILE__, 'r');\n        $this->beConstructedWith($resource);\n        $this->__toString()->shouldReturn('exact(stream:'.$resource.')');\n    }\n\n    function it_generates_proper_string_representation_for_object(\\stdClass $object)\n    {\n        $objHash = sprintf('exact(%s#%s',\n            get_class($object->getWrappedObject()),\n            spl_object_id($object->getWrappedObject())\n        ).\" Object (\\n    'objectProphecyClosure' => Closure#%s Object (\\n        0 => Closure#%s Object\\n    )\\n))\";\n\n        $this->beConstructedWith($object);\n\n        $idRegexExpr = '[0-9]+';\n        $this->__toString()->shouldMatch(sprintf('/^%s$/', sprintf(preg_quote(\"$objHash\"), $idRegexExpr, $idRegexExpr)));\n    }\n\n    function it_scores_10_if_value_an_numeric_and_equal_to_argument_as_stringable()\n    {\n        $value = 10;\n        $argument = new ExactValueTokenC(\"10\");\n\n        $this->beConstructedWith($value);\n        $this->scoreArgument($argument)->shouldReturn(10);\n    }\n\n    function it_does_not_scores_if_value_an_numeric_and_equal_to_argument_as_stringable()\n    {\n        $value = 10;\n        $argument = new ExactValueTokenC(\"example\");\n\n        $this->beConstructedWith($value);\n        $this->scoreArgument($argument)->shouldReturn(false);\n    }\n\n    function it_does_not_scores_if_value_an_object_and_not_equal_to_argument_object()\n    {\n        $value = new ExactValueTokenFixtureA();\n        $argument = new ExactValueTokenC(\"example\");\n\n        $this->beConstructedWith($value);\n        $this->scoreArgument($argument)->shouldReturn(false);\n    }\n}\n\nclass ExactValueTokenFixtureA\n{\n    public $errors;\n}\n\nclass ExactValueTokenFixtureB extends ExactValueTokenFixtureA\n{\n    public $errors;\n    public $value = null;\n\n    public function __construct($value)\n    {\n        $this->value = $value;\n    }\n}\n\nclass ExactValueTokenC\n{\n    public $value;\n    public function __construct($value)\n    {\n        $this->value = $value;\n    }\n\n    public function __toString()\n    {\n        return $this->value;\n    }\n}\n"
  },
  {
    "path": "spec/Prophecy/Argument/Token/IdenticalValueTokenSpec.php",
    "content": "<?php\n\nnamespace spec\\Prophecy\\Argument\\Token;\n\nuse PhpSpec\\ObjectBehavior;\n\nclass IdenticalValueTokenSpec extends ObjectBehavior\n{\n    function let()\n    {\n        $this->beConstructedWith(42);\n    }\n\n    function it_is_initializable()\n    {\n        $this->shouldHaveType('Prophecy\\Argument\\Token\\IdenticalValueToken');\n    }\n\n    function it_scores_11_if_string_value_is_identical_to_argument()\n    {\n        $this->beConstructedWith('foo');\n        $this->scoreArgument('foo')->shouldReturn(11);\n    }\n\n    function it_scores_11_if_boolean_value_is_identical_to_argument()\n    {\n        $this->beConstructedWith(false);\n        $this->scoreArgument(false)->shouldReturn(11);\n    }\n\n    function it_scores_11_if_integer_value_is_identical_to_argument()\n    {\n        $this->beConstructedWith(31);\n        $this->scoreArgument(31)->shouldReturn(11);\n    }\n\n    function it_scores_11_if_float_value_is_identical_to_argument()\n    {\n        $this->beConstructedWith(31.12);\n        $this->scoreArgument(31.12)->shouldReturn(11);\n    }\n\n    function it_scores_11_if_array_value_is_identical_to_argument()\n    {\n        $this->beConstructedWith(array('foo' => 'bar'));\n        $this->scoreArgument(array('foo' => 'bar'))->shouldReturn(11);\n    }\n\n    function it_scores_11_if_object_value_is_identical_to_argument()\n    {\n        $object = new \\stdClass();\n\n        $this->beConstructedWith($object);\n        $this->scoreArgument($object)->shouldReturn(11);\n    }\n\n    function it_scores_false_if_value_is_not_identical_to_argument()\n    {\n        $this->beConstructedWith(new \\stdClass());\n        $this->scoreArgument('foo')->shouldReturn(false);\n    }\n\n    function it_scores_false_if_object_value_is_not_the_same_instance_than_argument()\n    {\n        $this->beConstructedWith(new \\stdClass());\n        $this->scoreArgument(new \\stdClass())->shouldReturn(false);\n    }\n\n    function it_scores_false_if_integer_value_is_not_identical_to_boolean_argument()\n    {\n        $this->beConstructedWith(1);\n        $this->scoreArgument(true)->shouldReturn(false);\n    }\n\n    function it_is_not_last()\n    {\n        $this->shouldNotBeLast();\n    }\n\n    function it_generates_proper_string_representation_for_integer()\n    {\n        $this->beConstructedWith(42);\n        $this->__toString()->shouldReturn('identical(42)');\n    }\n\n    function it_generates_proper_string_representation_for_string()\n    {\n        $this->beConstructedWith('some string');\n        $this->__toString()->shouldReturn('identical(\"some string\")');\n    }\n\n    function it_generates_single_line_representation_for_multiline_string()\n    {\n        $this->beConstructedWith(\"some\\nstring\");\n        $this->__toString()->shouldReturn('identical(\"some\\\\nstring\")');\n    }\n\n    function it_generates_proper_string_representation_for_double()\n    {\n        $this->beConstructedWith(42.3);\n        $this->__toString()->shouldReturn('identical(42.3)');\n    }\n\n    function it_generates_proper_string_representation_for_boolean_true()\n    {\n        $this->beConstructedWith(true);\n        $this->__toString()->shouldReturn('identical(true)');\n    }\n\n    function it_generates_proper_string_representation_for_boolean_false()\n    {\n        $this->beConstructedWith(false);\n        $this->__toString()->shouldReturn('identical(false)');\n    }\n\n    function it_generates_proper_string_representation_for_null()\n    {\n        $this->beConstructedWith(null);\n        $this->__toString()->shouldReturn('identical(null)');\n    }\n\n    function it_generates_proper_string_representation_for_empty_array()\n    {\n        $this->beConstructedWith(array());\n        $this->__toString()->shouldReturn('identical([])');\n    }\n\n    function it_generates_proper_string_representation_for_array()\n    {\n        $this->beConstructedWith(array('zet', 42));\n        $this->__toString()->shouldReturn('identical([\"zet\", 42])');\n    }\n\n    function it_generates_proper_string_representation_for_resource()\n    {\n        $resource = fopen(__FILE__, 'r');\n        $this->beConstructedWith($resource);\n        $this->__toString()->shouldReturn('identical(stream:'.$resource.')');\n    }\n\n    function it_generates_proper_string_representation_for_object($object)\n    {\n        $objHash = sprintf('identical(%s#%s',\n            get_class($object->getWrappedObject()),\n            spl_object_id($object->getWrappedObject())\n        ).\" Object (\\n    'objectProphecyClosure' => Closure#%s Object (\\n        0 => Closure#%s Object\\n    )\\n))\";\n\n        $this->beConstructedWith($object);\n\n        $idRegexExpr = '[0-9]+';\n        $this->__toString()->shouldMatch(sprintf('/^%s$/', sprintf(preg_quote(\"$objHash\"), $idRegexExpr, $idRegexExpr)));\n    }\n}\n"
  },
  {
    "path": "spec/Prophecy/Argument/Token/InArrayTokenSpec.php",
    "content": "<?php\n\nnamespace spec\\Prophecy\\Argument\\Token;\n\nuse PhpSpec\\ObjectBehavior;\n\nclass InArrayTokenSpec extends ObjectBehavior\n{\n    function it_implements_TokenInterface()\n    {\n        $this->beConstructedWith(array());\n        $this->shouldBeAnInstanceOf('Prophecy\\Argument\\Token\\TokenInterface');\n    }\n\n    function it_is_not_last()\n    {\n        $this->beConstructedWith(array());\n        $this->shouldNotBeLast();\n    }\n\n    function it_scores_8_if_argument_is_in_array()\n    {\n        $this->beConstructedWith(array(1, 2, 3));\n        $this->scoreArgument(2)->shouldReturn(8);\n    }\n\n    function it_scores_false_if_argument_is_not_in_array()\n    {\n        $this->beConstructedWith(array(1, 2, 3));\n        $this->scoreArgument(5)->shouldReturn(false);\n    }\n\n    function it_generates_array_in_string_format()\n    {\n        $this->beConstructedWith(array(1, 2, 3));\n        $this->__toString()->shouldBe('[1, 2, 3]');\n    }\n\n    function it_generates_an_empty_array_as_string_when_token_is_empty()\n    {\n        $this->beConstructedWith(array());\n        $this->__toString()->shouldBe('[]');\n    }\n}\n"
  },
  {
    "path": "spec/Prophecy/Argument/Token/LogicalAndTokenSpec.php",
    "content": "<?php\n\nnamespace spec\\Prophecy\\Argument\\Token;\n\nuse PhpSpec\\ObjectBehavior;\nuse Prophecy\\Argument\\Token\\TokenInterface;\n\nclass LogicalAndTokenSpec extends ObjectBehavior\n{\n    function it_implements_TokenInterface()\n    {\n        $this->beConstructedWith(array());\n        $this->shouldBeAnInstanceOf('Prophecy\\Argument\\Token\\TokenInterface');\n    }\n\n    function it_is_not_last()\n    {\n        $this->beConstructedWith(array());\n        $this->shouldNotBeLast();\n    }\n\n    function it_generates_string_representation_from_all_tokens_imploded(\n        TokenInterface $token1,\n        TokenInterface $token2,\n        TokenInterface $token3\n    ) {\n        $token1->__toString()->willReturn('token_1');\n        $token2->__toString()->willReturn('token_2');\n        $token3->__toString()->willReturn('token_3');\n\n        $this->beConstructedWith(array($token1, $token2, $token3));\n        $this->__toString()->shouldReturn('bool(token_1 AND token_2 AND token_3)');\n    }\n\n    function it_wraps_non_token_arguments_into_ExactValueToken()\n    {\n        $this->beConstructedWith(array(15, '1985'));\n        $this->__toString()->shouldReturn(\"bool(exact(15) AND exact(\\\"1985\\\"))\");\n    }\n\n    function it_scores_the_maximum_score_from_all_scores_returned_by_tokens(TokenInterface $token1, TokenInterface $token2)\n    {\n        $token1->scoreArgument(1)->willReturn(10);\n        $token2->scoreArgument(1)->willReturn(5);\n        $this->beConstructedWith(array($token1, $token2));\n        $this->scoreArgument(1)->shouldReturn(10);\n    }\n\n    function it_does_not_score_if_there_are_no_arguments_or_tokens()\n    {\n        $this->beConstructedWith(array());\n        $this->scoreArgument('any')->shouldReturn(false);\n    }\n\n    function it_does_not_score_if_either_of_tokens_does_not_score(TokenInterface $token1, TokenInterface $token2)\n    {\n        $token1->scoreArgument(1)->willReturn(10);\n        $token1->scoreArgument(2)->willReturn(false);\n\n        $token2->scoreArgument(1)->willReturn(false);\n        $token2->scoreArgument(2)->willReturn(10);\n\n        $this->beConstructedWith(array($token1, $token2));\n\n        $this->scoreArgument(1)->shouldReturn(false);\n        $this->scoreArgument(2)->shouldReturn(false);\n    }\n}\n"
  },
  {
    "path": "spec/Prophecy/Argument/Token/LogicalNotTokenSpec.php",
    "content": "<?php\n\nnamespace spec\\Prophecy\\Argument\\Token;\n\nuse PhpSpec\\ObjectBehavior;\nuse Prophecy\\Argument\\Token\\TokenInterface;\n\nclass LogicalNotTokenSpec extends ObjectBehavior\n{\n    function let(TokenInterface $token)\n    {\n        $this->beConstructedWith($token);\n    }\n\n    function it_implements_TokenInterface()\n    {\n        $this->shouldBeAnInstanceOf('Prophecy\\Argument\\Token\\TokenInterface');\n    }\n\n    function it_holds_originating_token($token)\n    {\n        $this->getOriginatingToken()->shouldReturn($token);\n    }\n\n    function it_has_simple_string_representation($token)\n    {\n        $token->__toString()->willReturn('value');\n        $this->__toString()->shouldBe('not(value)');\n    }\n\n    function it_wraps_non_token_argument_into_ExactValueToken()\n    {\n        $this->beConstructedWith(5);\n        $token = $this->getOriginatingToken();\n        $token->shouldhaveType('Prophecy\\Argument\\Token\\ExactValueToken');\n        $token->getValue()->shouldBe(5);\n    }\n\n    function it_scores_4_if_preset_token_does_not_match_the_argument($token)\n    {\n        $token->scoreArgument('argument')->willReturn(false);\n        $this->scoreArgument('argument')->shouldBe(4);\n    }\n\n    function it_does_not_score_if_preset_token_matches_argument($token)\n    {\n        $token->scoreArgument('argument')->willReturn(5);\n        $this->scoreArgument('argument')->shouldBe(false);\n    }\n\n    function it_is_last_if_preset_token_is_last($token)\n    {\n        $token->isLast()->willReturn(true);\n        $this->shouldBeLast();\n    }\n\n    function it_is_not_last_if_preset_token_is_not_last($token)\n    {\n        $token->isLast()->willReturn(false);\n        $this->shouldNotBeLast();\n    }\n}\n"
  },
  {
    "path": "spec/Prophecy/Argument/Token/NotInArrayTokenSpec.php",
    "content": "<?php\n\nnamespace spec\\Prophecy\\Argument\\Token;\n\nuse PhpSpec\\ObjectBehavior;\n\nclass NotInArrayTokenSpec extends ObjectBehavior\n{\n    function it_implements_TokenInterface()\n    {\n        $this->beConstructedWith(array());\n        $this->shouldBeAnInstanceOf('Prophecy\\Argument\\Token\\TokenInterface');\n    }\n\n    function it_is_not_last()\n    {\n        $this->beConstructedWith(array());\n        $this->shouldNotBeLast();\n    }\n\n    function it_scores_8_if_argument_is_not_in_array()\n    {\n        $this->beConstructedWith(array(1, 2, 3));\n        $this->scoreArgument(5)->shouldReturn(8);\n    }\n\n    function it_scores_false_if_argument_is_in_array()\n    {\n        $this->beConstructedWith(array(1, 2, 3));\n        $this->scoreArgument(2)->shouldReturn(false);\n    }\n\n    function it_generates_array_in_string_format()\n    {\n        $this->beConstructedWith(array(1, 2, 3));\n        $this->__toString()->shouldBe('[1, 2, 3]');\n    }\n\n    function it_generates_an_empty_array_as_string_when_token_is_empty()\n    {\n        $this->beConstructedWith(array());\n        $this->__toString()->shouldBe('[]');\n    }\n}\n"
  },
  {
    "path": "spec/Prophecy/Argument/Token/ObjectStateTokenSpec.php",
    "content": "<?php\n\nnamespace spec\\Prophecy\\Argument\\Token;\n\nuse PhpSpec\\ObjectBehavior;\n\nclass ObjectStateTokenSpec extends ObjectBehavior\n{\n    function let()\n    {\n        $this->beConstructedWith('getName', 'stdClass');\n    }\n\n    function it_implements_TokenInterface()\n    {\n        $this->shouldBeAnInstanceOf('Prophecy\\Argument\\Token\\TokenInterface');\n    }\n\n    function it_is_not_last()\n    {\n        $this->shouldNotBeLast();\n    }\n\n    function it_scores_8_if_argument_object_has_specific_method_state(\\ReflectionClass $reflection)\n    {\n        $reflection->getName()->willReturn('stdClass');\n\n        $this->scoreArgument($reflection)->shouldReturn(8);\n    }\n\n    function it_scores_8_if_argument_object_has_specific_property_state(\\stdClass $class)\n    {\n        $class->getName = 'stdClass';\n\n        $this->scoreArgument($class)->shouldReturn(8);\n    }\n\n    function it_does_not_score_if_argument_method_state_does_not_match()\n    {\n        $value = new ObjectStateTokenFixtureB('ABC');\n        $value2 = new ObjectStateTokenFixtureB('CBA');\n\n        $this->beConstructedWith('getSelf', $value);\n        $this->scoreArgument($value2)->shouldReturn(false);\n    }\n\n    function it_does_not_score_if_argument_property_state_does_not_match(\\stdClass $class)\n    {\n        $class->getName = 'SplFileInfo';\n\n        $this->scoreArgument($class)->shouldReturn(false);\n    }\n\n    function it_does_not_score_if_argument_object_does_not_have_method_or_property(ObjectStateTokenFixtureA $class)\n    {\n        $this->scoreArgument($class)->shouldReturn(false);\n    }\n\n    function it_does_not_score_if_argument_is_not_object()\n    {\n        $this->scoreArgument(42)->shouldReturn(false);\n    }\n\n    function it_has_simple_string_representation()\n    {\n        $this->__toString()->shouldReturn('state(getName(), \"stdClass\")');\n    }\n}\n\nclass ObjectStateTokenFixtureA\n{\n    public $errors;\n}\n\nclass ObjectStateTokenFixtureB extends ObjectStateTokenFixtureA\n{\n    public $errors;\n    public $value = null;\n\n    public function __construct($value)\n    {\n        $this->value = $value;\n    }\n\n    public function getSelf()\n    {\n        return $this;\n    }\n}\n"
  },
  {
    "path": "spec/Prophecy/Argument/Token/StringContainsTokenSpec.php",
    "content": "<?php\n\nnamespace spec\\Prophecy\\Argument\\Token;\n\nuse PhpSpec\\ObjectBehavior;\n\nclass StringContainsTokenSpec extends ObjectBehavior\n{\n    function let()\n    {\n        $this->beConstructedWith('a substring');\n    }\n\n    function it_is_initializable()\n    {\n        $this->shouldHaveType('Prophecy\\Argument\\Token\\StringContainsToken');\n    }\n\n    function it_implements_TokenInterface()\n    {\n        $this->shouldBeAnInstanceOf('Prophecy\\Argument\\Token\\TokenInterface');\n    }\n\n    function it_holds_value()\n    {\n        $this->getValue()->shouldReturn('a substring');\n    }\n\n    function it_is_not_last()\n    {\n        $this->shouldNotBeLast();\n    }\n\n    function it_scores_6_if_the_argument_contains_the_value()\n    {\n        $this->scoreArgument('Argument containing a substring')->shouldReturn(6);\n    }\n\n    function it_does_not_score_if_the_argument_does_not_contain_the_value()\n    {\n        $this->scoreArgument('Argument will not match')->shouldReturn(false);\n    }\n\n    function it_does_not_score_if_the_argument_is_not_a_string()\n    {\n        $this->scoreArgument(array('a substring', 'other value'))->shouldReturn(false);\n    }\n\n    function its_string_representation_shows_substring()\n    {\n        $this->__toString()->shouldReturn('contains(\"a substring\")');\n    }\n}\n"
  },
  {
    "path": "spec/Prophecy/Argument/Token/TypeTokenSpec.php",
    "content": "<?php\n\nnamespace spec\\Prophecy\\Argument\\Token;\n\nuse PhpSpec\\ObjectBehavior;\nuse Prophecy\\Argument\\Token\\TokenInterface;\n\nclass TypeTokenSpec extends ObjectBehavior\n{\n    function let()\n    {\n        $this->beConstructedWith('integer');\n    }\n\n    function it_implements_TokenInterface()\n    {\n        $this->shouldBeAnInstanceOf('Prophecy\\Argument\\Token\\TokenInterface');\n    }\n\n    function it_is_not_last()\n    {\n        $this->shouldNotBeLast();\n    }\n\n    function it_scores_5_if_argument_matches_simple_type()\n    {\n        $this->beConstructedWith('integer');\n\n        $this->scoreArgument(42)->shouldReturn(5);\n    }\n\n    function it_does_not_scores_if_argument_does_not_match_simple_type()\n    {\n        $this->beConstructedWith('integer');\n\n        $this->scoreArgument(42.0)->shouldReturn(false);\n    }\n\n    function it_scores_5_if_argument_is_an_instance_of_specified_class(\\ReflectionObject $object)\n    {\n        $this->beConstructedWith('ReflectionClass');\n\n        $this->scoreArgument($object)->shouldReturn(5);\n    }\n\n    function it_has_simple_string_representation()\n    {\n        $this->__toString()->shouldReturn('type(integer)');\n    }\n\n    function it_scores_5_if_argument_is_an_instance_of_specified_interface(TokenInterface $interface)\n    {\n        $this->beConstructedWith('Prophecy\\Argument\\Token\\TokenInterface');\n\n        $this->scoreArgument($interface)->shouldReturn(5);\n    }\n}\n"
  },
  {
    "path": "spec/Prophecy/ArgumentSpec.php",
    "content": "<?php\n\nnamespace spec\\Prophecy;\n\nuse PhpSpec\\ObjectBehavior;\n\nclass ArgumentSpec extends ObjectBehavior\n{\n    function it_has_a_shortcut_for_exact_argument_token()\n    {\n        $token = $this->exact(42);\n        $token->shouldBeAnInstanceOf('Prophecy\\Argument\\Token\\ExactValueToken');\n        $token->getValue()->shouldReturn(42);\n    }\n\n    function it_has_a_shortcut_for_any_argument_token()\n    {\n        $token = $this->any();\n        $token->shouldBeAnInstanceOf('Prophecy\\Argument\\Token\\AnyValueToken');\n    }\n\n    function it_has_a_shortcut_for_multiple_arguments_token()\n    {\n        $token = $this->cetera();\n        $token->shouldBeAnInstanceOf('Prophecy\\Argument\\Token\\AnyValuesToken');\n    }\n\n    function it_has_a_shortcut_for_type_token()\n    {\n        $token = $this->type('integer');\n        $token->shouldBeAnInstanceOf('Prophecy\\Argument\\Token\\TypeToken');\n    }\n\n    function it_has_a_shortcut_for_callback_token()\n    {\n        $token = $this->that('get_class');\n        $token->shouldBeAnInstanceOf('Prophecy\\Argument\\Token\\CallbackToken');\n    }\n\n    function it_supports_customizing_tostring_representation_for_callback_token()\n    {\n        $token = $this->that('get_class', 'MyCustomTestCase');\n        $token->shouldBeAnInstanceOf('Prophecy\\Argument\\Token\\CallbackToken');\n        $token->__toString()->shouldReturn('MyCustomTestCase');\n    }\n\n    function it_has_a_shortcut_for_object_state_token()\n    {\n        $token = $this->which('getName', 'everzet');\n        $token->shouldBeAnInstanceOf('Prophecy\\Argument\\Token\\ObjectStateToken');\n    }\n\n    function it_has_a_shortcut_for_logical_and_token()\n    {\n        $token = $this->allOf('integer', 5);\n        $token->shouldBeAnInstanceOf('Prophecy\\Argument\\Token\\LogicalAndToken');\n    }\n\n    function it_has_a_shortcut_for_array_count_token()\n    {\n        $token = $this->size(5);\n        $token->shouldBeAnInstanceOf('Prophecy\\Argument\\Token\\ArrayCountToken');\n    }\n\n    function it_has_a_shortcut_for_array_entry_token()\n    {\n        $token = $this->withEntry('key', 'value');\n        $token->shouldBeAnInstanceOf('Prophecy\\Argument\\Token\\ArrayEntryToken');\n    }\n\n    function it_has_a_shortcut_for_array_every_entry_token()\n    {\n        $token = $this->withEveryEntry('value');\n        $token->shouldBeAnInstanceOf('Prophecy\\Argument\\Token\\ArrayEveryEntryToken');\n    }\n\n    function it_has_a_shortcut_for_identical_value_token()\n    {\n        $token = $this->is('value');\n        $token->shouldBeAnInstanceOf('Prophecy\\Argument\\Token\\IdenticalValueToken');\n    }\n\n    function it_has_a_shortcut_for_array_entry_token_matching_any_key()\n    {\n        $token = $this->containing('value');\n        $token->shouldBeAnInstanceOf('Prophecy\\Argument\\Token\\ArrayEntryToken');\n        $token->getKey()->shouldHaveType('Prophecy\\Argument\\Token\\AnyValueToken');\n    }\n\n    function it_has_a_shortcut_for_array_entry_token_matching_any_value()\n    {\n        $token = $this->withKey('key');\n        $token->shouldBeAnInstanceOf('Prophecy\\Argument\\Token\\ArrayEntryToken');\n        $token->getValue()->shouldHaveType('Prophecy\\Argument\\Token\\AnyValueToken');\n    }\n\n    function it_has_a_shortcut_for_logical_not_token()\n    {\n        $token = $this->not('kagux');\n        $token->shouldBeAnInstanceOf('Prophecy\\Argument\\Token\\LogicalNotToken');\n    }\n\n    function it_has_a_shortcut_for_string_contains_token()\n    {\n        $token = $this->containingString('string');\n        $token->shouldBeAnInstanceOf('Prophecy\\Argument\\Token\\StringContainsToken');\n    }\n\n    function it_has_a_shortcut_for_approximate_token()\n    {\n        $token = $this->approximate(10);\n        $token->shouldBeAnInstanceOf('Prophecy\\Argument\\Token\\ApproximateValueToken');\n    }\n\n    function it_has_a_shortcut_for_in_token()\n    {\n        $token = $this->in(array(1, 2, 3));\n        $token->shouldBeAnInstanceOf('Prophecy\\Argument\\Token\\InArrayToken');\n    }\n\n    function it_has_a_shortcut_for_not_in_token()\n    {\n        $token = $this->notIn(array(1, 2, 3));\n        $token->shouldBeAnInstanceOf('Prophecy\\Argument\\Token\\NotInArrayToken');\n    }\n}\n"
  },
  {
    "path": "spec/Prophecy/Call/CallCenterSpec.php",
    "content": "<?php\n\nnamespace spec\\Prophecy\\Call;\n\nuse PhpSpec\\ObjectBehavior;\nuse Prophecy\\Promise\\PromiseInterface;\nuse Prophecy\\Prophecy\\MethodProphecy;\nuse Prophecy\\Prophecy\\ObjectProphecy;\nuse Prophecy\\Argument\\ArgumentsWildcard;\n\nclass CallCenterSpec extends ObjectBehavior\n{\n    function let(ObjectProphecy $objectProphecy) {}\n\n    function it_records_calls_made_through_makeCall_method(ObjectProphecy $objectProphecy, ArgumentsWildcard $wildcard)\n    {\n        $wildcard->scoreArguments(array(5, 2, 3))->willReturn(10);\n        $objectProphecy->getMethodProphecies()->willReturn(array());\n\n        $this->makeCall($objectProphecy, 'setValues', array(5, 2, 3));\n\n        $calls = $this->findCalls('setValues', $wildcard);\n        $calls->shouldHaveCount(1);\n\n        $calls[0]->shouldBeAnInstanceOf('Prophecy\\Call\\Call');\n        $calls[0]->getMethodName()->shouldReturn('setValues');\n        $calls[0]->getArguments()->shouldReturn(array(5, 2, 3));\n        $calls[0]->getReturnValue()->shouldReturn(null);\n    }\n\n    function it_returns_null_for_any_call_through_makeCall_if_no_method_prophecies_added(\n        $objectProphecy\n    ) {\n        $objectProphecy->getMethodProphecies()->willReturn(array());\n\n        $this->makeCall($objectProphecy, 'setValues', array(5, 2, 3))->shouldReturn(null);\n    }\n\n    function it_executes_promise_of_method_prophecy_that_matches_signature_passed_to_makeCall(\n        $objectProphecy,\n        MethodProphecy $method1,\n        MethodProphecy $method2,\n        MethodProphecy $method3,\n        ArgumentsWildcard $arguments1,\n        ArgumentsWildcard $arguments2,\n        ArgumentsWildcard $arguments3,\n        PromiseInterface $promise\n    ) {\n        $method1->hasReturnVoid()->willReturn(false);\n        $method1->getMethodName()->willReturn('getName');\n        $method1->getArgumentsWildcard()->willReturn($arguments1);\n        $arguments1->scoreArguments(array('world', 'everything'))->willReturn(false);\n\n        $method2->hasReturnVoid()->willReturn(false);\n        $method2->getMethodName()->willReturn('setTitle');\n        $method2->getArgumentsWildcard()->willReturn($arguments2);\n        $arguments2->scoreArguments(array('world', 'everything'))->willReturn(false);\n\n        $method3->hasReturnVoid()->willReturn(false);\n        $method3->getMethodName()->willReturn('getName');\n        $method3->getArgumentsWildcard()->willReturn($arguments3);\n        $method3->getPromise()->willReturn($promise);\n        $arguments3->scoreArguments(array('world', 'everything'))->willReturn(200);\n\n        $objectProphecy->getMethodProphecies()->willReturn(array(\n            'method1' => array($method1),\n            'method2' => array($method2, $method3),\n        ));\n        $objectProphecy->getMethodProphecies('getName')->willReturn(array($method1, $method3));\n        $objectProphecy->reveal()->willReturn(new \\stdClass());\n\n        $promise->execute(array('world', 'everything'), $objectProphecy->getWrappedObject(), $method3)->willReturn(42);\n\n        $this->makeCall($objectProphecy, 'getName', array('world', 'everything'))->shouldReturn(42);\n\n        $calls = $this->findCalls('getName', $arguments3);\n        $calls->shouldHaveCount(1);\n        $calls[0]->getReturnValue()->shouldReturn(42);\n    }\n\n    function it_executes_promise_of_method_prophecy_that_matches_with_highest_score_to_makeCall(\n        $objectProphecy,\n        MethodProphecy $method1,\n        MethodProphecy $method2,\n        MethodProphecy $method3,\n        ArgumentsWildcard $arguments1,\n        ArgumentsWildcard $arguments2,\n        ArgumentsWildcard $arguments3,\n        PromiseInterface $promise\n    ) {\n        $method1->hasReturnVoid()->willReturn(false);\n        $method1->getMethodName()->willReturn('getName');\n        $method1->getArgumentsWildcard()->willReturn($arguments1);\n        $arguments1->scoreArguments(array('world', 'everything'))->willReturn(50);\n\n        $method2->hasReturnVoid()->willReturn(false);\n        $method2->getMethodName()->willReturn('getName');\n        $method2->getArgumentsWildcard()->willReturn($arguments2);\n        $method2->getPromise()->willReturn($promise);\n        $arguments2->scoreArguments(array('world', 'everything'))->willReturn(300);\n\n        $method3->hasReturnVoid()->willReturn(false);\n        $method3->getMethodName()->willReturn('getName');\n        $method3->getArgumentsWildcard()->willReturn($arguments3);\n        $arguments3->scoreArguments(array('world', 'everything'))->willReturn(200);\n\n        $objectProphecy->getMethodProphecies()->willReturn(array(\n            'method1' => array($method1),\n            'method2' => array($method2, $method3),\n        ));\n        $objectProphecy->getMethodProphecies('getName')->willReturn(array(\n            $method1, $method2, $method3,\n        ));\n        $objectProphecy->reveal()->willReturn(new \\stdClass());\n\n        $promise->execute(array('world', 'everything'), $objectProphecy->getWrappedObject(), $method2)\n            ->willReturn('second');\n\n        $this->makeCall($objectProphecy, 'getName', array('world', 'everything'))\n            ->shouldReturn('second');\n    }\n\n    function it_returns_null_if_method_prophecy_that_matches_makeCall_arguments_has_no_promise(\n        $objectProphecy,\n        MethodProphecy $method,\n        ArgumentsWildcard $arguments\n    ) {\n        $method->hasReturnVoid()->willReturn(false);\n        $method->getMethodName()->willReturn('getName');\n        $method->getArgumentsWildcard()->willReturn($arguments);\n        $method->getPromise()->willReturn(null);\n        $arguments->scoreArguments(array('world', 'everything'))->willReturn(100);\n\n        $objectProphecy->getMethodProphecies()->willReturn(array($method));\n        $objectProphecy->getMethodProphecies('getName')->willReturn(array($method));\n\n        $this->makeCall($objectProphecy, 'getName', array('world', 'everything'))\n            ->shouldReturn(null);\n    }\n\n    function it_finds_recorded_calls_by_a_method_name_and_arguments_wildcard(\n        $objectProphecy,\n        ArgumentsWildcard $wildcard\n    ) {\n        $objectProphecy->getMethodProphecies()->willReturn(array());\n\n        $this->makeCall($objectProphecy, 'getName', array('world'));\n        $this->makeCall($objectProphecy, 'getName', array('everything'));\n        $this->makeCall($objectProphecy, 'setName', array(42));\n\n        $wildcard->scoreArguments(array('world'))->willReturn(false);\n        $wildcard->scoreArguments(array('everything'))->willReturn(10);\n\n        $calls = $this->findCalls('getName', $wildcard);\n\n        $calls->shouldHaveCount(1);\n        $calls[0]->getMethodName()->shouldReturn('getName');\n        $calls[0]->getArguments()->shouldReturn(array('everything'));\n    }\n\n    function it_records_the_error_when_stub_has_got_unexpected_method_calls(\n        $objectProphecy,\n        MethodProphecy $method,\n        ArgumentsWildcard $arguments\n    ) {\n        $method->getMethodName()->willReturn('getName');\n        $method->getArgumentsWildcard()->willReturn($arguments);\n\n        $arguments->getTokens()->willReturn(array());\n\n        $objectProphecy->getMethodProphecies()->willReturn(array('getName' => array($method)));\n        $objectProphecy->getMethodProphecies('getName')->willReturn(array($method));\n        $objectProphecy->getMethodProphecies('method1')->willReturn(array());\n        $objectProphecy->reveal()->willReturn(new \\stdClass());\n\n        $this->shouldNotThrow('Prophecy\\Exception\\Call\\UnexpectedCallException')\n             ->duringMakeCall($objectProphecy, 'method1', array());\n\n        $this->shouldThrow('Prophecy\\Exception\\Call\\UnexpectedCallException')->duringCheckUnexpectedCalls();\n    }\n}\n"
  },
  {
    "path": "spec/Prophecy/Call/CallSpec.php",
    "content": "<?php\n\nnamespace spec\\Prophecy\\Call;\n\nuse PhpSpec\\ObjectBehavior;\nuse Prophecy\\Argument\\ArgumentsWildcard;\n\nclass CallSpec extends ObjectBehavior\n{\n    function let(\\Exception $exception)\n    {\n        $this->beConstructedWith('setValues', array(5, 2), 42, $exception, 'some_file.php', 23);\n    }\n\n    function it_exposes_method_name_through_getter()\n    {\n        $this->getMethodName()->shouldReturn('setValues');\n    }\n\n    function it_exposes_arguments_through_getter()\n    {\n        $this->getArguments()->shouldReturn(array(5, 2));\n    }\n\n    function it_exposes_return_value_through_getter()\n    {\n        $this->getReturnValue()->shouldReturn(42);\n    }\n\n    function it_exposes_exception_through_getter($exception)\n    {\n        $this->getException()->shouldReturn($exception);\n    }\n\n    function it_exposes_file_and_line_through_getter()\n    {\n        $this->getFile()->shouldReturn('some_file.php');\n        $this->getLine()->shouldReturn(23);\n    }\n\n    function it_returns_shortpath_to_callPlace()\n    {\n        $this->getCallPlace()->shouldReturn('some_file.php:23');\n    }\n\n    function it_returns_unknown_as_callPlace_if_no_file_or_line_provided()\n    {\n        $this->beConstructedWith('setValues', array(), 0, null, null, null);\n\n        $this->getCallPlace()->shouldReturn('unknown');\n    }\n\n    function it_adds_wildcard_match_score(ArgumentsWildcard $wildcard)\n    {\n        $this->addScore($wildcard, 99)->shouldReturn($this);\n        $this->getScore($wildcard)->shouldReturn(99);\n    }\n\n    function it_caches_and_returns_wildcard_match_score(ArgumentsWildcard $wildcard)\n    {\n        $wildcard->scoreArguments(array(5, 2))->willReturn(13)->shouldBeCalledTimes(1);\n        $this->getScore($wildcard)->shouldReturn(13);\n        $this->getScore($wildcard)->shouldReturn(13);\n    }\n}\n"
  },
  {
    "path": "spec/Prophecy/Comparator/ClosureComparatorSpec.php",
    "content": "<?php\n\nnamespace spec\\Prophecy\\Comparator;\n\nuse PhpSpec\\ObjectBehavior;\n\nclass ClosureComparatorSpec extends ObjectBehavior\n{\n    function it_is_comparator()\n    {\n        $this->shouldHaveType('SebastianBergmann\\Comparator\\Comparator');\n    }\n\n    function it_accepts_only_closures()\n    {\n        $this->accepts(123, 321)->shouldReturn(false);\n        $this->accepts('string', 'string')->shouldReturn(false);\n        $this->accepts(false, true)->shouldReturn(false);\n        $this->accepts(true, false)->shouldReturn(false);\n        $this->accepts((object) array(), (object) array())->shouldReturn(false);\n        $this->accepts(function () {}, (object) array())->shouldReturn(false);\n        $this->accepts(function () {}, (object) array())->shouldReturn(false);\n\n        $this->accepts(function () {}, function () {})->shouldReturn(true);\n    }\n\n    function it_asserts_that_different_closures_are_different()\n    {\n        $this->shouldThrow()->duringAssertEquals(function () {}, function () {});\n    }\n\n    function it_asserts_that_closures_are_equal_if_its_the_same_closure()\n    {\n        $closure = function () {};\n\n        $this->shouldNotThrow()->duringAssertEquals($closure, $closure);\n    }\n}\n"
  },
  {
    "path": "spec/Prophecy/Comparator/FactorySpec.php",
    "content": "<?php\n\nnamespace spec\\Prophecy\\Comparator;\n\nuse PhpSpec\\Exception\\Example\\SkippingException;\nuse PhpSpec\\ObjectBehavior;\nuse Prophecy\\Comparator\\Factory;\nuse SebastianBergmann\\Comparator\\Factory as BaseFactory;\n\nclass FactorySpec extends ObjectBehavior\n{\n    function let()\n    {\n        $ref = new \\ReflectionClass(BaseFactory::class);\n\n        if ($ref->isFinal()) {\n            throw new SkippingException(sprintf('The deprecated \"%s\" class cannot be used with sebastian/comparator 5+.', Factory::class));\n        }\n    }\n\n    function it_extends_Sebastian_Comparator_Factory()\n    {\n        $this->shouldHaveType('SebastianBergmann\\Comparator\\Factory');\n    }\n\n    function it_should_have_ClosureComparator_registered()\n    {\n        $comparator = $this->getInstance()->getComparatorFor(function () {}, function () {});\n        $comparator->shouldHaveType('Prophecy\\Comparator\\ClosureComparator');\n    }\n}\n"
  },
  {
    "path": "spec/Prophecy/Comparator/ProphecyComparatorSpec.php",
    "content": "<?php\n\nnamespace spec\\Prophecy\\Comparator;\n\nuse PhpSpec\\ObjectBehavior;\nuse Prophecy\\Prophet;\nuse SebastianBergmann\\Comparator\\Comparator;\nuse SebastianBergmann\\Comparator\\Factory;\n\nclass ProphecyComparatorSpec extends ObjectBehavior\n{\n    function it_is_a_comparator()\n    {\n        $this->shouldHaveType(Comparator::class);\n    }\n\n    function it_accepts_only_prophecy_objects()\n    {\n        $this->accepts(123, 321)->shouldReturn(false);\n        $this->accepts('string', 'string')->shouldReturn(false);\n        $this->accepts(false, true)->shouldReturn(false);\n        $this->accepts(true, false)->shouldReturn(false);\n        $this->accepts((object) array(), (object) array())->shouldReturn(false);\n        $this->accepts(function () {}, (object) array())->shouldReturn(false);\n        $this->accepts(function () {}, function () {})->shouldReturn(false);\n\n        $prophet = new Prophet();\n        $prophecy = $prophet->prophesize('Prophecy\\Prophecy\\ObjectProphecy');\n\n        $this->accepts($prophecy, $prophecy)->shouldReturn(true);\n    }\n\n    function it_asserts_that_an_object_is_equal_to_its_revealed_prophecy()\n    {\n        $prophet = new Prophet();\n        $prophecy = $prophet->prophesize('Prophecy\\Prophecy\\ObjectProphecy');\n        $prophecy->__call('reveal', array())->willReturn(new \\stdClass());\n\n        $factory = new Factory();\n        $factory->register($this->getWrappedObject());\n\n        $this->shouldNotThrow()->duringAssertEquals($prophecy->reveal(), $prophecy);\n    }\n}\n"
  },
  {
    "path": "spec/Prophecy/Doubler/CachedDoublerSpec.php",
    "content": "<?php\n\nnamespace spec\\Prophecy\\Doubler;\n\nuse PhpSpec\\ObjectBehavior;\nuse Prophecy\\Doubler\\ClassPatch\\ClassPatchInterface;\nuse Prophecy\\Doubler\\Generator\\ClassCreator;\nuse Prophecy\\Doubler\\Generator\\ClassMirror;\nuse Prophecy\\Doubler\\Generator\\Node\\ClassNode;\nuse Prophecy\\Doubler\\NameGenerator;\n\nclass CachedDoublerSpec extends ObjectBehavior\n{\n    function let(ClassMirror $mirror, ClassCreator $creator, NameGenerator $namer)\n    {\n        $this->beConstructedWith($mirror, $creator, $namer);\n        $this->resetCache();\n    }\n\n    /**\n     * @todo implement\n     * T - T\n     * T - F\n     * F - T\n     * F - F\n     * F T F\n     * F T T\n     */\n\n    // T - -\n    function it_creates_only_one_class_definition_for_the_same_class_without_interfaces_and_patches(\n        ClassMirror $mirror,\n        ClassCreator $creator,\n        NameGenerator $namer,\n        \\ReflectionClass $class,\n        ClassNode $node\n    ) {\n        $mirror->reflect($class, array())->willReturn($node);\n        $namer->name($class, array())->willReturn('SplStack');\n        $class->getName()->willReturn('stdClass');\n\n        $creator->create('SplStack', $node)->shouldBeCalledTimes(1);\n\n        $this->double($class, array());\n        $this->double($class, array());\n    }\n\n    // F - -\n    function it_creates_two_class_definitions_for_different_classes_without_interfaces_and_patches(\n        ClassMirror $mirror,\n        ClassCreator $creator,\n        NameGenerator $namer,\n        \\ReflectionClass $class1,\n        \\ReflectionClass $class2,\n        ClassNode $node1,\n        ClassNode $node2\n    ) {\n        $mirror->reflect($class1, array())->willReturn($node1);\n        $mirror->reflect($class2, array())->willReturn($node2);\n        $namer->name($class1, array())->willReturn('SplStack');\n        $namer->name($class2, array())->willReturn('spec\\Prophecy\\Doubler\\aClass');\n        $class1->getName()->willReturn('stdClass');\n        $class2->getName()->willReturn('aClass');\n\n        $creator->create('SplStack', $node1)->shouldBeCalledTimes(1);\n        $creator->create('spec\\Prophecy\\Doubler\\aClass', $node2)->shouldBeCalledTimes(1);\n\n        $this->double($class1, array());\n        $this->double($class2, array());\n    }\n\n    // T F T\n    function it_creates_two_different_class_definitions_for_the_same_class_with_different_interfaces_and_same_patches(\n        ClassMirror $mirror,\n        ClassCreator $creator,\n        NameGenerator $namer,\n        ClassPatchInterface $alt1,\n        ClassPatchInterface $alt2,\n        \\ReflectionClass $class,\n        \\ReflectionClass $interface1,\n        \\ReflectionClass $interface2,\n        ClassNode $node1,\n        ClassNode $node2\n    ) {\n        $mirror->reflect($class, array($interface1))->willReturn($node1);\n        $mirror->reflect($class, array($interface2))->willReturn($node2);\n        $alt1->supports($node1)->willReturn(true);\n        $alt1->supports($node2)->willReturn(true);\n        $alt2->supports($node1)->willReturn(false);\n        $alt2->supports($node2)->willReturn(false);\n        $alt1->getPriority()->willReturn(1);\n        $alt2->getPriority()->willReturn(2);\n        $namer->name($class, array($interface1))->willReturn('SplStack');\n        $namer->name($class, array($interface2))->willReturn('SplStack');\n        $class->getName()->willReturn('stdClass');\n        $interface1->getName()->willReturn('ArrayAccess');\n        $interface2->getName()->willReturn('Iterator');\n\n        $alt1->apply($node1)->shouldBeCalled();\n        $alt1->apply($node2)->shouldBeCalled();\n        $alt2->apply($node1)->shouldNotBeCalled();\n        $alt2->apply($node2)->shouldNotBeCalled();\n        $creator->create('SplStack', $node1)->shouldBeCalledTimes(1);\n        $creator->create('SplStack', $node2)->shouldBeCalledTimes(1);\n\n        $this->registerClassPatch($alt1);\n        $this->registerClassPatch($alt2);\n\n        $this->double($class, array($interface1));\n        $this->double($class, array($interface2));\n    }\n\n    // F F T\n    function it_creates_two_different_class_definitions_for_different_classes_with_different_interfaces_and_same_patches(\n        ClassMirror $mirror,\n        ClassCreator $creator,\n        NameGenerator $namer,\n        ClassPatchInterface $alt1,\n        ClassPatchInterface $alt2,\n        \\ReflectionClass $class1,\n        \\ReflectionClass $class2,\n        \\ReflectionClass $interface1,\n        \\ReflectionClass $interface2,\n        ClassNode $node1,\n        ClassNode $node2\n    ) {\n        $mirror->reflect($class1, array($interface1))->willReturn($node1);\n        $mirror->reflect($class2, array($interface2))->willReturn($node2);\n        $alt1->supports($node1)->willReturn(true);\n        $alt1->supports($node2)->willReturn(true);\n        $alt2->supports($node1)->willReturn(false);\n        $alt2->supports($node2)->willReturn(false);\n        $alt1->getPriority()->willReturn(1);\n        $alt2->getPriority()->willReturn(2);\n        $namer->name($class1, array($interface1))->willReturn('SplStack');\n        $namer->name($class2, array($interface2))->willReturn('spec\\Prophecy\\Doubler\\aClass');\n        $class1->getName()->willReturn('stdClass');\n        $class2->getName()->willReturn('aClass');\n        $interface1->getName()->willReturn('ArrayAccess');\n        $interface2->getName()->willReturn('Iterator');\n\n        $alt1->apply($node1)->shouldBeCalled();\n        $alt1->apply($node2)->shouldBeCalled();\n        $alt2->apply($node1)->shouldNotBeCalled();\n        $alt2->apply($node2)->shouldNotBeCalled();\n        $creator->create('SplStack', $node1)->shouldBeCalledTimes(1);\n        $creator->create('spec\\Prophecy\\Doubler\\aClass', $node2)->shouldBeCalledTimes(1);\n\n        $this->registerClassPatch($alt1);\n        $this->registerClassPatch($alt2);\n\n        $this->double($class1, array($interface1));\n        $this->double($class2, array($interface2));\n    }\n\n    // T T -\n    function it_creates_only_one_class_definition_for_the_same_class_with_same_interfaces_and_without_patches(\n        ClassMirror $mirror,\n        ClassCreator $creator,\n        NameGenerator $namer,\n        \\ReflectionClass $class,\n        \\ReflectionClass $interface1,\n        \\ReflectionClass $interface2,\n        ClassNode $node\n    ) {\n        $mirror->reflect($class, array($interface1, $interface2))->willReturn($node);\n        $namer->name($class, array($interface1, $interface2))->willReturn('SplStack');\n        $class->getName()->willReturn('stdClass');\n        $interface1->getName()->willReturn('ArrayAccess');\n        $interface2->getName()->willReturn('Iterator');\n\n        $creator->create('SplStack', $node)->shouldBeCalledTimes(1);\n\n        $this->double($class, array($interface1, $interface2));\n        $this->double($class, array($interface1, $interface2));\n    }\n\n    // F T -\n    function it_creates_only_one_class_definition_for_different_classes_with_same_interfaces_and_without_patches(\n        ClassMirror $mirror,\n        ClassCreator $creator,\n        NameGenerator $namer,\n        \\ReflectionClass $class1,\n        \\ReflectionClass $class2,\n        \\ReflectionClass $interface1,\n        \\ReflectionClass $interface2,\n        ClassNode $node1,\n        ClassNode $node2\n    ) {\n        $mirror->reflect($class1, array($interface1, $interface2))->willReturn($node1);\n        $mirror->reflect($class2, array($interface1, $interface2))->willReturn($node2);\n        $namer->name($class1, array($interface1, $interface2))->willReturn('SplStack');\n        $namer->name($class2, array($interface1, $interface2))->willReturn('spec\\Prophecy\\Doubler\\aClass');\n        $class1->getName()->willReturn('stdClass');\n        $class2->getName()->willReturn('aClass');\n        $interface1->getName()->willReturn('ArrayAccess');\n        $interface2->getName()->willReturn('Iterator');\n\n        $creator->create('SplStack', $node1)->shouldBeCalledTimes(1);\n        $creator->create('spec\\Prophecy\\Doubler\\aClass', $node2)->shouldBeCalledTimes(1);\n\n        $this->double($class1, array($interface1, $interface2));\n        $this->double($class2, array($interface1, $interface2));\n    }\n\n    // T F -\n    function it_creates_two_different_class_definitions_for_the_same_class_with_different_interfaces_and_without_patches(\n        ClassMirror $mirror,\n        ClassCreator $creator,\n        NameGenerator $namer,\n        \\ReflectionClass $class,\n        \\ReflectionClass $interface1,\n        \\ReflectionClass $interface2,\n        ClassNode $node1,\n        ClassNode $node2\n    ) {\n        $mirror->reflect($class, array($interface1))->willReturn($node1);\n        $mirror->reflect($class, array($interface2))->willReturn($node2);\n        $namer->name($class, array($interface1))->willReturn('SplStack');\n        $namer->name($class, array($interface2))->willReturn('SplStack');\n        $class->getName()->willReturn('stdClass');\n        $interface1->getName()->willReturn('ArrayAccess');\n        $interface2->getName()->willReturn('Iterator');\n\n        $creator->create('SplStack', $node1)->shouldBeCalledTimes(1);\n        $creator->create('SplStack', $node2)->shouldBeCalledTimes(1);\n\n        $this->double($class, array($interface1));\n        $this->double($class, array($interface2));\n    }\n\n    // F F -\n    function it_creates_two_different_class_definitions_for_different_classes_with_different_interfaces_and_without_patches(\n        ClassMirror $mirror,\n        ClassCreator $creator,\n        NameGenerator $namer,\n        \\ReflectionClass $class1,\n        \\ReflectionClass $class2,\n        \\ReflectionClass $interface1,\n        \\ReflectionClass $interface2,\n        ClassNode $node1,\n        ClassNode $node2\n    ) {\n        $mirror->reflect($class1, array($interface1))->willReturn($node1);\n        $mirror->reflect($class2, array($interface2))->willReturn($node2);\n        $namer->name($class1, array($interface1))->willReturn('SplStack');\n        $namer->name($class2, array($interface2))->willReturn('spec\\Prophecy\\Doubler\\aClass');\n        $class1->getName()->willReturn('stdClass');\n        $class2->getName()->willReturn('aClass');\n        $interface1->getName()->willReturn('ArrayAccess');\n        $interface2->getName()->willReturn('Iterator');\n\n        $creator->create('SplStack', $node1)->shouldBeCalledTimes(1);\n        $creator->create('spec\\Prophecy\\Doubler\\aClass', $node2)->shouldBeCalledTimes(1);\n\n        $this->double($class1, array($interface1));\n        $this->double($class2, array($interface2));\n    }\n\n    // T T T\n    function it_creates_only_one_class_definition_for_the_same_class_with_same_interfaces_and_same_patches(\n        ClassMirror $mirror,\n        ClassCreator $creator,\n        NameGenerator $namer,\n        ClassPatchInterface $alt1,\n        ClassPatchInterface $alt2,\n        \\ReflectionClass $class,\n        \\ReflectionClass $interface1,\n        \\ReflectionClass $interface2,\n        ClassNode $node\n    ) {\n        $mirror->reflect($class, array($interface1, $interface2))->willReturn($node);\n        $alt1->supports($node)->willReturn(true);\n        $alt2->supports($node)->willReturn(false);\n        $alt1->getPriority()->willReturn(1);\n        $alt2->getPriority()->willReturn(2);\n        $namer->name($class, array($interface1, $interface2))->willReturn('SplStack');\n        $class->getName()->willReturn('stdClass');\n        $interface1->getName()->willReturn('ArrayAccess');\n        $interface2->getName()->willReturn('Iterator');\n\n        $alt1->apply($node)->shouldBeCalled();\n        $alt2->apply($node)->shouldNotBeCalled();\n        $creator->create('SplStack', $node)->shouldBeCalledTimes(1);\n\n        $this->registerClassPatch($alt1);\n        $this->registerClassPatch($alt2);\n\n        $this->double($class, array($interface1, $interface2));\n        $this->double($class, array($interface1, $interface2));\n    }\n\n    // F F F\n    function it_creates_two_class_definitions_for_different_classes_with_different_interfaces_and_patches(\n        ClassMirror $mirror,\n        ClassCreator $creator,\n        NameGenerator $namer,\n        ClassPatchInterface $alt1,\n        ClassPatchInterface $alt2,\n        \\ReflectionClass $class1,\n        \\ReflectionClass $class2,\n        \\ReflectionClass $interface1,\n        \\ReflectionClass $interface2,\n        ClassNode $node1,\n        ClassNode $node2\n    ) {\n        $mirror->reflect($class1, array($interface1))->willReturn($node1);\n        $mirror->reflect($class2, array($interface2))->willReturn($node2);\n        $alt1->supports($node1)->willReturn(true);\n        $alt1->supports($node2)->willReturn(true);\n        $alt2->supports($node2)->willReturn(false);\n        $alt1->getPriority()->willReturn(1);\n        $alt2->getPriority()->willReturn(2);\n        $namer->name($class1, array($interface1))->willReturn('SplStack');\n        $namer->name($class2, array($interface2))->willReturn('spec\\Prophecy\\Doubler\\aClass');\n        $class1->getName()->willReturn('stdClass');\n        $class2->getName()->willReturn('aClass');\n        $interface1->getName()->willReturn('ArrayAccess');\n        $interface2->getName()->willReturn('Iterator');\n\n        $alt1->apply($node1)->shouldBeCalled();\n        $alt1->apply($node2)->shouldBeCalled();\n        $alt2->apply($node2)->shouldNotBeCalled();\n        $creator->create('SplStack', $node1)->shouldBeCalledTimes(1);\n        $creator->create('spec\\Prophecy\\Doubler\\aClass', $node2)->shouldBeCalledTimes(1);\n\n        $this->registerClassPatch($alt1);\n        $this->double($class1, array($interface1));\n\n        $this->registerClassPatch($alt2);\n        $this->double($class2, array($interface2));\n    }\n\n    // T F F\n    function it_creates_two_class_definitions_for_the_same_class_with_different_interfaces_and_patches(\n        ClassMirror $mirror,\n        ClassCreator $creator,\n        NameGenerator $namer,\n        ClassPatchInterface $alt1,\n        ClassPatchInterface $alt2,\n        \\ReflectionClass $class,\n        \\ReflectionClass $interface1,\n        \\ReflectionClass $interface2,\n        ClassNode $node1,\n        ClassNode $node2\n    ) {\n        $mirror->reflect($class, array($interface1))->willReturn($node1);\n        $mirror->reflect($class, array($interface2))->willReturn($node2);\n        $alt1->supports($node1)->willReturn(true);\n        $alt1->supports($node2)->willReturn(true);\n        $alt2->supports($node2)->willReturn(false);\n        $alt1->getPriority()->willReturn(1);\n        $alt2->getPriority()->willReturn(2);\n        $namer->name($class, array($interface1))->willReturn('SplStack');\n        $namer->name($class, array($interface2))->willReturn('SplStack');\n        $class->getName()->willReturn('stdClass');\n        $interface1->getName()->willReturn('ArrayAccess');\n        $interface2->getName()->willReturn('Iterator');\n\n        $alt1->apply($node1)->shouldBeCalled();\n        $alt1->apply($node2)->shouldBeCalled();\n        $alt2->apply($node2)->shouldNotBeCalled();\n        $creator->create('SplStack', $node1)->shouldBeCalledTimes(1);\n        $creator->create('SplStack', $node2)->shouldBeCalledTimes(1);\n\n        $this->registerClassPatch($alt1);\n        $this->double($class, array($interface1));\n\n        $this->registerClassPatch($alt2);\n        $this->double($class, array($interface2));\n    }\n\n    // T T F\n    function it_creates_two_different_class_definitions_for_the_same_class_with_same_interfaces_and_different_patches(\n        ClassMirror $mirror,\n        ClassCreator $creator,\n        NameGenerator $namer,\n        ClassPatchInterface $alt1,\n        ClassPatchInterface $alt2,\n        \\ReflectionClass $class,\n        \\ReflectionClass $interface1,\n        \\ReflectionClass $interface2,\n        ClassNode $node1,\n        ClassNode $node2\n    ) {\n        $mirror->reflect($class, array($interface1, $interface2))->willReturn($node1, $node2);\n        $alt1->supports($node1)->willReturn(true);\n        $alt1->supports($node2)->willReturn(true);\n        $alt2->supports($node2)->willReturn(false);\n        $alt1->getPriority()->willReturn(1);\n        $alt2->getPriority()->willReturn(2);\n        $namer->name($class, array($interface1, $interface2))->willReturn('SplStack');\n        $class->getName()->willReturn('stdClass');\n        $interface1->getName()->willReturn('ArrayAccess');\n        $interface2->getName()->willReturn('Iterator');\n\n        $alt1->apply($node1)->shouldBeCalled();\n        $creator->create('SplStack', $node1)->shouldBeCalledTimes(1);\n\n        $this->registerClassPatch($alt1);\n        $this->double($class, array($interface1, $interface2));\n\n        $alt1->apply($node2)->shouldBeCalled();\n        $alt2->apply($node2)->shouldNotBeCalled();\n        $creator->create('SplStack', $node2)->shouldBeCalledTimes(1);\n\n        $this->registerClassPatch($alt2);\n        $this->double($class, array($interface1, $interface2));\n    }\n}\n\nclass aClass {}\n"
  },
  {
    "path": "spec/Prophecy/Doubler/ClassPatch/DisableConstructorPatchSpec.php",
    "content": "<?php\n\nnamespace spec\\Prophecy\\Doubler\\ClassPatch;\n\nuse PhpSpec\\ObjectBehavior;\nuse Prophecy\\Argument;\nuse Prophecy\\Doubler\\Generator\\Node\\ArgumentNode;\nuse Prophecy\\Doubler\\Generator\\Node\\ArgumentTypeNode;\nuse Prophecy\\Doubler\\Generator\\Node\\ClassNode;\nuse Prophecy\\Doubler\\Generator\\Node\\MethodNode;\nuse Prophecy\\Doubler\\Generator\\Node\\Type\\BuiltinType;\nuse Prophecy\\Doubler\\Generator\\Node\\Type\\UnionType;\n\nclass DisableConstructorPatchSpec extends ObjectBehavior\n{\n    function it_is_a_patch()\n    {\n        $this->shouldBeAnInstanceOf('Prophecy\\Doubler\\ClassPatch\\ClassPatchInterface');\n    }\n\n    function its_priority_is_100()\n    {\n        $this->getPriority()->shouldReturn(100);\n    }\n\n    function it_supports_anything(ClassNode $node)\n    {\n        $this->supports($node)->shouldReturn(true);\n    }\n\n    function it_makes_all_constructor_arguments_optional(\n        ClassNode $class,\n        MethodNode $method,\n        ArgumentNode $arg1,\n        ArgumentNode $arg2,\n        ArgumentNode $arg3\n    ) {\n        $arg1->getTypeNode()->willReturn(new ArgumentTypeNode(new UnionType([\n            new BuiltinType('string'),\n            new BuiltinType('null'),\n        ])));\n        $arg2->getTypeNode()->willReturn(new ArgumentTypeNode(new BuiltinType('mixed')));\n        $arg3->getTypeNode()->willReturn(new ArgumentTypeNode(new BuiltinType('string')));\n\n        $class->isExtendable('__construct')->willReturn(true);\n        $class->hasMethod('__construct')->willReturn(true);\n        $class->getMethod('__construct')->willReturn($method);\n        $method->getArguments()->willReturn(array($arg1, $arg2, $arg3));\n\n        $arg1->setDefault(null)->shouldBeCalled();\n        $arg2->setDefault(null)->shouldBeCalled();\n        $arg3->setDefault(null)->shouldBeCalled();\n\n        $arg3->setTypeNode(new ArgumentTypeNode(new UnionType([new BuiltinType('null'), new BuiltinType('string')])))->shouldBeCalled();\n\n        $method->setCode(Argument::type('string'))->shouldBeCalled();\n\n        $this->apply($class);\n    }\n\n    function it_creates_new_constructor_if_object_has_none(ClassNode $class)\n    {\n        $class->isExtendable('__construct')->willReturn(true);\n        $class->hasMethod('__construct')->willReturn(false);\n        $class->addMethod(Argument::type('Prophecy\\Doubler\\Generator\\Node\\MethodNode'))\n            ->shouldBeCalled();\n\n        $this->apply($class);\n    }\n\n    function it_ignores_final_constructor(ClassNode $class)\n    {\n        $class->isExtendable('__construct')->willReturn(false);\n\n        $this->apply($class);\n    }\n}\n"
  },
  {
    "path": "spec/Prophecy/Doubler/ClassPatch/KeywordPatchSpec.php",
    "content": "<?php\n\nnamespace spec\\Prophecy\\Doubler\\ClassPatch;\n\nuse PhpSpec\\ObjectBehavior;\nuse Prophecy\\Doubler\\Generator\\Node\\ClassNode;\nuse Prophecy\\Doubler\\Generator\\Node\\MethodNode;\n\nclass KeywordPatchSpec extends ObjectBehavior\n{\n    function it_is_a_patch()\n    {\n        $this->shouldBeAnInstanceOf('Prophecy\\Doubler\\ClassPatch\\ClassPatchInterface');\n    }\n\n    function its_priority_is_49()\n    {\n        $this->getPriority()->shouldReturn(49);\n    }\n\n    function it_will_remove_halt_compiler_method(\n        ClassNode $node,\n        MethodNode $method1,\n        MethodNode $method2,\n        MethodNode $method3\n    ) {\n        $node->removeMethod('__halt_compiler')->shouldBeCalled();\n\n        $method1->getName()->willReturn('__halt_compiler');\n        $method2->getName()->willReturn('echo');\n        $method3->getName()->willReturn('notKeyword');\n\n        $node->getMethods()->willReturn(array(\n            '__halt_compiler' => $method1,\n            'echo' => $method2,\n            'notKeyword' => $method3,\n        ));\n\n        $this->apply($node);\n    }\n}\n"
  },
  {
    "path": "spec/Prophecy/Doubler/ClassPatch/MagicCallPatchSpec.php",
    "content": "<?php\n\nnamespace spec\\Prophecy\\Doubler\\ClassPatch;\n\nuse PhpSpec\\ObjectBehavior;\nuse Prophecy\\Doubler\\Generator\\Node\\ClassNode;\nuse Prophecy\\Doubler\\Generator\\Node\\MethodNode;\n\nclass MagicCallPatchSpec extends ObjectBehavior\n{\n    function it_is_a_patch()\n    {\n        $this->shouldBeAnInstanceOf('Prophecy\\Doubler\\ClassPatch\\ClassPatchInterface');\n    }\n\n    function it_supports_anything(ClassNode $node)\n    {\n        $this->supports($node)->shouldReturn(true);\n    }\n\n    function it_discovers_api_using_phpdoc(ClassNode $node)\n    {\n        $node->getParentClass()->willReturn('spec\\Prophecy\\Doubler\\ClassPatch\\MagicalApi');\n        $node->getInterfaces()->willReturn(array());\n\n        $node->addMethod(new MethodNode('undefinedMethod'))->shouldBeCalled();\n\n        $this->apply($node);\n    }\n\n    function it_ignores_existing_methods(ClassNode $node)\n    {\n        $node->getParentClass()->willReturn('spec\\Prophecy\\Doubler\\ClassPatch\\MagicalApiExtended');\n        $node->getInterfaces()->willReturn(array());\n\n        $node->addMethod(new MethodNode('undefinedMethod'))->shouldBeCalled();\n        $node->addMethod(new MethodNode('definedMethod'))->shouldNotBeCalled();\n\n        $this->apply($node);\n    }\n\n    function it_ignores_empty_methods_from_phpdoc(ClassNode $node)\n    {\n        $node->getParentClass()->willReturn('spec\\Prophecy\\Doubler\\ClassPatch\\MagicalApiInvalidMethodDefinition');\n        $node->getInterfaces()->willReturn(array());\n\n        $node->addMethod(new MethodNode(''))->shouldNotBeCalled();\n\n        $this->apply($node);\n    }\n\n    function it_discovers_api_using_phpdoc_from_implemented_interfaces(ClassNode $node)\n    {\n        $node->getParentClass()->willReturn('spec\\Prophecy\\Doubler\\ClassPatch\\MagicalApiImplemented');\n        $node->getInterfaces()->willReturn(array());\n\n        $node->addMethod(new MethodNode('implementedMethod'))->shouldBeCalled();\n\n        $this->apply($node);\n    }\n\n    function it_discovers_api_using_phpdoc_from_own_interfaces(ClassNode $node)\n    {\n        $node->getParentClass()->willReturn('stdClass');\n        $node->getInterfaces()->willReturn(array('spec\\Prophecy\\Doubler\\ClassPatch\\MagicalApiImplemented'));\n\n        $node->addMethod(new MethodNode('implementedMethod'))->shouldBeCalled();\n\n        $this->apply($node);\n    }\n\n    function it_discovers_api_using_phpdoc_from_extended_parent_interfaces(ClassNode $node)\n    {\n        $node->getParentClass()->willReturn('spec\\Prophecy\\Doubler\\ClassPatch\\MagicalApiImplementedExtended');\n        $node->getInterfaces()->willReturn(array());\n\n        $node->addMethod(new MethodNode('implementedMethod'))->shouldBeCalled();\n\n        $this->apply($node);\n    }\n\n    function it_has_50_priority()\n    {\n        $this->getPriority()->shouldReturn(50);\n    }\n}\n\n/**\n * @method void undefinedMethod()\n */\nclass MagicalApi\n{\n    /**\n     * @return void\n     */\n    public function definedMethod() {}\n}\n\n/**\n * @method\n */\nclass MagicalApiInvalidMethodDefinition {}\n\n/**\n * @method void definedMethod()\n */\nclass MagicalApiExtended extends MagicalApi {}\n\n/**\n */\nclass MagicalApiImplemented implements MagicalApiInterface {}\n\n/**\n */\nclass MagicalApiImplementedExtended extends MagicalApiImplemented {}\n\n/**\n * @method void implementedMethod()\n */\ninterface MagicalApiInterface {}\n"
  },
  {
    "path": "spec/Prophecy/Doubler/ClassPatch/ProphecySubjectPatchSpec.php",
    "content": "<?php\n\nnamespace spec\\Prophecy\\Doubler\\ClassPatch;\n\nuse PhpSpec\\ObjectBehavior;\nuse Prophecy\\Argument;\nuse Prophecy\\Doubler\\Generator\\Node\\ClassNode;\nuse Prophecy\\Doubler\\Generator\\Node\\MethodNode;\nuse Prophecy\\Doubler\\Generator\\Node\\ReturnTypeNode;\nuse Prophecy\\Doubler\\Generator\\Node\\Type\\BuiltinType;\n\nclass ProphecySubjectPatchSpec extends ObjectBehavior\n{\n    function it_is_a_patch()\n    {\n        $this->shouldBeAnInstanceOf('Prophecy\\Doubler\\ClassPatch\\ClassPatchInterface');\n    }\n\n    function it_has_priority_of_0()\n    {\n        $this->getPriority()->shouldReturn(0);\n    }\n\n    function it_supports_any_class(ClassNode $node)\n    {\n        $this->supports($node)->shouldReturn(true);\n    }\n\n    function it_forces_class_to_implement_ProphecySubjectInterface(ClassNode $node)\n    {\n        $node->addInterface('Prophecy\\Prophecy\\ProphecySubjectInterface')->shouldBeCalled();\n\n        $node->addProperty('objectProphecyClosure', 'private')->willReturn(null);\n        $node->getMethods()->willReturn(array());\n        $node->hasMethod(Argument::any())->willReturn(false);\n        $node->addMethod(Argument::type('Prophecy\\Doubler\\Generator\\Node\\MethodNode'), true)->willReturn(null);\n        $node->addMethod(Argument::type('Prophecy\\Doubler\\Generator\\Node\\MethodNode'), true)->willReturn(null);\n\n        $this->apply($node);\n    }\n\n    function it_forces_all_class_methods_except_constructor_to_proxy_calls_into_prophecy_makeCall(\n        ClassNode $node,\n        MethodNode $constructor,\n        MethodNode $method1,\n        MethodNode $method2,\n        MethodNode $method3,\n        MethodNode $method4\n    ) {\n        $node->addInterface('Prophecy\\Prophecy\\ProphecySubjectInterface')->willReturn(null);\n        $node->addProperty('objectProphecyClosure', 'private')->willReturn(null);\n        $node->hasMethod(Argument::any())->willReturn(false);\n        $node->addMethod(Argument::type('Prophecy\\Doubler\\Generator\\Node\\MethodNode'), true)->willReturn(null);\n        $node->addMethod(Argument::type('Prophecy\\Doubler\\Generator\\Node\\MethodNode'), true)->willReturn(null);\n\n        $constructor->getName()->willReturn('__construct');\n        $method1->getName()->willReturn('method1');\n        $method2->getName()->willReturn('method2');\n        $method3->getName()->willReturn('method3');\n        $method4->getName()->willReturn('method4');\n\n        $method1->getReturnTypeNode()->willReturn(new ReturnTypeNode(new BuiltinType('int')));\n        $method2->getReturnTypeNode()->willReturn(new ReturnTypeNode(new BuiltinType('int')));\n        $method3->getReturnTypeNode()->willReturn(new ReturnTypeNode(new BuiltinType('void')));\n        $method4->getReturnTypeNode()->willReturn(new ReturnTypeNode(new BuiltinType('never')));\n\n        $node->getMethods()->willReturn(array(\n            'method1' => $method1,\n            'method2' => $method2,\n            'method3' => $method3,\n            'method4' => $method4,\n        ));\n\n        $constructor->setCode(Argument::any())->shouldNotBeCalled();\n\n        $method1->setCode('return $this->getProphecy()->makeProphecyMethodCall(__FUNCTION__, func_get_args());')\n            ->shouldBeCalled();\n        $method2->setCode('return $this->getProphecy()->makeProphecyMethodCall(__FUNCTION__, func_get_args());')\n            ->shouldBeCalled();\n        $method3->setCode('$this->getProphecy()->makeProphecyMethodCall(__FUNCTION__, func_get_args());')\n            ->shouldBeCalled();\n        $method4->setCode('$this->getProphecy()->makeProphecyMethodCall(__FUNCTION__, func_get_args());')\n            ->shouldBeCalled();\n\n        $this->apply($node);\n    }\n}\n"
  },
  {
    "path": "spec/Prophecy/Doubler/ClassPatch/ReflectionClassNewInstancePatchSpec.php",
    "content": "<?php\n\nnamespace spec\\Prophecy\\Doubler\\ClassPatch;\n\nuse PhpSpec\\ObjectBehavior;\nuse Prophecy\\Doubler\\Generator\\Node\\ArgumentNode;\nuse Prophecy\\Doubler\\Generator\\Node\\ClassNode;\nuse Prophecy\\Doubler\\Generator\\Node\\MethodNode;\n\nclass ReflectionClassNewInstancePatchSpec extends ObjectBehavior\n{\n    function it_is_a_patch()\n    {\n        $this->shouldBeAnInstanceOf('Prophecy\\Doubler\\ClassPatch\\ClassPatchInterface');\n    }\n\n    function its_priority_is_50()\n    {\n        $this->getPriority()->shouldReturn(50);\n    }\n\n    function it_supports_ReflectionClass_only(ClassNode $reflectionClassNode, ClassNode $anotherClassNode)\n    {\n        $reflectionClassNode->getParentClass()->willReturn('ReflectionClass');\n        $anotherClassNode->getParentClass()->willReturn('stdClass');\n\n        $this->supports($reflectionClassNode)->shouldReturn(true);\n        $this->supports($anotherClassNode)->shouldReturn(false);\n    }\n\n    function it_makes_all_newInstance_arguments_optional(\n        ClassNode $class,\n        MethodNode $method,\n        ArgumentNode $arg1\n    ) {\n        $class->getMethod('newInstance')->willReturn($method);\n        $method->getArguments()->willReturn(array($arg1));\n        $arg1->setDefault(null)->shouldBeCalled();\n\n        $this->apply($class);\n    }\n}\n"
  },
  {
    "path": "spec/Prophecy/Doubler/ClassPatch/SplFileInfoPatchSpec.php",
    "content": "<?php\n\nnamespace spec\\Prophecy\\Doubler\\ClassPatch;\n\nuse PhpSpec\\ObjectBehavior;\nuse Prophecy\\Argument;\nuse Prophecy\\Doubler\\Generator\\Node\\ClassNode;\nuse Prophecy\\Doubler\\Generator\\Node\\MethodNode;\n\nclass SplFileInfoPatchSpec extends ObjectBehavior\n{\n    function it_is_a_patch()\n    {\n        $this->shouldBeAnInstanceOf('Prophecy\\Doubler\\ClassPatch\\ClassPatchInterface');\n    }\n\n    function its_priority_is_50()\n    {\n        $this->getPriority()->shouldReturn(50);\n    }\n\n    function it_does_not_support_nodes_without_parent_class(ClassNode $node)\n    {\n        $node->getParentClass()->willReturn('stdClass');\n        $this->supports($node)->shouldReturn(false);\n    }\n\n    function it_supports_nodes_with_SplFileInfo_as_parent_class(ClassNode $node)\n    {\n        $node->getParentClass()->willReturn('SplFileInfo');\n        $this->supports($node)->shouldReturn(true);\n    }\n\n    function it_supports_nodes_with_derivative_of_SplFileInfo_as_parent_class(ClassNode $node)\n    {\n        $node->getParentClass()->willReturn('SplFileInfo');\n        $this->supports($node)->shouldReturn(true);\n    }\n\n    function it_adds_a_method_to_node_if_not_exists(ClassNode $node)\n    {\n        $node->hasMethod('__construct')->willReturn(false);\n        $node->addMethod(Argument::any())->shouldBeCalled();\n        $node->getParentClass()->shouldBeCalled();\n\n        $this->apply($node);\n    }\n\n    function it_updates_existing_method_if_found(ClassNode $node, MethodNode $method)\n    {\n        $node->hasMethod('__construct')->willReturn(true);\n        $node->getMethod('__construct')->willReturn($method);\n        $node->getParentClass()->shouldBeCalled();\n\n        $method->useParentCode()->shouldBeCalled();\n\n        $this->apply($node);\n    }\n\n    function it_should_not_supply_a_file_for_a_directory_iterator(ClassNode $node, MethodNode $method)\n    {\n        $node->hasMethod('__construct')->willReturn(true);\n        $node->getMethod('__construct')->willReturn($method);\n        $node->getParentClass()->willReturn('DirectoryIterator');\n\n        $method->setCode(Argument::that(function ($value) {\n            return strpos($value, '.php') === false;\n        }))->shouldBeCalled();\n\n        $this->apply($node);\n    }\n\n    function it_should_supply_a_file_for_a_spl_file_object(ClassNode $node, MethodNode $method)\n    {\n        $node->hasMethod('__construct')->willReturn(true);\n        $node->getMethod('__construct')->willReturn($method);\n        $node->getParentClass()->willReturn('SplFileObject');\n\n        $method->setCode(Argument::that(function ($value) {\n            return strpos($value, '.php') !== false;\n        }))->shouldBeCalled();\n\n        $this->apply($node);\n    }\n\n    function it_should_supply_a_file_for_a_symfony_spl_file_info(ClassNode $node, MethodNode $method)\n    {\n        $node->hasMethod('__construct')->willReturn(true);\n        $node->getMethod('__construct')->willReturn($method);\n        $node->getParentClass()->willReturn('Symfony\\\\Component\\\\Finder\\\\SplFileInfo');\n\n        $method->setCode(Argument::that(function ($value) {\n            return strpos($value, '.php') !== false;\n        }))->shouldBeCalled();\n\n        $this->apply($node);\n    }\n}\n"
  },
  {
    "path": "spec/Prophecy/Doubler/ClassPatch/ThrowablePatchSpec.php",
    "content": "<?php\n\nnamespace spec\\Prophecy\\Doubler\\ClassPatch;\n\nuse PhpSpec\\ObjectBehavior;\nuse Prophecy\\Doubler\\Generator\\Node\\ClassNode;\n\nclass ThrowablePatchSpec extends ObjectBehavior\n{\n    function it_is_a_patch()\n    {\n        $this->shouldBeAnInstanceOf('Prophecy\\Doubler\\ClassPatch\\ClassPatchInterface');\n    }\n\n    function it_does_not_support_class_that_does_not_implement_throwable(ClassNode $node)\n    {\n        $node->getInterfaces()->willReturn(array());\n        $node->getParentClass()->willReturn('stdClass');\n\n        $this->supports($node)->shouldReturn(false);\n    }\n\n    function it_supports_class_that_extends_not_throwable_class(ClassNode $node)\n    {\n        $node->getInterfaces()->willReturn(array('Throwable'));\n        $node->getParentClass()->willReturn('stdClass');\n\n        $this->supports($node)->shouldReturn(true);\n    }\n\n    function it_does_not_support_class_that_already_extends_a_throwable_class(ClassNode $node)\n    {\n        $node->getInterfaces()->willReturn(array('Throwable'));\n        $node->getParentClass()->willReturn('InvalidArgumentException');\n\n        $this->supports($node)->shouldReturn(false);\n    }\n\n    function it_supports_class_implementing_interface_that_extends_throwable(ClassNode $node)\n    {\n        $node->getInterfaces()->willReturn(array('Fixtures\\Prophecy\\ThrowableInterface'));\n        $node->getParentClass()->willReturn('stdClass');\n\n        $this->supports($node)->shouldReturn(true);\n    }\n\n    function it_sets_the_parent_class_to_exception(ClassNode $node)\n    {\n        $node->getParentClass()->willReturn('stdClass');\n\n        $node->setParentClass('Exception')->shouldBeCalled();\n\n        $node->removeMethod('getMessage')->shouldBeCalled();\n        $node->removeMethod('getCode')->shouldBeCalled();\n        $node->removeMethod('getFile')->shouldBeCalled();\n        $node->removeMethod('getLine')->shouldBeCalled();\n        $node->removeMethod('getTrace')->shouldBeCalled();\n        $node->removeMethod('getPrevious')->shouldBeCalled();\n        $node->removeMethod('getNext')->shouldBeCalled();\n        $node->removeMethod('getTraceAsString')->shouldBeCalled();\n\n        $this->apply($node);\n    }\n\n    function it_throws_error_when_trying_to_double_concrete_class_and_throwable_interface(ClassNode $node)\n    {\n        $node->getParentClass()->willReturn('ArrayObject');\n\n        $this->shouldThrow('Prophecy\\Exception\\Doubler\\ClassCreatorException')->duringApply($node);\n    }\n}\n"
  },
  {
    "path": "spec/Prophecy/Doubler/ClassPatch/TraversablePatchSpec.php",
    "content": "<?php\n\nnamespace spec\\Prophecy\\Doubler\\ClassPatch;\n\nuse PhpSpec\\ObjectBehavior;\nuse Prophecy\\Argument;\nuse Prophecy\\Doubler\\Generator\\Node\\ClassNode;\nuse Prophecy\\Doubler\\Generator\\Node\\MethodNode;\n\nclass TraversablePatchSpec extends ObjectBehavior\n{\n    function it_is_a_patch()\n    {\n        $this->shouldBeAnInstanceOf('Prophecy\\Doubler\\ClassPatch\\ClassPatchInterface');\n    }\n\n    function it_supports_class_that_implements_only_Traversable(ClassNode $node)\n    {\n        $node->getInterfaces()->willReturn(array('Traversable'));\n\n        $this->supports($node)->shouldReturn(true);\n    }\n\n    function it_does_not_support_class_that_implements_Iterator(ClassNode $node)\n    {\n        $node->getInterfaces()->willReturn(array('Traversable', 'Iterator'));\n\n        $this->supports($node)->shouldReturn(false);\n    }\n\n    function it_does_not_support_class_that_implements_IteratorAggregate(ClassNode $node)\n    {\n        $node->getInterfaces()->willReturn(array('Traversable', 'IteratorAggregate'));\n\n        $this->supports($node)->shouldReturn(false);\n    }\n\n    function it_has_100_priority()\n    {\n        $this->getPriority()->shouldReturn(100);\n    }\n\n    function it_forces_node_to_implement_IteratorAggregate(ClassNode $node)\n    {\n        $node->addInterface('Iterator')->shouldBeCalled();\n\n        $node->addMethod(Argument::type('Prophecy\\Doubler\\Generator\\Node\\MethodNode'))->willReturn(null);\n\n        $this->apply($node);\n    }\n\n    function it_adds_methods_to_implement_iterator(ClassNode $node)\n    {\n        $node->addInterface('Iterator')->shouldBeCalled();\n\n        $methodReturnTypes = [\n            'current' => 'mixed',\n            'key' => 'mixed',\n            'next' => 'void',\n            'rewind' => 'void',\n            'valid' => 'bool',\n        ];\n\n        foreach ($methodReturnTypes as $methodName => $returnType) {\n            $node->addMethod(Argument::that(static function ($value) use ($methodName, $returnType) {\n                return $value instanceof MethodNode\n                    && $value->getName() === $methodName\n                    && (\\PHP_VERSION_ID < 80100 || $value->getReturnTypeNode()->getTypes() === [$returnType]);\n            }))->shouldBeCalled();\n        }\n\n        $this->apply($node);\n    }\n}\n"
  },
  {
    "path": "spec/Prophecy/Doubler/DoublerSpec.php",
    "content": "<?php\n\nnamespace spec\\Prophecy\\Doubler;\n\nuse PhpSpec\\ObjectBehavior;\nuse Prophecy\\Doubler\\ClassPatch\\ClassPatchInterface;\nuse Prophecy\\Doubler\\Generator\\ClassCreator;\nuse Prophecy\\Doubler\\Generator\\ClassMirror;\nuse Prophecy\\Doubler\\Generator\\Node\\ClassNode;\nuse Prophecy\\Doubler\\NameGenerator;\n\nclass DoublerSpec extends ObjectBehavior\n{\n    function let(ClassMirror $mirror, ClassCreator $creator, NameGenerator $namer)\n    {\n        $this->beConstructedWith($mirror, $creator, $namer);\n    }\n\n    function it_does_not_have_patches_by_default()\n    {\n        $this->getClassPatches()->shouldHaveCount(0);\n    }\n\n    function its_registerClassPatch_adds_a_patch_to_the_doubler(ClassPatchInterface $patch)\n    {\n        $this->registerClassPatch($patch);\n        $this->getClassPatches()->shouldReturn(array($patch));\n    }\n\n    function its_getClassPatches_sorts_patches_by_priority(\n        ClassPatchInterface $alt1,\n        ClassPatchInterface $alt2,\n        ClassPatchInterface $alt3,\n        ClassPatchInterface $alt4\n    ) {\n        $alt1->getPriority()->willReturn(2);\n        $alt2->getPriority()->willReturn(50);\n        $alt3->getPriority()->willReturn(10);\n        $alt4->getPriority()->willReturn(0);\n\n        $this->registerClassPatch($alt1);\n        $this->registerClassPatch($alt2);\n        $this->registerClassPatch($alt3);\n        $this->registerClassPatch($alt4);\n\n        $this->getClassPatches()->shouldReturn(array($alt2, $alt3, $alt1, $alt4));\n    }\n\n    function its_double_mirrors_alterates_and_instantiates_provided_class(\n        $mirror,\n        $creator,\n        $namer,\n        ClassPatchInterface $alt1,\n        ClassPatchInterface $alt2,\n        \\ReflectionClass $class,\n        \\ReflectionClass $interface1,\n        \\ReflectionClass $interface2,\n        ClassNode $node\n    ) {\n        $mirror->reflect($class, array($interface1, $interface2))->willReturn($node);\n        $alt1->supports($node)->willReturn(true);\n        $alt2->supports($node)->willReturn(false);\n        $alt1->getPriority()->willReturn(1);\n        $alt2->getPriority()->willReturn(2);\n        $namer->name($class, array($interface1, $interface2))->willReturn('SplStack');\n        $class->getName()->willReturn('stdClass');\n        $interface1->getName()->willReturn('ArrayAccess');\n        $interface2->getName()->willReturn('Iterator');\n\n        $alt1->apply($node)->shouldBeCalled();\n        $alt2->apply($node)->shouldNotBeCalled();\n        $creator->create('SplStack', $node)->shouldBeCalled();\n\n        $this->registerClassPatch($alt1);\n        $this->registerClassPatch($alt2);\n\n        $this->double($class, array($interface1, $interface2))\n            ->shouldReturnAnInstanceOf('SplStack');\n    }\n\n    function it_double_instantiates_a_class_with_constructor_argument(\n        $mirror,\n        \\ReflectionClass $class,\n        ClassNode $node,\n        $namer\n    ) {\n        $class->getName()->willReturn('ReflectionClass');\n        $mirror->reflect($class, array())->willReturn($node);\n        $namer->name($class, array())->willReturn('ReflectionClass');\n\n        $double = $this->double($class, array(), array('stdClass'));\n        $double->shouldBeAnInstanceOf('ReflectionClass');\n        $double->getName()->shouldReturn('stdClass');\n    }\n\n    function it_can_instantiate_class_with_final_constructor(\n        $mirror,\n        \\ReflectionClass $class,\n        ClassNode $node,\n        $namer\n    ) {\n        $class->getName()->willReturn('spec\\Prophecy\\Doubler\\WithFinalConstructor');\n        $mirror->reflect($class, array())->willReturn($node);\n        $namer->name($class, array())->willReturn('spec\\Prophecy\\Doubler\\WithFinalConstructor');\n\n        $double = $this->double($class, array());\n\n        $double->shouldBeAnInstanceOf('spec\\Prophecy\\Doubler\\WithFinalConstructor');\n    }\n}\n\nclass WithFinalConstructor\n{\n    final public function __construct() {}\n}\n"
  },
  {
    "path": "spec/Prophecy/Doubler/Generator/ClassCodeGeneratorSpec.php",
    "content": "<?php\n\nnamespace spec\\Prophecy\\Doubler\\Generator;\n\nuse PhpSpec\\ObjectBehavior;\nuse Prophecy\\Doubler\\Generator\\Node\\ArgumentNode;\nuse Prophecy\\Doubler\\Generator\\Node\\ArgumentTypeNode;\nuse Prophecy\\Doubler\\Generator\\Node\\ClassNode;\nuse Prophecy\\Doubler\\Generator\\Node\\MethodNode;\nuse Prophecy\\Doubler\\Generator\\Node\\ReturnTypeNode;\nuse Prophecy\\Doubler\\Generator\\Node\\Type\\BuiltinType;\nuse Prophecy\\Doubler\\Generator\\Node\\Type\\IntersectionType;\nuse Prophecy\\Doubler\\Generator\\Node\\Type\\ObjectType;\nuse Prophecy\\Doubler\\Generator\\Node\\Type\\UnionType;\n\nclass ClassCodeGeneratorSpec extends ObjectBehavior\n{\n    function it_generates_proper_php_code_for_specific_ClassNode(\n        ClassNode $class,\n        MethodNode $method1,\n        MethodNode $method2,\n        MethodNode $method3,\n        MethodNode $method4,\n        MethodNode $method5,\n        ArgumentNode $argument11,\n        ArgumentNode $argument12,\n        ArgumentNode $argument13,\n        ArgumentNode $argument21,\n        ArgumentNode $argument31\n    ) {\n        $class->getParentClass()->willReturn('RuntimeException');\n        $class->getInterfaces()->willReturn(array(\n            'Prophecy\\Doubler\\Generator\\MirroredInterface', 'ArrayAccess', 'ArrayIterator',\n        ));\n        $class->getProperties()->willReturn(array('name' => 'public', 'email' => 'private'));\n        $class->getMethods()->willReturn(array($method1, $method2, $method3, $method4, $method5));\n        $class->isReadOnly()->willReturn(false);\n\n        $method1->getName()->willReturn('getName');\n        $method1->getVisibility()->willReturn('public');\n        $method1->returnsReference()->willReturn(false);\n        $method1->isStatic()->willReturn(true);\n        $method1->getArguments()->willReturn(array($argument11, $argument12, $argument13));\n        $method1->getReturnTypeNode()->willReturn(new ReturnTypeNode(new UnionType([\n            new BuiltinType('string'),\n            new BuiltinType('null'),\n        ])));\n        $method1->getCode()->willReturn('return $this->name;');\n\n        $method2->getName()->willReturn('getEmail');\n        $method2->getVisibility()->willReturn('protected');\n        $method2->returnsReference()->willReturn(false);\n        $method2->isStatic()->willReturn(false);\n        $method2->getArguments()->willReturn(array($argument21));\n        $method2->getReturnTypeNode()->willReturn(new ReturnTypeNode());\n        $method2->getCode()->willReturn('return $this->email;');\n\n        $method3->getName()->willReturn('getRefValue');\n        $method3->getVisibility()->willReturn('public');\n        $method3->returnsReference()->willReturn(true);\n        $method3->isStatic()->willReturn(false);\n        $method3->getArguments()->willReturn(array($argument31));\n        $method3->getReturnTypeNode()->willReturn(new ReturnTypeNode(new BuiltinType('string')));\n        $method3->getCode()->willReturn('return $this->refValue;');\n\n        $method4->getName()->willReturn('doSomething');\n        $method4->getVisibility()->willReturn('public');\n        $method4->returnsReference()->willReturn(false);\n        $method4->isStatic()->willReturn(false);\n        $method4->getArguments()->willReturn(array());\n        $method4->getReturnTypeNode()->willReturn(new ReturnTypeNode(new BuiltinType('void')));\n        $method4->getCode()->willReturn('return;');\n\n        $method5->getName()->willReturn('returnObject');\n        $method5->getVisibility()->willReturn('public');\n        $method5->returnsReference()->willReturn(false);\n        $method5->isStatic()->willReturn(false);\n        $method5->getArguments()->willReturn(array());\n        $method5->getReturnTypeNode()->willReturn(new ReturnTypeNode(new BuiltinType('object')));\n        $method5->getCode()->willReturn('return;');\n\n        $argument11->getName()->willReturn('fullname');\n        $argument11->isOptional()->willReturn(false);\n        $argument11->isPassedByReference()->willReturn(false);\n        $argument11->isVariadic()->willReturn(false);\n        $argument11->getTypeNode()->willReturn(new ArgumentTypeNode(new BuiltinType('array')));\n\n        $argument12->getName()->willReturn('class');\n        $argument12->isOptional()->willReturn(false);\n        $argument12->isPassedByReference()->willReturn(false);\n        $argument12->isVariadic()->willReturn(false);\n        $argument12->getTypeNode()->willReturn(new ArgumentTypeNode(new ObjectType('ReflectionClass')));\n\n        $argument13->getName()->willReturn('instance');\n        $argument13->isOptional()->willReturn(false);\n        $argument13->isPassedByReference()->willReturn(false);\n        $argument13->isVariadic()->willReturn(false);\n        $argument13->getTypeNode()->willReturn(new ArgumentTypeNode(new BuiltinType('object')));\n\n        $argument21->getName()->willReturn('default');\n        $argument21->isOptional()->willReturn(true);\n        $argument21->getDefault()->willReturn('ever.zet@gmail.com');\n        $argument21->isPassedByReference()->willReturn(false);\n        $argument21->isVariadic()->willReturn(false);\n        $argument21->getTypeNode()->willReturn(new ArgumentTypeNode(new UnionType([\n            new BuiltinType('string'),\n            new BuiltinType('null'),\n        ])));\n\n        $argument31->getName()->willReturn('refValue');\n        $argument31->isOptional()->willReturn(false);\n        $argument31->getDefault()->willReturn();\n        $argument31->isPassedByReference()->willReturn(false);\n        $argument31->isVariadic()->willReturn(false);\n        $argument31->getTypeNode()->willReturn(new ArgumentTypeNode());\n\n\n        $code = $this->generate('CustomClass', $class);\n\n        $expected = <<<'PHP'\nnamespace  {\nclass CustomClass extends \\RuntimeException implements \\Prophecy\\Doubler\\Generator\\MirroredInterface, \\ArrayAccess, \\ArrayIterator {\npublic $name;\nprivate $email;\n\npublic static function getName(array $fullname, \\ReflectionClass $class, object $instance): string|null {\nreturn $this->name;\n}\nprotected  function getEmail(string|null $default = 'ever.zet@gmail.com') {\nreturn $this->email;\n}\npublic  function &getRefValue( $refValue): string {\nreturn $this->refValue;\n}\npublic  function doSomething(): void {\nreturn;\n}\npublic  function returnObject(): object {\nreturn;\n}\n\n}\n}\nPHP;\n\n        $expected = strtr($expected, array(\"\\r\\n\" => \"\\n\", \"\\r\" => \"\\n\"));\n        $code->shouldBe($expected);\n    }\n\n    function it_generates_proper_php_code_for_variadics(\n        ClassNode $class,\n        MethodNode $method1,\n        MethodNode $method2,\n        MethodNode $method3,\n        MethodNode $method4,\n        ArgumentNode $argument1,\n        ArgumentNode $argument2,\n        ArgumentNode $argument3,\n        ArgumentNode $argument4\n    ) {\n        $class->getParentClass()->willReturn('stdClass');\n        $class->getInterfaces()->willReturn(array('Prophecy\\Doubler\\Generator\\MirroredInterface'));\n        $class->getProperties()->willReturn(array());\n        $class->getMethods()->willReturn(array(\n            $method1, $method2, $method3, $method4,\n        ));\n        $class->isReadOnly()->willReturn(false);\n\n        $method1->getName()->willReturn('variadic');\n        $method1->getVisibility()->willReturn('public');\n        $method1->returnsReference()->willReturn(false);\n        $method1->isStatic()->willReturn(false);\n        $method1->getArguments()->willReturn(array($argument1));\n        $method1->getReturnTypeNode()->willReturn(new ReturnTypeNode());\n        $method1->getCode()->willReturn('');\n\n        $method2->getName()->willReturn('variadicByRef');\n        $method2->getVisibility()->willReturn('public');\n        $method2->returnsReference()->willReturn(false);\n        $method2->isStatic()->willReturn(false);\n        $method2->getArguments()->willReturn(array($argument2));\n        $method2->getReturnTypeNode()->willReturn(new ReturnTypeNode());\n        $method2->getCode()->willReturn('');\n\n        $method3->getName()->willReturn('variadicWithType');\n        $method3->getVisibility()->willReturn('public');\n        $method3->returnsReference()->willReturn(false);\n        $method3->isStatic()->willReturn(false);\n        $method3->getArguments()->willReturn(array($argument3));\n        $method3->getReturnTypeNode()->willReturn(new ReturnTypeNode());\n        $method3->getCode()->willReturn('');\n\n        $method4->getName()->willReturn('variadicWithTypeByRef');\n        $method4->getVisibility()->willReturn('public');\n        $method4->returnsReference()->willReturn(false);\n        $method4->isStatic()->willReturn(false);\n        $method4->getArguments()->willReturn(array($argument4));\n        $method4->getReturnTypeNode()->willReturn(new ReturnTypeNode());\n        $method4->getCode()->willReturn('');\n\n        $argument1->getName()->willReturn('args');\n        $argument1->isOptional()->willReturn(false);\n        $argument1->isPassedByReference()->willReturn(false);\n        $argument1->isVariadic()->willReturn(true);\n        $argument1->getTypeNode()->willReturn(new ArgumentTypeNode());\n\n        $argument2->getName()->willReturn('args');\n        $argument2->isOptional()->willReturn(false);\n        $argument2->isPassedByReference()->willReturn(true);\n        $argument2->isVariadic()->willReturn(true);\n        $argument2->getTypeNode()->willReturn(new ArgumentTypeNode());\n\n        $argument3->getName()->willReturn('args');\n        $argument3->isOptional()->willReturn(false);\n        $argument3->isPassedByReference()->willReturn(false);\n        $argument3->isVariadic()->willReturn(true);\n        $argument3->getTypeNode()->willReturn(new ArgumentTypeNode(new ObjectType('ReflectionClass')));\n\n        $argument4->getName()->willReturn('args');\n        $argument4->isOptional()->willReturn(false);\n        $argument4->isPassedByReference()->willReturn(true);\n        $argument4->isVariadic()->willReturn(true);\n        $argument4->getTypeNode()->willReturn(new ArgumentTypeNode(new ObjectType('ReflectionClass')));\n\n\n        $code = $this->generate('CustomClass', $class);\n        $expected = <<<'PHP'\nnamespace  {\nclass CustomClass extends \\stdClass implements \\Prophecy\\Doubler\\Generator\\MirroredInterface {\n\npublic  function variadic( ...$args) {\n\n}\npublic  function variadicByRef( &...$args) {\n\n}\npublic  function variadicWithType(\\ReflectionClass ...$args) {\n\n}\npublic  function variadicWithTypeByRef(\\ReflectionClass &...$args) {\n\n}\n\n}\n}\nPHP;\n        $expected = strtr($expected, array(\"\\r\\n\" => \"\\n\", \"\\r\" => \"\\n\"));\n        $code->shouldBe($expected);\n    }\n\n    function it_overrides_properly_methods_with_args_passed_by_reference(\n        ClassNode $class,\n        MethodNode $method,\n        ArgumentNode $argument\n    ) {\n        $class->getParentClass()->willReturn('RuntimeException');\n        $class->getInterfaces()->willReturn(array('Prophecy\\Doubler\\Generator\\MirroredInterface'));\n        $class->getProperties()->willReturn(array());\n        $class->getMethods()->willReturn(array($method));\n        $class->isReadOnly()->willReturn(false);\n\n        $method->getName()->willReturn('getName');\n        $method->getVisibility()->willReturn('public');\n        $method->isStatic()->willReturn(false);\n        $method->getArguments()->willReturn(array($argument));\n        $method->getReturnTypeNode()->willReturn(new ReturnTypeNode());\n        $method->returnsReference()->willReturn(false);\n        $method->getCode()->willReturn('return $this->name;');\n\n        $argument->getName()->willReturn('fullname');\n        $argument->isOptional()->willReturn(true);\n        $argument->getDefault()->willReturn(null);\n        $argument->isPassedByReference()->willReturn(true);\n        $argument->isVariadic()->willReturn(false);\n        $argument->getTypeNode()->willReturn(new ArgumentTypeNode(new UnionType([\n            new BuiltinType('array'),\n            new BuiltinType('null'),\n        ])));\n\n        $code = $this->generate('CustomClass', $class);\n        $expected = <<<'PHP'\nnamespace  {\nclass CustomClass extends \\RuntimeException implements \\Prophecy\\Doubler\\Generator\\MirroredInterface {\n\npublic  function getName(array|null &$fullname = NULL) {\nreturn $this->name;\n}\n\n}\n}\nPHP;\n        $expected = strtr($expected, array(\"\\r\\n\" => \"\\n\", \"\\r\" => \"\\n\"));\n        $code->shouldBe($expected);\n    }\n\n    function it_generates_proper_code_for_union_return_types(\n        ClassNode $class,\n        MethodNode $method\n    ) {\n        $class->getParentClass()->willReturn('stdClass');\n        $class->getInterfaces()->willReturn([]);\n        $class->getProperties()->willReturn([]);\n        $class->getMethods()->willReturn(array($method));\n        $class->isReadOnly()->willReturn(false);\n\n        $method->getName()->willReturn('foo');\n        $method->getVisibility()->willReturn('public');\n        $method->isStatic()->willReturn(false);\n        $method->getArguments()->willReturn([]);\n        $method->getReturnTypeNode()->willReturn(new ReturnTypeNode(new UnionType([\n            new BuiltinType('int'),\n            new BuiltinType('string'),\n            new BuiltinType('null'),\n        ])));\n        $method->returnsReference()->willReturn(false);\n        $method->getCode()->willReturn('');\n\n        $code = $this->generate('CustomClass', $class);\n\n        $expected = <<<'PHP'\nnamespace  {\nclass CustomClass extends \\stdClass implements  {\n\npublic  function foo(): int|string|null {\n\n}\n\n}\n}\nPHP;\n        $expected = strtr($expected, array(\"\\r\\n\" => \"\\n\", \"\\r\" => \"\\n\"));\n\n        $code->shouldBe($expected);\n    }\n\n    function it_generates_proper_code_for_dnf_types(\n        ClassNode $class,\n        MethodNode $method\n    ) {\n        $class->getParentClass()->willReturn('stdClass');\n        $class->getInterfaces()->willReturn([]);\n        $class->getProperties()->willReturn([]);\n        $class->getMethods()->willReturn(array($method));\n        $class->isReadOnly()->willReturn(false);\n\n        $method->getName()->willReturn('foo');\n        $method->getVisibility()->willReturn('public');\n        $method->isStatic()->willReturn(false);\n        $method->getArguments()->willReturn([]);\n        $method->getReturnTypeNode()->willReturn(new ReturnTypeNode(\n            new UnionType([\n                new IntersectionType([new ObjectType('Foo'), new ObjectType('Bar')]),\n                new BuiltinType('string'),\n            ])\n        ));\n        $method->returnsReference()->willReturn(false);\n        $method->getCode()->willReturn('');\n\n        $code = $this->generate('CustomClass', $class);\n\n        $expected = <<<'PHP'\nnamespace  {\nclass CustomClass extends \\stdClass implements  {\n\npublic  function foo(): (\\Foo&\\Bar)|string {\n\n}\n\n}\n}\nPHP;\n        $expected = strtr($expected, array(\"\\r\\n\" => \"\\n\", \"\\r\" => \"\\n\"));\n\n        $code->shouldBe($expected);\n    }\n\n\n    function it_generates_proper_code_for_intersection_return_types(\n        ClassNode $class,\n        MethodNode $method\n    ) {\n        $class->getParentClass()->willReturn('stdClass');\n        $class->getInterfaces()->willReturn([]);\n        $class->getProperties()->willReturn([]);\n        $class->getMethods()->willReturn(array($method));\n        $class->isReadOnly()->willReturn(false);\n\n        $method->getName()->willReturn('foo');\n        $method->getVisibility()->willReturn('public');\n        $method->isStatic()->willReturn(false);\n        $method->getArguments()->willReturn([]);\n        $method->getReturnTypeNode()->willReturn(new ReturnTypeNode(\n            new IntersectionType([new ObjectType('Foo'), new ObjectType('Bar')])\n        ));\n        $method->returnsReference()->willReturn(false);\n        $method->getCode()->willReturn('');\n\n        $code = $this->generate('CustomClass', $class);\n\n        $expected = <<<'PHP'\nnamespace  {\nclass CustomClass extends \\stdClass implements  {\n\npublic  function foo(): \\Foo&\\Bar {\n\n}\n\n}\n}\nPHP;\n        $expected = strtr($expected, array(\"\\r\\n\" => \"\\n\", \"\\r\" => \"\\n\"));\n\n        $code->shouldBe($expected);\n    }\n\n    function it_generates_proper_code_for_union_argument_types(\n        ClassNode $class,\n        MethodNode $method,\n        ArgumentNode $argument\n    ) {\n        $class->getParentClass()->willReturn('stdClass');\n        $class->getInterfaces()->willReturn([]);\n        $class->getProperties()->willReturn([]);\n        $class->getMethods()->willReturn(array($method));\n        $class->isReadOnly()->willReturn(false);\n\n        $method->getName()->willReturn('foo');\n        $method->getVisibility()->willReturn('public');\n        $method->isStatic()->willReturn(false);\n        $method->getArguments()->willReturn([$argument]);\n        $method->getReturnTypeNode()->willReturn(new ReturnTypeNode());\n        $method->returnsReference()->willReturn(false);\n        $method->getCode()->willReturn('');\n\n        $argument->getTypeNode()->willReturn(new ArgumentTypeNode(new UnionType([\n            new BuiltinType('int'),\n            new BuiltinType('string'),\n            new BuiltinType('null'),\n        ])));\n        $argument->getName()->willReturn('arg');\n        $argument->isPassedByReference()->willReturn(false);\n        $argument->isVariadic()->willReturn(false);\n        $argument->isOptional()->willReturn(false);\n\n        $code = $this->generate('CustomClass', $class);\n\n        $expected = <<<'PHP'\nnamespace  {\nclass CustomClass extends \\stdClass implements  {\n\npublic  function foo(int|string|null $arg) {\n\n}\n\n}\n}\nPHP;\n        $expected = strtr($expected, array(\"\\r\\n\" => \"\\n\", \"\\r\" => \"\\n\"));\n\n        $code->shouldBe($expected);\n    }\n\n    function it_generates_empty_class_for_empty_ClassNode(ClassNode $class)\n    {\n        $class->getParentClass()->willReturn('stdClass');\n        $class->getInterfaces()->willReturn(array('Prophecy\\Doubler\\Generator\\MirroredInterface'));\n        $class->getProperties()->willReturn(array());\n        $class->getMethods()->willReturn(array());\n        $class->isReadOnly()->willReturn(false);\n\n        $code = $this->generate('CustomClass', $class);\n        $expected = <<<'PHP'\nnamespace  {\nclass CustomClass extends \\stdClass implements \\Prophecy\\Doubler\\Generator\\MirroredInterface {\n\n\n}\n}\nPHP;\n        $expected = strtr($expected, array(\"\\r\\n\" => \"\\n\", \"\\r\" => \"\\n\"));\n        $code->shouldBe($expected);\n    }\n\n    function it_wraps_class_in_namespace_if_it_is_namespaced(ClassNode $class)\n    {\n        $class->getParentClass()->willReturn('stdClass');\n        $class->getInterfaces()->willReturn(array('Prophecy\\Doubler\\Generator\\MirroredInterface'));\n        $class->getProperties()->willReturn(array());\n        $class->getMethods()->willReturn(array());\n        $class->isReadOnly()->willReturn(false);\n\n        $code = $this->generate('My\\Awesome\\CustomClass', $class);\n        $expected = <<<'PHP'\nnamespace My\\Awesome {\nclass CustomClass extends \\stdClass implements \\Prophecy\\Doubler\\Generator\\MirroredInterface {\n\n\n}\n}\nPHP;\n        $expected = strtr($expected, array(\"\\r\\n\" => \"\\n\", \"\\r\" => \"\\n\"));\n        $code->shouldBe($expected);\n    }\n\n    function it_generates_read_only_class_if_parent_class_is_read_only(ClassNode $class)\n    {\n        $class->getParentClass()->willReturn('ReadOnlyClass');\n        $class->getInterfaces()->willReturn(array('Prophecy\\Doubler\\Generator\\MirroredInterface'));\n        $class->getProperties()->willReturn(array());\n        $class->getMethods()->willReturn(array());\n        $class->isReadOnly()->willReturn(true);\n\n        $code = $this->generate('CustomClass', $class);\n        $expected = <<<'PHP'\nnamespace  {\nreadonly class CustomClass extends \\ReadOnlyClass implements \\Prophecy\\Doubler\\Generator\\MirroredInterface {\n\n\n}\n}\nPHP;\n        $expected = strtr($expected, array(\"\\r\\n\" => \"\\n\", \"\\r\" => \"\\n\"));\n        $code->shouldBe($expected);\n    }\n}\n"
  },
  {
    "path": "spec/Prophecy/Doubler/Generator/ClassCreatorSpec.php",
    "content": "<?php\n\nnamespace spec\\Prophecy\\Doubler\\Generator;\n\nuse PhpSpec\\ObjectBehavior;\nuse Prophecy\\Doubler\\Generator\\ClassCodeGenerator;\nuse Prophecy\\Doubler\\Generator\\Node\\ClassNode;\n\nclass ClassCreatorSpec extends ObjectBehavior\n{\n    function let(ClassCodeGenerator $generator)\n    {\n        $this->beConstructedWith($generator);\n    }\n\n    function it_evaluates_code_generated_by_ClassCodeGenerator($generator, ClassNode $class)\n    {\n        $generator->generate('stdClass', $class)->shouldBeCalled()->willReturn(\n            'return 42;'\n        );\n\n        $this->create('stdClass', $class)->shouldReturn(42);\n    }\n\n    function it_throws_an_exception_if_class_does_not_exist_after_evaluation($generator, ClassNode $class)\n    {\n        $generator->generate('CustomClass', $class)->shouldBeCalled()->willReturn(\n            'return 42;'\n        );\n\n        $class->getParentClass()->willReturn('stdClass');\n        $class->getInterfaces()->willReturn(array('Interface1', 'Interface2'));\n\n        $this->shouldThrow('Prophecy\\Exception\\Doubler\\ClassCreatorException')\n            ->duringCreate('CustomClass', $class);\n    }\n}\n"
  },
  {
    "path": "spec/Prophecy/Doubler/Generator/Node/ArgumentNodeSpec.php",
    "content": "<?php\n\nnamespace spec\\Prophecy\\Doubler\\Generator\\Node;\n\nuse PhpSpec\\ObjectBehavior;\nuse Prophecy\\Doubler\\Generator\\Node\\ArgumentTypeNode;\nuse Prophecy\\Doubler\\Generator\\Node\\Type\\BuiltinType;\n\nclass ArgumentNodeSpec extends ObjectBehavior\n{\n    function let()\n    {\n        $this->beConstructedWith('name');\n    }\n\n    function it_is_not_be_passed_by_reference_by_default()\n    {\n        $this->shouldNotBePassedByReference();\n    }\n\n    function it_is_passed_by_reference_if_marked()\n    {\n        $this->setAsPassedByReference();\n        $this->shouldBePassedByReference();\n    }\n\n    function it_is_not_variadic_by_default()\n    {\n        $this->shouldNotBeVariadic();\n    }\n\n    function it_is_variadic_if_marked()\n    {\n        $this->setAsVariadic();\n        $this->shouldBeVariadic();\n    }\n\n    function it_does_not_have_default_by_default()\n    {\n        $this->shouldNotHaveDefault();\n    }\n\n    function it_does_not_have_default_if_variadic()\n    {\n        $this->setDefault(null);\n        $this->setAsVariadic();\n        $this->shouldNotHaveDefault();\n    }\n\n    function it_does_have_default_if_not_variadic()\n    {\n        $this->setDefault(null);\n        $this->setAsVariadic(false);\n        $this->hasDefault()->shouldReturn(true);\n    }\n\n    function it_has_name_with_which_it_was_been_constructed()\n    {\n        $this->getName()->shouldReturn('name');\n    }\n\n    function it_has_no_typehint_by_default()\n    {\n        $this->getTypeHint()->shouldReturn(null);\n    }\n\n    function its_typeHint_is_mutable_with_deprecated_accessors()\n    {\n        $this->setTypeHint('array');\n        $this->getTypeHint()->shouldReturn('array');\n    }\n\n    function it_can_set_nullable_type_using_deprecated_method()\n    {\n        $this->setTypeHint('int');\n\n        $this->setAsNullable();\n\n        $this->shouldBeNullable();\n    }\n\n    function it_can_unset_nullable_type_using_deprecated_method()\n    {\n        $this->setTypeHint('int');\n\n        $this->setAsNullable(false);\n\n        $this->shouldNotBeNullable();\n    }\n\n    function it_has_an_empty_type_by_default()\n    {\n        $this->getTypeNode()->shouldBeLike(new ArgumentTypeNode());\n    }\n\n    function it_has_a_mutable_type()\n    {\n        $this->setTypeNode(new ArgumentTypeNode(new BuiltinType('int')));\n\n        $this->getTypeNode()->shouldBeLike(new ArgumentTypeNode(new BuiltinType('int')));\n    }\n\n    function it_does_not_have_default_value_by_default()\n    {\n        $this->getDefault()->shouldReturn(null);\n    }\n\n    function it_is_not_optional_by_default()\n    {\n        $this->isOptional()->shouldReturn(false);\n    }\n\n    function its_default_is_mutable()\n    {\n        $this->setDefault(array());\n        $this->getDefault()->shouldReturn(array());\n    }\n\n    function it_is_marked_as_optional_when_default_is_set()\n    {\n        $this->setDefault(null);\n        $this->isOptional()->shouldReturn(true);\n    }\n}\n"
  },
  {
    "path": "spec/Prophecy/Doubler/Generator/Node/ArgumentTypeNodeSpec.php",
    "content": "<?php\n\nnamespace spec\\Prophecy\\Doubler\\Generator\\Node;\n\nuse PhpSpec\\ObjectBehavior;\nuse Prophecy\\Exception\\Doubler\\DoubleException;\n\nclass ArgumentTypeNodeSpec extends ObjectBehavior\n{\n    function it_has_no_types_at_start()\n    {\n        $this->getTypes()->shouldReturn([]);\n    }\n\n    function it_can_have_a_simple_type()\n    {\n        $this->beConstructedWith('int');\n\n        $this->getTypes()->shouldReturn(['int']);\n    }\n\n    function it_can_have_multiple_types()\n    {\n        $this->beConstructedWith('int', 'string');\n\n        $this->getTypes()->shouldReturn(['int', 'string']);\n    }\n\n    function it_will_prefix_fcqns()\n    {\n        $this->beConstructedWith('Foo');\n\n        $this->getTypes()->shouldReturn(['\\\\Foo']);\n    }\n\n    function it_will_not_prefix_fcqns_that_already_have_prefix()\n    {\n        $this->beConstructedWith('\\\\Foo');\n\n        $this->getTypes()->shouldReturn(['\\\\Foo']);\n    }\n\n    function it_can_use_shorthand_null_syntax_if_it_has_single_type_plus_null()\n    {\n        $this->beConstructedWith('int', 'null');\n\n        $this->canUseNullShorthand()->shouldReturn(true);\n    }\n\n    function it_can_not_use_shorthand_null_syntax_if_it_does_not_allow_null()\n    {\n        $this->beConstructedWith('int');\n\n        $this->canUseNullShorthand()->shouldReturn(false);\n    }\n\n    function it_can_not_use_shorthand_null_syntax_if_it_has_more_than_one_non_null_type()\n    {\n        $this->beConstructedWith('int', 'string', 'null');\n\n        $this->canUseNullShorthand()->shouldReturn(false);\n    }\n\n    function it_can_return_non_null_types()\n    {\n        $this->beConstructedWith('int', 'null');\n\n        $this->getNonNullTypes()->shouldReturn(['int']);\n    }\n\n    function it_does_not_allow_union_mixed()\n    {\n        $this->beConstructedWith('mixed', 'int');\n\n        if (PHP_VERSION_ID >= 80000) {\n            $this->shouldThrow(DoubleException::class)->duringInstantiation();\n        }\n    }\n\n    function it_does_not_prefix_false()\n    {\n        $this->beConstructedWith('false', 'array');\n\n        $this->getTypes()->shouldReturn(['false', 'array']);\n    }\n\n    function it_allows_standalone_false()\n    {\n        $this->beConstructedWith('false');\n\n        if (PHP_VERSION_ID >= 80000 && PHP_VERSION_ID < 80200) {\n            $this->shouldThrow(DoubleException::class)->duringInstantiation();\n        }\n\n        if (PHP_VERSION_ID >= 80200) {\n            $this->getTypes()->shouldReturn(['false']);\n        }\n    }\n\n    function it_allows_standalone_null()\n    {\n        $this->beConstructedWith('null');\n\n        if (PHP_VERSION_ID >= 80000 && PHP_VERSION_ID < 80200) {\n            $this->shouldThrow(DoubleException::class)->duringInstantiation();\n        }\n\n        if (PHP_VERSION_ID >= 80200) {\n            $this->getTypes()->shouldReturn(['null']);\n        }\n    }\n\n    function it_allows_standalone_true()\n    {\n        $this->beConstructedWith('true');\n\n        if (PHP_VERSION_ID >= 80000 && PHP_VERSION_ID < 80200) {\n            $this->shouldThrow(DoubleException::class)->duringInstantiation();\n        }\n\n        if (PHP_VERSION_ID >= 80200) {\n            $this->getTypes()->shouldReturn(['true']);\n        }\n    }\n\n    function it_allows_nullable_false()\n    {\n        $this->beConstructedWith('null', 'false');\n\n        if (PHP_VERSION_ID >= 80000 && PHP_VERSION_ID < 80200) {\n            $this->shouldThrow(DoubleException::class)->duringInstantiation();\n        }\n\n        if (PHP_VERSION_ID >= 80200) {\n            $this->getTypes()->shouldReturn(['null', 'false']);\n        }\n    }\n\n    function it_allows_nullable_true()\n    {\n        $this->beConstructedWith('null', 'true');\n\n        if (PHP_VERSION_ID >= 80000 && PHP_VERSION_ID < 80200) {\n            $this->shouldThrow(DoubleException::class)->duringInstantiation();\n        }\n\n        if (PHP_VERSION_ID >= 80200) {\n            $this->getTypes()->shouldReturn(['null', 'true']);\n        }\n    }\n\n    function it_allows_union_with_false()\n    {\n        $this->beConstructedWith('false', 'Foo');\n\n        if (PHP_VERSION_ID >= 80000) {\n            $this->getTypes()->shouldReturn(['false', '\\\\Foo']);\n        }\n    }\n}\n"
  },
  {
    "path": "spec/Prophecy/Doubler/Generator/Node/ClassNodeSpec.php",
    "content": "<?php\n\nnamespace spec\\Prophecy\\Doubler\\Generator\\Node;\n\nuse PhpSpec\\ObjectBehavior;\nuse Prophecy\\Doubler\\Generator\\Node\\MethodNode;\nuse Prophecy\\Exception\\Doubler\\MethodNotExtendableException;\n\nclass ClassNodeSpec extends ObjectBehavior\n{\n    function its_parentClass_is_a_stdClass_by_default()\n    {\n        $this->getParentClass()->shouldReturn('stdClass');\n    }\n\n    function its_parentClass_is_mutable()\n    {\n        $this->setParentClass('Exception');\n        $this->getParentClass()->shouldReturn('Exception');\n    }\n\n    function its_parentClass_is_set_to_stdClass_if_user_set_null()\n    {\n        $this->setParentClass(null);\n        $this->getParentClass()->shouldReturn('stdClass');\n    }\n\n    function it_does_not_implement_any_interface_by_default()\n    {\n        $this->getInterfaces()->shouldHaveCount(0);\n    }\n\n    function its_addInterface_adds_item_to_the_list_of_implemented_interfaces()\n    {\n        $this->addInterface('MyInterface');\n        $this->getInterfaces()->shouldHaveCount(1);\n    }\n\n    function its_hasInterface_returns_true_if_class_implements_interface()\n    {\n        $this->addInterface('MyInterface');\n        $this->hasInterface('MyInterface')->shouldReturn(true);\n    }\n\n    function its_hasInterface_returns_false_if_class_does_not_implements_interface()\n    {\n        $this->hasInterface('MyInterface')->shouldReturn(false);\n    }\n\n    function it_supports_implementation_of_multiple_interfaces()\n    {\n        $this->addInterface('MyInterface');\n        $this->addInterface('MySecondInterface');\n        $this->getInterfaces()->shouldHaveCount(2);\n    }\n\n    function it_ignores_same_interfaces_added_twice()\n    {\n        $this->addInterface('MyInterface');\n        $this->addInterface('MyInterface');\n\n        $this->getInterfaces()->shouldHaveCount(1);\n        $this->getInterfaces()->shouldReturn(array('MyInterface'));\n    }\n\n    function it_does_not_have_methods_by_default()\n    {\n        $this->getMethods()->shouldHaveCount(0);\n    }\n\n    function it_can_has_methods(MethodNode $method1, MethodNode $method2)\n    {\n        $method1->getName()->willReturn('__construct');\n        $method2->getName()->willReturn('getName');\n\n        $this->addMethod($method1);\n        $this->addMethod($method2);\n\n        $this->getMethods()->shouldReturn([\n            '__construct' => $method1,\n            'getName'     => $method2,\n        ]);\n    }\n\n    function its_hasMethod_returns_true_if_method_exists(MethodNode $method)\n    {\n        $method->getName()->willReturn('getName');\n\n        $this->addMethod($method);\n\n        $this->hasMethod('getName')->shouldReturn(true);\n    }\n\n    function its_getMethod_returns_method_by_name(MethodNode $method)\n    {\n        $method->getName()->willReturn('getName');\n\n        $this->addMethod($method);\n\n        $this->getMethod('getName')->shouldReturn($method);\n    }\n\n    function its_hasMethod_returns_false_if_method_does_not_exists()\n    {\n        $this->hasMethod('getName')->shouldReturn(false);\n    }\n\n    function its_hasMethod_returns_false_if_method_has_been_removed(MethodNode $method)\n    {\n        $method->getName()->willReturn('getName');\n        $this->addMethod($method);\n        $this->removeMethod('getName');\n\n        $this->hasMethod('getName')->shouldReturn(false);\n    }\n\n\n    function it_does_not_have_properties_by_default()\n    {\n        $this->getProperties()->shouldHaveCount(0);\n    }\n\n    function it_is_able_to_have_properties()\n    {\n        $this->addProperty('title');\n        $this->addProperty('text', 'private');\n        $this->getProperties()->shouldReturn(array(\n            'title' => 'public',\n            'text'  => 'private',\n        ));\n    }\n\n    function its_addProperty_does_not_accept_unsupported_visibility()\n    {\n        $this->shouldThrow('InvalidArgumentException')->duringAddProperty('title', 'town');\n    }\n\n    function its_addProperty_lowercases_visibility_before_setting()\n    {\n        $this->addProperty('text', 'PRIVATE');\n        $this->getProperties()->shouldReturn(array('text' => 'private'));\n    }\n\n    function its_has_no_unextendable_methods_by_default()\n    {\n        $this->getUnextendableMethods()->shouldHaveCount(0);\n    }\n\n    function its_addUnextendableMethods_adds_an_unextendable_method()\n    {\n        $this->addUnextendableMethod('testMethod');\n        $this->getUnextendableMethods()->shouldHaveCount(1);\n    }\n\n    function its_methods_are_extendable_by_default()\n    {\n        $this->isExtendable('testMethod')->shouldReturn(true);\n    }\n\n    function its_unextendable_methods_are_not_extendable()\n    {\n        $this->addUnextendableMethod('testMethod');\n        $this->isExtendable('testMethod')->shouldReturn(false);\n    }\n\n    function its_addUnextendableMethods_doesnt_create_duplicates()\n    {\n        $this->addUnextendableMethod('testMethod');\n        $this->addUnextendableMethod('testMethod');\n        $this->getUnextendableMethods()->shouldHaveCount(1);\n    }\n\n    function it_throws_an_exception_when_adding_a_method_that_isnt_extendable(MethodNode $method)\n    {\n        $this->addUnextendableMethod('testMethod');\n        $method->getName()->willReturn('testMethod');\n\n        $expectedException = new MethodNotExtendableException(\n            \"Method `testMethod` is not extendable, so can not be added.\",\n            \"stdClass\",\n            \"testMethod\"\n        );\n        $this->shouldThrow($expectedException)->duringAddMethod($method);\n    }\n\n    function it_is_non_read_only_by_default()\n    {\n        $this->isReadOnly()->shouldReturn(false);\n    }\n\n    function its_read_only_is_mutable()\n    {\n        $this->setReadOnly(true);\n\n        $this->isReadOnly()->shouldReturn(true);\n    }\n}\n"
  },
  {
    "path": "spec/Prophecy/Doubler/Generator/Node/MethodNodeSpec.php",
    "content": "<?php\n\nnamespace spec\\Prophecy\\Doubler\\Generator\\Node;\n\nuse PhpSpec\\ObjectBehavior;\nuse Prophecy\\Doubler\\Generator\\Node\\ArgumentNode;\nuse Prophecy\\Doubler\\Generator\\Node\\ReturnTypeNode;\nuse Prophecy\\Doubler\\Generator\\Node\\Type\\BuiltinType;\n\nclass MethodNodeSpec extends ObjectBehavior\n{\n    function let()\n    {\n        $this->beConstructedWith('getTitle');\n    }\n\n    function it_has_a_name()\n    {\n        $this->getName()->shouldReturn('getTitle');\n    }\n\n    function it_has_public_visibility_by_default()\n    {\n        $this->getVisibility()->shouldReturn('public');\n    }\n\n    function its_visibility_is_mutable()\n    {\n        $this->setVisibility('private');\n        $this->getVisibility()->shouldReturn('private');\n    }\n\n    function it_is_not_static_by_default()\n    {\n        $this->shouldNotBeStatic();\n    }\n\n    function it_does_not_return_a_reference_by_default()\n    {\n        $this->returnsReference()->shouldReturn(false);\n    }\n\n    function it_should_be_settable_as_returning_a_reference_through_setter()\n    {\n        $this->setReturnsReference();\n        $this->returnsReference()->shouldReturn(true);\n    }\n\n    function it_should_be_settable_as_static_through_setter()\n    {\n        $this->setStatic();\n        $this->shouldBeStatic();\n    }\n\n    function it_accepts_only_supported_visibilities()\n    {\n        $this->shouldThrow('InvalidArgumentException')->duringSetVisibility('stealth');\n    }\n\n    function it_lowercases_visibility_before_setting_it()\n    {\n        $this->setVisibility('Public');\n        $this->getVisibility()->shouldReturn('public');\n    }\n\n    function its_useParentCode_causes_method_to_call_parent(ArgumentNode $argument1, ArgumentNode $argument2)\n    {\n        $argument1->getName()->willReturn('objectName');\n        $argument2->getName()->willReturn('default');\n\n        $argument1->isVariadic()->willReturn(false);\n        $argument2->isVariadic()->willReturn(true);\n\n        $this->addArgument($argument1);\n        $this->addArgument($argument2);\n\n        $this->useParentCode();\n\n        $this->getCode()->shouldReturn(\n            'return parent::getTitle($objectName, ...$default);'\n        );\n    }\n\n    function its_code_is_mutable()\n    {\n        $this->setCode('echo \"code\";');\n        $this->getCode()->shouldReturn('echo \"code\";');\n    }\n\n    function its_reference_returning_methods_will_generate_exceptions()\n    {\n        $this->setCode('echo \"code\";');\n        $this->setReturnsReference();\n        $this->getCode()->shouldReturn(\"throw new \\Prophecy\\Exception\\Doubler\\ReturnByReferenceException('Returning by reference not supported', get_class(\\$this), 'getTitle');\");\n    }\n\n    function its_setCode_provided_with_null_cleans_method_body()\n    {\n        $this->setCode(null);\n        $this->getCode()->shouldReturn('');\n    }\n\n    function it_is_constructable_with_code()\n    {\n        $this->beConstructedWith('getTitle', 'die();');\n        $this->getCode()->shouldReturn('die();');\n    }\n\n    function it_does_not_have_arguments_by_default()\n    {\n        $this->getArguments()->shouldHaveCount(0);\n    }\n\n    function it_supports_adding_arguments(ArgumentNode $argument1, ArgumentNode $argument2)\n    {\n        $this->addArgument($argument1);\n        $this->addArgument($argument2);\n\n        $this->getArguments()->shouldReturn(array($argument1, $argument2));\n    }\n\n    function it_has_an_empty_return_type_by_default()\n    {\n        $this->getReturnTypeNode()->shouldBeLike(new ReturnTypeNode());\n    }\n\n    function it_can_modify_return_type()\n    {\n        $this->setReturnTypeNode(new ReturnTypeNode(new BuiltinType('array')));\n\n        $this->getReturnTypeNode()->shouldBeLike(new ReturnTypeNode(new BuiltinType('array')));\n    }\n\n    function it_can_modify_return_type_as_strings_using_deprecated_methods()\n    {\n        $this->setReturnType('array');\n\n        $this->hasReturnType()->shouldReturn(true);\n        $this->getReturnType()->shouldReturn('array');\n    }\n\n    function it_can_set_nullable_type_using_deprecated_method()\n    {\n        $this->setReturnType('int');\n\n        $this->setNullableReturnType();\n\n        $this->shouldHaveNullableReturnType();\n    }\n\n    function it_can_unset_nullable_type_using_deprecated_method()\n    {\n        $this->setReturnType('int');\n\n        $this->setNullableReturnType(false);\n\n        $this->shouldNotHaveNullableReturnType();\n    }\n\n}\n"
  },
  {
    "path": "spec/Prophecy/Doubler/Generator/Node/ReturnTypeNodeSpec.php",
    "content": "<?php\n\nnamespace spec\\Prophecy\\Doubler\\Generator\\Node;\n\nuse PhpSpec\\ObjectBehavior;\nuse Prophecy\\Exception\\Doubler\\DoubleException;\n\nclass ReturnTypeNodeSpec extends ObjectBehavior\n{\n    function it_has_no_return_types_at_start()\n    {\n        $this->getTypes()->shouldReturn([]);\n    }\n\n    function it_can_have_a_simple_type()\n    {\n        $this->beConstructedWith('int');\n\n        $this->getTypes()->shouldReturn(['int']);\n    }\n\n    function it_can_have_multiple_types()\n    {\n        $this->beConstructedWith('int', 'string');\n\n        $this->getTypes()->shouldReturn(['int', 'string']);\n    }\n\n    function it_can_have_void_type()\n    {\n        $this->beConstructedWith('void');\n\n        $this->getTypes()->shouldReturn(['void']);\n    }\n\n    function it_will_normalise_type_aliases_types()\n    {\n        $this->beConstructedWith('double', 'real', 'boolean', 'integer');\n        $this->getTypes()->shouldReturn(['float', 'bool', 'int']);\n    }\n\n    function it_will_prefix_fcqns()\n    {\n        $this->beConstructedWith('Foo');\n\n        $this->getTypes()->shouldReturn(['\\\\Foo']);\n    }\n\n    function it_will_not_prefix_fcqns_that_already_have_prefix()\n    {\n        $this->beConstructedWith('\\\\Foo');\n\n        $this->getTypes()->shouldReturn(['\\\\Foo']);\n    }\n\n    function it_can_use_shorthand_null_syntax_if_it_has_single_type_plus_null()\n    {\n        $this->beConstructedWith('int', 'null');\n\n        $this->canUseNullShorthand()->shouldReturn(true);\n    }\n\n    function it_can_not_use_shorthand_null_syntax_if_it_does_not_allow_null()\n    {\n        $this->beConstructedWith('int');\n\n        $this->canUseNullShorthand()->shouldReturn(false);\n    }\n\n    function it_can_not_use_shorthand_null_syntax_if_it_has_more_than_one_non_null_type()\n    {\n        $this->beConstructedWith('int', 'string', 'null');\n\n        $this->canUseNullShorthand()->shouldReturn(false);\n    }\n\n    function it_can_return_non_null_types()\n    {\n        $this->beConstructedWith('int', 'null');\n\n        $this->getNonNullTypes()->shouldReturn(['int']);\n    }\n\n    function it_does_not_allow_union_void()\n    {\n        $this->beConstructedWith('void', 'int');\n\n        $this->shouldThrow(DoubleException::class)->duringInstantiation();\n    }\n\n    function it_does_not_allow_union_mixed()\n    {\n        $this->beConstructedWith('mixed', 'int');\n\n        if (PHP_VERSION_ID >= 80000) {\n            $this->shouldThrow(DoubleException::class)->duringInstantiation();\n        }\n    }\n\n    function it_does_not_prefix_false()\n    {\n        $this->beConstructedWith('false', 'array');\n\n        $this->getTypes()->shouldReturn(['false', 'array']);\n    }\n\n    function it_allows_standalone_false()\n    {\n        $this->beConstructedWith('false');\n\n        if (PHP_VERSION_ID >= 80000 && PHP_VERSION_ID < 80200) {\n            $this->shouldThrow(DoubleException::class)->duringInstantiation();\n        }\n\n        if (PHP_VERSION_ID >= 80200) {\n            $this->getTypes()->shouldReturn(['false']);\n        }\n    }\n\n    function it_allows_standalone_null()\n    {\n        $this->beConstructedWith('null');\n\n        if (PHP_VERSION_ID >= 80000 && PHP_VERSION_ID < 80200) {\n            $this->shouldThrow(DoubleException::class)->duringInstantiation();\n        }\n\n        if (PHP_VERSION_ID >= 80200) {\n            $this->getTypes()->shouldReturn(['null']);\n        }\n    }\n\n    function it_allows_standalone_true()\n    {\n        $this->beConstructedWith('true');\n\n        if (PHP_VERSION_ID >= 80000 && PHP_VERSION_ID < 80200) {\n            $this->shouldThrow(DoubleException::class)->duringInstantiation();\n        }\n\n        if (PHP_VERSION_ID >= 80200) {\n            $this->getTypes()->shouldReturn(['true']);\n        }\n    }\n\n    function it_allows_nullable_false()\n    {\n        $this->beConstructedWith('null', 'false');\n\n        if (PHP_VERSION_ID >= 80000 && PHP_VERSION_ID < 80200) {\n            $this->shouldThrow(DoubleException::class)->duringInstantiation();\n        }\n\n        if (PHP_VERSION_ID >= 80200) {\n            $this->getTypes()->shouldReturn(['null', 'false']);\n        }\n    }\n\n    function it_allows_nullable_true()\n    {\n        $this->beConstructedWith('null', 'true');\n\n        if (PHP_VERSION_ID >= 80000 && PHP_VERSION_ID < 80200) {\n            $this->shouldThrow(DoubleException::class)->duringInstantiation();\n        }\n\n        if (PHP_VERSION_ID >= 80200) {\n            $this->getTypes()->shouldReturn(['null', 'true']);\n        }\n    }\n\n    function it_allows_union_with_false()\n    {\n        $this->beConstructedWith('false', 'Foo');\n\n        if (PHP_VERSION_ID >= 80000) {\n            $this->getTypes()->shouldReturn(['false', '\\\\Foo']);\n        }\n    }\n\n    function it_does_not_prefix_never()\n    {\n        $this->beConstructedWith('never');\n\n        $this->getTypes()->shouldReturn(['never']);\n    }\n\n    function it_does_not_allow_union_never()\n    {\n        $this->beConstructedWith('never', 'int');\n\n        $this->shouldThrow(DoubleException::class)->duringInstantiation();\n    }\n\n    function it_has_a_return_statement_if_it_is_a_simple_type()\n    {\n        $this->beConstructedWith('int');\n\n        $this->shouldHaveReturnStatement();\n    }\n\n    function it_does_not_have_return_statement_if_it_returns_void()\n    {\n        $this->beConstructedWith('void');\n\n        $this->shouldNotHaveReturnStatement();\n    }\n\n    function it_does_not_have_return_statement_if_it_returns_never()\n    {\n        $this->beConstructedWith('never');\n\n        $this->shouldNotHaveReturnStatement();\n    }\n}\n"
  },
  {
    "path": "spec/Prophecy/Doubler/Generator/Node/Type/BuiltinTypeSpec.php",
    "content": "<?php\n\nnamespace spec\\Prophecy\\Doubler\\Generator\\Node\\Type;\n\nuse PhpSpec\\ObjectBehavior;\nuse Prophecy\\Doubler\\Generator\\Node\\Type\\TypeInterface;\n\nclass BuiltinTypeSpec extends ObjectBehavior\n{\n    function let(): void\n    {\n        $this->beConstructedWith('string');\n    }\n\n    function it_implements_type_interface(): void\n    {\n        $this->shouldImplement(TypeInterface::class);\n    }\n\n    function it_is_stringable(): void\n    {\n        $this->beConstructedWith('int');\n        $this->getType()->shouldReturn('int');\n        $this->__toString()->shouldReturn('int');\n    }\n}\n"
  },
  {
    "path": "spec/Prophecy/Doubler/Generator/Node/Type/IntersectionTypeSpec.php",
    "content": "<?php\n\nnamespace spec\\Prophecy\\Doubler\\Generator\\Node\\Type;\n\nuse PhpSpec\\ObjectBehavior;\nuse Prophecy\\Doubler\\Generator\\Node\\Type\\BuiltinType;\nuse Prophecy\\Doubler\\Generator\\Node\\Type\\ObjectType;\nuse Prophecy\\Doubler\\Generator\\Node\\Type\\TypeInterface;\nuse Prophecy\\Doubler\\Generator\\Node\\Type\\UnionType;\nuse Prophecy\\Exception\\Doubler\\DoubleException;\n\nclass IntersectionTypeSpec extends ObjectBehavior\n{\n    function let(): void\n    {\n        $this->beConstructedWith([\n            new ObjectType('Foo'),\n            new ObjectType('Bar'),\n        ]);\n    }\n\n    function it_should_implement_type_union(): void\n    {\n        $this->shouldImplement(TypeInterface::class);\n    }\n\n    function it_should_throw_double_exception_for_builtin_types()\n    {\n        $this->beConstructedWith([\n            new BuiltinType('string'),\n            new ObjectType('Foo'),\n        ]);\n        $this->shouldThrow(DoubleException::class)->duringInstantiation();\n    }\n\n    function it_should_throw_double_exception_if_less_than_2_types_provided()\n    {\n        $this->beConstructedWith([\n            new ObjectType('Bar'),\n        ]);\n        $this->shouldThrow(DoubleException::class)->duringInstantiation();\n    }\n\n    function it_should_throw_double_exception_if_union_type_given(): void\n    {\n        $this->beConstructedWith([\n            new ObjectType('Bar'),\n            new UnionType([new ObjectType('Foo'), new ObjectType('Baz')]),\n        ]);\n        $this->shouldThrow(DoubleException::class)->duringInstantiation();\n    }\n\n    function it_is_stringable(): void\n    {\n        $bar = new ObjectType('Bar');\n        $foo = new ObjectType('Foo');\n        $this->beConstructedWith([\n            $bar,\n            $foo,\n        ]);\n        $this->__toString()->shouldReturn('\\\\Bar&\\\\Foo');\n    }\n}\n"
  },
  {
    "path": "spec/Prophecy/Doubler/Generator/Node/Type/ObjectTypeSpec.php",
    "content": "<?php\n\nnamespace spec\\Prophecy\\Doubler\\Generator\\Node\\Type;\n\nuse PhpSpec\\ObjectBehavior;\nuse Prophecy\\Doubler\\Generator\\Node\\Type\\TypeInterface;\nuse stdClass;\n\nclass ObjectTypeSpec extends ObjectBehavior\n{\n    function let(): void\n    {\n        $this->beConstructedWith(stdClass::class);\n    }\n\n    function it_implements_type_interface(): void\n    {\n        $this->shouldImplement(TypeInterface::class);\n    }\n\n    function it_is_stringable(): void\n    {\n        $this->beConstructedWith('stdClass');\n        $this->getType()->shouldReturn('stdClass');\n        $this->__toString()->shouldReturn('\\stdClass');\n    }\n}\n"
  },
  {
    "path": "spec/Prophecy/Doubler/Generator/Node/Type/UnionTypeSpec.php",
    "content": "<?php\n\nnamespace spec\\Prophecy\\Doubler\\Generator\\Node\\Type;\n\nuse PhpSpec\\ObjectBehavior;\nuse Prophecy\\Doubler\\Generator\\Node\\Type\\BuiltinType;\nuse Prophecy\\Doubler\\Generator\\Node\\Type\\IntersectionType;\nuse Prophecy\\Doubler\\Generator\\Node\\Type\\ObjectType;\nuse Prophecy\\Doubler\\Generator\\Node\\Type\\TypeInterface;\nuse Prophecy\\Doubler\\Generator\\Node\\Type\\UnionType;\nuse Prophecy\\Exception\\Doubler\\DoubleException;\n\nclass UnionTypeSpec extends ObjectBehavior\n{\n    function let(): void\n    {\n        $this->beConstructedWith([\n            new BuiltinType('int'),\n            new BuiltinType('string'),\n        ]);\n    }\n    function it_implements_type_interface(): void\n    {\n        $this->shouldImplement(TypeInterface::class);\n    }\n\n    function it_throws_double_exception_when_union_type_given(): void\n    {\n        $this->beConstructedWith([\n            new UnionType([new BuiltinType('int'), new BuiltinType('string')]),\n            new BuiltinType('bool'),\n        ]);\n        $this->shouldThrow(DoubleException::class)->duringInstantiation();\n    }\n\n    function it_throws_double_exception_when_types_duplicated(): void\n    {\n        $this->beConstructedWith([new BuiltinType('string'), new BuiltinType('string')]);\n        $this->shouldThrow(DoubleException::class)->duringInstantiation();\n    }\n\n    function it_throws_double_exception_when_union_with_void(): void\n    {\n        $this->beConstructedWith([new BuiltinType('void'), new BuiltinType('string')]);\n        $this->shouldThrow(DoubleException::class)->duringInstantiation();\n    }\n\n    function it_throws_double_exception_when_union_with_never(): void\n    {\n        $this->beConstructedWith([new BuiltinType('never'), new BuiltinType('string')]);\n        $this->shouldThrow(DoubleException::class)->duringInstantiation();\n    }\n\n    function it_throws_double_exception_when_union_with_mixed(): void\n    {\n        $this->beConstructedWith([new BuiltinType('mixed'), new BuiltinType('string')]);\n        $this->shouldThrow(DoubleException::class)->duringInstantiation();\n    }\n\n    function it_throws_double_exception_when_union_with_only_one_type(): void\n    {\n        $this->beConstructedWith([new BuiltinType('string')]);\n        $this->shouldThrow(DoubleException::class)->duringInstantiation();\n    }\n\n    function it_return_array_of_its_types(): void\n    {\n        $this->getTypes()->shouldBeLike([\n            new BuiltinType('int'),\n            new BuiltinType('string'),\n        ]);\n    }\n\n    function it_should_accept_simple_type_and_intersection()\n    {\n        $type1 = new BuiltinType('string');\n        $type2 = new IntersectionType([new ObjectType('A'), new ObjectType('B')]);\n        $this->beConstructedWith([$type1, $type2]);\n\n        $this->has($type1)->shouldBe(true);\n        $this->has($type2)->shouldBe(true);\n    }\n\n    function it_is_stringable(): void\n    {\n        $bar = new ObjectType('Bar');\n        $foo = new ObjectType('Foo');\n        $baz = new ObjectType('Baz');\n        $intersection = new IntersectionType([$foo, $baz]);\n\n        $this->beConstructedWith([$bar, $intersection]);\n\n        $this->__toString()->shouldBe('\\\\Bar|(\\\\Foo&\\\\Baz)');\n    }\n}\n"
  },
  {
    "path": "spec/Prophecy/Doubler/LazyDoubleSpec.php",
    "content": "<?php\n\nnamespace spec\\Prophecy\\Doubler;\n\nuse PhpSpec\\ObjectBehavior;\nuse Prophecy\\Doubler\\Doubler;\nuse Prophecy\\Prophecy\\ProphecySubjectInterface;\n\nclass LazyDoubleSpec extends ObjectBehavior\n{\n    function let(Doubler $doubler)\n    {\n        $this->beConstructedWith($doubler);\n    }\n\n    function it_returns_anonymous_double_instance_by_default($doubler, ProphecySubjectInterface $double)\n    {\n        $doubler->double(null, array())->willReturn($double);\n\n        $this->getInstance()->shouldReturn($double);\n    }\n\n    function it_returns_class_double_instance_if_set($doubler, ProphecySubjectInterface $double, \\ReflectionClass $class)\n    {\n        $doubler->double($class, array())->willReturn($double);\n\n        $this->setParentClass($class);\n\n        $this->getInstance()->shouldReturn($double);\n    }\n\n    function it_returns_same_double_instance_if_called_2_times(\n        $doubler,\n        ProphecySubjectInterface $double1,\n        ProphecySubjectInterface $double2\n    ) {\n        $doubler->double(null, array())->willReturn($double1);\n        $doubler->double(null, array())->willReturn($double2);\n\n        $this->getInstance()->shouldReturn($double2);\n        $this->getInstance()->shouldReturn($double2);\n    }\n\n    function its_setParentClass_throws_ClassNotFoundException_if_class_not_found()\n    {\n        $this->shouldThrow('Prophecy\\Exception\\Doubler\\ClassNotFoundException')\n            ->duringSetParentClass('SomeUnexistingClass');\n    }\n\n    function its_setParentClass_throws_exception_if_prophecy_is_already_created(\n        $doubler,\n        ProphecySubjectInterface $double\n    ) {\n        $doubler->double(null, array())->willReturn($double);\n\n        $this->getInstance();\n\n        $this->shouldThrow('Prophecy\\Exception\\Doubler\\DoubleException')\n            ->duringSetParentClass('stdClass');\n    }\n\n    function its_addInterface_throws_InterfaceNotFoundException_if_no_interface_found()\n    {\n        $this->shouldThrow('Prophecy\\Exception\\Doubler\\InterfaceNotFoundException')\n            ->duringAddInterface('SomeUnexistingInterface');\n    }\n\n    function its_addInterface_throws_exception_if_prophecy_is_already_created(\n        $doubler,\n        ProphecySubjectInterface $double\n    ) {\n        $doubler->double(null, array())->willReturn($double);\n\n        $this->getInstance();\n\n        $this->shouldThrow('Prophecy\\Exception\\Doubler\\DoubleException')\n            ->duringAddInterface('ArrayAccess');\n    }\n}\n"
  },
  {
    "path": "spec/Prophecy/Doubler/NameGeneratorSpec.php",
    "content": "<?php\n\nnamespace spec\\Prophecy\\Doubler;\n\nuse PhpSpec\\ObjectBehavior;\n\nclass NameGeneratorSpec extends ObjectBehavior\n{\n    function its_name_generates_name_based_on_simple_class_reflection(\\ReflectionClass $class)\n    {\n        $class->getName()->willReturn('stdClass');\n        $this->name($class, array())->shouldStartWith('Double\\stdClass\\\\');\n    }\n\n    function its_name_generates_name_based_on_namespaced_class_reflection(\\ReflectionClass $class)\n    {\n        $class->getName()->willReturn('Some\\Custom\\Class');\n        $this->name($class, array())->shouldStartWith('Double\\Some\\Custom\\Class\\P');\n    }\n\n    function its_name_generates_name_based_on_interface_shortnames(\n        \\ReflectionClass $interface1,\n        \\ReflectionClass $interface2\n    ) {\n        $interface1->getShortName()->willReturn('HandlerInterface');\n        $interface2->getShortName()->willReturn('LoaderInterface');\n\n        $this->name(null, array($interface1, $interface2))->shouldStartWith(\n            'Double\\HandlerInterface\\LoaderInterface\\P'\n        );\n    }\n\n    function it_generates_proper_name_for_no_class_and_interfaces_list()\n    {\n        $this->name(null, array())->shouldStartWith('Double\\stdClass\\P');\n    }\n\n    function its_name_generates_name_based_only_on_class_if_its_available(\n        \\ReflectionClass $class,\n        \\ReflectionClass $interface1,\n        \\ReflectionClass $interface2\n    ) {\n        $class->getName()->willReturn('Some\\Custom\\Class');\n        $interface1->getShortName()->willReturn('HandlerInterface');\n        $interface2->getShortName()->willReturn('LoaderInterface');\n\n        $this->name($class, array($interface1, $interface2))->shouldStartWith(\n            'Double\\Some\\Custom\\Class\\P'\n        );\n    }\n\n    public function getMatchers(): array\n    {\n        return array(\n            'startWith' => function ($subject, $string) {\n                return 0 === strpos($subject, $string);\n            },\n        );\n    }\n}\n"
  },
  {
    "path": "spec/Prophecy/Exception/Call/UnexpectedCallExceptionSpec.php",
    "content": "<?php\n\nnamespace spec\\Prophecy\\Exception\\Call;\n\nuse PhpSpec\\ObjectBehavior;\nuse Prophecy\\Prophecy\\ObjectProphecy;\n\nclass UnexpectedCallExceptionSpec extends ObjectBehavior\n{\n    function let(ObjectProphecy $objectProphecy)\n    {\n        $this->beConstructedWith('msg', $objectProphecy, 'getName', array('arg1', 'arg2'));\n    }\n\n    function it_is_prophecy_exception()\n    {\n        $this->shouldBeAnInstanceOf('Prophecy\\Exception\\Prophecy\\ObjectProphecyException');\n    }\n\n    function it_exposes_method_name_through_getter()\n    {\n        $this->getMethodName()->shouldReturn('getName');\n    }\n\n    function it_exposes_arguments_through_getter()\n    {\n        $this->getArguments()->shouldReturn(array('arg1', 'arg2'));\n    }\n}\n"
  },
  {
    "path": "spec/Prophecy/Exception/Doubler/ClassCreatorExceptionSpec.php",
    "content": "<?php\n\nnamespace spec\\Prophecy\\Exception\\Doubler;\n\nuse PhpSpec\\ObjectBehavior;\nuse Prophecy\\Doubler\\Generator\\Node\\ClassNode;\n\nclass ClassCreatorExceptionSpec extends ObjectBehavior\n{\n    function let(ClassNode $node)\n    {\n        $this->beConstructedWith('', $node);\n    }\n\n    function it_is_a_prophecy_exception()\n    {\n        $this->shouldBeAnInstanceOf('Prophecy\\Exception\\Exception');\n        $this->shouldBeAnInstanceOf('Prophecy\\Exception\\Doubler\\DoublerException');\n    }\n\n    function it_contains_a_reflected_node($node)\n    {\n        $this->getClassNode()->shouldReturn($node);\n    }\n}\n"
  },
  {
    "path": "spec/Prophecy/Exception/Doubler/ClassMirrorExceptionSpec.php",
    "content": "<?php\n\nnamespace spec\\Prophecy\\Exception\\Doubler;\n\nuse PhpSpec\\ObjectBehavior;\n\nclass ClassMirrorExceptionSpec extends ObjectBehavior\n{\n    function let(\\ReflectionClass $class)\n    {\n        $this->beConstructedWith('', $class);\n    }\n\n    function it_is_a_prophecy_exception()\n    {\n        $this->shouldBeAnInstanceOf('Prophecy\\Exception\\Exception');\n        $this->shouldBeAnInstanceOf('Prophecy\\Exception\\Doubler\\DoublerException');\n    }\n\n    function it_contains_a_reflected_class_link($class)\n    {\n        $this->getReflectedClass()->shouldReturn($class);\n    }\n}\n"
  },
  {
    "path": "spec/Prophecy/Exception/Doubler/ClassNotFoundExceptionSpec.php",
    "content": "<?php\n\nnamespace spec\\Prophecy\\Exception\\Doubler;\n\nuse PhpSpec\\ObjectBehavior;\n\nclass ClassNotFoundExceptionSpec extends ObjectBehavior\n{\n    function let()\n    {\n        $this->beConstructedWith('msg', 'CustomClass');\n    }\n\n    function it_is_a_prophecy_exception()\n    {\n        $this->shouldBeAnInstanceOf('Prophecy\\Exception\\Exception');\n        $this->shouldBeAnInstanceOf('Prophecy\\Exception\\Doubler\\DoubleException');\n    }\n\n    function its_getClassname_returns_classname()\n    {\n        $this->getClassname()->shouldReturn('CustomClass');\n    }\n}\n"
  },
  {
    "path": "spec/Prophecy/Exception/Doubler/DoubleExceptionSpec.php",
    "content": "<?php\n\nnamespace spec\\Prophecy\\Exception\\Doubler;\n\nuse PhpSpec\\ObjectBehavior;\n\nclass DoubleExceptionSpec extends ObjectBehavior\n{\n    function it_is_a_double_exception()\n    {\n        $this->shouldBeAnInstanceOf('RuntimeException');\n        $this->shouldBeAnInstanceOf('Prophecy\\Exception\\Doubler\\DoublerException');\n    }\n}\n"
  },
  {
    "path": "spec/Prophecy/Exception/Doubler/InterfaceNotFoundExceptionSpec.php",
    "content": "<?php\n\nnamespace spec\\Prophecy\\Exception\\Doubler;\n\nuse PhpSpec\\ObjectBehavior;\n\nclass InterfaceNotFoundExceptionSpec extends ObjectBehavior\n{\n    function let()\n    {\n        $this->beConstructedWith('msg', 'CustomInterface');\n    }\n\n    function it_extends_ClassNotFoundException()\n    {\n        $this->shouldBeAnInstanceOf('Prophecy\\Exception\\Doubler\\ClassNotFoundException');\n    }\n\n    function its_getClassname_returns_classname()\n    {\n        $this->getClassname()->shouldReturn('CustomInterface');\n    }\n}\n"
  },
  {
    "path": "spec/Prophecy/Exception/Doubler/MethodNotExtendableExceptionSpec.php",
    "content": "<?php\n\nnamespace spec\\Prophecy\\Exception\\Doubler;\n\nuse PhpSpec\\ObjectBehavior;\n\nclass MethodNotExtendableExceptionSpec extends ObjectBehavior\n{\n    function let()\n    {\n        $this->beConstructedWith('', 'User', 'getName');\n    }\n\n    function it_is_DoubleException()\n    {\n        $this->shouldHaveType('Prophecy\\Exception\\Doubler\\DoubleException');\n    }\n\n    function it_has_MethodName()\n    {\n        $this->getMethodName()->shouldReturn('getName');\n    }\n\n    function it_has_classname()\n    {\n        $this->getClassName()->shouldReturn('User');\n    }\n}\n"
  },
  {
    "path": "spec/Prophecy/Exception/Doubler/MethodNotFoundExceptionSpec.php",
    "content": "<?php\n\nnamespace spec\\Prophecy\\Exception\\Doubler;\n\nuse PhpSpec\\ObjectBehavior;\n\nclass MethodNotFoundExceptionSpec extends ObjectBehavior\n{\n    function let()\n    {\n        $this->beConstructedWith('', 'User', 'getName', array(1, 2, 3));\n    }\n\n    function it_is_DoubleException()\n    {\n        $this->shouldHaveType('Prophecy\\Exception\\Doubler\\DoubleException');\n    }\n\n    function it_has_MethodName()\n    {\n        $this->getMethodName()->shouldReturn('getName');\n    }\n\n    function it_has_classnamej()\n    {\n        $this->getClassname()->shouldReturn('User');\n    }\n\n    function it_has_an_arguments_list()\n    {\n        $this->getArguments()->shouldReturn(array(1, 2, 3));\n    }\n\n    function it_has_a_default_null_argument_list()\n    {\n        $this->beConstructedWith('', 'User', 'getName');\n        $this->getArguments()->shouldReturn(null);\n    }\n}\n"
  },
  {
    "path": "spec/Prophecy/Exception/Prediction/AggregateExceptionSpec.php",
    "content": "<?php\n\nnamespace spec\\Prophecy\\Exception\\Prediction;\n\nuse PhpSpec\\ObjectBehavior;\nuse Prophecy\\Exception\\Prediction\\FailedPredictionException;\nuse Prophecy\\Exception\\Prediction\\PredictionException;\nuse Prophecy\\Prophecy\\ObjectProphecy;\n\nclass AggregateExceptionSpec extends ObjectBehavior\n{\n    function let()\n    {\n        $this->beConstructedWith('');\n    }\n\n    function it_is_prediction_exception()\n    {\n        $this->shouldBeAnInstanceOf('RuntimeException');\n        $this->shouldBeAnInstanceOf('Prophecy\\Exception\\Prediction\\PredictionException');\n    }\n\n    function it_can_store_objectProphecy_link(ObjectProphecy $object)\n    {\n        $this->setObjectProphecy($object);\n        $this->getObjectProphecy()->shouldReturn($object);\n    }\n\n    function it_should_not_have_exceptions_at_the_beginning()\n    {\n        $this->getExceptions()->shouldHaveCount(0);\n    }\n\n    function it_should_append_exception_through_append_method()\n    {\n        $exception = new FailedPredictionException();\n\n        $this->append($exception);\n\n        $this->getExceptions()->shouldReturn(array($exception));\n    }\n\n    function it_should_update_message_during_append()\n    {\n        $exception = new FailedPredictionException('Exception #1');\n\n        $this->append($exception);\n\n        $this->getMessage()->shouldReturn('Exception #1');\n    }\n\n    function it_should_update_message_during_append_more_exceptions(\n        PredictionException $exception1,\n        PredictionException $exception2\n    ) {\n        $exception1 = new FailedPredictionException('Exception #1');\n        $exception2 = new FailedPredictionException('Exception #2');\n\n        $this->append($exception1);\n        $this->append($exception2);\n        $this->getMessage()->shouldReturn(\"Exception #1\\nException #2\");\n    }\n}\n"
  },
  {
    "path": "spec/Prophecy/Exception/Prediction/NoCallsExceptionSpec.php",
    "content": "<?php\n\nnamespace spec\\Prophecy\\Exception\\Prediction;\n\nuse PhpSpec\\ObjectBehavior;\nuse Prophecy\\Prophecy\\MethodProphecy;\nuse Prophecy\\Prophecy\\ObjectProphecy;\n\nclass NoCallsExceptionSpec extends ObjectBehavior\n{\n    function let(ObjectProphecy $objectProphecy, MethodProphecy $methodProphecy)\n    {\n        $methodProphecy->getObjectProphecy()->willReturn($objectProphecy);\n\n        $this->beConstructedWith('message', $methodProphecy);\n    }\n\n    function it_is_PredictionException()\n    {\n        $this->shouldHaveType('Prophecy\\Exception\\Prediction\\PredictionException');\n    }\n\n    function it_extends_MethodProphecyException()\n    {\n        $this->shouldHaveType('Prophecy\\Exception\\Prophecy\\MethodProphecyException');\n    }\n}\n"
  },
  {
    "path": "spec/Prophecy/Exception/Prediction/UnexpectedCallsCountExceptionSpec.php",
    "content": "<?php\n\nnamespace spec\\Prophecy\\Exception\\Prediction;\n\nuse PhpSpec\\ObjectBehavior;\nuse Prophecy\\Call\\Call;\nuse Prophecy\\Prophecy\\MethodProphecy;\nuse Prophecy\\Prophecy\\ObjectProphecy;\n\nclass UnexpectedCallsCountExceptionSpec extends ObjectBehavior\n{\n    function let(ObjectProphecy $objectProphecy, MethodProphecy $methodProphecy, Call $call1, Call $call2)\n    {\n        $methodProphecy->getObjectProphecy()->willReturn($objectProphecy);\n\n        $this->beConstructedWith('message', $methodProphecy, 5, array($call1, $call2));\n    }\n\n    function it_extends_UnexpectedCallsException()\n    {\n        $this->shouldBeAnInstanceOf('Prophecy\\Exception\\Prediction\\UnexpectedCallsException');\n    }\n\n    function it_should_expose_expectedCount_through_getter()\n    {\n        $this->getExpectedCount()->shouldReturn(5);\n    }\n}\n"
  },
  {
    "path": "spec/Prophecy/Exception/Prediction/UnexpectedCallsExceptionSpec.php",
    "content": "<?php\n\nnamespace spec\\Prophecy\\Exception\\Prediction;\n\nuse PhpSpec\\ObjectBehavior;\nuse Prophecy\\Call\\Call;\nuse Prophecy\\Prophecy\\MethodProphecy;\nuse Prophecy\\Prophecy\\ObjectProphecy;\n\nclass UnexpectedCallsExceptionSpec extends ObjectBehavior\n{\n    function let(ObjectProphecy $objectProphecy, MethodProphecy $methodProphecy, Call $call1, Call $call2)\n    {\n        $methodProphecy->getObjectProphecy()->willReturn($objectProphecy);\n\n        $this->beConstructedWith('message', $methodProphecy, array($call1, $call2));\n    }\n\n    function it_is_PredictionException()\n    {\n        $this->shouldHaveType('Prophecy\\Exception\\Prediction\\PredictionException');\n    }\n\n    function it_extends_MethodProphecyException()\n    {\n        $this->shouldHaveType('Prophecy\\Exception\\Prophecy\\MethodProphecyException');\n    }\n\n    function it_should_expose_calls_list_through_getter($call1, $call2)\n    {\n        $this->getCalls()->shouldReturn(array($call1, $call2));\n    }\n}\n"
  },
  {
    "path": "spec/Prophecy/Exception/Prophecy/MethodProphecyExceptionSpec.php",
    "content": "<?php\n\nnamespace spec\\Prophecy\\Exception\\Prophecy;\n\nuse PhpSpec\\ObjectBehavior;\nuse Prophecy\\Prophecy\\MethodProphecy;\nuse Prophecy\\Prophecy\\ObjectProphecy;\n\nclass MethodProphecyExceptionSpec extends ObjectBehavior\n{\n    function let(ObjectProphecy $objectProphecy, MethodProphecy $methodProphecy)\n    {\n        $methodProphecy->getObjectProphecy()->willReturn($objectProphecy);\n\n        $this->beConstructedWith('message', $methodProphecy);\n    }\n\n    function it_extends_DoubleException()\n    {\n        $this->shouldBeAnInstanceOf('Prophecy\\Exception\\Prophecy\\ObjectProphecyException');\n    }\n\n    function it_holds_a_stub_reference($methodProphecy)\n    {\n        $this->getMethodProphecy()->shouldReturn($methodProphecy);\n    }\n}\n"
  },
  {
    "path": "spec/Prophecy/Exception/Prophecy/ObjectProphecyExceptionSpec.php",
    "content": "<?php\n\nnamespace spec\\Prophecy\\Exception\\Prophecy;\n\nuse PhpSpec\\ObjectBehavior;\nuse Prophecy\\Prophecy\\ObjectProphecy;\n\nclass ObjectProphecyExceptionSpec extends ObjectBehavior\n{\n    function let(ObjectProphecy $objectProphecy)\n    {\n        $this->beConstructedWith('message', $objectProphecy);\n    }\n\n    function it_should_be_a_prophecy_exception()\n    {\n        $this->shouldBeAnInstanceOf('Prophecy\\Exception\\Prophecy\\ProphecyException');\n    }\n\n    function it_holds_double_reference($objectProphecy)\n    {\n        $this->getObjectProphecy()->shouldReturn($objectProphecy);\n    }\n}\n"
  },
  {
    "path": "spec/Prophecy/Prediction/CallPredictionSpec.php",
    "content": "<?php\n\nnamespace spec\\Prophecy\\Prediction;\n\nuse PhpSpec\\ObjectBehavior;\nuse Prophecy\\Argument;\nuse Prophecy\\Argument\\ArgumentsWildcard;\nuse Prophecy\\Call\\Call;\nuse Prophecy\\Prophecy\\MethodProphecy;\nuse Prophecy\\Prophecy\\ObjectProphecy;\n\nclass CallPredictionSpec extends ObjectBehavior\n{\n    function it_is_prediction()\n    {\n        $this->shouldHaveType('Prophecy\\Prediction\\PredictionInterface');\n    }\n\n    function it_does_nothing_if_there_is_more_than_one_call_been_made(\n        ObjectProphecy $object,\n        MethodProphecy $method,\n        Call $call\n    ) {\n        $this->check(array($call), $object, $method)->shouldReturn(null);\n    }\n\n    function it_throws_NoCallsException_if_no_calls_found(\n        ObjectProphecy $object,\n        MethodProphecy $method,\n        ArgumentsWildcard $arguments\n    ) {\n        $method->getObjectProphecy()->willReturn($object);\n        $method->getMethodName()->willReturn('getName');\n        $method->getArgumentsWildcard()->willReturn($arguments);\n        $arguments->__toString()->willReturn('123');\n        $object->reveal()->willReturn(new \\stdClass());\n        $object->findProphecyMethodCalls('getName', Argument::any())->willReturn(array());\n\n        $this->shouldThrow('Prophecy\\Exception\\Prediction\\NoCallsException')\n            ->duringCheck(array(), $object, $method);\n    }\n}\n"
  },
  {
    "path": "spec/Prophecy/Prediction/CallTimesPredictionSpec.php",
    "content": "<?php\n\nnamespace spec\\Prophecy\\Prediction;\n\nuse PhpSpec\\ObjectBehavior;\nuse Prophecy\\Argument;\nuse Prophecy\\Argument\\ArgumentsWildcard;\nuse Prophecy\\Call\\Call;\nuse Prophecy\\Prophecy\\MethodProphecy;\nuse Prophecy\\Prophecy\\ObjectProphecy;\n\nclass CallTimesPredictionSpec extends ObjectBehavior\n{\n    function let()\n    {\n        $this->beConstructedWith(2);\n    }\n\n    function it_is_prediction()\n    {\n        $this->shouldHaveType('Prophecy\\Prediction\\PredictionInterface');\n    }\n\n    function it_does_nothing_if_there_were_exact_amount_of_calls_being_made(\n        ObjectProphecy $object,\n        MethodProphecy $method,\n        Call $call1,\n        Call $call2\n    ) {\n        $this->check(array($call1, $call2), $object, $method)->shouldReturn(null);\n    }\n\n    function it_throws_UnexpectedCallsCountException_if_calls_found(\n        ObjectProphecy $object,\n        MethodProphecy $method,\n        Call $call,\n        ArgumentsWildcard $arguments\n    ) {\n        $object->reveal()->willReturn(new \\stdClass());\n        $object->findProphecyMethodCalls('getName', Argument::any())->willReturn(array());\n        $method->getObjectProphecy()->willReturn($object);\n        $method->getMethodName()->willReturn('getName');\n        $method->getArgumentsWildcard()->willReturn($arguments);\n        $arguments->__toString()->willReturn('123');\n\n        $call->getMethodName()->willReturn('getName');\n        $call->getArguments()->willReturn(array(5, 4, 'three'));\n        $call->getCallPlace()->willReturn('unknown');\n\n        $this->shouldThrow('Prophecy\\Exception\\Prediction\\UnexpectedCallsCountException')\n            ->duringCheck(array($call), $object, $method);\n    }\n}\n"
  },
  {
    "path": "spec/Prophecy/Prediction/CallbackPredictionSpec.php",
    "content": "<?php\n\nnamespace spec\\Prophecy\\Prediction;\n\nuse PhpSpec\\ObjectBehavior;\nuse Prophecy\\Call\\Call;\nuse Prophecy\\Prophecy\\MethodProphecy;\nuse Prophecy\\Prophecy\\ObjectProphecy;\nuse RuntimeException;\n\nclass CallbackPredictionSpec extends ObjectBehavior\n{\n    function let()\n    {\n        $this->beConstructedWith('get_class');\n    }\n\n    function it_is_prediction()\n    {\n        $this->shouldHaveType('Prophecy\\Prediction\\PredictionInterface');\n    }\n\n    function it_proxies_call_to_callback(ObjectProphecy $object, MethodProphecy $method, Call $call)\n    {\n        $returnFirstCallCallback = function ($calls, $object, $method) {\n            throw new RuntimeException();\n        };\n\n        $this->beConstructedWith($returnFirstCallCallback);\n\n        $this->shouldThrow('RuntimeException')->duringCheck(array($call), $object, $method);\n    }\n}\n"
  },
  {
    "path": "spec/Prophecy/Prediction/NoCallsPredictionSpec.php",
    "content": "<?php\n\nnamespace spec\\Prophecy\\Prediction;\n\nuse PhpSpec\\ObjectBehavior;\nuse Prophecy\\Argument\\ArgumentsWildcard;\nuse Prophecy\\Call\\Call;\nuse Prophecy\\Prophecy\\MethodProphecy;\nuse Prophecy\\Prophecy\\ObjectProphecy;\n\nclass NoCallsPredictionSpec extends ObjectBehavior\n{\n    function it_is_prediction()\n    {\n        $this->shouldHaveType('Prophecy\\Prediction\\PredictionInterface');\n    }\n\n    function it_does_nothing_if_there_is_no_calls_made(ObjectProphecy $object, MethodProphecy $method)\n    {\n        $this->check(array(), $object, $method)->shouldReturn(null);\n    }\n\n    function it_throws_UnexpectedCallsException_if_calls_found(\n        ObjectProphecy $object,\n        MethodProphecy $method,\n        Call $call,\n        ArgumentsWildcard $arguments\n    ) {\n        $object->reveal()->willReturn(new \\stdClass());\n        $method->getObjectProphecy()->willReturn($object);\n        $method->getMethodName()->willReturn('getName');\n        $method->getArgumentsWildcard()->willReturn($arguments);\n        $arguments->__toString()->willReturn('123');\n\n        $call->getMethodName()->willReturn('getName');\n        $call->getArguments()->willReturn(array(5, 4, 'three'));\n        $call->getCallPlace()->willReturn('unknown');\n\n        $this->shouldThrow('Prophecy\\Exception\\Prediction\\UnexpectedCallsException')\n            ->duringCheck(array($call), $object, $method);\n    }\n}\n"
  },
  {
    "path": "spec/Prophecy/Promise/CallbackPromiseSpec.php",
    "content": "<?php\n\nnamespace spec\\Prophecy\\Promise;\n\nuse PhpSpec\\ObjectBehavior;\nuse Prophecy\\Prophecy\\MethodProphecy;\nuse Prophecy\\Prophecy\\ObjectProphecy;\n\nclass CallbackPromiseSpec extends ObjectBehavior\n{\n    function let()\n    {\n        $this->beConstructedWith('get_class');\n    }\n\n    function it_is_promise()\n    {\n        $this->shouldBeAnInstanceOf('Prophecy\\Promise\\PromiseInterface');\n    }\n\n    function it_should_execute_closure_callback(ObjectProphecy $object, MethodProphecy $method)\n    {\n        $firstArgumentCallback = function ($args) {\n            return $args[0];\n        };\n\n        $this->beConstructedWith($firstArgumentCallback);\n\n        $this->execute(array('one', 'two'), $object, $method)->shouldReturn('one');\n    }\n\n    function it_should_execute_static_array_callback(ObjectProphecy $object, MethodProphecy $method)\n    {\n        $firstArgumentCallback = array('spec\\Prophecy\\Promise\\ClassCallback', 'staticCallbackMethod');\n\n        $this->beConstructedWith($firstArgumentCallback);\n\n        $this->execute(array('one', 'two'), $object, $method)->shouldReturn('one');\n    }\n\n    function it_should_execute_instance_array_callback(ObjectProphecy $object, MethodProphecy $method)\n    {\n        $class = new ClassCallback();\n        $firstArgumentCallback = array($class, 'callbackMethod');\n\n        $this->beConstructedWith($firstArgumentCallback);\n\n        $this->execute(array('one', 'two'), $object, $method)->shouldReturn('one');\n    }\n\n    function it_should_execute_string_function_callback(ObjectProphecy $object, MethodProphecy $method)\n    {\n        $firstArgumentCallback = 'spec\\Prophecy\\Promise\\functionCallbackFirstArgument';\n\n        $this->beConstructedWith($firstArgumentCallback);\n\n        $this->execute(array('one', 'two'), $object, $method)->shouldReturn('one');\n    }\n\n}\n\n/**\n * Class used to test callbackpromise\n *\n * @param array\n * @return string\n */\nclass ClassCallback\n{\n    /**\n     * @param array $args\n     */\n    function callbackMethod($args)\n    {\n        return $args[0];\n    }\n\n    /**\n     * @param array $args\n     */\n    static function staticCallbackMethod($args)\n    {\n        return $args[0];\n    }\n}\n\n/**\n * Callback function used to test callbackpromise\n *\n * @param array\n * @return string\n */\nfunction functionCallbackFirstArgument($args)\n{\n    return $args[0];\n}\n"
  },
  {
    "path": "spec/Prophecy/Promise/ReturnArgumentPromiseSpec.php",
    "content": "<?php\n\nnamespace spec\\Prophecy\\Promise;\n\nuse PhpSpec\\ObjectBehavior;\nuse Prophecy\\Prophecy\\MethodProphecy;\nuse Prophecy\\Prophecy\\ObjectProphecy;\n\nclass ReturnArgumentPromiseSpec extends ObjectBehavior\n{\n    function it_is_promise()\n    {\n        $this->shouldBeAnInstanceOf('Prophecy\\Promise\\PromiseInterface');\n    }\n\n    function it_should_return_first_argument_if_provided(ObjectProphecy $object, MethodProphecy $method)\n    {\n        $this->execute(array('one', 'two'), $object, $method)->shouldReturn('one');\n    }\n\n    function it_should_return_null_if_no_arguments_provided(ObjectProphecy $object, MethodProphecy $method)\n    {\n        $this->execute(array(), $object, $method)->shouldReturn(null);\n    }\n\n    function it_should_return_nth_argument_if_provided(ObjectProphecy $object, MethodProphecy $method)\n    {\n        $this->beConstructedWith(1);\n        $this->execute(array('one', 'two'), $object, $method)->shouldReturn('two');\n    }\n}\n"
  },
  {
    "path": "spec/Prophecy/Promise/ReturnPromiseSpec.php",
    "content": "<?php\n\nnamespace spec\\Prophecy\\Promise;\n\nuse PhpSpec\\ObjectBehavior;\nuse Prophecy\\Prophecy\\MethodProphecy;\nuse Prophecy\\Prophecy\\ObjectProphecy;\n\nclass ReturnPromiseSpec extends ObjectBehavior\n{\n    function let()\n    {\n        $this->beConstructedWith(array(42));\n    }\n\n    function it_is_promise()\n    {\n        $this->shouldBeAnInstanceOf('Prophecy\\Promise\\PromiseInterface');\n    }\n\n    function it_returns_value_it_was_constructed_with(ObjectProphecy $object, MethodProphecy $method)\n    {\n        $this->execute(array(), $object, $method)->shouldReturn(42);\n    }\n\n    function it_always_returns_last_value_left_in_the_return_values(ObjectProphecy $object, MethodProphecy $method)\n    {\n        $this->execute(array(), $object, $method)->shouldReturn(42);\n        $this->execute(array(), $object, $method)->shouldReturn(42);\n    }\n\n    function it_consequently_returns_multiple_values_it_was_constructed_with(\n        ObjectProphecy $object,\n        MethodProphecy $method\n    ) {\n        $this->beConstructedWith(array(42, 24, 12));\n\n        $this->execute(array(), $object, $method)->shouldReturn(42);\n        $this->execute(array(), $object, $method)->shouldReturn(24);\n        $this->execute(array(), $object, $method)->shouldReturn(12);\n    }\n\n    function it_returns_null_if_constructed_with_empty_array(ObjectProphecy $object, MethodProphecy $method)\n    {\n        $this->beConstructedWith(array());\n\n        $this->execute(array(), $object, $method)->shouldReturn(null);\n    }\n}\n"
  },
  {
    "path": "spec/Prophecy/Promise/ThrowPromiseSpec.php",
    "content": "<?php\n\nnamespace spec\\Prophecy\\Promise;\n\nuse PhpSpec\\Exception\\Example\\SkippingException;\nuse PhpSpec\\ObjectBehavior;\nuse Prophecy\\Prophecy\\MethodProphecy;\nuse Prophecy\\Prophecy\\ObjectProphecy;\n\nclass ThrowPromiseSpec extends ObjectBehavior\n{\n    function let()\n    {\n        $this->beConstructedWith('RuntimeException');\n    }\n\n    function it_is_promise()\n    {\n        $this->shouldBeAnInstanceOf('Prophecy\\Promise\\PromiseInterface');\n    }\n\n    function it_instantiates_and_throws_exception_from_provided_classname(ObjectProphecy $object, MethodProphecy $method)\n    {\n        $this->beConstructedWith('InvalidArgumentException');\n\n        $this->shouldThrow('InvalidArgumentException')\n            ->duringExecute(array(), $object, $method);\n    }\n\n    function it_instantiates_exceptions_with_required_arguments(ObjectProphecy $object, MethodProphecy $method)\n    {\n        $this->beConstructedWith('spec\\Prophecy\\Promise\\RequiredArgumentException');\n\n        $this->shouldThrow('spec\\Prophecy\\Promise\\RequiredArgumentException')\n            ->duringExecute(array(), $object, $method);\n    }\n\n    function it_throws_provided_exception(ObjectProphecy $object, MethodProphecy $method)\n    {\n        $this->beConstructedWith($exc = new \\RuntimeException('Some exception'));\n\n        $this->shouldThrow($exc)->duringExecute(array(), $object, $method);\n    }\n\n    function it_throws_error_instances(ObjectProphecy $object, MethodProphecy $method)\n    {\n        if (!class_exists('\\Error')) {\n            throw new SkippingException('The class Error, introduced in PHP 7, does not exist');\n        }\n\n        $this->beConstructedWith($exc = new \\Error('Error exception'));\n\n        $this->shouldThrow($exc)->duringExecute(array(), $object, $method);\n    }\n\n    function it_throws_errors_by_class_name()\n    {\n        if (!class_exists('\\Error')) {\n            throw new SkippingException('The class Error, introduced in PHP 7, does not exist');\n        }\n\n        $this->beConstructedWith('\\Error');\n\n        $this->shouldNotThrow('Prophecy\\Exception\\InvalidArgumentException')->duringInstantiation();\n    }\n\n    function it_does_not_throw_something_that_is_not_throwable_by_class_name()\n    {\n        $this->beConstructedWith('\\stdClass');\n\n        $this->shouldThrow('Prophecy\\Exception\\InvalidArgumentException')->duringInstantiation();\n    }\n\n    function it_does_not_throw_something_that_is_not_throwable_by_instance()\n    {\n        $this->beConstructedWith(new \\stdClass());\n\n        $this->shouldThrow('Prophecy\\Exception\\InvalidArgumentException')->duringInstantiation();\n    }\n\n    function it_throws_an_exception_by_class_name()\n    {\n        $this->beConstructedWith('\\Exception');\n\n        $this->shouldNotThrow('Prophecy\\Exception\\InvalidArgumentException')->duringInstantiation();\n    }\n\n    function it_throws_an_extension_of_throwable_by_class_name()\n    {\n        if (!interface_exists('\\Throwable')) {\n            throw new SkippingException('The interface Throwable, introduced in PHP 7, does not exist');\n        }\n\n        $this->beConstructedWith('\\Fixtures\\Prophecy\\ThrowableInterface');\n\n        $this->shouldNotThrow('Prophecy\\Exception\\InvalidArgumentException')->duringInstantiation();\n    }\n\n    function it_throws_a_throwable_by_class_name()\n    {\n        if (!interface_exists('\\Throwable')) {\n            throw new SkippingException('The interface Throwable, introduced in PHP 7, does not exist');\n        }\n\n        $this->beConstructedWith('\\Throwable');\n\n        $this->shouldNotThrow('Prophecy\\Exception\\InvalidArgumentException')->duringInstantiation();\n    }\n}\n\nclass RequiredArgumentException extends \\Exception\n{\n    final public function __construct($message, $code) {}\n}\n"
  },
  {
    "path": "spec/Prophecy/Prophecy/MethodProphecySpec.php",
    "content": "<?php\n\nnamespace spec\\Prophecy\\Prophecy;\n\nuse PhpSpec\\ObjectBehavior;\nuse Prophecy\\Argument;\nuse Prophecy\\Argument\\ArgumentsWildcard;\nuse Prophecy\\Call\\Call;\nuse Prophecy\\Exception\\Prophecy\\MethodProphecyException;\nuse Prophecy\\Prediction\\PredictionInterface;\nuse Prophecy\\Promise\\PromiseInterface;\nuse Prophecy\\Prophecy\\ObjectProphecy;\nuse Prophecy\\Prophecy\\ProphecySubjectInterface;\nuse ReflectionClass;\nuse RuntimeException;\n\nclass MethodProphecySpec extends ObjectBehavior\n{\n    function let(ObjectProphecy $objectProphecy, ReflectionClass $reflection, ArgumentsWildcard $argumentsWildcard)\n    {\n        $objectProphecy->reveal()->willReturn($reflection);\n\n        if (\\PHP_VERSION_ID >= 80100) {\n            $objectProphecy->addMethodProphecy(Argument::any())->willReturn();\n        }\n\n        $this->beConstructedWith($objectProphecy, 'getName', $argumentsWildcard);\n    }\n\n    function it_is_initializable()\n    {\n        $this->shouldHaveType('Prophecy\\Prophecy\\MethodProphecy');\n    }\n\n    function its_constructor_throws_MethodNotFoundException_for_unexisting_method(\n        ObjectProphecy $objectProphecy,\n        ObjectProphecy $objectProphecyInner,\n        ReflectionClass $reflection,\n        ArgumentsWildcard $argumentsWildcard\n    ) {\n        $objectProphecy->reveal()->willReturn($objectProphecyInner);\n        $objectProphecyInner->reveal()->willReturn($reflection);\n        $this->beConstructedWith($objectProphecy, 'getUnexisting', $argumentsWildcard);\n        $this->shouldThrow('Prophecy\\Exception\\Doubler\\MethodNotFoundException')->duringInstantiation();\n    }\n\n    function its_constructor_throws_MethodProphecyException_for_final_methods(\n        ObjectProphecy $objectProphecy,\n        ObjectProphecy $objectProphecyInner,\n        ClassWithFinalMethod $subject\n    ) {\n        $objectProphecy->reveal()->willReturn($objectProphecyInner);\n        $objectProphecyInner->reveal()->willReturn($subject);\n\n        $this->shouldThrow('Prophecy\\Exception\\Prophecy\\MethodProphecyException')->during(\n            '__construct', array($objectProphecy, 'finalMethod', null)\n        );\n    }\n\n    function its_constructor_transforms_array_passed_as_3rd_argument_to_ArgumentsWildcard(\n        ObjectProphecy $objectProphecy\n    ) {\n        $this->beConstructedWith($objectProphecy, 'getName', array(42, 33));\n\n        $wildcard = $this->getArgumentsWildcard();\n        $wildcard->__toString()->shouldReturn('exact(42), exact(33)');\n    }\n\n    function its_constructor_records_default_callback_promise_for_return_type_hinted_methods(\n        ObjectProphecy $objectProphecy,\n        $subject,\n        ArgumentsWildcard $argumentsWildcard\n    ) {\n        $subject->beADoubleOf('spec\\Prophecy\\Prophecy\\ClassWithVoidTypeHintedMethods');\n        $objectProphecy->addMethodProphecy(Argument::cetera())->willReturn(null);\n        $objectProphecy->reveal()->willReturn($subject);\n\n        $this->beConstructedWith($objectProphecy, 'getVoid', $argumentsWildcard);\n        $this->getPromise()->shouldBeAnInstanceOf('Prophecy\\Promise\\CallbackPromise');\n    }\n\n    function its_constructor_records_promise_that_returns_null_for_void_type_hinted_methods(\n        ObjectProphecy $objectProphecy,\n        $subject,\n        ArgumentsWildcard $argumentsWildcard\n    ) {\n        $subject->beADoubleOf('spec\\Prophecy\\Prophecy\\ClassWithVoidTypeHintedMethods');\n        $objectProphecy->addMethodProphecy(Argument::cetera())->willReturn(null);\n        $objectProphecy->reveal()->willReturn($subject);\n\n        $this->beConstructedWith($objectProphecy, 'getVoid', $argumentsWildcard);\n        $this->getPromise()->execute(array(), $objectProphecy, $this)->shouldBeNull();\n    }\n\n    function its_constructor_adds_itself_to_ObjectProphecy_for_return_type_hinted_methods(\n        ObjectProphecy $objectProphecy,\n        $subject,\n        ArgumentsWildcard $argumentsWildcard\n    ) {\n        $subject->beADoubleOf('spec\\Prophecy\\Prophecy\\ClassWithVoidTypeHintedMethods');\n        $objectProphecy->addMethodProphecy(Argument::cetera())->willReturn(null);\n        $objectProphecy->reveal()->willReturn($subject);\n\n        $this->beConstructedWith($objectProphecy, 'getVoid', $argumentsWildcard);\n        $objectProphecy->addMethodProphecy($this)->shouldHaveBeenCalled();\n    }\n\n    function it_records_promise_through_will_method(PromiseInterface $promise, ObjectProphecy $objectProphecy)\n    {\n        $objectProphecy->addMethodProphecy($this)->willReturn(null);\n\n        $this->will($promise);\n        $this->getPromise()->shouldReturn($promise);\n    }\n\n    function it_adds_itself_to_ObjectProphecy_during_call_to_will(\n        ObjectProphecy $objectProphecy,\n        PromiseInterface $promise\n    ) {\n        $objectProphecy->addMethodProphecy($this)->shouldBeCalled();\n\n        $this->will($promise);\n    }\n\n    function it_adds_ReturnPromise_during_willReturn_call(ObjectProphecy $objectProphecy)\n    {\n        $objectProphecy->addMethodProphecy($this)->willReturn(null);\n\n        $this->willReturn(42);\n        $this->getPromise()->shouldBeAnInstanceOf('Prophecy\\Promise\\ReturnPromise');\n    }\n\n    function it_adds_CallbackPromise_during_willYield_call(ObjectProphecy $objectProphecy)\n    {\n        $objectProphecy->addMethodProphecy($this)->willReturn(null);\n\n        $this->willYield(array('foo', 'bar'));\n        $this->getPromise()->shouldBeAnInstanceOf('Prophecy\\Promise\\CallbackPromise');\n    }\n\n    function it_yields_elements_configured_in_willYield(ObjectProphecy $objectProphecy)\n    {\n        $objectProphecy->addMethodProphecy($this)->willReturn(null);\n\n        $this->willYield(array('foo', 'bar'));\n        $this->getPromise()->execute(array(), $objectProphecy, $this)->shouldYield(array('foo', 'bar'));\n    }\n\n    function it_yields_key_value_pairs_configured_in_willYield(ObjectProphecy $objectProphecy)\n    {\n        $objectProphecy->addMethodProphecy($this)->willReturn(null);\n\n        $this->willYield(array(10 => 'foo', 11 => 'bar'));\n        $this->getPromise()->execute(array(), $objectProphecy, $this)->shouldYield(array(10 => 'foo', 11 => 'bar'));\n    }\n\n    function it_yields_and_return_elements_configured_in_willYield(ObjectProphecy $objectProphecy)\n    {\n        $objectProphecy->addMethodProphecy($this)->willReturn(null);\n\n        $this->willYield(array('foo', 'bar'), true);\n        $generator = $this->getPromise()->execute(array(), $objectProphecy, $this);\n        $generator->shouldYield(array('foo', 'bar'));\n        $generator->callOnWrappedObject('getReturn')->shouldReturn(true);\n    }\n\n    function it_adds_ThrowPromise_during_willThrow_call(ObjectProphecy $objectProphecy)\n    {\n        $objectProphecy->addMethodProphecy($this)->willReturn(null);\n\n        $this->willThrow('RuntimeException');\n        $this->getPromise()->shouldBeAnInstanceOf('Prophecy\\Promise\\ThrowPromise');\n    }\n\n    function it_adds_ReturnArgumentPromise_during_willReturnArgument_call(ObjectProphecy $objectProphecy)\n    {\n        $objectProphecy->addMethodProphecy($this)->willReturn(null);\n\n        $this->willReturnArgument();\n        $this->getPromise()->shouldBeAnInstanceOf('Prophecy\\Promise\\ReturnArgumentPromise');\n    }\n\n    function it_adds_ReturnArgumentPromise_during_willReturnArgument_call_with_index_argument(\n        ObjectProphecy $objectProphecy\n    ) {\n        $objectProphecy->addMethodProphecy($this)->willReturn(null);\n\n        $this->willReturnArgument(1);\n        $promise = $this->getPromise();\n        $promise->shouldBeAnInstanceOf('Prophecy\\Promise\\ReturnArgumentPromise');\n        $promise->execute(array('one', 'two'), $objectProphecy, $this)->shouldReturn('two');\n    }\n\n    function it_adds_CallbackPromise_during_will_call_with_callback_argument(ObjectProphecy $objectProphecy)\n    {\n        $objectProphecy->addMethodProphecy($this)->willReturn(null);\n\n        $callback = function () {};\n\n        $this->will($callback);\n        $this->getPromise()->shouldBeAnInstanceOf('Prophecy\\Promise\\CallbackPromise');\n    }\n\n    function it_records_prediction_through_should_method(\n        PredictionInterface $prediction,\n        ObjectProphecy $objectProphecy\n    ) {\n        $objectProphecy->addMethodProphecy($this)->willReturn(null);\n\n        $this->callOnWrappedObject('should', array($prediction));\n        $this->getPrediction()->shouldReturn($prediction);\n    }\n\n    function it_adds_CallbackPrediction_during_should_call_with_callback_argument(ObjectProphecy $objectProphecy)\n    {\n        $objectProphecy->addMethodProphecy($this)->willReturn(null);\n\n        $callback = function () {};\n\n        $this->callOnWrappedObject('should', array($callback));\n        $this->getPrediction()->shouldBeAnInstanceOf('Prophecy\\Prediction\\CallbackPrediction');\n    }\n\n    function it_adds_itself_to_ObjectProphecy_during_call_to_should(\n        ObjectProphecy $objectProphecy,\n        PredictionInterface $prediction\n    ) {\n        $objectProphecy->addMethodProphecy($this)->shouldBeCalled();\n\n        $this->callOnWrappedObject('should', array($prediction));\n    }\n\n    function it_adds_CallPrediction_during_shouldBeCalled_call($objectProphecy)\n    {\n        $objectProphecy->addMethodProphecy($this)->willReturn(null);\n\n        $this->callOnWrappedObject('shouldBeCalled', array());\n        $this->getPrediction()->shouldBeAnInstanceOf('Prophecy\\Prediction\\CallPrediction');\n    }\n\n    function it_adds_NoCallsPrediction_during_shouldNotBeCalled_call(ObjectProphecy $objectProphecy)\n    {\n        $objectProphecy->addMethodProphecy($this)->willReturn(null);\n\n        $this->callOnWrappedObject('shouldNotBeCalled', array());\n        $this->getPrediction()->shouldBeAnInstanceOf('Prophecy\\Prediction\\NoCallsPrediction');\n    }\n\n    function it_adds_CallTimesPrediction_during_shouldBeCalledTimes_call(ObjectProphecy $objectProphecy)\n    {\n        $objectProphecy->addMethodProphecy($this)->willReturn(null);\n\n        $this->callOnWrappedObject('shouldBeCalledTimes', array(5));\n        $this->getPrediction()->shouldBeAnInstanceOf('Prophecy\\Prediction\\CallTimesPrediction');\n    }\n\n    function it_adds_CallTimesPrediction_during_shouldBeCalledOnce_call(ObjectProphecy $objectProphecy)\n    {\n        $objectProphecy->addMethodProphecy($this)->willReturn(null);\n\n        $this->callOnWrappedObject('shouldBeCalledOnce');\n        $this->getPrediction()->shouldBeAnInstanceOf('Prophecy\\Prediction\\CallTimesPrediction');\n    }\n\n    function it_checks_prediction_via_shouldHave_method_call(\n        ObjectProphecy $objectProphecy,\n        ArgumentsWildcard $arguments,\n        PredictionInterface $prediction,\n        Call $call1,\n        Call $call2\n    ) {\n        $objectProphecy->addMethodProphecy($this)->willReturn(null);\n        $prediction->check(array($call1, $call2), $objectProphecy->getWrappedObject(), $this)->shouldBeCalled();\n        $objectProphecy->findProphecyMethodCalls('getName', $arguments)->willReturn(array($call1, $call2));\n\n        $this->withArguments($arguments);\n        $this->callOnWrappedObject('shouldHave', array($prediction));\n    }\n\n    function it_sets_return_promise_during_shouldHave_call_if_none_was_set_before(\n        ObjectProphecy $objectProphecy,\n        ArgumentsWildcard $arguments,\n        PredictionInterface $prediction,\n        Call $call1,\n        Call $call2\n    ) {\n        $objectProphecy->addMethodProphecy($this)->willReturn(null);\n        $prediction->check(array($call1, $call2), $objectProphecy->getWrappedObject(), $this)->shouldBeCalled();\n        $objectProphecy->findProphecyMethodCalls('getName', $arguments)->willReturn(array($call1, $call2));\n\n        $this->withArguments($arguments);\n        $this->callOnWrappedObject('shouldHave', array($prediction));\n\n        $this->getPromise()->shouldReturnAnInstanceOf(\n            \\PHP_VERSION_ID < 80100\n                ? 'Prophecy\\Promise\\ReturnPromise'\n                : 'Prophecy\\Promise\\CallbackPromise'\n        );\n    }\n\n    function it_does_not_set_return_promise_during_shouldHave_call_if_it_was_set_before(\n        ObjectProphecy $objectProphecy,\n        ArgumentsWildcard $arguments,\n        PredictionInterface $prediction,\n        Call $call1,\n        Call $call2,\n        PromiseInterface $promise\n    ) {\n        $objectProphecy->addMethodProphecy($this)->willReturn(null);\n        $prediction->check(array($call1, $call2), $objectProphecy->getWrappedObject(), $this)->shouldBeCalled();\n        $objectProphecy->findProphecyMethodCalls('getName', $arguments)->willReturn(array($call1, $call2));\n\n        $this->will($promise);\n        $this->withArguments($arguments);\n        $this->callOnWrappedObject('shouldHave', array($prediction));\n\n        $this->getPromise()->shouldReturn($promise);\n    }\n\n    function it_records_checked_predictions(\n        ObjectProphecy $objectProphecy,\n        ArgumentsWildcard $arguments,\n        PredictionInterface $prediction1,\n        PredictionInterface $prediction2,\n        Call $call1,\n        Call $call2,\n        PromiseInterface $promise\n    ) {\n        $objectProphecy->addMethodProphecy($this)->willReturn(null);\n        $prediction1->check(array($call1, $call2), $objectProphecy->getWrappedObject(), $this)->willReturn();\n        $prediction2->check(array($call1, $call2), $objectProphecy->getWrappedObject(), $this)->willReturn();\n        $objectProphecy->findProphecyMethodCalls('getName', $arguments)->willReturn(array($call1, $call2));\n\n        $this->will($promise);\n        $this->withArguments($arguments);\n        $this->callOnWrappedObject('shouldHave', array($prediction1));\n        $this->callOnWrappedObject('shouldHave', array($prediction2));\n\n        $this->getCheckedPredictions()->shouldReturn(array($prediction1, $prediction2));\n    }\n\n    function it_records_even_failed_checked_predictions(\n        ObjectProphecy $objectProphecy,\n        ArgumentsWildcard $arguments,\n        PredictionInterface $prediction,\n        Call $call1,\n        Call $call2,\n        PromiseInterface $promise\n    ) {\n        $objectProphecy->addMethodProphecy($this)->willReturn(null);\n        $prediction->check(array($call1, $call2), $objectProphecy->getWrappedObject(), $this)->willThrow(new RuntimeException());\n        $objectProphecy->findProphecyMethodCalls('getName', $arguments)->willReturn(array($call1, $call2));\n\n        $this->will($promise);\n        $this->withArguments($arguments);\n\n        try {\n            $this->callOnWrappedObject('shouldHave', array($prediction));\n        } catch (\\Exception $e) {\n        }\n\n        $this->getCheckedPredictions()->shouldReturn(array($prediction));\n    }\n\n    function it_checks_prediction_via_shouldHave_method_call_with_callback(\n        ObjectProphecy $objectProphecy,\n        ArgumentsWildcard $arguments,\n        Call $call1,\n        Call $call2\n    ) {\n        $objectProphecy->addMethodProphecy($this)->willReturn(null);\n        $callback = function ($calls, $object, $method) {\n            throw new RuntimeException();\n        };\n        $objectProphecy->findProphecyMethodCalls('getName', $arguments)->willReturn(array($call1, $call2));\n\n        $this->withArguments($arguments);\n        $this->shouldThrow('RuntimeException')->duringShouldHave($callback);\n    }\n\n    function it_does_nothing_during_checkPrediction_if_no_prediction_set()\n    {\n        $this->checkPrediction()->shouldReturn(null);\n    }\n\n    function it_checks_set_prediction_during_checkPrediction(\n        ObjectProphecy $objectProphecy,\n        ArgumentsWildcard $arguments,\n        PredictionInterface $prediction,\n        Call $call1,\n        Call $call2\n    ) {\n        $prediction->check(array($call1, $call2), $objectProphecy->getWrappedObject(), $this)->shouldBeCalled();\n        $objectProphecy->findProphecyMethodCalls('getName', $arguments)->willReturn(array($call1, $call2));\n        $objectProphecy->addMethodProphecy($this)->willReturn(null);\n\n        $this->withArguments($arguments);\n        $this->callOnWrappedObject('should', array($prediction));\n        $this->checkPrediction();\n    }\n\n    function it_links_back_to_ObjectProphecy_through_getter(ObjectProphecy $objectProphecy)\n    {\n        $this->getObjectProphecy()->shouldReturn($objectProphecy);\n    }\n\n    function it_has_MethodName()\n    {\n        $this->getMethodName()->shouldReturn('getName');\n    }\n\n    function it_contains_ArgumentsWildcard_it_was_constructed_with(\n        ObjectProphecy $objectProphecy,\n        ArgumentsWildcard $wildcard\n    ) {\n        $this->beConstructedWith($objectProphecy, 'getName', $wildcard);\n\n        $this->getArgumentsWildcard()->shouldReturn($wildcard);\n    }\n\n    function its_ArgumentWildcard_is_mutable_through_setter(ArgumentsWildcard $wildcard)\n    {\n        $this->withArguments($wildcard);\n\n        $this->getArgumentsWildcard()->shouldReturn($wildcard);\n    }\n\n    function its_withArguments_transforms_passed_array_into_ArgumentsWildcard()\n    {\n        $this->withArguments(array(42, 33));\n\n        $wildcard = $this->getArgumentsWildcard();\n        $wildcard->shouldNotBe(null);\n        $wildcard->__toString()->shouldReturn('exact(42), exact(33)');\n    }\n\n    function its_withArguments_throws_exception_if_wrong_arguments_provided()\n    {\n        $this->shouldThrow('Prophecy\\Exception\\InvalidArgumentException')->duringWithArguments(42);\n    }\n\n    function it_returns_null_for_void_return_type(ObjectProphecy $objectProphecy, ArgumentsWildcard $argumentsWildcard)\n    {\n        $this->generateMethodProphecyWithReturnValue($objectProphecy, 'foo', 'void');\n        $this->beConstructedWith($objectProphecy, 'foo', $argumentsWildcard);\n\n        $this->getPromise()->execute([], $objectProphecy, $this)->shouldBeNull();\n    }\n\n    function it_returns_empty_string_for_string_return_type(ObjectProphecy $objectProphecy, ArgumentsWildcard $argumentsWildcard)\n    {\n        $this->generateMethodProphecyWithReturnValue($objectProphecy, 'foo', 'string');\n        $this->beConstructedWith($objectProphecy, 'foo', $argumentsWildcard);\n\n        $this->getPromise()->execute([], $objectProphecy, $this)->shouldBe('');\n    }\n\n    function it_returns_zero_for_float_return_type(ObjectProphecy $objectProphecy, ArgumentsWildcard $argumentsWildcard)\n    {\n        $this->generateMethodProphecyWithReturnValue($objectProphecy, 'foo', 'float');\n        $this->beConstructedWith($objectProphecy, 'foo', $argumentsWildcard);\n\n        $this->getPromise()->execute([], $objectProphecy, $this)->shouldBe(0.00);\n    }\n\n    function it_returns_false_for_bool_return_type(ObjectProphecy $objectProphecy, ArgumentsWildcard $argumentsWildcard)\n    {\n        $this->generateMethodProphecyWithReturnValue($objectProphecy, 'foo', 'bool');\n        $this->beConstructedWith($objectProphecy, 'foo', $argumentsWildcard);\n\n        $this->getPromise()->execute([], $objectProphecy, $this)->shouldBe(false);\n    }\n\n    function it_returns_empty_for_array_return_type(ObjectProphecy $objectProphecy, ArgumentsWildcard $argumentsWildcard)\n    {\n        $this->generateMethodProphecyWithReturnValue($objectProphecy, 'foo', 'array');\n        $this->beConstructedWith($objectProphecy, 'foo', $argumentsWildcard);\n\n        $this->getPromise()->execute([], $objectProphecy, $this)->shouldBe([]);\n    }\n\n    function it_returns_empty_closure_for_callable_return_type(ObjectProphecy $objectProphecy, ArgumentsWildcard $argumentsWildcard)\n    {\n        $this->generateMethodProphecyWithReturnValue($objectProphecy, 'foo', 'callable');\n        $this->beConstructedWith($objectProphecy, 'foo', $argumentsWildcard);\n\n        $this->getPromise()->execute([], $objectProphecy, $this)->shouldBeAnInstanceOf(\\Closure::class);\n    }\n\n    function it_returns_empty_closure_for_closure_return_type(ObjectProphecy $objectProphecy, ArgumentsWildcard $argumentsWildcard)\n    {\n        $this->generateMethodProphecyWithReturnValue($objectProphecy, 'foo', 'Closure');\n        $this->beConstructedWith($objectProphecy, 'foo', $argumentsWildcard);\n\n        $this->getPromise()->execute([], $objectProphecy, $this)->shouldBeAnInstanceOf(\\Closure::class);\n    }\n\n    function it_returns_null_generator_for_traversable_return_type(ObjectProphecy $objectProphecy, ArgumentsWildcard $argumentsWildcard)\n    {\n        $this->generateMethodProphecyWithReturnValue($objectProphecy, 'foo', 'Traversable');\n        $this->beConstructedWith($objectProphecy, 'foo', $argumentsWildcard);\n\n        $this->getPromise()->execute([], $objectProphecy, $this)->shouldYieldLike([null]);\n    }\n\n    function it_returns_null_generator_for_generator_return_type(ObjectProphecy $objectProphecy, ArgumentsWildcard $argumentsWildcard)\n    {\n        $this->generateMethodProphecyWithReturnValue($objectProphecy, 'foo', 'Generator');\n        $this->beConstructedWith($objectProphecy, 'foo', $argumentsWildcard);\n\n        $this->getPromise()->execute([], $objectProphecy, $this)->shouldYieldLike([null]);\n    }\n\n    function it_returns_an_object_prophecy_for_other_object_return_types(ObjectProphecy $objectProphecy, ArgumentsWildcard $argumentsWildcard)\n    {\n        $this->generateMethodProphecyWithReturnValue($objectProphecy, 'foo', 'ArrayObject');\n        $this->beConstructedWith($objectProphecy, 'foo', $argumentsWildcard);\n\n        $return = $this->getPromise()->execute([], $objectProphecy, $this);\n        $return->shouldBeAnInstanceOf(\\ArrayObject::class);\n        $return->shouldImplement(ProphecySubjectInterface::class);\n    }\n\n    function it_returns_object_prophecy_for_nullable_return_type(ObjectProphecy $objectProphecy, ArgumentsWildcard $argumentsWildcard)\n    {\n        $this->generateMethodProphecyWithReturnValue($objectProphecy, 'foo', '?ArrayObject');\n        $this->beConstructedWith($objectProphecy, 'foo', $argumentsWildcard);\n\n        $return = $this->getPromise()->execute([], $objectProphecy, $this);\n        $return->shouldBeAnInstanceOf(\\ArrayObject::class);\n        $return->shouldImplement(ProphecySubjectInterface::class);\n    }\n\n    function it_returns_scalar_prophecy_for_scalar_and_null_union(ObjectProphecy $objectProphecy, ArgumentsWildcard $argumentsWildcard)\n    {\n        if (\\PHP_VERSION_ID < 80000) {\n            return;\n        }\n\n        $this->generateMethodProphecyWithReturnValue($objectProphecy, 'foo', 'string|null|int');\n        $this->beConstructedWith($objectProphecy, 'foo', $argumentsWildcard);\n\n        $this->getPromise()->execute([], $objectProphecy, $this)->shouldNotBeNull();\n    }\n\n    function it_returns_object_prophecy_for_object_scalar_union(ObjectProphecy $objectProphecy, ArgumentsWildcard $argumentsWildcard)\n    {\n        if (\\PHP_VERSION_ID < 80000) {\n            return;\n        }\n\n        $this->generateMethodProphecyWithReturnValue($objectProphecy, 'foo', 'string|ArrayObject|int');\n        $this->beConstructedWith($objectProphecy, 'foo', $argumentsWildcard);\n\n        $return = $this->getPromise()->execute([], $objectProphecy, $this);\n        $return->shouldBeAnInstanceOf(\\ArrayObject::class);\n        $return->shouldImplement(ProphecySubjectInterface::class);\n    }\n\n    function it_returns_object_prophecy_for_object_return_type(ObjectProphecy $objectProphecy, ArgumentsWildcard $argumentsWildcard)\n    {\n        $this->generateMethodProphecyWithReturnValue($objectProphecy, 'foo', 'object');\n        $this->beConstructedWith($objectProphecy, 'foo', $argumentsWildcard);\n\n        $return = $this->getPromise()->execute([], $objectProphecy, $this);\n        $return->shouldImplement(ProphecySubjectInterface::class);\n    }\n\n    function it_throws_for_non_existent_class_return_type(ObjectProphecy $objectProphecy, ArgumentsWildcard $argumentsWildcard)\n    {\n        $this->generateMethodProphecyWithReturnValue($objectProphecy, 'foo', 'NonExistentClass');\n        $this->beConstructedWith($objectProphecy, 'foo', $argumentsWildcard);\n\n        $return = $this->getPromise()->shouldThrow(MethodProphecyException::class)->during('execute', [[], $objectProphecy, $this]);\n    }\n\n    function it_returns_true_prophecy_for_true_return_type(ObjectProphecy $objectProphecy, ArgumentsWildcard $argumentsWildcard)\n    {\n        if (\\PHP_VERSION_ID < 80200) {\n            return;\n        }\n\n        $this->generateMethodProphecyWithReturnValue($objectProphecy, 'foo', 'true');\n        $this->beConstructedWith($objectProphecy, 'foo', $argumentsWildcard);\n\n        $this->getPromise()->execute([], $objectProphecy, $this)->shouldBe(true);\n    }\n\n    function it_returns_false_prophecy_for_false_return_type(ObjectProphecy $objectProphecy, ArgumentsWildcard $argumentsWildcard)\n    {\n        if (\\PHP_VERSION_ID < 80200) {\n            return;\n        }\n\n        $this->generateMethodProphecyWithReturnValue($objectProphecy, 'foo', 'false');\n        $this->beConstructedWith($objectProphecy, 'foo', $argumentsWildcard);\n\n        $this->getPromise()->execute([], $objectProphecy, $this)->shouldBe(false);\n    }\n\n    function it_returns_null_prophecy_for_null_return_type(ObjectProphecy $objectProphecy, ArgumentsWildcard $argumentsWildcard)\n    {\n        if (\\PHP_VERSION_ID < 80200) {\n            return;\n        }\n\n        $this->generateMethodProphecyWithReturnValue($objectProphecy, 'foo', 'null');\n        $this->beConstructedWith($objectProphecy, 'foo', $argumentsWildcard);\n\n        $this->getPromise()->execute([], $objectProphecy, $this)->shouldBe(null);\n    }\n\n    private function generateMethodProphecyWithReturnValue($objectProphecy, string $methodName, string $returnType): void\n    {\n        $objectProphecy->reveal()->willReturn(\n            eval(\n                <<<CODE\nreturn new class() {\n     public function $methodName() : $returnType {}\n};\nCODE\n            )\n        );\n        $objectProphecy->addMethodProphecy(Argument::any())->willReturn();\n    }\n\n\n}\n\nclass ClassWithFinalMethod\n{\n    final public function finalMethod() {}\n}\n\nclass ClassWithVoidTypeHintedMethods\n{\n    public function getVoid(): void {}\n}\n"
  },
  {
    "path": "spec/Prophecy/Prophecy/ObjectProphecySpec.php",
    "content": "<?php\n\nnamespace spec\\Prophecy\\Prophecy;\n\nuse PhpSpec\\ObjectBehavior;\nuse Prophecy\\Argument;\nuse Prophecy\\Argument\\ArgumentsWildcard;\nuse Prophecy\\Call\\Call;\nuse Prophecy\\Call\\CallCenter;\nuse Prophecy\\Doubler\\Doubler;\nuse Prophecy\\Doubler\\LazyDouble;\nuse Prophecy\\Prophecy\\MethodProphecy;\nuse Prophecy\\Prophecy\\ProphecySubjectInterface;\nuse Prophecy\\Prophecy\\RevealerInterface;\n\nclass ObjectProphecySpec extends ObjectBehavior\n{\n    function let(LazyDouble $lazyDouble, ProphecySubjectInterface $double)\n    {\n        $this->beConstructedWith($lazyDouble);\n\n        $lazyDouble->getInstance()->willReturn($double);\n    }\n\n    function it_implements_ProphecyInterface()\n    {\n        $this->shouldBeAnInstanceOf('Prophecy\\Prophecy\\ProphecyInterface');\n    }\n\n    function it_sets_parentClass_during_willExtend_call($lazyDouble)\n    {\n        $lazyDouble->setParentClass('123')->shouldBeCalled();\n\n        $this->willExtend('123');\n    }\n\n    function it_adds_interface_during_willImplement_call($lazyDouble)\n    {\n        $lazyDouble->addInterface('222')->shouldBeCalled();\n\n        $this->willImplement('222');\n    }\n\n    function it_sets_constructor_arguments_during_willBeConstructedWith_call($lazyDouble)\n    {\n        $lazyDouble->setArguments(array(1, 2, 5))->shouldBeCalled();\n\n        $this->willBeConstructedWith(array(1, 2, 5));\n    }\n\n    function it_does_not_have_method_prophecies_by_default()\n    {\n        $this->getMethodProphecies()->shouldHaveCount(0);\n    }\n\n    function it_should_get_method_prophecies_by_method_name(\n        MethodProphecy $method1,\n        MethodProphecy $method2,\n        ArgumentsWildcard $arguments\n    ) {\n        $method1->getMethodName()->willReturn('getName');\n        $method1->getArgumentsWildcard()->willReturn($arguments);\n        $method2->getMethodName()->willReturn('setName');\n        $method2->getArgumentsWildcard()->willReturn($arguments);\n\n        $this->addMethodProphecy($method1);\n        $this->addMethodProphecy($method2);\n\n        $methods = $this->getMethodProphecies('setName');\n        $methods->shouldHaveCount(1);\n        $methods[0]->getMethodName()->shouldReturn('setName');\n    }\n\n    function it_should_return_empty_array_if_no_method_prophecies_found()\n    {\n        $methods = $this->getMethodProphecies('setName');\n        $methods->shouldHaveCount(0);\n    }\n\n    function it_should_proxy_makeProphecyMethodCall_to_CallCenter($lazyDouble, CallCenter $callCenter)\n    {\n        $this->beConstructedWith($lazyDouble, $callCenter);\n\n        $callCenter->makeCall($this->getWrappedObject(), 'setName', array('everzet'))->willReturn(42);\n\n        $this->makeProphecyMethodCall('setName', array('everzet'))->shouldReturn(42);\n    }\n\n    function it_should_reveal_arguments_and_return_values_from_callCenter(\n        $lazyDouble,\n        CallCenter $callCenter,\n        RevealerInterface $revealer\n    ) {\n        $this->beConstructedWith($lazyDouble, $callCenter, $revealer);\n\n        $revealer->reveal(array('question'))->willReturn(array('life'));\n        $revealer->reveal('answer')->willReturn(42);\n\n        $callCenter->makeCall($this->getWrappedObject(), 'setName', array('life'))->willReturn('answer');\n\n        $this->makeProphecyMethodCall('setName', array('question'))->shouldReturn(42);\n    }\n\n    function it_should_proxy_getProphecyMethodCalls_to_CallCenter(\n        $lazyDouble,\n        CallCenter $callCenter,\n        ArgumentsWildcard $wildcard,\n        Call $call\n    ) {\n        $this->beConstructedWith($lazyDouble, $callCenter);\n\n        $callCenter->findCalls('setName', $wildcard)->willReturn(array($call));\n\n        $this->findProphecyMethodCalls('setName', $wildcard)->shouldReturn(array($call));\n    }\n\n    function its_addMethodProphecy_adds_method_prophecy(\n        MethodProphecy $methodProphecy,\n        ArgumentsWildcard $argumentsWildcard\n    ) {\n        $methodProphecy->getArgumentsWildcard()->willReturn($argumentsWildcard);\n        $methodProphecy->getMethodName()->willReturn('getUsername');\n\n        $this->addMethodProphecy($methodProphecy);\n\n        $this->getMethodProphecies()->shouldReturn(array(\n            'getusername' => array($methodProphecy),\n        ));\n    }\n\n    function its_addMethodProphecy_handles_prophecies_with_different_arguments(\n        MethodProphecy $methodProphecy1,\n        MethodProphecy $methodProphecy2,\n        ArgumentsWildcard $argumentsWildcard1,\n        ArgumentsWildcard $argumentsWildcard2\n    ) {\n        $methodProphecy1->getArgumentsWildcard()->willReturn($argumentsWildcard1);\n        $methodProphecy1->getMethodName()->willReturn('getUsername');\n\n        $methodProphecy2->getArgumentsWildcard()->willReturn($argumentsWildcard2);\n        $methodProphecy2->getMethodName()->willReturn('getUsername');\n\n        $this->addMethodProphecy($methodProphecy1);\n        $this->addMethodProphecy($methodProphecy2);\n\n        $this->getMethodProphecies()->shouldReturn(array(\n            'getusername' => array(\n                $methodProphecy1,\n                $methodProphecy2,\n            ),\n        ));\n    }\n\n    function its_addMethodProphecy_handles_prophecies_for_caseinsensitive_method_names(\n        MethodProphecy $methodProphecy1,\n        MethodProphecy $methodProphecy2,\n        ArgumentsWildcard $argumentsWildcard1,\n        ArgumentsWildcard $argumentsWildcard2\n    ) {\n        $methodProphecy1->getArgumentsWildcard()->willReturn($argumentsWildcard1);\n        $methodProphecy1->getMethodName()->willReturn('getUsername');\n\n        $methodProphecy2->getArgumentsWildcard()->willReturn($argumentsWildcard2);\n        $methodProphecy2->getMethodName()->willReturn('getUserName');\n\n        $this->addMethodProphecy($methodProphecy1);\n        $this->addMethodProphecy($methodProphecy2);\n\n        $this->getMethodProphecies()->shouldReturn(array(\n            'getusername' => array(\n                $methodProphecy1,\n                $methodProphecy2,\n            ),\n        ));\n    }\n\n    function its_addMethodProphecy_handles_prophecies_for_different_methods(\n        MethodProphecy $methodProphecy1,\n        MethodProphecy $methodProphecy2,\n        ArgumentsWildcard $argumentsWildcard1,\n        ArgumentsWildcard $argumentsWildcard2\n    ) {\n        $methodProphecy1->getArgumentsWildcard()->willReturn($argumentsWildcard1);\n        $methodProphecy1->getMethodName()->willReturn('getUsername');\n\n        $methodProphecy2->getArgumentsWildcard()->willReturn($argumentsWildcard2);\n        $methodProphecy2->getMethodName()->willReturn('isUsername');\n\n        $this->addMethodProphecy($methodProphecy1);\n        $this->addMethodProphecy($methodProphecy2);\n\n        $this->getMethodProphecies()->shouldReturn(array(\n            'getusername' => array(\n                $methodProphecy1,\n            ),\n            'isusername' => array(\n                $methodProphecy2,\n            ),\n        ));\n    }\n\n    function it_returns_null_after_checkPredictions_call_if_there_is_no_method_prophecies()\n    {\n        $this->checkProphecyMethodsPredictions()->shouldReturn(null);\n    }\n\n    function it_throws_AggregateException_during_checkPredictions_if_predictions_fail(\n        MethodProphecy $methodProphecy1, MethodProphecy $methodProphecy2,\n        ArgumentsWildcard $argumentsWildcard1,\n        ArgumentsWildcard $argumentsWildcard2\n    ) {\n        $methodProphecy1->getMethodName()->willReturn('getName');\n        $methodProphecy1->getArgumentsWildcard()->willReturn($argumentsWildcard1);\n        $methodProphecy1->checkPrediction()\n            ->willThrow('Prophecy\\Exception\\Prediction\\AggregateException');\n\n        $methodProphecy2->getMethodName()->willReturn('setName');\n        $methodProphecy2->getArgumentsWildcard()->willReturn($argumentsWildcard2);\n        $methodProphecy2->checkPrediction()\n            ->willThrow('Prophecy\\Exception\\Prediction\\AggregateException');\n\n        $this->addMethodProphecy($methodProphecy1);\n        $this->addMethodProphecy($methodProphecy2);\n\n        $this->shouldThrow('Prophecy\\Exception\\Prediction\\AggregateException')\n            ->duringCheckProphecyMethodsPredictions();\n    }\n\n    function it_returns_new_MethodProphecy_instance_for_arbitrary_call(\n        Doubler $doubler,\n        ProphecySubjectInterface $reflection\n    ) {\n        $doubler->double(Argument::any())->willReturn($reflection);\n\n        $return = $this->getProphecy();\n        $return->shouldBeAnInstanceOf('Prophecy\\Prophecy\\MethodProphecy');\n        $return->getMethodName()->shouldReturn('getProphecy');\n    }\n\n    function it_returns_same_MethodProphecy_for_same_registered_signature(\n        Doubler $doubler,\n        ProphecySubjectInterface $reflection\n    ) {\n        $doubler->double(Argument::any())->willReturn($reflection);\n\n        $this->addMethodProphecy($methodProphecy1 = $this->getProphecy(1, 2, 3));\n        $methodProphecy2 = $this->getProphecy(1, 2, 3);\n\n        $methodProphecy2->shouldBe($methodProphecy1);\n    }\n\n    function it_returns_new_MethodProphecy_for_different_signatures(\n        Doubler $doubler,\n        ProphecySubjectInterface $reflection\n    ) {\n        $doubler->double(Argument::any())->willReturn($reflection);\n\n        $value = new ObjectProphecySpecFixtureB('ABC');\n        $value2 = new ObjectProphecySpecFixtureB('CBA');\n\n        $this->addMethodProphecy($methodProphecy1 = $this->getProphecy(1, 2, 3, $value));\n        $methodProphecy2 = $this->getProphecy(1, 2, 3, $value2);\n\n        $methodProphecy2->shouldNotBe($methodProphecy1);\n    }\n\n    function it_returns_new_MethodProphecy_for_all_callback_signatures(\n        Doubler $doubler,\n        ProphecySubjectInterface $reflection\n    ) {\n        $doubler->double(Argument::any())->willReturn($reflection);\n\n        $this->addMethodProphecy($methodProphecy1 = $this->getProphecy(function () {}));\n        $methodProphecy2 = $this->getProphecy(function () {});\n\n        $methodProphecy2->shouldNotBe($methodProphecy1);\n    }\n\n    function it_throws_UnexpectedCallException_during_checkPredictions_if_unexpected_method_was_called(\n        $lazyDouble, CallCenter $callCenter\n    ) {\n        $this->beConstructedWith($lazyDouble, $callCenter);\n\n        $callCenter->checkUnexpectedCalls()->willThrow('Prophecy\\Exception\\Call\\UnexpectedCallException');\n\n        $this->shouldThrow('Prophecy\\Exception\\Call\\UnexpectedCallException')\n             ->duringCheckProphecyMethodsPredictions();\n    }\n}\n\nclass ObjectProphecySpecFixtureA\n{\n    public $errors;\n}\n\nclass ObjectProphecySpecFixtureB extends ObjectProphecySpecFixtureA\n{\n    public $errors;\n    public $value = null;\n\n    public function __construct($value)\n    {\n        $this->value = $value;\n    }\n}\n"
  },
  {
    "path": "spec/Prophecy/Prophecy/RevealerSpec.php",
    "content": "<?php\n\nnamespace spec\\Prophecy\\Prophecy;\n\nuse PhpSpec\\ObjectBehavior;\nuse Prophecy\\Prophecy\\ProphecyInterface;\n\nclass RevealerSpec extends ObjectBehavior\n{\n    function it_is_revealer()\n    {\n        $this->shouldBeAnInstanceOf('Prophecy\\Prophecy\\RevealerInterface');\n    }\n\n    function it_reveals_single_instance_of_ProphecyInterface(ProphecyInterface $prophecy, \\stdClass $object)\n    {\n        $prophecy->reveal()->willReturn($object);\n\n        $this->reveal($prophecy)->shouldReturn($object);\n    }\n\n    function it_reveals_instances_of_ProphecyInterface_inside_array(\n        ProphecyInterface $prophecy1,\n        ProphecyInterface $prophecy2,\n        \\stdClass $object1,\n        \\stdClass $object2\n    ) {\n        $prophecy1->reveal()->willReturn($object1);\n        $prophecy2->reveal()->willReturn($object2);\n\n        $this->reveal(array(\n            array('item' => $prophecy2),\n            $prophecy1,\n        ))->shouldReturn(array(\n            array('item' => $object2),\n            $object1,\n        ));\n    }\n\n    function it_does_not_touch_non_prophecy_interface()\n    {\n        $this->reveal(42)->shouldReturn(42);\n    }\n}\n"
  },
  {
    "path": "spec/Prophecy/ProphetSpec.php",
    "content": "<?php\n\nnamespace spec\\Prophecy;\n\nuse PhpSpec\\ObjectBehavior;\nuse Prophecy\\Argument;\nuse Prophecy\\Argument\\ArgumentsWildcard;\nuse Prophecy\\Doubler\\Doubler;\nuse Prophecy\\Prophecy\\MethodProphecy;\nuse Prophecy\\Prophecy\\ProphecySubjectInterface;\n\nclass ProphetSpec extends ObjectBehavior\n{\n    function let(Doubler $doubler, ProphecySubjectInterface $double)\n    {\n        $doubler->double(null, array())->willReturn($double);\n\n        $this->beConstructedWith($doubler);\n    }\n\n    function it_constructs_new_prophecy_on_prophesize_call()\n    {\n        $prophecy = $this->prophesize();\n        $prophecy->shouldBeAnInstanceOf('Prophecy\\Prophecy\\ObjectProphecy');\n    }\n\n    function it_constructs_new_prophecy_with_parent_class_if_specified($doubler, ProphecySubjectInterface $newDouble)\n    {\n        $doubler->double(Argument::any(), array())->willReturn($newDouble);\n\n        $this->prophesize('Prophecy\\Prophet')->reveal()->shouldReturn($newDouble);\n    }\n\n    function it_constructs_new_prophecy_with_interface_if_specified($doubler, ProphecySubjectInterface $newDouble)\n    {\n        $doubler->double(null, Argument::any())->willReturn($newDouble);\n\n        $this->prophesize('ArrayAccess')->reveal()->shouldReturn($newDouble);\n    }\n\n    function it_exposes_all_created_prophecies_through_getter()\n    {\n        $prophecy1 = $this->prophesize();\n        $prophecy2 = $this->prophesize();\n\n        $this->getProphecies()->shouldReturn(array($prophecy1, $prophecy2));\n    }\n\n    function it_does_nothing_during_checkPredictions_call_if_no_predictions_defined()\n    {\n        $this->checkPredictions()->shouldReturn(null);\n    }\n\n    function it_throws_AggregateException_if_defined_predictions_fail(\n        MethodProphecy $method1,\n        MethodProphecy $method2,\n        ArgumentsWildcard $arguments1,\n        ArgumentsWildcard $arguments2\n    ) {\n        $method1->getMethodName()->willReturn('getName');\n        $method1->getArgumentsWildcard()->willReturn($arguments1);\n        $method1->checkPrediction()->willReturn(null);\n\n        $method2->getMethodName()->willReturn('isSet');\n        $method2->getArgumentsWildcard()->willReturn($arguments2);\n        $method2->checkPrediction()->willThrow(\n            'Prophecy\\Exception\\Prediction\\AggregateException'\n        );\n\n        $this->prophesize()->addMethodProphecy($method1);\n        $this->prophesize()->addMethodProphecy($method2);\n\n        $this->shouldThrow('Prophecy\\Exception\\Prediction\\AggregateException')\n            ->duringCheckPredictions();\n    }\n\n    function it_exposes_doubler_through_getter($doubler)\n    {\n        $this->getDoubler()->shouldReturn($doubler);\n    }\n\n    function it_throws_ClassNotFound_if_class_to_prophesize_does_not_exist()\n    {\n        $this->shouldThrow('Prophecy\\Exception\\Doubler\\ClassNotFoundException')\n            ->duringProphesize('This\\ClassOrInterface\\Does\\Not\\Exist');\n\n    }\n\n    function it_does_not_throw_when_creating_void_mock()\n    {\n        $this->shouldNotThrow()\n            ->duringProphesize();\n    }\n}\n"
  },
  {
    "path": "spec/Prophecy/Util/StringUtilSpec.php",
    "content": "<?php\n\nnamespace spec\\Prophecy\\Util;\n\nuse PhpSpec\\ObjectBehavior;\n\nclass StringUtilSpec extends ObjectBehavior\n{\n    function it_generates_proper_string_representation_for_integer()\n    {\n        $this->stringify(42)->shouldReturn('42');\n    }\n\n    function it_generates_proper_string_representation_for_string()\n    {\n        $this->stringify('some string')->shouldReturn('\"some string\"');\n    }\n\n    function it_generates_single_line_representation_for_multiline_string()\n    {\n        $this->stringify(\"some\\nstring\")->shouldReturn('\"some\\\\nstring\"');\n    }\n\n    function it_generates_proper_string_representation_for_double()\n    {\n        $this->stringify(42.3)->shouldReturn('42.3');\n    }\n\n    function it_generates_proper_string_representation_for_boolean_true()\n    {\n        $this->stringify(true)->shouldReturn('true');\n    }\n\n    function it_generates_proper_string_representation_for_boolean_false()\n    {\n        $this->stringify(false)->shouldReturn('false');\n    }\n\n    function it_generates_proper_string_representation_for_null()\n    {\n        $this->stringify(null)->shouldReturn('null');\n    }\n\n    function it_generates_proper_string_representation_for_empty_array()\n    {\n        $this->stringify(array())->shouldReturn('[]');\n    }\n\n    function it_generates_proper_string_representation_for_array()\n    {\n        $this->stringify(array('zet', 42))->shouldReturn('[\"zet\", 42]');\n    }\n\n    function it_generates_proper_string_representation_for_hash_containing_one_value()\n    {\n        $this->stringify(array('ever' => 'zet'))->shouldReturn('[\"ever\" => \"zet\"]');\n    }\n\n    function it_generates_proper_string_representation_for_hash()\n    {\n        $this->stringify(array('ever' => 'zet', 52 => 'hey', 'num' => 42))->shouldReturn(\n            '[\"ever\" => \"zet\", 52 => \"hey\", \"num\" => 42]'\n        );\n    }\n\n    function it_generates_proper_string_representation_for_resource()\n    {\n        $resource = fopen(__FILE__, 'r');\n        $this->stringify($resource)->shouldReturn('stream:'.$resource);\n    }\n\n    function it_generates_proper_string_representation_for_object(\\stdClass $object)\n    {\n        $objHash = sprintf('%s#%s',\n            get_class($object->getWrappedObject()),\n            spl_object_id($object->getWrappedObject())\n        ).\" Object (\\n    'objectProphecyClosure' => Closure#%s Object (\\n        0 => Closure#%s Object\\n    )\\n)\";\n\n        $idRegexExpr = '[0-9]+';\n        $this->stringify($object)->shouldMatch(sprintf('/^%s$/', sprintf(preg_quote(\"$objHash\"), $idRegexExpr, $idRegexExpr)));\n    }\n\n    function it_generates_proper_string_representation_for_object_without_exporting(\\stdClass $object)\n    {\n        $objHash = sprintf('%s#%s',\n            get_class($object->getWrappedObject()),\n            spl_object_id($object->getWrappedObject())\n        );\n\n        $this->stringify($object, false)->shouldReturn(\"$objHash\");\n    }\n}\n"
  },
  {
    "path": "src/Prophecy/Argument/ArgumentsWildcard.php",
    "content": "<?php\n\n/*\n * This file is part of the Prophecy.\n * (c) Konstantin Kudryashov <ever.zet@gmail.com>\n *     Marcello Duarte <marcello.duarte@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Prophecy\\Argument;\n\n/**\n * Arguments wildcarding.\n *\n * @author Konstantin Kudryashov <ever.zet@gmail.com>\n */\nclass ArgumentsWildcard\n{\n    /**\n     * @var list<Token\\TokenInterface>\n     */\n    private $tokens = array();\n    /**\n     * @var string|null\n     */\n    private $string;\n\n    /**\n     * Initializes wildcard.\n     *\n     * @param array<mixed> $arguments Array of argument tokens or values\n     */\n    public function __construct(array $arguments)\n    {\n        foreach ($arguments as $argument) {\n            if (!$argument instanceof Token\\TokenInterface) {\n                $argument = new Token\\ExactValueToken($argument);\n            }\n\n            $this->tokens[] = $argument;\n        }\n    }\n\n    /**\n     * Calculates wildcard match score for provided arguments.\n     *\n     * @param array<mixed> $arguments\n     *\n     * @return false|int False OR integer score (higher - better)\n     */\n    public function scoreArguments(array $arguments)\n    {\n        if (0 == count($arguments) && 0 == count($this->tokens)) {\n            return 1;\n        }\n\n        $arguments  = array_values($arguments);\n        $totalScore = 0;\n        foreach ($this->tokens as $i => $token) {\n            $argument = isset($arguments[$i]) ? $arguments[$i] : null;\n            if (1 >= $score = $token->scoreArgument($argument)) {\n                return false;\n            }\n\n            $totalScore += $score;\n\n            if (true === $token->isLast()) {\n                return $totalScore;\n            }\n        }\n\n        if (count($arguments) > count($this->tokens)) {\n            return false;\n        }\n\n        return $totalScore;\n    }\n\n    /**\n     * Returns string representation for wildcard.\n     *\n     * @return string\n     */\n    public function __toString()\n    {\n        if (null === $this->string) {\n            $this->string = implode(', ', array_map(function ($token) {\n                return (string) $token;\n            }, $this->tokens));\n        }\n\n        return $this->string;\n    }\n\n    /**\n     * @return list<Token\\TokenInterface>\n     */\n    public function getTokens()\n    {\n        return $this->tokens;\n    }\n}\n"
  },
  {
    "path": "src/Prophecy/Argument/Token/AnyValueToken.php",
    "content": "<?php\n\n/*\n * This file is part of the Prophecy.\n * (c) Konstantin Kudryashov <ever.zet@gmail.com>\n *     Marcello Duarte <marcello.duarte@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Prophecy\\Argument\\Token;\n\n/**\n * Any single value token.\n *\n * @author Konstantin Kudryashov <ever.zet@gmail.com>\n */\nclass AnyValueToken implements TokenInterface\n{\n    /**\n     * Always scores 3 for any argument.\n     *\n     * @param mixed $argument\n     *\n     * @return int\n     */\n    public function scoreArgument($argument)\n    {\n        return 3;\n    }\n\n    /**\n     * Returns false.\n     *\n     * @return bool\n     */\n    public function isLast()\n    {\n        return false;\n    }\n\n    /**\n     * Returns string representation for token.\n     *\n     * @return string\n     */\n    public function __toString()\n    {\n        return '*';\n    }\n}\n"
  },
  {
    "path": "src/Prophecy/Argument/Token/AnyValuesToken.php",
    "content": "<?php\n\n/*\n * This file is part of the Prophecy.\n * (c) Konstantin Kudryashov <ever.zet@gmail.com>\n *     Marcello Duarte <marcello.duarte@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Prophecy\\Argument\\Token;\n\n/**\n * Any values token.\n *\n * @author Konstantin Kudryashov <ever.zet@gmail.com>\n */\nclass AnyValuesToken implements TokenInterface\n{\n    /**\n     * Always scores 2 for any argument.\n     *\n     * @param $argument\n     *\n     * @return int\n     */\n    public function scoreArgument($argument)\n    {\n        return 2;\n    }\n\n    /**\n     * Returns true to stop wildcard from processing other tokens.\n     *\n     * @return bool\n     */\n    public function isLast()\n    {\n        return true;\n    }\n\n    /**\n     * Returns string representation for token.\n     *\n     * @return string\n     */\n    public function __toString()\n    {\n        return '* [, ...]';\n    }\n}\n"
  },
  {
    "path": "src/Prophecy/Argument/Token/ApproximateValueToken.php",
    "content": "<?php\n\n/*\n * This file is part of the Prophecy.\n * (c) Konstantin Kudryashov <ever.zet@gmail.com>\n *     Marcello Duarte <marcello.duarte@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Prophecy\\Argument\\Token;\n\n/**\n * Approximate value token\n *\n * @author Daniel Leech <daniel@dantleech.com>\n */\nclass ApproximateValueToken implements TokenInterface\n{\n    private $value;\n    private $precision;\n\n    /**\n     * @param float $value\n     * @param int $precision\n     */\n    public function __construct($value, $precision = 0)\n    {\n        $this->value = $value;\n        $this->precision = $precision;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function scoreArgument($argument)\n    {\n        if (!\\is_float($argument) && !\\is_int($argument) && !\\is_numeric($argument)) {\n            return false;\n        }\n\n        return round((float) $argument, $this->precision) === round($this->value, $this->precision) ? 10 : false;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function isLast()\n    {\n        return false;\n    }\n\n    /**\n     * Returns string representation for token.\n     *\n     * @return string\n     */\n    public function __toString()\n    {\n        return sprintf('≅%s', round($this->value, $this->precision));\n    }\n}\n"
  },
  {
    "path": "src/Prophecy/Argument/Token/ArrayCountToken.php",
    "content": "<?php\n\n/*\n * This file is part of the Prophecy.\n * (c) Konstantin Kudryashov <ever.zet@gmail.com>\n *     Marcello Duarte <marcello.duarte@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Prophecy\\Argument\\Token;\n\n/**\n * Array elements count token.\n *\n * @author Boris Mikhaylov <kaguxmail@gmail.com>\n */\n\nclass ArrayCountToken implements TokenInterface\n{\n    private $count;\n\n    /**\n     * @param integer $value\n     */\n    public function __construct($value)\n    {\n        $this->count = $value;\n    }\n\n    /**\n     * Scores 6 when argument has preset number of elements.\n     *\n     * @param mixed $argument\n     *\n     * @return false|int\n     */\n    public function scoreArgument($argument)\n    {\n        return $this->isCountable($argument) && $this->hasProperCount($argument) ? 6 : false;\n    }\n\n    /**\n     * Returns false.\n     *\n     * @return boolean\n     */\n    public function isLast()\n    {\n        return false;\n    }\n\n    /**\n     * Returns string representation for token.\n     *\n     * @return string\n     */\n    public function __toString()\n    {\n        return sprintf('count(%s)', $this->count);\n    }\n\n    /**\n     * Returns true if object is either array or instance of \\Countable\n     *\n     * @param mixed $argument\n     * @return bool\n     *\n     * @phpstan-assert-if-true array<mixed>|\\Countable $argument\n     */\n    private function isCountable($argument)\n    {\n        return (is_array($argument) || $argument instanceof \\Countable);\n    }\n\n    /**\n     * Returns true if $argument has expected number of elements\n     *\n     * @param array<mixed>|\\Countable $argument\n     *\n     * @return bool\n     */\n    private function hasProperCount($argument)\n    {\n        return $this->count === count($argument);\n    }\n}\n"
  },
  {
    "path": "src/Prophecy/Argument/Token/ArrayEntryToken.php",
    "content": "<?php\n\n/*\n * This file is part of the Prophecy.\n * (c) Konstantin Kudryashov <ever.zet@gmail.com>\n *     Marcello Duarte <marcello.duarte@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Prophecy\\Argument\\Token;\n\nuse Prophecy\\Exception\\InvalidArgumentException;\n\n/**\n * Array entry token.\n *\n * @author Boris Mikhaylov <kaguxmail@gmail.com>\n */\nclass ArrayEntryToken implements TokenInterface\n{\n    /** @var TokenInterface */\n    private $key;\n    /** @var TokenInterface */\n    private $value;\n\n    /**\n     * @param mixed $key   exact value or token\n     * @param mixed $value exact value or token\n     */\n    public function __construct($key, $value)\n    {\n        $this->key = $this->wrapIntoExactValueToken($key);\n        $this->value = $this->wrapIntoExactValueToken($value);\n    }\n\n    /**\n     * Scores half of combined scores from key and value tokens for same entry. Capped at 8.\n     * If argument implements \\ArrayAccess without \\Traversable, then key token is restricted to ExactValueToken.\n     *\n     * @param mixed $argument\n     *\n     * @throws InvalidArgumentException\n     * @return false|int\n     */\n    public function scoreArgument($argument)\n    {\n        if ($argument instanceof \\Traversable) {\n            $argument = iterator_to_array($argument);\n        }\n\n        if ($argument instanceof \\ArrayAccess) {\n            $argument = $this->convertArrayAccessToEntry($argument);\n        }\n\n        if (!is_array($argument) || empty($argument)) {\n            return false;\n        }\n\n        $keyScores = array_map(array($this->key,'scoreArgument'), array_keys($argument));\n        $valueScores = array_map(array($this->value,'scoreArgument'), $argument);\n        $scoreEntry = static function ($value, $key) {\n            return $value && $key ? (int) min(8, ($key + $value) / 2) : false;\n        };\n\n        return max(array_map($scoreEntry, $valueScores, $keyScores));\n    }\n\n    /**\n     * Returns false.\n     *\n     * @return boolean\n     */\n    public function isLast()\n    {\n        return false;\n    }\n\n    /**\n     * Returns string representation for token.\n     *\n     * @return string\n     */\n    public function __toString()\n    {\n        return sprintf('[..., %s => %s, ...]', $this->key, $this->value);\n    }\n\n    /**\n     * Returns key\n     *\n     * @return TokenInterface\n     */\n    public function getKey()\n    {\n        return $this->key;\n    }\n\n    /**\n     * Returns value\n     *\n     * @return TokenInterface\n     */\n    public function getValue()\n    {\n        return $this->value;\n    }\n\n    /**\n     * Wraps non token $value into ExactValueToken\n     *\n     * @param mixed $value\n     * @return TokenInterface\n     */\n    private function wrapIntoExactValueToken($value)\n    {\n        return $value instanceof TokenInterface ? $value : new ExactValueToken($value);\n    }\n\n    /**\n     * Converts instance of \\ArrayAccess to key => value array entry\n     *\n     * @param \\ArrayAccess<array-key, mixed> $object\n     *\n     * @return array<mixed>\n     * @throws InvalidArgumentException\n     */\n    private function convertArrayAccessToEntry(\\ArrayAccess $object)\n    {\n        if (!$this->key instanceof ExactValueToken) {\n            throw new InvalidArgumentException(sprintf(\n                'You can only use exact value tokens to match key of ArrayAccess object'.PHP_EOL\n                .'But you used `%s`.',\n                $this->key\n            ));\n        }\n\n        $key = $this->key->getValue();\n\n        if (!\\is_int($key) && !\\is_string($key)) {\n            throw new InvalidArgumentException(sprintf(\n                'You can only use integer or string keys to match key of ArrayAccess object'.PHP_EOL\n                    .'But you used `%s`.',\n                $this->key\n            ));\n        }\n\n        return $object->offsetExists($key) ? array($key => $object[$key]) : array();\n    }\n}\n"
  },
  {
    "path": "src/Prophecy/Argument/Token/ArrayEveryEntryToken.php",
    "content": "<?php\n\n/*\n * This file is part of the Prophecy.\n * (c) Konstantin Kudryashov <ever.zet@gmail.com>\n *     Marcello Duarte <marcello.duarte@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Prophecy\\Argument\\Token;\n\n/**\n * Array every entry token.\n *\n * @author Adrien Brault <adrien.brault@gmail.com>\n */\nclass ArrayEveryEntryToken implements TokenInterface\n{\n    /**\n     * @var TokenInterface\n     */\n    private $value;\n\n    /**\n     * @param mixed $value exact value or token\n     */\n    public function __construct($value)\n    {\n        if (!$value instanceof TokenInterface) {\n            $value = new ExactValueToken($value);\n        }\n\n        $this->value = $value;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function scoreArgument($argument)\n    {\n        if (!$argument instanceof \\Traversable && !is_array($argument)) {\n            return false;\n        }\n\n        $scores = array();\n        foreach ($argument as $key => $argumentEntry) {\n            $scores[] = $this->value->scoreArgument($argumentEntry);\n        }\n\n        if (empty($scores) || in_array(false, $scores, true)) {\n            return false;\n        }\n\n        return array_sum($scores) / count($scores);\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function isLast()\n    {\n        return false;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function __toString()\n    {\n        return sprintf('[%s, ..., %s]', $this->value, $this->value);\n    }\n\n    /**\n     * @return TokenInterface\n     */\n    public function getValue()\n    {\n        return $this->value;\n    }\n}\n"
  },
  {
    "path": "src/Prophecy/Argument/Token/CallbackToken.php",
    "content": "<?php\n\n/*\n * This file is part of the Prophecy.\n * (c) Konstantin Kudryashov <ever.zet@gmail.com>\n *     Marcello Duarte <marcello.duarte@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Prophecy\\Argument\\Token;\n\nuse Prophecy\\Exception\\InvalidArgumentException;\n\n/**\n * Callback-verified token.\n *\n * @author Konstantin Kudryashov <ever.zet@gmail.com>\n */\nclass CallbackToken implements TokenInterface\n{\n    private $callback;\n\n    /**\n     * @var string|null\n     */\n    private $customStringRepresentation;\n\n    /**\n     * Initializes token.\n     *\n     * @param callable $callback\n     * @param string|null $customStringRepresentation Customize the __toString() representation of this token\n     *\n     * @throws \\Prophecy\\Exception\\InvalidArgumentException\n     */\n    public function __construct($callback, ?string $customStringRepresentation = null)\n    {\n        if (!is_callable($callback)) {\n            throw new InvalidArgumentException(sprintf(\n                'Callable expected as an argument to CallbackToken, but got %s.',\n                gettype($callback)\n            ));\n        }\n\n        $this->callback = $callback;\n        $this->customStringRepresentation = $customStringRepresentation;\n    }\n\n    /**\n     * Scores 7 if callback returns true, false otherwise.\n     *\n     * @param mixed $argument\n     *\n     * @return false|int\n     */\n    public function scoreArgument($argument)\n    {\n        return call_user_func($this->callback, $argument) ? 7 : false;\n    }\n\n    /**\n     * Returns false.\n     *\n     * @return bool\n     */\n    public function isLast()\n    {\n        return false;\n    }\n\n    /**\n     * Returns string representation for token.\n     *\n     * @return string\n     */\n    public function __toString()\n    {\n        if ($this->customStringRepresentation !== null) {\n            return $this->customStringRepresentation;\n        }\n\n        return 'callback()';\n    }\n}\n"
  },
  {
    "path": "src/Prophecy/Argument/Token/ExactValueToken.php",
    "content": "<?php\n\n/*\n * This file is part of the Prophecy.\n * (c) Konstantin Kudryashov <ever.zet@gmail.com>\n *     Marcello Duarte <marcello.duarte@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Prophecy\\Argument\\Token;\n\nuse Prophecy\\Comparator\\FactoryProvider;\nuse SebastianBergmann\\Comparator\\ComparisonFailure;\nuse SebastianBergmann\\Comparator\\Factory as ComparatorFactory;\nuse Prophecy\\Util\\StringUtil;\n\n/**\n * Exact value token.\n *\n * @author Konstantin Kudryashov <ever.zet@gmail.com>\n */\nclass ExactValueToken implements TokenInterface\n{\n    private $value;\n    /**\n     * @var string|null\n     */\n    private $string;\n    private $util;\n    private $comparatorFactory;\n\n    /**\n     * Initializes token.\n     *\n     * @param mixed $value\n     */\n    public function __construct($value, ?StringUtil $util = null, ?ComparatorFactory $comparatorFactory = null)\n    {\n        $this->value = $value;\n        $this->util  = $util ?: new StringUtil();\n\n        $this->comparatorFactory = $comparatorFactory ?: FactoryProvider::getInstance();\n    }\n\n    /**\n     * Scores 10 if argument matches preset value.\n     *\n     * @param mixed $argument\n     *\n     * @return false|int\n     */\n    public function scoreArgument($argument)\n    {\n        if (is_object($argument) && is_object($this->value)) {\n            $comparator = $this->comparatorFactory->getComparatorFor(\n                $argument, $this->value\n            );\n\n            try {\n                $comparator->assertEquals($argument, $this->value);\n                return 10;\n            } catch (ComparisonFailure $failure) {\n                return false;\n            }\n        }\n\n        // If either one is an object it should be castable to a string\n        if (is_object($argument) xor is_object($this->value)) {\n            if (is_object($argument) && !method_exists($argument, '__toString')) {\n                return false;\n            }\n\n            if (is_object($this->value) && !method_exists($this->value, '__toString')) {\n                return false;\n            }\n\n            if (is_numeric($argument) xor is_numeric($this->value)) {\n                return strval($argument) == strval($this->value) ? 10 : false;\n            }\n        } elseif (is_numeric($argument) && is_numeric($this->value)) {\n            // noop\n        } elseif (gettype($argument) !== gettype($this->value)) {\n            return false;\n        }\n\n        return $argument == $this->value ? 10 : false;\n    }\n\n    /**\n     * Returns preset value against which token checks arguments.\n     *\n     * @return mixed\n     */\n    public function getValue()\n    {\n        return $this->value;\n    }\n\n    /**\n     * Returns false.\n     *\n     * @return bool\n     */\n    public function isLast()\n    {\n        return false;\n    }\n\n    /**\n     * Returns string representation for token.\n     *\n     * @return string\n     */\n    public function __toString()\n    {\n        if (null === $this->string) {\n            $this->string = sprintf('exact(%s)', $this->util->stringify($this->value));\n        }\n\n        return $this->string;\n    }\n}\n"
  },
  {
    "path": "src/Prophecy/Argument/Token/IdenticalValueToken.php",
    "content": "<?php\n\n/*\n * This file is part of the Prophecy.\n * (c) Konstantin Kudryashov <ever.zet@gmail.com>\n *     Marcello Duarte <marcello.duarte@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Prophecy\\Argument\\Token;\n\nuse Prophecy\\Util\\StringUtil;\n\n/**\n * Identical value token.\n *\n * @author Florian Voutzinos <florian@voutzinos.com>\n */\nclass IdenticalValueToken implements TokenInterface\n{\n    private $value;\n    /**\n     * @var string|null\n     */\n    private $string;\n    private $util;\n\n    /**\n     * Initializes token.\n     *\n     * @param mixed $value\n     */\n    public function __construct($value, ?StringUtil $util = null)\n    {\n        $this->value = $value;\n        $this->util  = $util ?: new StringUtil();\n    }\n\n    /**\n     * Scores 11 if argument matches preset value.\n     *\n     * @param mixed $argument\n     *\n     * @return false|int\n     */\n    public function scoreArgument($argument)\n    {\n        return $argument === $this->value ? 11 : false;\n    }\n\n    /**\n     * Returns false.\n     *\n     * @return bool\n     */\n    public function isLast()\n    {\n        return false;\n    }\n\n    /**\n     * Returns string representation for token.\n     *\n     * @return string\n     */\n    public function __toString()\n    {\n        if (null === $this->string) {\n            $this->string = sprintf('identical(%s)', $this->util->stringify($this->value));\n        }\n\n        return $this->string;\n    }\n}\n"
  },
  {
    "path": "src/Prophecy/Argument/Token/InArrayToken.php",
    "content": "<?php\n\n/*\n * This file is part of the Prophecy.\n * (c) Konstantin Kudryashov <ever.zet@gmail.com>\n *     Marcello Duarte <marcello.duarte@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Prophecy\\Argument\\Token;\n\n/**\n * Check if values is in array\n *\n * @author Vinícius Alonso <vba321@hotmail.com>\n */\nclass InArrayToken implements TokenInterface\n{\n    private $token = array();\n    private $strict;\n\n    /**\n     * @param array<mixed> $arguments tokens\n     * @param bool $strict\n     */\n    public function __construct(array $arguments, $strict = true)\n    {\n        $this->token = $arguments;\n        $this->strict = $strict;\n    }\n\n    /**\n     * Return scores 8 score if argument is in array.\n     *\n     * @param $argument\n     *\n     * @return bool|int\n     */\n    public function scoreArgument($argument)\n    {\n        if (count($this->token) === 0) {\n            return false;\n        }\n\n        if (\\in_array($argument, $this->token, $this->strict)) {\n            return 8;\n        }\n\n        return false;\n    }\n\n    /**\n     * Returns false.\n     *\n     * @return boolean\n     */\n    public function isLast()\n    {\n        return false;\n    }\n\n    /**\n     * Returns string representation for token.\n     *\n     * @return string\n     */\n    public function __toString()\n    {\n        $arrayAsString = implode(', ', $this->token);\n        return \"[{$arrayAsString}]\";\n    }\n}\n"
  },
  {
    "path": "src/Prophecy/Argument/Token/LogicalAndToken.php",
    "content": "<?php\n\n/*\n * This file is part of the Prophecy.\n * (c) Konstantin Kudryashov <ever.zet@gmail.com>\n *     Marcello Duarte <marcello.duarte@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Prophecy\\Argument\\Token;\n\n/**\n * Logical AND token.\n *\n * @author Boris Mikhaylov <kaguxmail@gmail.com>\n */\nclass LogicalAndToken implements TokenInterface\n{\n    /**\n     * @var list<TokenInterface>\n     */\n    private $tokens = array();\n\n    /**\n     * @param array<mixed> $arguments exact values or tokens\n     */\n    public function __construct(array $arguments)\n    {\n        foreach ($arguments as $argument) {\n            if (!$argument instanceof TokenInterface) {\n                $argument = new ExactValueToken($argument);\n            }\n            $this->tokens[] = $argument;\n        }\n    }\n\n    /**\n     * Scores maximum score from scores returned by tokens for this argument if all of them score.\n     *\n     * @param mixed $argument\n     *\n     * @return false|int\n     */\n    public function scoreArgument($argument)\n    {\n        if (0 === count($this->tokens)) {\n            return false;\n        }\n\n        $maxScore = 0;\n        foreach ($this->tokens as $token) {\n            $score = $token->scoreArgument($argument);\n            if (false === $score) {\n                return false;\n            }\n            $maxScore = max($score, $maxScore);\n        }\n\n        return $maxScore;\n    }\n\n    /**\n     * Returns false.\n     *\n     * @return boolean\n     */\n    public function isLast()\n    {\n        return false;\n    }\n\n    /**\n     * Returns string representation for token.\n     *\n     * @return string\n     */\n    public function __toString()\n    {\n        return sprintf('bool(%s)', implode(' AND ', $this->tokens));\n    }\n}\n"
  },
  {
    "path": "src/Prophecy/Argument/Token/LogicalNotToken.php",
    "content": "<?php\n\n/*\n * This file is part of the Prophecy.\n * (c) Konstantin Kudryashov <ever.zet@gmail.com>\n *     Marcello Duarte <marcello.duarte@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Prophecy\\Argument\\Token;\n\n/**\n * Logical NOT token.\n *\n * @author Boris Mikhaylov <kaguxmail@gmail.com>\n */\nclass LogicalNotToken implements TokenInterface\n{\n    /** @var TokenInterface */\n    private $token;\n\n    /**\n     * @param mixed $value exact value or token\n     */\n    public function __construct($value)\n    {\n        $this->token = $value instanceof TokenInterface ? $value : new ExactValueToken($value);\n    }\n\n    /**\n     * Scores 4 when preset token does not match the argument.\n     *\n     * @param mixed $argument\n     *\n     * @return false|int\n     */\n    public function scoreArgument($argument)\n    {\n        return false === $this->token->scoreArgument($argument) ? 4 : false;\n    }\n\n    /**\n     * Returns true if preset token is last.\n     *\n     * @return bool\n     */\n    public function isLast()\n    {\n        return $this->token->isLast();\n    }\n\n    /**\n     * Returns originating token.\n     *\n     * @return TokenInterface\n     */\n    public function getOriginatingToken()\n    {\n        return $this->token;\n    }\n\n    /**\n     * Returns string representation for token.\n     *\n     * @return string\n     */\n    public function __toString()\n    {\n        return sprintf('not(%s)', $this->token);\n    }\n}\n"
  },
  {
    "path": "src/Prophecy/Argument/Token/NotInArrayToken.php",
    "content": "<?php\n\n/*\n * This file is part of the Prophecy.\n * (c) Konstantin Kudryashov <ever.zet@gmail.com>\n *     Marcello Duarte <marcello.duarte@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Prophecy\\Argument\\Token;\n\n/**\n * Check if values is not in array\n *\n * @author Vinícius Alonso <vba321@hotmail.com>\n */\nclass NotInArrayToken implements TokenInterface\n{\n    private $token = array();\n    private $strict;\n\n    /**\n     * @param array<mixed> $arguments tokens\n     * @param bool $strict\n     */\n    public function __construct(array $arguments, $strict = true)\n    {\n        $this->token = $arguments;\n        $this->strict = $strict;\n    }\n\n    /**\n     * Return scores 8 score if argument is in array.\n     *\n     * @param $argument\n     *\n     * @return bool|int\n     */\n    public function scoreArgument($argument)\n    {\n        if (count($this->token) === 0) {\n            return false;\n        }\n\n        if (!\\in_array($argument, $this->token, $this->strict)) {\n            return 8;\n        }\n\n        return false;\n    }\n\n    /**\n     * Returns false.\n     *\n     * @return boolean\n     */\n    public function isLast()\n    {\n        return false;\n    }\n\n    /**\n     * Returns string representation for token.\n     *\n     * @return string\n     */\n    public function __toString()\n    {\n        $arrayAsString = implode(', ', $this->token);\n        return \"[{$arrayAsString}]\";\n    }\n}\n"
  },
  {
    "path": "src/Prophecy/Argument/Token/ObjectStateToken.php",
    "content": "<?php\n\n/*\n * This file is part of the Prophecy.\n * (c) Konstantin Kudryashov <ever.zet@gmail.com>\n *     Marcello Duarte <marcello.duarte@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Prophecy\\Argument\\Token;\n\nuse Prophecy\\Comparator\\FactoryProvider;\nuse SebastianBergmann\\Comparator\\ComparisonFailure;\nuse SebastianBergmann\\Comparator\\Factory as ComparatorFactory;\nuse Prophecy\\Util\\StringUtil;\n\n/**\n * Object state-checker token.\n *\n * @author Konstantin Kudryashov <ever.zet@gmail.com>\n */\nclass ObjectStateToken implements TokenInterface\n{\n    private $name;\n    private $value;\n    private $util;\n    private $comparatorFactory;\n\n    /**\n     * Initializes token.\n     *\n     * @param string $methodName\n     * @param mixed  $value             Expected return value\n     */\n    public function __construct(\n        $methodName,\n        $value,\n        ?StringUtil $util = null,\n        ?ComparatorFactory $comparatorFactory = null\n    ) {\n        $this->name  = $methodName;\n        $this->value = $value;\n        $this->util  = $util ?: new StringUtil();\n\n        $this->comparatorFactory = $comparatorFactory ?: FactoryProvider::getInstance();\n    }\n\n    /**\n     * Scores 8 if argument is an object, which method returns expected value.\n     *\n     * @param mixed $argument\n     *\n     * @return bool|int\n     */\n    public function scoreArgument($argument)\n    {\n        $methodCallable = array($argument, $this->name);\n        if (is_object($argument) && method_exists($argument, $this->name) && is_callable($methodCallable)) {\n            $actual = call_user_func($methodCallable);\n\n            $comparator = $this->comparatorFactory->getComparatorFor(\n                $this->value, $actual\n            );\n\n            try {\n                $comparator->assertEquals($this->value, $actual);\n                return 8;\n            } catch (ComparisonFailure $failure) {\n                return false;\n            }\n        }\n\n        if (is_object($argument) && property_exists($argument, $this->name)) {\n            return $argument->{$this->name} === $this->value ? 8 : false;\n        }\n\n        return false;\n    }\n\n    /**\n     * Returns false.\n     *\n     * @return bool\n     */\n    public function isLast()\n    {\n        return false;\n    }\n\n    /**\n     * Returns string representation for token.\n     *\n     * @return string\n     */\n    public function __toString()\n    {\n        return sprintf('state(%s(), %s)',\n            $this->name,\n            $this->util->stringify($this->value)\n        );\n    }\n}\n"
  },
  {
    "path": "src/Prophecy/Argument/Token/StringContainsToken.php",
    "content": "<?php\n\n/*\n * This file is part of the Prophecy.\n * (c) Konstantin Kudryashov <ever.zet@gmail.com>\n *     Marcello Duarte <marcello.duarte@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Prophecy\\Argument\\Token;\n\n/**\n * String contains token.\n *\n * @author Peter Mitchell <pete@peterjmit.com>\n */\nclass StringContainsToken implements TokenInterface\n{\n    private $value;\n\n    /**\n     * Initializes token.\n     *\n     * @param string $value\n     */\n    public function __construct($value)\n    {\n        $this->value = $value;\n    }\n\n    public function scoreArgument($argument)\n    {\n        return is_string($argument) && strpos($argument, $this->value) !== false ? 6 : false;\n    }\n\n    /**\n     * Returns preset value against which token checks arguments.\n     *\n     * @return mixed\n     */\n    public function getValue()\n    {\n        return $this->value;\n    }\n\n    /**\n     * Returns false.\n     *\n     * @return bool\n     */\n    public function isLast()\n    {\n        return false;\n    }\n\n    /**\n     * Returns string representation for token.\n     *\n     * @return string\n     */\n    public function __toString()\n    {\n        return sprintf('contains(\"%s\")', $this->value);\n    }\n}\n"
  },
  {
    "path": "src/Prophecy/Argument/Token/TokenInterface.php",
    "content": "<?php\n\n/*\n * This file is part of the Prophecy.\n * (c) Konstantin Kudryashov <ever.zet@gmail.com>\n *     Marcello Duarte <marcello.duarte@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Prophecy\\Argument\\Token;\n\n/**\n * Argument token interface.\n *\n * @author Konstantin Kudryashov <ever.zet@gmail.com>\n */\ninterface TokenInterface\n{\n    /**\n     * Calculates token match score for provided argument.\n     *\n     * @param mixed $argument\n     *\n     * @return false|int\n     */\n    public function scoreArgument($argument);\n\n    /**\n     * Returns true if this token prevents check of other tokens (is last one).\n     *\n     * @return bool\n     */\n    public function isLast();\n\n    /**\n     * Returns string representation for token.\n     *\n     * @return string\n     */\n    public function __toString();\n}\n"
  },
  {
    "path": "src/Prophecy/Argument/Token/TypeToken.php",
    "content": "<?php\n\n/*\n * This file is part of the Prophecy.\n * (c) Konstantin Kudryashov <ever.zet@gmail.com>\n *     Marcello Duarte <marcello.duarte@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Prophecy\\Argument\\Token;\n\nuse Prophecy\\Exception\\InvalidArgumentException;\n\n/**\n * Value type token.\n *\n * @author Konstantin Kudryashov <ever.zet@gmail.com>\n */\nclass TypeToken implements TokenInterface\n{\n    private $type;\n\n    /**\n     * @param string $type\n     */\n    public function __construct($type)\n    {\n        $checker = \"is_{$type}\";\n        if (!function_exists($checker) && !interface_exists($type) && !class_exists($type)) {\n            throw new InvalidArgumentException(sprintf(\n                'Type or class name expected as an argument to TypeToken, but got %s.', $type\n            ));\n        }\n\n        $this->type = $type;\n    }\n\n    /**\n     * Scores 5 if argument has the same type this token was constructed with.\n     *\n     * @param $argument\n     *\n     * @return bool|int\n     */\n    public function scoreArgument($argument)\n    {\n        $checker = \"is_{$this->type}\";\n        if (function_exists($checker)) {\n            return call_user_func($checker, $argument) ? 5 : false;\n        }\n\n        return $argument instanceof $this->type ? 5 : false;\n    }\n\n    /**\n     * Returns false.\n     *\n     * @return bool\n     */\n    public function isLast()\n    {\n        return false;\n    }\n\n    /**\n     * Returns string representation for token.\n     *\n     * @return string\n     */\n    public function __toString()\n    {\n        return sprintf('type(%s)', $this->type);\n    }\n}\n"
  },
  {
    "path": "src/Prophecy/Argument.php",
    "content": "<?php\n\n/*\n * This file is part of the Prophecy.\n * (c) Konstantin Kudryashov <ever.zet@gmail.com>\n *     Marcello Duarte <marcello.duarte@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Prophecy;\n\nuse Prophecy\\Argument\\Token;\n\n/**\n * Argument tokens shortcuts.\n *\n * @author Konstantin Kudryashov <ever.zet@gmail.com>\n */\nclass Argument\n{\n    /**\n     * Checks that argument is exact value or object.\n     *\n     * @param mixed $value\n     *\n     * @return Token\\ExactValueToken\n     */\n    public static function exact($value)\n    {\n        return new Token\\ExactValueToken($value);\n    }\n\n    /**\n     * Checks that argument is of specific type or instance of specific class.\n     *\n     * @param string $type Type name (`integer`, `string`) or full class name\n     *\n     * @return Token\\TypeToken\n     */\n    public static function type($type)\n    {\n        return new Token\\TypeToken($type);\n    }\n\n    /**\n     * Checks that argument object has specific state.\n     *\n     * @param string $methodName\n     * @param mixed  $value\n     *\n     * @return Token\\ObjectStateToken\n     */\n    public static function which($methodName, $value)\n    {\n        return new Token\\ObjectStateToken($methodName, $value);\n    }\n\n    /**\n     * Checks that argument matches provided callback.\n     *\n     * @param callable $callback\n     * @param string|null $customStringRepresentation Customize the __toString() representation of this token\n     *\n     * @return Token\\CallbackToken\n     */\n    public static function that($callback, ?string $customStringRepresentation = null)\n    {\n        return new Token\\CallbackToken($callback, $customStringRepresentation);\n    }\n\n    /**\n     * Matches any single value.\n     *\n     * @return Token\\AnyValueToken\n     */\n    public static function any()\n    {\n        return new Token\\AnyValueToken();\n    }\n\n    /**\n     * Matches all values to the rest of the signature.\n     *\n     * @return Token\\AnyValuesToken\n     */\n    public static function cetera()\n    {\n        return new Token\\AnyValuesToken();\n    }\n\n    /**\n     * Checks that argument matches all tokens\n     *\n     * @param mixed ...$tokens a list of tokens\n     *\n     * @return Token\\LogicalAndToken\n     */\n    public static function allOf(...$tokens)\n    {\n        return new Token\\LogicalAndToken($tokens);\n    }\n\n    /**\n     * Checks that argument array or countable object has exact number of elements.\n     *\n     * @param integer $value array elements count\n     *\n     * @return Token\\ArrayCountToken\n     */\n    public static function size($value)\n    {\n        return new Token\\ArrayCountToken($value);\n    }\n\n    /**\n     * Checks that argument array contains (key, value) pair\n     *\n     * @param mixed $key   exact value or token\n     * @param mixed $value exact value or token\n     *\n     * @return Token\\ArrayEntryToken\n     */\n    public static function withEntry($key, $value)\n    {\n        return new Token\\ArrayEntryToken($key, $value);\n    }\n\n    /**\n     * Checks that arguments array entries all match value\n     *\n     * @param mixed $value\n     *\n     * @return Token\\ArrayEveryEntryToken\n     */\n    public static function withEveryEntry($value)\n    {\n        return new Token\\ArrayEveryEntryToken($value);\n    }\n\n    /**\n     * Checks that argument array contains value\n     *\n     * @param mixed $value\n     *\n     * @return Token\\ArrayEntryToken\n     */\n    public static function containing($value)\n    {\n        return new Token\\ArrayEntryToken(self::any(), $value);\n    }\n\n    /**\n     * Checks that argument array has key\n     *\n     * @param mixed $key exact value or token\n     *\n     * @return Token\\ArrayEntryToken\n     */\n    public static function withKey($key)\n    {\n        return new Token\\ArrayEntryToken($key, self::any());\n    }\n\n    /**\n     * Checks that argument does not match the value|token.\n     *\n     * @param mixed $value either exact value or argument token\n     *\n     * @return Token\\LogicalNotToken\n     */\n    public static function not($value)\n    {\n        return new Token\\LogicalNotToken($value);\n    }\n\n    /**\n     * @param string $value\n     *\n     * @return Token\\StringContainsToken\n     */\n    public static function containingString($value)\n    {\n        return new Token\\StringContainsToken($value);\n    }\n\n    /**\n     * Checks that argument is identical value.\n     *\n     * @param mixed $value\n     *\n     * @return Token\\IdenticalValueToken\n     */\n    public static function is($value)\n    {\n        return new Token\\IdenticalValueToken($value);\n    }\n\n    /**\n     * Check that argument is same value when rounding to the\n     * given precision.\n     *\n     * @param float $value\n     * @param int $precision\n     *\n     * @return Token\\ApproximateValueToken\n     */\n    public static function approximate($value, $precision = 0)\n    {\n        return new Token\\ApproximateValueToken($value, $precision);\n    }\n\n    /**\n     * Checks that argument is in array.\n     *\n     * @param array<mixed> $value\n     *\n     * @return Token\\InArrayToken\n     */\n\n    public static function in($value)\n    {\n        return new Token\\InArrayToken($value);\n    }\n\n    /**\n     * Checks that argument is not in array.\n     *\n     * @param array<mixed> $value\n     *\n     * @return Token\\NotInArrayToken\n     */\n\n    public static function notIn($value)\n    {\n        return new Token\\NotInArrayToken($value);\n    }\n\n}\n"
  },
  {
    "path": "src/Prophecy/Call/Call.php",
    "content": "<?php\n\n/*\n * This file is part of the Prophecy.\n * (c) Konstantin Kudryashov <ever.zet@gmail.com>\n *     Marcello Duarte <marcello.duarte@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Prophecy\\Call;\n\nuse Exception;\nuse Prophecy\\Argument\\ArgumentsWildcard;\n\n/**\n * Call object.\n *\n * @author Konstantin Kudryashov <ever.zet@gmail.com>\n */\nclass Call\n{\n    private $methodName;\n    private $arguments;\n    private $returnValue;\n    private $exception;\n    /**\n     * @var string|null\n     */\n    private $file;\n    /**\n     * @var int|null\n     */\n    private $line;\n    /**\n     * @var \\SplObjectStorage<ArgumentsWildcard, int|false>\n     */\n    private $scores;\n\n    /**\n     * Initializes call.\n     *\n     * @param string      $methodName\n     * @param array<mixed> $arguments\n     * @param mixed       $returnValue\n     * @param Exception|null $exception\n     * @param null|string $file\n     * @param null|int    $line\n     */\n    public function __construct($methodName, array $arguments, $returnValue,\n        ?Exception $exception, $file, $line)\n    {\n        $this->methodName  = $methodName;\n        $this->arguments   = $arguments;\n        $this->returnValue = $returnValue;\n        $this->exception   = $exception;\n        $this->scores      = new \\SplObjectStorage();\n\n        if ($file) {\n            $this->file = $file;\n            $this->line = intval($line);\n        }\n    }\n\n    /**\n     * Returns called method name.\n     *\n     * @return string\n     */\n    public function getMethodName()\n    {\n        return $this->methodName;\n    }\n\n    /**\n     * Returns called method arguments.\n     *\n     * @return array<mixed>\n     */\n    public function getArguments()\n    {\n        return $this->arguments;\n    }\n\n    /**\n     * Returns called method return value.\n     *\n     * @return null|mixed\n     */\n    public function getReturnValue()\n    {\n        return $this->returnValue;\n    }\n\n    /**\n     * Returns exception that call thrown.\n     *\n     * @return null|Exception\n     */\n    public function getException()\n    {\n        return $this->exception;\n    }\n\n    /**\n     * Returns callee filename.\n     *\n     * @return string|null\n     */\n    public function getFile()\n    {\n        return $this->file;\n    }\n\n    /**\n     * Returns callee line number.\n     *\n     * @return int|null\n     */\n    public function getLine()\n    {\n        return $this->line;\n    }\n\n    /**\n     * Returns short notation for callee place.\n     *\n     * @return string\n     */\n    public function getCallPlace()\n    {\n        if (null === $this->file) {\n            return 'unknown';\n        }\n\n        return sprintf('%s:%d', $this->file, $this->line);\n    }\n\n    /**\n     * Adds the wildcard match score for the provided wildcard.\n     *\n     * @param ArgumentsWildcard $wildcard\n     * @param false|int $score\n     *\n     * @return $this\n     */\n    public function addScore(ArgumentsWildcard $wildcard, $score)\n    {\n        $this->scores[$wildcard] = $score;\n\n        return $this;\n    }\n\n    /**\n     * Returns wildcard match score for the provided wildcard. The score is\n     * calculated if not already done.\n     *\n     * @param ArgumentsWildcard $wildcard\n     *\n     * @return false|int False OR integer score (higher - better)\n     */\n    public function getScore(ArgumentsWildcard $wildcard)\n    {\n        if (isset($this->scores[$wildcard])) {\n            return $this->scores[$wildcard];\n        }\n\n        return $this->scores[$wildcard] = $wildcard->scoreArguments($this->getArguments());\n    }\n}\n"
  },
  {
    "path": "src/Prophecy/Call/CallCenter.php",
    "content": "<?php\n\n/*\n * This file is part of the Prophecy.\n * (c) Konstantin Kudryashov <ever.zet@gmail.com>\n *     Marcello Duarte <marcello.duarte@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Prophecy\\Call;\n\nuse Prophecy\\Exception\\Prophecy\\MethodProphecyException;\nuse Prophecy\\Prophecy\\MethodProphecy;\nuse Prophecy\\Prophecy\\ObjectProphecy;\nuse Prophecy\\Argument\\ArgumentsWildcard;\nuse Prophecy\\Util\\StringUtil;\nuse Prophecy\\Exception\\Call\\UnexpectedCallException;\nuse SplObjectStorage;\n\n/**\n * Calls receiver & manager.\n *\n * @author Konstantin Kudryashov <ever.zet@gmail.com>\n */\nclass CallCenter\n{\n    private $util;\n\n    /**\n     * @var Call[]\n     */\n    private $recordedCalls = array();\n\n    /**\n     * @var SplObjectStorage<Call, ObjectProphecy<object>>\n     */\n    private $unexpectedCalls;\n\n    /**\n     * Initializes call center.\n     *\n     * @param StringUtil $util\n     */\n    public function __construct(?StringUtil $util = null)\n    {\n        $this->util = $util ?: new StringUtil();\n        $this->unexpectedCalls = new SplObjectStorage();\n    }\n\n    /**\n     * Makes and records specific method call for object prophecy.\n     *\n     * @param ObjectProphecy<object> $prophecy\n     * @param string         $methodName\n     * @param array<mixed>          $arguments\n     *\n     * @return mixed Returns null if no promise for prophecy found or promise return value.\n     *\n     * @throws \\Prophecy\\Exception\\Call\\UnexpectedCallException If no appropriate method prophecy found\n     */\n    public function makeCall(ObjectProphecy $prophecy, $methodName, array $arguments)\n    {\n        // For efficiency exclude 'args' from the generated backtrace\n        // Limit backtrace to last 3 calls as we don't use the rest\n        $backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 3);\n\n        $file = $line = null;\n        if (isset($backtrace[2]) && isset($backtrace[2]['file']) && isset($backtrace[2]['line'])) {\n            $file = $backtrace[2]['file'];\n            $line = $backtrace[2]['line'];\n        }\n\n        // If no method prophecies defined, then it's a dummy, so we'll just return null\n        if ('__destruct' === strtolower($methodName) || 0 == count($prophecy->getMethodProphecies())) {\n            $this->recordedCalls[] = new Call($methodName, $arguments, null, null, $file, $line);\n\n            return null;\n        }\n\n        // There are method prophecies, so it's a fake/stub. Searching prophecy for this call\n        $matches = $this->findMethodProphecies($prophecy, $methodName, $arguments);\n\n        // If fake/stub doesn't have method prophecy for this call - throw exception\n        if (!count($matches)) {\n            $this->unexpectedCalls->offsetSet(new Call($methodName, $arguments, null, null, $file, $line), $prophecy);\n            $this->recordedCalls[] = new Call($methodName, $arguments, null, null, $file, $line);\n\n            return null;\n        }\n\n        // Sort matches by their score value\n        @usort($matches, function ($match1, $match2) { return $match2[0] - $match1[0]; });\n\n        $score = $matches[0][0];\n        // If Highest rated method prophecy has a promise - execute it or return null instead\n        $methodProphecy = $matches[0][1];\n        $returnValue = null;\n        $exception   = null;\n        if ($promise = $methodProphecy->getPromise()) {\n            try {\n                $returnValue = $promise->execute($arguments, $prophecy, $methodProphecy);\n            } catch (\\Exception $e) {\n                $exception = $e;\n            }\n        }\n\n        if ($methodProphecy->hasReturnVoid() && $returnValue !== null) {\n            throw new MethodProphecyException(\n                \"The method \\\"$methodName\\\" has a void return type, but the promise returned a value\",\n                $methodProphecy\n            );\n        }\n\n        $this->recordedCalls[] = $call = new Call(\n            $methodName, $arguments, $returnValue, $exception, $file, $line\n        );\n        $call->addScore($methodProphecy->getArgumentsWildcard(), $score);\n\n        if (null !== $exception) {\n            throw $exception;\n        }\n\n        return $returnValue;\n    }\n\n    /**\n     * Searches for calls by method name & arguments wildcard.\n     *\n     * @param string            $methodName\n     * @param ArgumentsWildcard $wildcard\n     *\n     * @return list<Call>\n     */\n    public function findCalls($methodName, ArgumentsWildcard $wildcard)\n    {\n        $methodName = strtolower($methodName);\n\n        return array_values(\n            array_filter($this->recordedCalls, function (Call $call) use ($methodName, $wildcard) {\n                return $methodName === strtolower($call->getMethodName())\n                    && 0 < $call->getScore($wildcard)\n                ;\n            })\n        );\n    }\n\n    /**\n     * @return void\n     * @throws UnexpectedCallException\n     */\n    public function checkUnexpectedCalls()\n    {\n        foreach ($this->unexpectedCalls as $call) {\n            $prophecy = $this->unexpectedCalls[$call];\n\n            // If fake/stub doesn't have method prophecy for this call - throw exception\n            if (!count($this->findMethodProphecies($prophecy, $call->getMethodName(), $call->getArguments()))) {\n                throw $this->createUnexpectedCallException($prophecy, $call->getMethodName(), $call->getArguments());\n            }\n        }\n    }\n\n    /**\n     * @param ObjectProphecy<object> $prophecy\n     * @param string                 $methodName\n     * @param array<mixed>           $arguments\n     *\n     * @return UnexpectedCallException\n     */\n    private function createUnexpectedCallException(ObjectProphecy $prophecy, $methodName,\n        array $arguments)\n    {\n        $classname = get_class($prophecy->reveal());\n        $indentationLength = 8; // looks good\n        $argstring = implode(\n            \",\\n\",\n            $this->indentArguments(\n                array_map(array($this->util, 'stringify'), $arguments),\n                $indentationLength\n            )\n        );\n\n        $expected = array();\n\n        foreach (array_merge(...array_values($prophecy->getMethodProphecies())) as $methodProphecy) {\n            $expected[] = sprintf(\n                \"  - %s(\\n\"\n                .\"%s\\n\"\n                .\"    )\",\n                $methodProphecy->getMethodName(),\n                implode(\n                    \",\\n\",\n                    $this->indentArguments(\n                        array_map('strval', $methodProphecy->getArgumentsWildcard()->getTokens()),\n                        $indentationLength\n                    )\n                )\n            );\n        }\n\n        return new UnexpectedCallException(\n            sprintf(\n                \"Unexpected method call on %s:\\n\"\n                .\"  - %s(\\n\"\n                .\"%s\\n\"\n                .\"    )\\n\"\n                .\"expected calls were:\\n\"\n                .\"%s\",\n\n                $classname, $methodName, $argstring, implode(\"\\n\", $expected)\n            ),\n            $prophecy, $methodName, $arguments\n\n        );\n    }\n\n    /**\n     * @param string[] $arguments\n     * @param int      $indentationLength\n     *\n     * @return string[]\n     */\n    private function indentArguments(array $arguments, $indentationLength)\n    {\n        return preg_replace_callback(\n            '/^/m',\n            function () use ($indentationLength) {\n                return str_repeat(' ', $indentationLength);\n            },\n            $arguments\n        );\n    }\n\n    /**\n     * @param ObjectProphecy<object> $prophecy\n     * @param string $methodName\n     * @param array<mixed> $arguments\n     *\n     * @return array\n     *\n     * @phpstan-return list<array{int, MethodProphecy}>\n     */\n    private function findMethodProphecies(ObjectProphecy $prophecy, $methodName, array $arguments)\n    {\n        $matches = array();\n        foreach ($prophecy->getMethodProphecies($methodName) as $methodProphecy) {\n            if (0 < $score = $methodProphecy->getArgumentsWildcard()->scoreArguments($arguments)) {\n                $matches[] = array($score, $methodProphecy);\n            }\n        }\n\n        return $matches;\n    }\n}\n"
  },
  {
    "path": "src/Prophecy/Comparator/ClosureComparator.php",
    "content": "<?php\n\n/*\n * This file is part of the Prophecy.\n * (c) Konstantin Kudryashov <ever.zet@gmail.com>\n *     Marcello Duarte <marcello.duarte@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Prophecy\\Comparator;\n\nuse SebastianBergmann\\Comparator\\Comparator;\nuse SebastianBergmann\\Comparator\\ComparisonFailure;\n\n/**\n * Closure comparator.\n *\n * @author Konstantin Kudryashov <ever.zet@gmail.com>\n */\nfinal class ClosureComparator extends Comparator\n{\n    /**\n     * @param mixed $expected\n     * @param mixed $actual\n     */\n    public function accepts($expected, $actual): bool\n    {\n        return is_object($expected) && $expected instanceof \\Closure\n            && is_object($actual) && $actual instanceof \\Closure;\n    }\n\n    /**\n     * @param mixed $expected\n     * @param mixed $actual\n     * @param float $delta\n     * @param bool  $canonicalize\n     * @param bool  $ignoreCase\n     */\n    public function assertEquals($expected, $actual, $delta = 0.0, $canonicalize = false, $ignoreCase = false): void\n    {\n        if ($expected !== $actual) {\n            // Support for sebastian/comparator < 5\n            if ((new \\ReflectionMethod(ComparisonFailure::class, '__construct'))->getNumberOfParameters() >= 6) {\n                // @phpstan-ignore-next-line\n                throw new ComparisonFailure($expected, $actual, '', '', false, 'all closures are different if not identical');\n            }\n\n            throw new ComparisonFailure(\n                $expected,\n                $actual,\n                // we don't need a diff\n                '',\n                '',\n                'all closures are different if not identical'\n            );\n        }\n    }\n}\n"
  },
  {
    "path": "src/Prophecy/Comparator/Factory.php",
    "content": "<?php\n\n/*\n * This file is part of the Prophecy.\n * (c) Konstantin Kudryashov <ever.zet@gmail.com>\n *     Marcello Duarte <marcello.duarte@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Prophecy\\Comparator;\n\nuse SebastianBergmann\\Comparator\\Factory as BaseFactory;\n\n/**\n * Prophecy comparator factory.\n *\n * @author Konstantin Kudryashov <ever.zet@gmail.com>\n *\n * @deprecated Use \"Prophecy\\Comparator\\FactoryProvider\" instead to get a \"SebastianBergmann\\Comparator\\Factory\" instance.\n */\nfinal class Factory extends BaseFactory\n{\n    /**\n     * @var Factory\n     */\n    private static $instance;\n\n    public function __construct()\n    {\n        parent::__construct();\n\n        $this->register(new ClosureComparator());\n        $this->register(new ProphecyComparator());\n    }\n\n    /**\n     * @return Factory\n     */\n    public static function getInstance()\n    {\n        if (self::$instance === null) {\n            self::$instance = new Factory();\n        }\n\n        return self::$instance;\n    }\n}\n"
  },
  {
    "path": "src/Prophecy/Comparator/FactoryProvider.php",
    "content": "<?php\n\n/*\n * This file is part of the Prophecy.\n * (c) Konstantin Kudryashov <ever.zet@gmail.com>\n *     Marcello Duarte <marcello.duarte@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Prophecy\\Comparator;\n\nuse SebastianBergmann\\Comparator\\Factory;\n\n/**\n * Prophecy comparator factory.\n *\n * @author Konstantin Kudryashov <ever.zet@gmail.com>\n */\nfinal class FactoryProvider\n{\n    /**\n     * @var Factory|null\n     */\n    private static $instance;\n\n    private function __construct() {}\n\n    public static function getInstance(): Factory\n    {\n        if (self::$instance === null) {\n            self::$instance = new Factory();\n            self::$instance->register(new ClosureComparator());\n            self::$instance->register(new ProphecyComparator());\n        }\n\n        return self::$instance;\n    }\n}\n"
  },
  {
    "path": "src/Prophecy/Comparator/ProphecyComparator.php",
    "content": "<?php\n\n/*\n * This file is part of the Prophecy.\n * (c) Konstantin Kudryashov <ever.zet@gmail.com>\n *     Marcello Duarte <marcello.duarte@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Prophecy\\Comparator;\n\nuse Prophecy\\Prophecy\\ProphecyInterface;\nuse SebastianBergmann\\Comparator\\Comparator;\nuse SebastianBergmann\\Comparator\\Factory;\n\n/**\n * @final\n */\nclass ProphecyComparator extends Comparator\n{\n    /**\n     * @param mixed $expected\n     * @param mixed $actual\n     */\n    public function accepts($expected, $actual): bool\n    {\n        return \\is_object($expected) && $actual instanceof ProphecyInterface;\n    }\n\n    /**\n     * @param mixed $expected\n     * @param mixed $actual\n     * @param float $delta\n     * @param bool  $canonicalize\n     * @param bool  $ignoreCase\n     */\n    public function assertEquals($expected, $actual, $delta = 0.0, $canonicalize = false, $ignoreCase = false): void\n    {\n        \\assert($actual instanceof ProphecyInterface);\n        $this->getComparatorFactory()->getComparatorFor($expected, $actual->reveal())->assertEquals($expected, $actual->reveal(), $delta, $canonicalize, $ignoreCase);\n    }\n\n    private function getComparatorFactory(): Factory\n    {\n        // sebastianbergmann/comparator 5+\n        // @phpstan-ignore function.alreadyNarrowedType\n        if (\\method_exists($this, 'factory')) {\n            return $this->factory();\n        }\n\n        // sebastianbergmann/comparator <5\n        // @phpstan-ignore property.private\n        return $this->factory;\n    }\n}\n"
  },
  {
    "path": "src/Prophecy/Doubler/CachedDoubler.php",
    "content": "<?php\n\n/*\n * This file is part of the Prophecy.\n * (c) Konstantin Kudryashov <ever.zet@gmail.com>\n *     Marcello Duarte <marcello.duarte@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Prophecy\\Doubler;\n\nuse ReflectionClass;\n\n/**\n * Cached class doubler.\n * Prevents mirroring/creation of the same structure twice.\n *\n * @author Konstantin Kudryashov <ever.zet@gmail.com>\n */\nclass CachedDoubler extends Doubler\n{\n    /**\n     * @var array<string, class-string>\n     */\n    private static $classes = array();\n\n    protected function createDoubleClass(?ReflectionClass $class, array $interfaces)\n    {\n        $classId = $this->generateClassId($class, $interfaces);\n        if (isset(self::$classes[$classId])) {\n            return self::$classes[$classId];\n        }\n\n        return self::$classes[$classId] = parent::createDoubleClass($class, $interfaces);\n    }\n\n    /**\n     * @param ReflectionClass<object>|null $class\n     * @param ReflectionClass<object>[]    $interfaces\n     *\n     * @return string\n     */\n    private function generateClassId(?ReflectionClass $class, array $interfaces)\n    {\n        $parts = array();\n        if (null !== $class) {\n            $parts[] = $class->getName();\n        }\n        foreach ($interfaces as $interface) {\n            $parts[] = $interface->getName();\n        }\n        foreach ($this->getClassPatches() as $patch) {\n            $parts[] = get_class($patch);\n        }\n        sort($parts);\n\n        return md5(implode('', $parts));\n    }\n\n    /**\n     * @return void\n     */\n    public function resetCache()\n    {\n        self::$classes = array();\n    }\n}\n"
  },
  {
    "path": "src/Prophecy/Doubler/ClassPatch/ClassPatchInterface.php",
    "content": "<?php\n\n/*\n * This file is part of the Prophecy.\n * (c) Konstantin Kudryashov <ever.zet@gmail.com>\n *     Marcello Duarte <marcello.duarte@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Prophecy\\Doubler\\ClassPatch;\n\nuse Prophecy\\Doubler\\Generator\\Node\\ClassNode;\n\n/**\n * Class patch interface.\n * Class patches extend doubles functionality or help\n * Prophecy to avoid some internal PHP bugs.\n *\n * @author Konstantin Kudryashov <ever.zet@gmail.com>\n */\ninterface ClassPatchInterface\n{\n    /**\n     * Checks if patch supports specific class node.\n     *\n     * @param ClassNode $node\n     *\n     * @return bool\n     */\n    public function supports(ClassNode $node);\n\n    /**\n     * Applies patch to the specific class node.\n     *\n     * @param ClassNode $node\n     * @return void\n     */\n    public function apply(ClassNode $node);\n\n    /**\n     * Returns patch priority, which determines when patch will be applied.\n     *\n     * @return int Priority number (higher - earlier)\n     */\n    public function getPriority();\n}\n"
  },
  {
    "path": "src/Prophecy/Doubler/ClassPatch/DisableConstructorPatch.php",
    "content": "<?php\n\n/*\n * This file is part of the Prophecy.\n * (c) Konstantin Kudryashov <ever.zet@gmail.com>\n *     Marcello Duarte <marcello.duarte@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Prophecy\\Doubler\\ClassPatch;\n\nuse Prophecy\\Doubler\\Generator\\Node\\ArgumentTypeNode;\nuse Prophecy\\Doubler\\Generator\\Node\\ClassNode;\nuse Prophecy\\Doubler\\Generator\\Node\\MethodNode;\nuse Prophecy\\Doubler\\Generator\\Node\\Type\\BuiltinType;\nuse Prophecy\\Doubler\\Generator\\Node\\Type\\UnionType;\n\n/**\n * Disable constructor.\n * Makes all constructor arguments optional.\n *\n * @author Konstantin Kudryashov <ever.zet@gmail.com>\n */\nclass DisableConstructorPatch implements ClassPatchInterface\n{\n    /**\n     * Checks if class has `__construct` method.\n     *\n     * @param ClassNode $node\n     *\n     * @return bool\n     */\n    public function supports(ClassNode $node)\n    {\n        return true;\n    }\n\n    /**\n     * Makes all class constructor arguments optional.\n     *\n     * @param ClassNode $node\n     */\n    public function apply(ClassNode $node)\n    {\n        if (!$node->isExtendable('__construct')) {\n            return;\n        }\n\n        if (!$node->hasMethod('__construct')) {\n            $node->addMethod(new MethodNode('__construct', ''));\n\n            return;\n        }\n\n        $constructor = $node->getMethod('__construct');\n        \\assert($constructor !== null);\n        foreach ($constructor->getArguments() as $argument) {\n            $argument->setDefault(null);\n\n            $type = $argument->getTypeNode()->getType();\n            if (\n                $type instanceof BuiltinType\n                && ($type->getType() === 'null' || $type->getType() === 'mixed')\n            ) {\n                continue;\n            }\n\n            if ($type instanceof UnionType && $type->has(new BuiltinType('null'))) {\n                continue;\n            }\n\n            if (null === $type) {\n                continue;\n            }\n\n            if ($type instanceof UnionType) {\n                $argument->setTypeNode(new ArgumentTypeNode(new UnionType(\n                    [new BuiltinType('null'), ...$type->getTypes()]\n                )));\n                continue;\n            }\n\n            $argument->setTypeNode(new ArgumentTypeNode(new UnionType(\n                [new BuiltinType('null'), $type]\n            )));\n        }\n\n        $constructor->setCode(<<<PHP\nif (0 < func_num_args()) {\n    call_user_func_array(array(parent::class, '__construct'), func_get_args());\n}\nPHP\n        );\n    }\n\n    /**\n     * Returns patch priority, which determines when patch will be applied.\n     *\n     * @return int Priority number (higher - earlier)\n     */\n    public function getPriority()\n    {\n        return 100;\n    }\n}\n"
  },
  {
    "path": "src/Prophecy/Doubler/ClassPatch/KeywordPatch.php",
    "content": "<?php\n\n/*\n * This file is part of the Prophecy.\n * (c) Konstantin Kudryashov <ever.zet@gmail.com>\n *     Marcello Duarte <marcello.duarte@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Prophecy\\Doubler\\ClassPatch;\n\nuse Prophecy\\Doubler\\Generator\\Node\\ClassNode;\n\n/**\n * Remove method functionality from the double which will clash with php keywords.\n *\n * @author Milan Magudia <milan@magudia.com>\n */\nclass KeywordPatch implements ClassPatchInterface\n{\n    /**\n     * Support any class\n     *\n     * @param ClassNode $node\n     *\n     * @return boolean\n     */\n    public function supports(ClassNode $node)\n    {\n        return true;\n    }\n\n    /**\n     * Remove methods that clash with php keywords\n     *\n     * @param ClassNode $node\n     */\n    public function apply(ClassNode $node)\n    {\n        $methodNames = array_keys($node->getMethods());\n        $methodsToRemove = array_intersect($methodNames, $this->getKeywords());\n        foreach ($methodsToRemove as $methodName) {\n            $node->removeMethod($methodName);\n        }\n    }\n\n    /**\n     * Returns patch priority, which determines when patch will be applied.\n     *\n     * @return int Priority number (higher - earlier)\n     */\n    public function getPriority()\n    {\n        return 49;\n    }\n\n    /**\n     * Returns array of php keywords.\n     *\n     * @return list<string>\n     */\n    private function getKeywords()\n    {\n        return ['__halt_compiler'];\n    }\n}\n"
  },
  {
    "path": "src/Prophecy/Doubler/ClassPatch/MagicCallPatch.php",
    "content": "<?php\n\n/*\n * This file is part of the Prophecy.\n * (c) Konstantin Kudryashov <ever.zet@gmail.com>\n *     Marcello Duarte <marcello.duarte@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Prophecy\\Doubler\\ClassPatch;\n\nuse Prophecy\\Doubler\\Generator\\Node\\ArgumentNode;\nuse Prophecy\\Doubler\\Generator\\Node\\ClassNode;\nuse Prophecy\\Doubler\\Generator\\Node\\MethodNode;\nuse Prophecy\\PhpDocumentor\\ClassAndInterfaceTagRetriever;\nuse Prophecy\\PhpDocumentor\\MethodTagRetrieverInterface;\n\n/**\n * Discover Magical API using \"@method\" PHPDoc format.\n *\n * @author Thomas Tourlourat <thomas@tourlourat.com>\n * @author Kévin Dunglas <dunglas@gmail.com>\n * @author Théo FIDRY <theo.fidry@gmail.com>\n */\nclass MagicCallPatch implements ClassPatchInterface\n{\n    const MAGIC_METHODS_WITH_ARGUMENTS = ['__call', '__callStatic', '__get', '__isset', '__set', '__set_state', '__unserialize', '__unset'];\n\n    private $tagRetriever;\n\n    public function __construct(?MethodTagRetrieverInterface $tagRetriever = null)\n    {\n        $this->tagRetriever = null === $tagRetriever ? new ClassAndInterfaceTagRetriever() : $tagRetriever;\n    }\n\n    /**\n     * Support any class\n     *\n     * @param ClassNode $node\n     *\n     * @return boolean\n     */\n    public function supports(ClassNode $node)\n    {\n        return true;\n    }\n\n    /**\n     * Discover Magical API\n     *\n     * @param ClassNode $node\n     */\n    public function apply(ClassNode $node)\n    {\n        $types = array_filter($node->getInterfaces(), function ($interface) {\n            return 0 !== strpos($interface, 'Prophecy\\\\');\n        });\n        $types[] = $node->getParentClass();\n\n        foreach ($types as $type) {\n            $reflectionClass = new \\ReflectionClass($type);\n\n            while ($reflectionClass) {\n                $tagList = $this->tagRetriever->getTagList($reflectionClass);\n\n                foreach ($tagList as $tag) {\n                    $methodName = $tag->getMethodName();\n\n                    if (empty($methodName)) {\n                        continue;\n                    }\n\n                    if (!$reflectionClass->hasMethod($methodName)) {\n                        $methodNode = new MethodNode($methodName);\n\n                        // only magic methods can have a contract that needs to be enforced\n                        if (in_array($methodName, self::MAGIC_METHODS_WITH_ARGUMENTS)) {\n                            if (method_exists($tag, 'getParameters')) {\n                                // Reflection Docblock 5.4.0+.\n                                foreach ($tag->getParameters() as $argument) {\n                                    $argumentNode = new ArgumentNode($argument->getName());\n                                    $methodNode->addArgument($argumentNode);\n                                }\n                            } else {\n                                // Reflection Docblock < 5.4.0.\n                                foreach ($tag->getArguments() as $argument) {\n                                    $argumentNode = new ArgumentNode($argument['name']);\n                                    $methodNode->addArgument($argumentNode);\n                                }\n                            }\n                        }\n\n                        $methodNode->setStatic($tag->isStatic());\n                        $node->addMethod($methodNode);\n                    }\n                }\n\n                $reflectionClass = $reflectionClass->getParentClass();\n            }\n        }\n    }\n\n    /**\n     * Returns patch priority, which determines when patch will be applied.\n     *\n     * @return integer Priority number (higher - earlier)\n     */\n    public function getPriority()\n    {\n        return 50;\n    }\n}\n"
  },
  {
    "path": "src/Prophecy/Doubler/ClassPatch/ProphecySubjectPatch.php",
    "content": "<?php\n\n/*\n * This file is part of the Prophecy.\n * (c) Konstantin Kudryashov <ever.zet@gmail.com>\n *     Marcello Duarte <marcello.duarte@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Prophecy\\Doubler\\ClassPatch;\n\nuse Prophecy\\Doubler\\Generator\\Node\\ArgumentTypeNode;\nuse Prophecy\\Doubler\\Generator\\Node\\ClassNode;\nuse Prophecy\\Doubler\\Generator\\Node\\MethodNode;\nuse Prophecy\\Doubler\\Generator\\Node\\ArgumentNode;\nuse Prophecy\\Doubler\\Generator\\Node\\Type\\ObjectType;\n\n/**\n * Add Prophecy functionality to the double.\n * This is a core class patch for Prophecy.\n *\n * @author Konstantin Kudryashov <ever.zet@gmail.com>\n */\nclass ProphecySubjectPatch implements ClassPatchInterface\n{\n    /**\n     * Always returns true.\n     *\n     * @param ClassNode $node\n     *\n     * @return bool\n     */\n    public function supports(ClassNode $node)\n    {\n        return true;\n    }\n\n    /**\n     * Apply Prophecy functionality to class node.\n     *\n     * @param ClassNode $node\n     */\n    public function apply(ClassNode $node)\n    {\n        $node->addInterface('Prophecy\\Prophecy\\ProphecySubjectInterface');\n        $node->addProperty('objectProphecyClosure', 'private');\n\n        foreach ($node->getMethods() as $name => $method) {\n            if ('__construct' === strtolower($name)) {\n                continue;\n            }\n\n            if (!$method->getReturnTypeNode()->hasReturnStatement()) {\n                $method->setCode(\n                    '$this->getProphecy()->makeProphecyMethodCall(__FUNCTION__, func_get_args());'\n                );\n            } else {\n                $method->setCode(\n                    'return $this->getProphecy()->makeProphecyMethodCall(__FUNCTION__, func_get_args());'\n                );\n            }\n        }\n\n        $prophecySetter = new MethodNode('setProphecy');\n        $prophecyArgument = new ArgumentNode('prophecy');\n        $prophecyArgument->setTypeNode(new ArgumentTypeNode(new ObjectType('Prophecy\\Prophecy\\ProphecyInterface')));\n        $prophecySetter->addArgument($prophecyArgument);\n        $prophecySetter->setCode(<<<PHP\nif (null === \\$this->objectProphecyClosure) {\n    \\$this->objectProphecyClosure = static function () use (\\$prophecy) {\n        return \\$prophecy;\n    };\n}\nPHP\n        );\n\n        $prophecyGetter = new MethodNode('getProphecy');\n        $prophecyGetter->setCode('return \\call_user_func($this->objectProphecyClosure);');\n\n        if ($node->hasMethod('__call')) {\n            $__call = $node->getMethod('__call');\n            \\assert($__call !== null);\n        } else {\n            $__call = new MethodNode('__call');\n            $__call->addArgument(new ArgumentNode('name'));\n            $__call->addArgument(new ArgumentNode('arguments'));\n\n            $node->addMethod($__call, true);\n        }\n\n        $__call->setCode(<<<PHP\nthrow new \\Prophecy\\Exception\\Doubler\\MethodNotFoundException(\n    sprintf('Method `%s::%s()` not found.', get_class(\\$this), func_get_arg(0)),\n    get_class(\\$this), func_get_arg(0)\n);\nPHP\n        );\n\n        $node->addMethod($prophecySetter, true);\n        $node->addMethod($prophecyGetter, true);\n    }\n\n    /**\n     * Returns patch priority, which determines when patch will be applied.\n     *\n     * @return int Priority number (higher - earlier)\n     */\n    public function getPriority()\n    {\n        return 0;\n    }\n}\n"
  },
  {
    "path": "src/Prophecy/Doubler/ClassPatch/ReflectionClassNewInstancePatch.php",
    "content": "<?php\n\n/*\n * This file is part of the Prophecy.\n * (c) Konstantin Kudryashov <ever.zet@gmail.com>\n *     Marcello Duarte <marcello.duarte@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Prophecy\\Doubler\\ClassPatch;\n\nuse Prophecy\\Doubler\\Generator\\Node\\ClassNode;\n\n/**\n * ReflectionClass::newInstance patch.\n * Makes first argument of newInstance optional, since it works but signature is misleading\n *\n * @author Florian Klein <florian.klein@free.fr>\n */\nclass ReflectionClassNewInstancePatch implements ClassPatchInterface\n{\n    /**\n     * Supports ReflectionClass\n     *\n     * @param ClassNode $node\n     *\n     * @return bool\n     */\n    public function supports(ClassNode $node)\n    {\n        return 'ReflectionClass' === $node->getParentClass();\n    }\n\n    /**\n     * Updates newInstance's first argument to make it optional\n     *\n     * @param ClassNode $node\n     */\n    public function apply(ClassNode $node)\n    {\n        $method = $node->getMethod('newInstance');\n        \\assert($method !== null);\n        foreach ($method->getArguments() as $argument) {\n            $argument->setDefault(null);\n        }\n    }\n\n    /**\n     * Returns patch priority, which determines when patch will be applied.\n     *\n     * @return int Priority number (higher = earlier)\n     */\n    public function getPriority()\n    {\n        return 50;\n    }\n}\n"
  },
  {
    "path": "src/Prophecy/Doubler/ClassPatch/SplFileInfoPatch.php",
    "content": "<?php\n\n/*\n * This file is part of the Prophecy.\n * (c) Konstantin Kudryashov <ever.zet@gmail.com>\n *     Marcello Duarte <marcello.duarte@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Prophecy\\Doubler\\ClassPatch;\n\nuse Prophecy\\Doubler\\Generator\\Node\\ClassNode;\nuse Prophecy\\Doubler\\Generator\\Node\\MethodNode;\n\n/**\n * SplFileInfo patch.\n * Makes SplFileInfo and derivative classes usable with Prophecy.\n *\n * @author Konstantin Kudryashov <ever.zet@gmail.com>\n */\nclass SplFileInfoPatch implements ClassPatchInterface\n{\n    /**\n     * Supports everything that extends SplFileInfo.\n     *\n     * @param ClassNode $node\n     *\n     * @return bool\n     */\n    public function supports(ClassNode $node)\n    {\n        return 'SplFileInfo' === $node->getParentClass()\n            || is_subclass_of($node->getParentClass(), 'SplFileInfo')\n        ;\n    }\n\n    /**\n     * Updated constructor code to call parent one with dummy file argument.\n     *\n     * @param ClassNode $node\n     */\n    public function apply(ClassNode $node)\n    {\n        if ($node->hasMethod('__construct')) {\n            $constructor = $node->getMethod('__construct');\n            \\assert($constructor !== null);\n        } else {\n            $constructor = new MethodNode('__construct');\n            $node->addMethod($constructor);\n        }\n\n        if ($this->nodeIsDirectoryIterator($node)) {\n            $constructor->setCode('return parent::__construct(\"'.__DIR__.'\");');\n\n            return;\n        }\n\n        if ($this->nodeIsSplFileObject($node)) {\n            $filePath = str_replace('\\\\', '\\\\\\\\', __FILE__);\n            $constructor->setCode('return parent::__construct(\"'.$filePath.'\");');\n\n            return;\n        }\n\n        if ($this->nodeIsSymfonySplFileInfo($node)) {\n            $filePath = str_replace('\\\\', '\\\\\\\\', __FILE__);\n            $constructor->setCode('return parent::__construct(\"'.$filePath.'\", \"\", \"\");');\n\n            return;\n        }\n\n        $constructor->useParentCode();\n    }\n\n    /**\n     * Returns patch priority, which determines when patch will be applied.\n     *\n     * @return int Priority number (higher - earlier)\n     */\n    public function getPriority()\n    {\n        return 50;\n    }\n\n    /**\n     * @param ClassNode $node\n     * @return boolean\n     */\n    private function nodeIsDirectoryIterator(ClassNode $node)\n    {\n        $parent = $node->getParentClass();\n\n        return 'DirectoryIterator' === $parent\n            || is_subclass_of($parent, 'DirectoryIterator');\n    }\n\n    /**\n     * @param ClassNode $node\n     * @return boolean\n     */\n    private function nodeIsSplFileObject(ClassNode $node)\n    {\n        $parent = $node->getParentClass();\n\n        return 'SplFileObject' === $parent\n            || is_subclass_of($parent, 'SplFileObject');\n    }\n\n    /**\n     * @param ClassNode $node\n     * @return boolean\n     */\n    private function nodeIsSymfonySplFileInfo(ClassNode $node)\n    {\n        $parent = $node->getParentClass();\n\n        return 'Symfony\\\\Component\\\\Finder\\\\SplFileInfo' === $parent;\n    }\n}\n"
  },
  {
    "path": "src/Prophecy/Doubler/ClassPatch/ThrowablePatch.php",
    "content": "<?php\n\nnamespace Prophecy\\Doubler\\ClassPatch;\n\nuse Prophecy\\Doubler\\Generator\\Node\\ClassNode;\nuse Prophecy\\Exception\\Doubler\\ClassCreatorException;\n\nclass ThrowablePatch implements ClassPatchInterface\n{\n    /**\n     * Checks if patch supports specific class node.\n     *\n     * @param ClassNode $node\n     * @return bool\n     */\n    public function supports(ClassNode $node)\n    {\n        return $this->implementsAThrowableInterface($node) && $this->doesNotExtendAThrowableClass($node);\n    }\n\n    /**\n     * @param ClassNode $node\n     * @return bool\n     */\n    private function implementsAThrowableInterface(ClassNode $node)\n    {\n        foreach ($node->getInterfaces() as $type) {\n            if (is_a($type, 'Throwable', true)) {\n                return true;\n            }\n        }\n\n        return false;\n    }\n\n    /**\n     * @param ClassNode $node\n     * @return bool\n     */\n    private function doesNotExtendAThrowableClass(ClassNode $node)\n    {\n        return !is_a($node->getParentClass(), 'Throwable', true);\n    }\n\n    /**\n     * Applies patch to the specific class node.\n     *\n     * @param ClassNode $node\n     *\n     * @return void\n     */\n    public function apply(ClassNode $node)\n    {\n        $this->checkItCanBeDoubled($node);\n        $this->setParentClassToException($node);\n    }\n\n    private function checkItCanBeDoubled(ClassNode $node): void\n    {\n        $className = $node->getParentClass();\n        if ($className !== 'stdClass') {\n            throw new ClassCreatorException(\n                sprintf(\n                    'Cannot double concrete class %s as well as implement Traversable',\n                    $className\n                ),\n                $node\n            );\n        }\n    }\n\n    private function setParentClassToException(ClassNode $node): void\n    {\n        $node->setParentClass('Exception');\n\n        $node->removeMethod('getMessage');\n        $node->removeMethod('getCode');\n        $node->removeMethod('getFile');\n        $node->removeMethod('getLine');\n        $node->removeMethod('getTrace');\n        $node->removeMethod('getPrevious');\n        $node->removeMethod('getNext');\n        $node->removeMethod('getTraceAsString');\n    }\n\n    /**\n     * Returns patch priority, which determines when patch will be applied.\n     *\n     * @return int Priority number (higher - earlier)\n     */\n    public function getPriority()\n    {\n        return 100;\n    }\n}\n"
  },
  {
    "path": "src/Prophecy/Doubler/ClassPatch/TraversablePatch.php",
    "content": "<?php\n\n/*\n * This file is part of the Prophecy.\n * (c) Konstantin Kudryashov <ever.zet@gmail.com>\n *     Marcello Duarte <marcello.duarte@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Prophecy\\Doubler\\ClassPatch;\n\nuse Prophecy\\Doubler\\Generator\\Node\\ClassNode;\nuse Prophecy\\Doubler\\Generator\\Node\\MethodNode;\nuse Prophecy\\Doubler\\Generator\\Node\\ReturnTypeNode;\nuse Prophecy\\Doubler\\Generator\\Node\\Type\\BuiltinType;\n\n/**\n * Traversable interface patch.\n * Forces classes that implement interfaces, that extend Traversable to also implement Iterator.\n *\n * @author Konstantin Kudryashov <ever.zet@gmail.com>\n */\nclass TraversablePatch implements ClassPatchInterface\n{\n    /**\n     * Supports nodetree, that implement Traversable, but not Iterator or IteratorAggregate.\n     *\n     * @param ClassNode $node\n     *\n     * @return bool\n     */\n    public function supports(ClassNode $node)\n    {\n        if (in_array('Iterator', $node->getInterfaces())) {\n            return false;\n        }\n        if (in_array('IteratorAggregate', $node->getInterfaces())) {\n            return false;\n        }\n\n        foreach ($node->getInterfaces() as $interface) {\n            if ('Traversable' !== $interface && !is_subclass_of($interface, 'Traversable')) {\n                continue;\n            }\n            if ('Iterator' === $interface || is_subclass_of($interface, 'Iterator')) {\n                continue;\n            }\n            if ('IteratorAggregate' === $interface || is_subclass_of($interface, 'IteratorAggregate')) {\n                continue;\n            }\n\n            return true;\n        }\n\n        return false;\n    }\n\n    /**\n     * Forces class to implement Iterator interface.\n     *\n     * @param ClassNode $node\n     */\n    public function apply(ClassNode $node)\n    {\n        $node->addInterface('Iterator');\n\n        $currentMethod = new MethodNode('current');\n        $currentMethod->setReturnTypeNode(new ReturnTypeNode(new BuiltinType('mixed')));\n        $node->addMethod($currentMethod);\n\n        $keyMethod = new MethodNode('key');\n        $keyMethod->setReturnTypeNode(new ReturnTypeNode(new BuiltinType('mixed')));\n        $node->addMethod($keyMethod);\n\n        $nextMethod = new MethodNode('next');\n        $nextMethod->setReturnTypeNode(new ReturnTypeNode(new BuiltinType('void')));\n        $node->addMethod($nextMethod);\n\n        $rewindMethod = new MethodNode('rewind');\n        $rewindMethod->setReturnTypeNode(new ReturnTypeNode(new BuiltinType('void')));\n        $node->addMethod($rewindMethod);\n\n        $validMethod = new MethodNode('valid');\n        $validMethod->setReturnTypeNode(new ReturnTypeNode(new BuiltinType('bool')));\n        $node->addMethod($validMethod);\n    }\n\n    /**\n     * Returns patch priority, which determines when patch will be applied.\n     *\n     * @return int Priority number (higher - earlier)\n     */\n    public function getPriority()\n    {\n        return 100;\n    }\n}\n"
  },
  {
    "path": "src/Prophecy/Doubler/DoubleInterface.php",
    "content": "<?php\n\n/*\n * This file is part of the Prophecy.\n * (c) Konstantin Kudryashov <ever.zet@gmail.com>\n *     Marcello Duarte <marcello.duarte@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Prophecy\\Doubler;\n\n/**\n * Core double interface.\n * All doubled classes will implement this one.\n *\n * @author Konstantin Kudryashov <ever.zet@gmail.com>\n */\ninterface DoubleInterface {}\n"
  },
  {
    "path": "src/Prophecy/Doubler/Doubler.php",
    "content": "<?php\n\n/*\n * This file is part of the Prophecy.\n * (c) Konstantin Kudryashov <ever.zet@gmail.com>\n *     Marcello Duarte <marcello.duarte@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Prophecy\\Doubler;\n\nuse Doctrine\\Instantiator\\Instantiator;\nuse Prophecy\\Doubler\\ClassPatch\\ClassPatchInterface;\nuse Prophecy\\Doubler\\Generator\\ClassMirror;\nuse Prophecy\\Doubler\\Generator\\ClassCreator;\nuse Prophecy\\Exception\\InvalidArgumentException;\nuse ReflectionClass;\n\n/**\n * Cached class doubler.\n * Prevents mirroring/creation of the same structure twice.\n *\n * @author Konstantin Kudryashov <ever.zet@gmail.com>\n */\nclass Doubler\n{\n    private $mirror;\n    private $creator;\n    private $namer;\n\n    /**\n     * @var list<ClassPatchInterface>\n     */\n    private $patches = array();\n\n    /**\n     * @var Instantiator|null\n     */\n    private $instantiator;\n\n    public function __construct(?ClassMirror $mirror = null, ?ClassCreator $creator = null,\n        ?NameGenerator $namer = null)\n    {\n        $this->mirror  = $mirror ?: new ClassMirror();\n        $this->creator = $creator ?: new ClassCreator();\n        $this->namer   = $namer ?: new NameGenerator();\n    }\n\n    /**\n     * Returns list of registered class patches.\n     *\n     * @return list<ClassPatchInterface>\n     */\n    public function getClassPatches()\n    {\n        return $this->patches;\n    }\n\n    /**\n     * Registers new class patch.\n     *\n     * @param ClassPatchInterface $patch\n     *\n     * @return void\n     */\n    public function registerClassPatch(ClassPatchInterface $patch)\n    {\n        $this->patches[] = $patch;\n\n        @usort($this->patches, function (ClassPatchInterface $patch1, ClassPatchInterface $patch2) {\n            return $patch2->getPriority() - $patch1->getPriority();\n        });\n    }\n\n    /**\n     * Creates double from specific class or/and list of interfaces.\n     *\n     * @template T of object\n     *\n     * @param ReflectionClass<T>|null   $class\n     * @param ReflectionClass<object>[] $interfaces Array of ReflectionClass instances\n     * @param array<mixed>|null         $args       Constructor arguments\n     *\n     * @return T&DoubleInterface\n     *\n     * @throws \\Prophecy\\Exception\\InvalidArgumentException\n     */\n    public function double(?ReflectionClass $class, array $interfaces, ?array $args = null)\n    {\n        foreach ($interfaces as $interface) {\n            if (!$interface instanceof ReflectionClass) {\n                throw new InvalidArgumentException(sprintf(\n                    \"[ReflectionClass \\$interface1 [, ReflectionClass \\$interface2]] array expected as\\n\"\n                    .\"a second argument to `Doubler::double(...)`, but got %s.\",\n                    is_object($interface) ? get_class($interface).' class' : gettype($interface)\n                ));\n            }\n        }\n\n        $classname  = $this->createDoubleClass($class, $interfaces);\n        $reflection = new ReflectionClass($classname);\n\n        if (null !== $args) {\n            return $reflection->newInstanceArgs($args);\n        }\n        if ((null === $constructor = $reflection->getConstructor())\n            || ($constructor->isPublic() && !$constructor->isFinal())) {\n            return $reflection->newInstance();\n        }\n\n        if (!$this->instantiator) {\n            $this->instantiator = new Instantiator();\n        }\n\n        return $this->instantiator->instantiate($classname);\n    }\n\n    /**\n     * Creates double class and returns its FQN.\n     *\n     * @template T of object\n     *\n     * @param ReflectionClass<T>|null   $class\n     * @param ReflectionClass<object>[] $interfaces\n     *\n     * @return class-string<T&DoubleInterface>\n     */\n    protected function createDoubleClass(?ReflectionClass $class, array $interfaces)\n    {\n        $name = $this->namer->name($class, $interfaces);\n        $node = $this->mirror->reflect($class, $interfaces);\n\n        foreach ($this->patches as $patch) {\n            if ($patch->supports($node)) {\n                $patch->apply($node);\n            }\n        }\n        $node->addInterface(DoubleInterface::class);\n\n        $this->creator->create($name, $node);\n        \\assert(class_exists($name, false));\n\n        return $name;\n    }\n}\n"
  },
  {
    "path": "src/Prophecy/Doubler/Generator/ClassCodeGenerator.php",
    "content": "<?php\n\n/*\n * This file is part of the Prophecy.\n * (c) Konstantin Kudryashov <ever.zet@gmail.com>\n *     Marcello Duarte <marcello.duarte@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Prophecy\\Doubler\\Generator;\n\nuse Prophecy\\Doubler\\Generator\\Node\\TypeNodeAbstract;\n\n/**\n * Class code creator.\n * Generates PHP code for specific class node tree.\n *\n * @author Konstantin Kudryashov <ever.zet@gmail.com>\n */\nclass ClassCodeGenerator\n{\n    // Used to accept an optional first argument with the deprecated Prophecy\\Doubler\\Generator\\TypeHintReference so careful when adding a new argument in a minor version.\n    public function __construct() {}\n\n    /**\n     * Generates PHP code for class node.\n     *\n     * @param string         $classname\n     * @param Node\\ClassNode $class\n     *\n     * @return string\n     */\n    public function generate($classname, Node\\ClassNode $class)\n    {\n        $parts     = explode('\\\\', $classname);\n        $classname = array_pop($parts);\n        $namespace = implode('\\\\', $parts);\n\n        $code = sprintf(\"%sclass %s extends \\%s implements %s {\\n\",\n            $class->isReadOnly() ? 'readonly ' : '',\n            $classname,\n            $class->getParentClass(),\n            implode(', ',\n                array_map(function ($interface) {return '\\\\'.$interface;}, $class->getInterfaces())\n            )\n        );\n\n        foreach ($class->getProperties() as $name => $visibility) {\n            $code .= sprintf(\"%s \\$%s;\\n\", $visibility, $name);\n        }\n        $code .= \"\\n\";\n\n        foreach ($class->getMethods() as $method) {\n            $code .= $this->generateMethod($method).\"\\n\";\n        }\n        $code .= \"\\n}\";\n\n        return sprintf(\"namespace %s {\\n%s\\n}\", $namespace, $code);\n    }\n\n    private function generateMethod(Node\\MethodNode $method): string\n    {\n        $php = sprintf(\"%s %s function %s%s(%s)%s {\\n\",\n            $method->getVisibility(),\n            $method->isStatic() ? 'static' : '',\n            $method->returnsReference() ? '&' : '',\n            $method->getName(),\n            implode(', ', $this->generateArguments($method->getArguments())),\n            ($ret = $this->generateTypes($method->getReturnTypeNode())) ? ': '.$ret : ''\n        );\n        $php .= $method->getCode().\"\\n\";\n\n        return $php.'}';\n    }\n\n    private function generateTypes(TypeNodeAbstract $typeNode): string\n    {\n        if ($typeNode->getType() === null) {\n            return '';\n        }\n\n        return (string) $typeNode->getType();\n    }\n\n    /**\n     * @param list<Node\\ArgumentNode> $arguments\n     *\n     * @return list<string>\n     */\n    private function generateArguments(array $arguments): array\n    {\n        return array_map(function (Node\\ArgumentNode $argument) {\n\n            $php = $this->generateTypes($argument->getTypeNode());\n\n            $php .= ' '.($argument->isPassedByReference() ? '&' : '');\n\n            $php .= $argument->isVariadic() ? '...' : '';\n\n            $php .= '$'.$argument->getName();\n\n            if ($argument->isOptional() && !$argument->isVariadic()) {\n                $default = var_export($argument->getDefault(), true);\n\n                // This is necessary for PHP 8.1, as enum cases are exported without a leading slash in this version\n                if ($argument->getDefault() instanceof \\UnitEnum && 0 !== strpos($default, '\\\\')) {\n                    $default = '\\\\'.$default;\n                }\n\n                $php .= ' = '.$default;\n            }\n\n            return $php;\n        }, $arguments);\n    }\n}\n"
  },
  {
    "path": "src/Prophecy/Doubler/Generator/ClassCreator.php",
    "content": "<?php\n\n/*\n * This file is part of the Prophecy.\n * (c) Konstantin Kudryashov <ever.zet@gmail.com>\n *     Marcello Duarte <marcello.duarte@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Prophecy\\Doubler\\Generator;\n\nuse Prophecy\\Exception\\Doubler\\ClassCreatorException;\n\n/**\n * Class creator.\n * Creates specific class in current environment.\n *\n * @author Konstantin Kudryashov <ever.zet@gmail.com>\n */\nclass ClassCreator\n{\n    private $generator;\n\n    public function __construct(?ClassCodeGenerator $generator = null)\n    {\n        $this->generator = $generator ?: new ClassCodeGenerator();\n    }\n\n    /**\n     * Creates class.\n     *\n     * @param string         $classname\n     * @param Node\\ClassNode $class\n     *\n     * @return mixed\n     *\n     * @throws \\Prophecy\\Exception\\Doubler\\ClassCreatorException\n     */\n    public function create($classname, Node\\ClassNode $class)\n    {\n        $code = $this->generator->generate($classname, $class);\n        $return = eval($code);\n\n        if (!class_exists($classname, false)) {\n            if (count($class->getInterfaces())) {\n                throw new ClassCreatorException(sprintf(\n                    'Could not double `%s` and implement interfaces: [%s].',\n                    $class->getParentClass(), implode(', ', $class->getInterfaces())\n                ), $class);\n            }\n\n            throw new ClassCreatorException(\n                sprintf('Could not double `%s`.', $class->getParentClass()),\n                $class\n            );\n        }\n\n        return $return;\n    }\n}\n"
  },
  {
    "path": "src/Prophecy/Doubler/Generator/ClassMirror.php",
    "content": "<?php\n\n/*\n * This file is part of the Prophecy.\n * (c) Konstantin Kudryashov <ever.zet@gmail.com>\n *     Marcello Duarte <marcello.duarte@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Prophecy\\Doubler\\Generator;\n\nuse Prophecy\\Doubler\\Generator\\Node\\ArgumentTypeNode;\nuse Prophecy\\Doubler\\Generator\\Node\\ReturnTypeNode;\nuse Prophecy\\Doubler\\Generator\\Node\\Type\\BuiltinType;\nuse Prophecy\\Doubler\\Generator\\Node\\Type\\IntersectionType;\nuse Prophecy\\Doubler\\Generator\\Node\\Type\\ObjectType;\nuse Prophecy\\Doubler\\Generator\\Node\\Type\\TypeInterface;\nuse Prophecy\\Doubler\\Generator\\Node\\Type\\SimpleType;\nuse Prophecy\\Doubler\\Generator\\Node\\Type\\UnionType;\nuse Prophecy\\Exception\\InvalidArgumentException;\nuse Prophecy\\Exception\\Doubler\\ClassMirrorException;\nuse ReflectionClass;\nuse ReflectionIntersectionType;\nuse ReflectionMethod;\nuse ReflectionNamedType;\nuse ReflectionParameter;\nuse ReflectionType;\nuse ReflectionUnionType;\n\n/**\n * Class mirror.\n * Core doubler class. Mirrors specific class and/or interfaces into class node tree.\n *\n * @author Konstantin Kudryashov <ever.zet@gmail.com>\n */\nclass ClassMirror\n{\n    private const REFLECTABLE_METHODS = array(\n        '__construct',\n        '__destruct',\n        '__sleep',\n        '__wakeup',\n        '__toString',\n        '__call',\n        '__invoke',\n    );\n\n    /**\n     * Reflects provided arguments into class node.\n     *\n     * @param ReflectionClass<object>|null $class\n     * @param ReflectionClass<object>[]    $interfaces\n     *\n     * @return Node\\ClassNode\n     *\n     */\n    public function reflect(?ReflectionClass $class, array $interfaces)\n    {\n        $node = new Node\\ClassNode();\n\n        if (null !== $class) {\n            if (true === $class->isInterface()) {\n                throw new InvalidArgumentException(sprintf(\n                    \"Could not reflect %s as a class, because it\\n\"\n                    .\"is interface - use the second argument instead.\",\n                    $class->getName()\n                ));\n            }\n\n            $this->reflectClassToNode($class, $node);\n        }\n\n        foreach ($interfaces as $interface) {\n            if (!$interface instanceof ReflectionClass) {\n                throw new InvalidArgumentException(sprintf(\n                    \"[ReflectionClass \\$interface1 [, ReflectionClass \\$interface2]] array expected as\\n\"\n                    .\"a second argument to `ClassMirror::reflect(...)`, but got %s.\",\n                    is_object($interface) ? get_class($interface).' class' : gettype($interface)\n                ));\n            }\n            if (false === $interface->isInterface()) {\n                throw new InvalidArgumentException(sprintf(\n                    \"Could not reflect %s as an interface, because it\\n\"\n                    .\"is class - use the first argument instead.\",\n                    $interface->getName()\n                ));\n            }\n\n            $this->reflectInterfaceToNode($interface, $node);\n        }\n\n        $node->addInterface('Prophecy\\Doubler\\Generator\\ReflectionInterface');\n\n        return $node;\n    }\n\n    /**\n     * @param ReflectionClass<object> $class\n     */\n    private function reflectClassToNode(ReflectionClass $class, Node\\ClassNode $node): void\n    {\n        if (true === $class->isFinal()) {\n            throw new ClassMirrorException(sprintf(\n                'Could not reflect class %s as it is marked final.', $class->getName()\n            ), $class);\n        }\n\n        if (method_exists(ReflectionClass::class, 'isReadOnly')) {\n            $node->setReadOnly($class->isReadOnly());\n        }\n\n        $node->setParentClass($class->getName());\n\n        foreach ($class->getMethods(ReflectionMethod::IS_ABSTRACT) as $method) {\n            if (false === $method->isProtected()) {\n                continue;\n            }\n\n            $this->reflectMethodToNode($method, $node);\n        }\n\n        foreach ($class->getMethods(ReflectionMethod::IS_PUBLIC) as $method) {\n            if (0 === strpos($method->getName(), '_')\n                && !in_array($method->getName(), self::REFLECTABLE_METHODS)) {\n                continue;\n            }\n\n            if (true === $method->isFinal()) {\n                $node->addUnextendableMethod($method->getName());\n                continue;\n            }\n\n            $this->reflectMethodToNode($method, $node);\n        }\n    }\n\n    /**\n     * @param ReflectionClass<object> $interface\n     */\n    private function reflectInterfaceToNode(ReflectionClass $interface, Node\\ClassNode $node): void\n    {\n        $node->addInterface($interface->getName());\n\n        foreach ($interface->getMethods() as $method) {\n            $this->reflectMethodToNode($method, $node);\n        }\n    }\n\n    private function reflectMethodToNode(ReflectionMethod $method, Node\\ClassNode $classNode): void\n    {\n        $node = new Node\\MethodNode($method->getName());\n\n        if (true === $method->isProtected()) {\n            $node->setVisibility('protected');\n        }\n\n        if (true === $method->isStatic()) {\n            $node->setStatic();\n        }\n\n        if (true === $method->returnsReference()) {\n            $node->setReturnsReference();\n        }\n\n        $returnReflectionType = null;\n        if ($method->hasReturnType()) {\n            $returnReflectionType = $method->getReturnType();\n        } elseif (method_exists($method, 'hasTentativeReturnType') && $method->hasTentativeReturnType()) {\n            // Tentative return types also need reflection\n            $returnReflectionType = $method->getTentativeReturnType();\n        }\n\n        if (null !== $returnReflectionType) {\n            $returnType = $this->createTypeFromReflection(\n                $returnReflectionType,\n                $method->getDeclaringClass()\n            );\n            $node->setReturnTypeNode(new ReturnTypeNode($returnType));\n        }\n\n        if (is_array($params = $method->getParameters()) && count($params)) {\n            foreach ($params as $param) {\n                $this->reflectArgumentToNode($param, $method->getDeclaringClass(), $node);\n            }\n        }\n\n        $classNode->addMethod($node);\n    }\n\n    /**\n     * @param ReflectionClass<object> $declaringClass\n     *\n     * @return void\n     */\n    private function reflectArgumentToNode(ReflectionParameter $parameter, ReflectionClass $declaringClass, Node\\MethodNode $methodNode): void\n    {\n        $name = $parameter->getName() == '...' ? '__dot_dot_dot__' : $parameter->getName();\n        $node = new Node\\ArgumentNode($name);\n\n        $refType = $parameter->getType();\n        if (null !== $refType) {\n            $typeHint = $this->createTypeFromReflection($refType, $declaringClass);\n            $node->setTypeNode(new ArgumentTypeNode($typeHint));\n        }\n\n        if ($parameter->isVariadic()) {\n            $node->setAsVariadic();\n        }\n\n        if ($this->hasDefaultValue($parameter)) {\n            $node->setDefault($this->getDefaultValue($parameter));\n        }\n\n        if ($parameter->isPassedByReference()) {\n            $node->setAsPassedByReference();\n        }\n\n        $methodNode->addArgument($node);\n    }\n\n    private function hasDefaultValue(ReflectionParameter $parameter): bool\n    {\n        if ($parameter->isVariadic()) {\n            return false;\n        }\n\n        if ($parameter->isDefaultValueAvailable()) {\n            return true;\n        }\n\n        return $parameter->isOptional();\n    }\n\n    /**\n     * @return mixed\n     */\n    private function getDefaultValue(ReflectionParameter $parameter)\n    {\n        if (!$parameter->isDefaultValueAvailable()) {\n            return null;\n        }\n\n        return $parameter->getDefaultValue();\n    }\n\n    /**\n     * @param ReflectionClass<object> $declaringClass Context reflection class\n     */\n    private function createTypeFromReflection(ReflectionType $type, ReflectionClass $declaringClass): TypeInterface\n    {\n        if ($type instanceof ReflectionIntersectionType) {\n            $innerTypes = [];\n            /** @var ReflectionNamedType $innerReflectionType */\n            foreach ($type->getTypes() as $innerReflectionType) {\n                // Intersections cannot be composed of builtin types\n                /** @var class-string $objectType */\n                $objectType = $innerReflectionType->getName();\n                $innerTypes[] = new ObjectType($objectType);\n            }\n            return new IntersectionType($innerTypes);\n        }\n\n        if ($type instanceof ReflectionUnionType) {\n            $innerTypes = [];\n            /** @var ReflectionIntersectionType|ReflectionNamedType $innerReflectionType */\n            foreach ($type->getTypes() as $innerReflectionType) {\n                if ($innerReflectionType instanceof ReflectionIntersectionType) {\n                    /** @var IntersectionType $intersection */\n                    $intersection = $this->createTypeFromReflection($innerReflectionType, $declaringClass);\n                    $innerTypes[] = $intersection;\n                    continue;\n                }\n                $name = $this->resolveTypeName($innerReflectionType->getName(), $declaringClass);\n                if ($innerReflectionType->isBuiltin() || $name === 'static') {\n                    $innerTypes[] = new BuiltinType($name);\n                } elseif ($name === 'self') {\n                    $innerTypes[] = new ObjectType($declaringClass->getName());\n                } else {\n                    /** @var class-string $name */\n                    $innerTypes[] = new ObjectType($name);\n                }\n            }\n            // Nullability is handled by 'null' being one of the types in the union\n            return new UnionType($innerTypes);\n        }\n\n        // Handle Named Types (single types like int, string, MyClass, ?MyClass)\n        if ($type instanceof ReflectionNamedType) {\n            $name = $this->resolveTypeName($type->getName(), $declaringClass);\n            if ($type->isBuiltin() || $name === 'static') {\n                $simpleType = new BuiltinType($name); // SimpleType constructor normalizes\n            } else {\n                /** @var class-string $name */\n                $simpleType = new ObjectType($name);\n            }\n\n            // Handle nullability for named types explicitly by wrapping in a UnionType if needed\n            if ($type->allowsNull() && $name !== 'mixed' && $name !== 'null') {\n                return new UnionType([new BuiltinType('null'), $simpleType]);\n            }\n\n            return $simpleType;\n        }\n\n        // Unknown ReflectionType implementation\n        throw new ClassMirrorException('Unknown reflection type: '.get_class($type), $declaringClass);\n    }\n\n    /**\n     * @param ReflectionClass<object> $contextClass\n     */\n    private function resolveTypeName(string $name, \\ReflectionClass $contextClass): string\n    {\n        if ($name === 'self') {\n            return $contextClass->getName();\n        }\n        if ($name === 'parent') {\n            $parent = $contextClass->getParentClass();\n            if (false === $parent) {\n                throw new ClassMirrorException(sprintf('Cannot use \"parent\" type hint in class \"%s\" as it does not have a parent.', $contextClass->getName()), $contextClass);\n            }\n            return $parent->getName();\n        }\n\n        return $name;\n    }\n}\n"
  },
  {
    "path": "src/Prophecy/Doubler/Generator/Node/ArgumentNode.php",
    "content": "<?php\n\n/*\n * This file is part of the Prophecy.\n * (c) Konstantin Kudryashov <ever.zet@gmail.com>\n *     Marcello Duarte <marcello.duarte@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Prophecy\\Doubler\\Generator\\Node;\n\n/**\n * Argument node.\n *\n * @author Konstantin Kudryashov <ever.zet@gmail.com>\n */\nclass ArgumentNode\n{\n    private $name;\n    /**\n     * @var mixed\n     */\n    private $default;\n    /**\n     * @var bool\n     */\n    private $optional    = false;\n\n    /**\n     * @var bool\n     */\n    private $byReference = false;\n\n    /**\n     * @var bool\n     */\n    private $isVariadic  = false;\n\n    /** @var ArgumentTypeNode */\n    private $typeNode;\n\n    /**\n     * @param string $name\n     */\n    public function __construct($name)\n    {\n        $this->name = $name;\n        $this->typeNode = new ArgumentTypeNode();\n    }\n\n    /**\n     * @return string\n     */\n    public function getName()\n    {\n        return $this->name;\n    }\n\n    /**\n     * @return void\n     */\n    public function setTypeNode(ArgumentTypeNode $typeNode)\n    {\n        $this->typeNode = $typeNode;\n    }\n\n    public function getTypeNode(): ArgumentTypeNode\n    {\n        return $this->typeNode;\n    }\n\n    /**\n     * @return bool\n     */\n    public function hasDefault()\n    {\n        return $this->isOptional() && !$this->isVariadic();\n    }\n\n    /**\n     * @return mixed\n     */\n    public function getDefault()\n    {\n        return $this->default;\n    }\n\n    /**\n     * @param mixed $default\n     *\n     * @return void\n     */\n    public function setDefault($default = null)\n    {\n        $this->optional = true;\n        $this->default  = $default;\n    }\n\n    /**\n     * @return bool\n     */\n    public function isOptional()\n    {\n        return $this->optional;\n    }\n\n    /**\n     * @param bool $byReference\n     *\n     * @return void\n     */\n    public function setAsPassedByReference($byReference = true)\n    {\n        $this->byReference = $byReference;\n    }\n\n    /**\n     * @return bool\n     */\n    public function isPassedByReference()\n    {\n        return $this->byReference;\n    }\n\n    /**\n     * @param bool $isVariadic\n     *\n     * @return void\n     */\n    public function setAsVariadic($isVariadic = true)\n    {\n        $this->isVariadic = $isVariadic;\n    }\n\n    /**\n     * @return bool\n     */\n    public function isVariadic()\n    {\n        return $this->isVariadic;\n    }\n\n    /**\n     * @deprecated use getArgumentTypeNode instead\n     * @return string|null\n     */\n    public function getTypeHint()\n    {\n        $type = $this->typeNode->getNonNullTypes() ? $this->typeNode->getNonNullTypes()[0] : null;\n\n        return $type ? ltrim($type, '\\\\') : null;\n    }\n\n    /**\n     * @deprecated use setArgumentTypeNode instead\n     * @param string|null $typeHint\n     *\n     * @return void\n     */\n    public function setTypeHint($typeHint = null)\n    {\n        $this->typeNode = ($typeHint === null) ? new ArgumentTypeNode() : new ArgumentTypeNode($typeHint);\n    }\n\n    /**\n     * @deprecated use getArgumentTypeNode instead\n     * @return bool\n     */\n    public function isNullable()\n    {\n        return $this->typeNode->canUseNullShorthand();\n    }\n\n    /**\n     * @deprecated use getArgumentTypeNode instead\n     * @param bool $isNullable\n     *\n     * @return void\n     */\n    public function setAsNullable($isNullable = true)\n    {\n        $nonNullTypes = $this->typeNode->getNonNullTypes();\n        $this->typeNode = $isNullable ? new ArgumentTypeNode('null', ...$nonNullTypes) : new ArgumentTypeNode(...$nonNullTypes);\n    }\n}\n"
  },
  {
    "path": "src/Prophecy/Doubler/Generator/Node/ArgumentTypeNode.php",
    "content": "<?php\n\nnamespace Prophecy\\Doubler\\Generator\\Node;\n\nclass ArgumentTypeNode extends TypeNodeAbstract {}\n"
  },
  {
    "path": "src/Prophecy/Doubler/Generator/Node/ClassNode.php",
    "content": "<?php\n\n/*\n * This file is part of the Prophecy.\n * (c) Konstantin Kudryashov <ever.zet@gmail.com>\n *     Marcello Duarte <marcello.duarte@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Prophecy\\Doubler\\Generator\\Node;\n\nuse Prophecy\\Exception\\Doubler\\MethodNotExtendableException;\nuse Prophecy\\Exception\\InvalidArgumentException;\n\n/**\n * Class node.\n *\n * @author Konstantin Kudryashov <ever.zet@gmail.com>\n */\nclass ClassNode\n{\n    /**\n     * @var class-string\n     */\n    private $parentClass = 'stdClass';\n    /**\n     * @var list<class-string>\n     */\n    private $interfaces  = array();\n\n    /**\n     * @var array<string, string>\n     *\n     * @phpstan-var array<string, 'public'|'private'|'protected'>\n     */\n    private $properties  = array();\n\n    /**\n     * @var list<string>\n     */\n    private $unextendableMethods = array();\n\n    /**\n     * @var bool\n     */\n    private $readOnly = false;\n\n    /**\n     * @var array<string, MethodNode>\n     */\n    private $methods = array();\n\n    /**\n     * @return class-string\n     */\n    public function getParentClass()\n    {\n        return $this->parentClass;\n    }\n\n    /**\n     * @param class-string|null $class\n     *\n     * @return void\n     */\n    public function setParentClass($class)\n    {\n        $this->parentClass = $class ?: 'stdClass';\n    }\n\n    /**\n     * @return list<class-string>\n     */\n    public function getInterfaces()\n    {\n        return $this->interfaces;\n    }\n\n    /**\n     * @param class-string $interface\n     *\n     * @return void\n     */\n    public function addInterface($interface)\n    {\n        if ($this->hasInterface($interface)) {\n            return;\n        }\n\n        array_unshift($this->interfaces, $interface);\n    }\n\n    /**\n     * @param class-string $interface\n     *\n     * @return bool\n     */\n    public function hasInterface($interface)\n    {\n        return in_array($interface, $this->interfaces);\n    }\n\n    /**\n     * @return array<string, string>\n     *\n     * @phpstan-return array<string, 'public'|'private'|'protected'>\n     */\n    public function getProperties()\n    {\n        return $this->properties;\n    }\n\n    /**\n     * @param string $name\n     * @param string $visibility\n     *\n     * @return void\n     *\n     * @phpstan-param 'public'|'private'|'protected' $visibility\n     */\n    public function addProperty($name, $visibility = 'public')\n    {\n        $visibility = strtolower($visibility);\n\n        if (!\\in_array($visibility, array('public', 'private', 'protected'), true)) {\n            throw new InvalidArgumentException(sprintf(\n                '`%s` property visibility is not supported.', $visibility\n            ));\n        }\n\n        $this->properties[$name] = $visibility;\n    }\n\n    /**\n     * @return array<string, MethodNode>\n     */\n    public function getMethods()\n    {\n        return $this->methods;\n    }\n\n    /**\n     * @param MethodNode $method\n     * @param bool       $force\n     *\n     * @return void\n     */\n    public function addMethod(MethodNode $method, $force = false)\n    {\n        if (!$this->isExtendable($method->getName())) {\n            $message = sprintf(\n                'Method `%s` is not extendable, so can not be added.', $method->getName()\n            );\n            throw new MethodNotExtendableException($message, $this->getParentClass(), $method->getName());\n        }\n\n        if ($force || !isset($this->methods[$method->getName()])) {\n            $this->methods[$method->getName()] = $method;\n        }\n    }\n\n    /**\n     * @param string $name\n     *\n     * @return void\n     */\n    public function removeMethod($name)\n    {\n        unset($this->methods[$name]);\n    }\n\n    /**\n     * @param string $name\n     *\n     * @return MethodNode|null\n     */\n    public function getMethod($name)\n    {\n        return $this->hasMethod($name) ? $this->methods[$name] : null;\n    }\n\n    /**\n     * @param string $name\n     *\n     * @return bool\n     */\n    public function hasMethod($name)\n    {\n        return isset($this->methods[$name]);\n    }\n\n    /**\n     * @return list<string>\n     */\n    public function getUnextendableMethods()\n    {\n        return $this->unextendableMethods;\n    }\n\n    /**\n     * @param string $unextendableMethod\n     *\n     * @return void\n     */\n    public function addUnextendableMethod($unextendableMethod)\n    {\n        if (!$this->isExtendable($unextendableMethod)) {\n            return;\n        }\n        $this->unextendableMethods[] = $unextendableMethod;\n    }\n\n    /**\n     * @param string $method\n     *\n     * @return bool\n     */\n    public function isExtendable($method)\n    {\n        return !in_array($method, $this->unextendableMethods);\n    }\n\n    /**\n     * @return bool\n     */\n    public function isReadOnly()\n    {\n        return $this->readOnly;\n    }\n\n    /**\n     * @param bool $readOnly\n     *\n     * @return void\n     */\n    public function setReadOnly($readOnly)\n    {\n        $this->readOnly = $readOnly;\n    }\n}\n"
  },
  {
    "path": "src/Prophecy/Doubler/Generator/Node/MethodNode.php",
    "content": "<?php\n\n/*\n * This file is part of the Prophecy.\n * (c) Konstantin Kudryashov <ever.zet@gmail.com>\n *     Marcello Duarte <marcello.duarte@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Prophecy\\Doubler\\Generator\\Node;\n\nuse Prophecy\\Exception\\InvalidArgumentException;\n\n/**\n * Method node.\n *\n * @author Konstantin Kudryashov <ever.zet@gmail.com>\n */\nclass MethodNode\n{\n    private $name;\n    private $code;\n    /**\n     * @var string\n     *\n     * @phpstan-var 'public'|'private'|'protected'\n     */\n    private $visibility = 'public';\n    /**\n     * @var bool\n     */\n    private $static = false;\n    /**\n     * @var bool\n     */\n    private $returnsReference = false;\n\n    /** @var ReturnTypeNode */\n    private $returnTypeNode;\n\n    /**\n     * @var list<ArgumentNode>\n     */\n    private $arguments = array();\n\n    // Used to accept an optional third argument with the deprecated Prophecy\\Doubler\\Generator\\TypeHintReference so careful when adding a new argument in a minor version.\n    /**\n     * @param string      $name\n     * @param string|null $code\n     */\n    public function __construct($name, $code = null)\n    {\n        $this->name = $name;\n        $this->code = $code;\n        $this->returnTypeNode = new ReturnTypeNode();\n    }\n\n    /**\n     * @return string\n     *\n     * @phpstan-return 'public'|'private'|'protected'\n     */\n    public function getVisibility()\n    {\n        return $this->visibility;\n    }\n\n    /**\n     * @param string $visibility\n     *\n     * @return void\n     */\n    public function setVisibility($visibility)\n    {\n        $visibility = strtolower($visibility);\n\n        if (!\\in_array($visibility, array('public', 'private', 'protected'), true)) {\n            throw new InvalidArgumentException(sprintf(\n                '`%s` method visibility is not supported.', $visibility\n            ));\n        }\n\n        $this->visibility = $visibility;\n    }\n\n    /**\n     * @return bool\n     */\n    public function isStatic()\n    {\n        return $this->static;\n    }\n\n    /**\n     * @param bool $static\n     *\n     * @return void\n     */\n    public function setStatic($static = true)\n    {\n        $this->static = (bool) $static;\n    }\n\n    /**\n     * @return bool\n     */\n    public function returnsReference()\n    {\n        return $this->returnsReference;\n    }\n\n    /**\n     * @return void\n     */\n    public function setReturnsReference()\n    {\n        $this->returnsReference = true;\n    }\n\n    /**\n     * @return string\n     */\n    public function getName()\n    {\n        return $this->name;\n    }\n\n    /**\n     * @return void\n     */\n    public function addArgument(ArgumentNode $argument)\n    {\n        $this->arguments[] = $argument;\n    }\n\n    /**\n     * @return list<ArgumentNode>\n     */\n    public function getArguments()\n    {\n        return $this->arguments;\n    }\n\n    /**\n     * @deprecated use getReturnTypeNode instead\n     * @return bool\n     */\n    public function hasReturnType()\n    {\n        return (bool) $this->returnTypeNode->getNonNullTypes();\n    }\n\n    public function setReturnTypeNode(ReturnTypeNode $returnTypeNode): void\n    {\n        $this->returnTypeNode = $returnTypeNode;\n    }\n\n    /**\n     * @deprecated use setReturnTypeNode instead\n     * @param string $type\n     *\n     * @return void\n     */\n    public function setReturnType($type = null)\n    {\n        $this->returnTypeNode = ($type === '' || $type === null) ? new ReturnTypeNode() : new ReturnTypeNode($type);\n    }\n\n    /**\n     * @deprecated use setReturnTypeNode instead\n     * @param bool $bool\n     *\n     * @return void\n     */\n    public function setNullableReturnType($bool = true)\n    {\n        if ($bool) {\n            $this->returnTypeNode = new ReturnTypeNode('null', ...$this->returnTypeNode->getTypes());\n        } else {\n            $this->returnTypeNode = new ReturnTypeNode(...$this->returnTypeNode->getNonNullTypes());\n        }\n    }\n\n    /**\n     * @deprecated use getReturnTypeNode instead\n     * @return string|null\n     */\n    public function getReturnType()\n    {\n        if ($types = $this->returnTypeNode->getNonNullTypes()) {\n            return $types[0];\n        }\n\n        return null;\n    }\n\n    public function getReturnTypeNode(): ReturnTypeNode\n    {\n        return $this->returnTypeNode;\n    }\n\n    /**\n     * @deprecated use getReturnTypeNode instead\n     * @return bool\n     */\n    public function hasNullableReturnType()\n    {\n        return $this->returnTypeNode->isNullable();\n    }\n\n    /**\n     * @param string $code\n     *\n     * @return void\n     */\n    public function setCode($code)\n    {\n        $this->code = $code;\n    }\n\n    /**\n     * @return string\n     */\n    public function getCode()\n    {\n        if ($this->returnsReference) {\n            return \"throw new \\Prophecy\\Exception\\Doubler\\ReturnByReferenceException('Returning by reference not supported', get_class(\\$this), '{$this->name}');\";\n        }\n\n        return (string) $this->code;\n    }\n\n    /**\n     * @return void\n     */\n    public function useParentCode()\n    {\n        $this->code = sprintf(\n            'return parent::%s(%s);', $this->getName(), implode(', ',\n                array_map(array($this, 'generateArgument'), $this->arguments)\n            )\n        );\n    }\n\n    /**\n     * @return string\n     */\n    private function generateArgument(ArgumentNode $arg)\n    {\n        $argument = '$'.$arg->getName();\n\n        if ($arg->isVariadic()) {\n            $argument = '...'.$argument;\n        }\n\n        return $argument;\n    }\n}\n"
  },
  {
    "path": "src/Prophecy/Doubler/Generator/Node/ReturnTypeNode.php",
    "content": "<?php\n\nnamespace Prophecy\\Doubler\\Generator\\Node;\n\nuse Prophecy\\Doubler\\Generator\\Node\\Type\\BuiltinType;\n\nfinal class ReturnTypeNode extends TypeNodeAbstract\n{\n    protected function isBuiltIn(string $type): bool\n    {\n        switch ($type) {\n            case 'void':\n            case 'never':\n                return true;\n            default:\n                return parent::isBuiltIn($type);\n        }\n    }\n\n    /**\n     * @deprecated use hasReturnStatement\n     *\n     * @return bool\n     */\n    public function isVoid(): bool\n    {\n        if ($this->getType() === null) {\n            return true;\n        }\n\n        return $this->getType()->equals(new BuiltinType('void'));\n    }\n\n    public function hasReturnStatement(): bool\n    {\n        if ($this->getType() === null) {\n            return true;\n        }\n\n        return !$this->getType()->equals(new BuiltinType('void'))\n            && !$this->getType()->equals(new BuiltinType('never'));\n    }\n}\n"
  },
  {
    "path": "src/Prophecy/Doubler/Generator/Node/Type/BuiltinType.php",
    "content": "<?php\n\nnamespace Prophecy\\Doubler\\Generator\\Node\\Type;\n\nfinal class BuiltinType implements SimpleType\n{\n    public function __construct(private readonly string $type) {}\n\n    public function __toString(): string\n    {\n        return $this->getType();\n    }\n\n    public function getType(): string\n    {\n        return $this->type;\n    }\n\n    public function equals(TypeInterface $givenType): bool\n    {\n        if (!$givenType instanceof BuiltinType) {\n            return false;\n        }\n\n        return $this->getType() === $givenType->getType();\n    }\n}\n"
  },
  {
    "path": "src/Prophecy/Doubler/Generator/Node/Type/IntersectionType.php",
    "content": "<?php\n\nnamespace Prophecy\\Doubler\\Generator\\Node\\Type;\n\nuse Prophecy\\Exception\\Doubler\\DoubleException;\n\nfinal class IntersectionType implements TypeInterface\n{\n    /**\n     * @param list<ObjectType> $types\n     */\n    public function __construct(private array $types)\n    {\n        $this->guard();\n    }\n\n    /**\n     * @return list<ObjectType>\n     */\n    public function getTypes(): array\n    {\n        return $this->types;\n    }\n\n    /**\n     * @param SimpleType $givenType\n     */\n    private function has(SimpleType $givenType): bool\n    {\n        foreach ($this->types as $type) {\n            if ($type->equals($givenType)) {\n                return true;\n            }\n        }\n\n        return false;\n    }\n\n    public function equals(TypeInterface $givenType): bool\n    {\n        if (!$givenType instanceof IntersectionType) {\n            return false;\n        }\n\n        if (count($this->types) !== count($givenType->getTypes())) {\n            return false;\n        }\n\n        foreach ($this->types as $type) {\n            if (!$givenType->has($type)) {\n                return false;\n            }\n        }\n\n        return true;\n    }\n\n    private function guard(): void\n    {\n        // Cannot contain void, never, null, scalar types, mixed, union types etc.\n        foreach ($this->types as $type) {\n            if (!$type instanceof ObjectType) {\n                throw new DoubleException('Intersection types can only contain class/interface names.');\n            }\n        }\n        if (count($this->types) < 2) {\n            throw new DoubleException('Intersection types must contain at least two types.');\n        }\n    }\n\n    public function __toString(): string\n    {\n        $result = '';\n        foreach ($this->types as $type) {\n            if ($result !== '') {\n                $result .= '&';\n            }\n            $result .= (string) $type;\n        }\n\n        return $result;\n    }\n}\n"
  },
  {
    "path": "src/Prophecy/Doubler/Generator/Node/Type/ObjectType.php",
    "content": "<?php\n\nnamespace Prophecy\\Doubler\\Generator\\Node\\Type;\n\nfinal class ObjectType implements SimpleType\n{\n    /**\n     * @param class-string $type\n     */\n    public function __construct(private readonly string $type) {}\n\n    public function __toString(): string\n    {\n        return '\\\\'.$this->type;\n    }\n\n    /**\n     * @return class-string\n     */\n    public function getType(): string\n    {\n        return $this->type;\n    }\n\n    public function equals(TypeInterface $givenType): bool\n    {\n        if (!$givenType instanceof ObjectType) {\n            return false;\n        }\n\n        return $this->getType() === $givenType->getType();\n    }\n}\n"
  },
  {
    "path": "src/Prophecy/Doubler/Generator/Node/Type/SimpleType.php",
    "content": "<?php\n\nnamespace Prophecy\\Doubler\\Generator\\Node\\Type;\n\ninterface SimpleType extends TypeInterface\n{\n    public function getType(): string;\n}\n"
  },
  {
    "path": "src/Prophecy/Doubler/Generator/Node/Type/TypeInterface.php",
    "content": "<?php\n\nnamespace Prophecy\\Doubler\\Generator\\Node\\Type;\n\ninterface TypeInterface extends \\Stringable\n{\n    public function equals(TypeInterface $givenType): bool;\n}\n"
  },
  {
    "path": "src/Prophecy/Doubler/Generator/Node/Type/UnionType.php",
    "content": "<?php\n\nnamespace Prophecy\\Doubler\\Generator\\Node\\Type;\n\nuse Prophecy\\Exception\\Doubler\\DoubleException;\n\nfinal class UnionType implements TypeInterface\n{\n    /**\n     * @param list<SimpleType|IntersectionType> $types\n     */\n    public function __construct(private array $types)\n    {\n        $this->guard();\n    }\n\n    /**\n     * @return list<SimpleType|IntersectionType>\n     */\n    public function getTypes(): array\n    {\n        return $this->types;\n    }\n\n    private function guard(): void\n    {\n        $typeCount = count($this->types);\n\n        if ($typeCount < 2) {\n            // Throwing LogicException as this indicates misuse of the UnionType class itself.\n            throw new DoubleException(sprintf(\n                'UnionType must be constructed with at least two types. Got %d.',\n                $typeCount\n            ));\n        }\n\n        // To detect duplicates\n        $typeStrings = [];\n\n        foreach ($this->types as $type) {\n            if ($type instanceof UnionType) {\n                throw new DoubleException('Union types cannot contain other unions.');\n            }\n            if ($type instanceof IntersectionType) {\n                $typeStrings[] = implode('&', array_map(fn(SimpleType $type) => (string) $type, $type->getTypes()));\n                continue; // Valid type, nothing to be checked\n            }\n            if (!$type instanceof SimpleType) {\n                throw new DoubleException(sprintf('Unexpected type \"%s\". Only IntersectionType and SimpleType are supported in UnionType.', get_class($type)));\n            }\n            $typeName = $type->getType();\n            $typeStrings[] = $typeName;\n\n            if (in_array($typeName, ['void', 'never', 'mixed'], true)) {\n                throw new DoubleException(sprintf('Type \"%s\" cannot be part of a union type.', $typeName));\n            }\n        }\n\n        // Rule: Union types cannot contain duplicate types (e.g., int|string|int is invalid).\n        // Reflection usually resolves this, but it's good practice to ensure consistency.\n        if (count(array_unique($typeStrings)) !== $typeCount) {\n            throw new DoubleException(sprintf(\n                'Union types cannot contain duplicate types. Found duplicates in: %s',\n                implode('|', $typeStrings)\n            ));\n        }\n    }\n\n    public function has(SimpleType|IntersectionType $givenType): bool\n    {\n        foreach ($this->types as $type) {\n            if ($type->equals($givenType)) {\n                return true;\n            }\n        }\n\n        return false;\n    }\n\n    public function equals(TypeInterface $givenType): bool\n    {\n        if (!$givenType instanceof UnionType) {\n            return false;\n        }\n\n        if (count($this->types) !== count($givenType->getTypes())) {\n            return false;\n        }\n\n        foreach ($this->types as $type) {\n            if (!$givenType->has($type)) {\n                return false;\n            }\n        }\n\n        return true;\n    }\n\n    public function __toString(): string\n    {\n        $result = '';\n        foreach ($this->types as $type) {\n            if ($result !== '') {\n                $result .= '|';\n            }\n\n            if ($type instanceof IntersectionType && count($this->types) > 1) {\n                $result .= '('.((string) $type).')';\n                continue;\n            }\n            $result .= (string) $type;\n        }\n\n        return $result;\n    }\n}\n"
  },
  {
    "path": "src/Prophecy/Doubler/Generator/Node/TypeNodeAbstract.php",
    "content": "<?php\n\nnamespace Prophecy\\Doubler\\Generator\\Node;\n\nuse Prophecy\\Doubler\\Generator\\Node\\Type\\BuiltinType;\nuse Prophecy\\Doubler\\Generator\\Node\\Type\\IntersectionType;\nuse Prophecy\\Doubler\\Generator\\Node\\Type\\ObjectType;\nuse Prophecy\\Doubler\\Generator\\Node\\Type\\TypeInterface;\nuse Prophecy\\Doubler\\Generator\\Node\\Type\\SimpleType;\nuse Prophecy\\Doubler\\Generator\\Node\\Type\\UnionType;\nuse Prophecy\\Exception\\Doubler\\DoubleException;\n\nabstract class TypeNodeAbstract\n{\n    // null means no type, NOT BuiltInType(\"null\")\n    private ?TypeInterface $type;\n\n    /**\n     * @param string|TypeInterface|null $type\n     */\n    public function __construct(string|TypeInterface|null $type = null, string ...$types)\n    {\n        if (!empty($types) || is_string($type)) {\n            $types = [$type, ...$types];\n        }\n\n        if (!empty($types)) {\n            // BC Layer for usage with strings\n            trigger_deprecation(\n                'phpspec/prophecy',\n                '1.23',\n                'Instanciating node type with a string type will not be supported in the future, use a TypeInterface instance instead.',\n            );\n\n            // BC Layer for usage with strings\n            $typesNormalized = [];\n            /** @var list<BuiltinType|ObjectType|IntersectionType> $union */\n            $union = [];\n            foreach ($types as $type) {\n                if (!is_string($type)) {\n                    throw new DoubleException('Building a TypeNode with string is deprecated. Mixing strings and type object is not allowed.');\n                }\n\n                if ($this->isBuiltIn($type)) {\n                    $type = new BuiltinType($this->normalizeBuiltinType($type));\n                } else {\n                    /** @var class-string $typeName */\n                    $typeName = $this->removePrefixNsSeparator($type);\n                    $type = new ObjectType($typeName);\n                }\n                if (!in_array($type->getType(), $typesNormalized, true)) {\n                    $union[] = $type;\n                    $typesNormalized[] = $type->getType();\n                }\n            }\n\n            if (count($union) > 1) {\n                $this->type = new UnionType($union);\n            } else {\n                $this->type = $union[0];\n            }\n        } else {\n            /** @var TypeInterface|null $type */\n            $this->type = $type;\n        }\n    }\n\n    /**\n     * @deprecated use isNullable() instead\n     */\n    public function canUseNullShorthand(): bool\n    {\n        trigger_deprecation(\n            'phpspec/prophecy',\n            '1.23',\n            'This method is deprecated in favor of nullable()'\n        );\n        if ($this->type instanceof UnionType) {\n            return $this->type->has(new BuiltinType('null')) && count($this->type->getTypes()) === 2;\n        }\n\n        return false;\n    }\n\n    public function isNullable(): bool\n    {\n        if ($this->type instanceof UnionType) {\n            return $this->type->has(new BuiltinType('null'));\n        }\n\n        if ($this->type instanceof SimpleType && $this->type->getType() === 'null') {\n            return true;\n        }\n\n        return false;\n    }\n\n    /**\n     * @return list<string>\n     * @deprecated use getType() instead\n     */\n    public function getTypes(): array\n    {\n        trigger_deprecation(\n            'phpspec/prophecy',\n            '1.23',\n            'This method is deprecated in favor of getType()',\n        );\n        if ($this->type instanceof SimpleType) {\n            return [(string) $this->type];\n        }\n\n        $types = [];\n\n        if ($this->type instanceof UnionType) {\n            foreach ($this->type->getTypes() as $type) {\n                if ($type instanceof IntersectionType) {\n                    throw new DoubleException('getType() method is deprecated and do not support IntersectionType by design. Use getType() instead.');\n                }\n                $types[$type->getType()] = (string) $type;\n            }\n        }\n\n        $types =  array_values($types);\n        $types = array_map([$this, 'normalizeBuiltinType'], $types);\n\n        return array_values(array_unique($types));\n    }\n\n    public function getType(): ?TypeInterface\n    {\n        return $this->type;\n    }\n\n    /**\n     * @deprecated use getType() instead\n     * @return list<string>\n     */\n    public function getNonNullTypes(): array\n    {\n        trigger_deprecation(\n            'phpspec/prophecy',\n            '1.23',\n            'This method is deprecated in favor of getType() and the usage of the new type API.',\n        );\n        if ($this->type === null) {\n            return [];\n        }\n        if ($this->type instanceof UnionType) {\n            $types = [];\n            foreach ($this->type->getTypes() as $type) {\n                if ($type instanceof IntersectionType) {\n                    throw new DoubleException('You are using the old (and deprecated) API which is not compatible with intersections');\n                }\n                if (!$type instanceof BuiltinType || $type->getType() !== 'null') {\n                    $types[] = $type->getType();\n                }\n            }\n\n            return $types;\n        }\n\n        if ($this->type instanceof SimpleType) {\n            if ($this->type->getType() === 'null') {\n                return [];\n            }\n            return [$this->type->getType()];\n        }\n\n        throw new DoubleException('getNonNullTypes() method is deprecated and do not support IntersectionType by design. Use getType() instead.');\n    }\n\n    private function normalizeBuiltinType(string $type): string\n    {\n        switch ($type) {\n            // normalize alias types\n            case 'double':\n            case 'real':\n                return 'float';\n            case 'integer':\n                return 'int';\n            case 'boolean':\n                return 'bool';\n            default:\n                return $type;\n        }\n    }\n\n    protected function isBuiltIn(string $type): bool\n    {\n        switch ($type) {\n            // type aliases\n            case 'double':\n            case 'real':\n            case 'boolean':\n            case 'integer':\n\n                //  built in types\n            case 'self':\n            case 'static':\n            case 'array':\n            case 'callable':\n            case 'bool':\n            case 'false':\n            case 'true':\n            case 'float':\n            case 'int':\n            case 'string':\n            case 'iterable':\n            case 'object':\n            case 'null':\n            case 'mixed':\n            case 'void':\n            case 'never':\n                return true;\n            default:\n                // Class / Interface type\n                return false;\n        }\n    }\n\n    protected function removePrefixNsSeparator(string $type): string\n    {\n        return ltrim($type, '\\\\');\n    }\n}\n"
  },
  {
    "path": "src/Prophecy/Doubler/Generator/ReflectionInterface.php",
    "content": "<?php\n\n/*\n * This file is part of the Prophecy.\n * (c) Konstantin Kudryashov <ever.zet@gmail.com>\n *     Marcello Duarte <marcello.duarte@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Prophecy\\Doubler\\Generator;\n\n/**\n * Reflection interface.\n * All reflected classes implement this interface.\n *\n * @author Konstantin Kudryashov <ever.zet@gmail.com>\n */\ninterface ReflectionInterface {}\n"
  },
  {
    "path": "src/Prophecy/Doubler/Generator/TypeHintReference.php",
    "content": "<?php\n\nnamespace Prophecy\\Doubler\\Generator;\n\n/**\n * Tells whether a keyword refers to a class or to a built-in type for the\n * current version of php\n *\n * @deprecated in favour of Node\\TypeNodeAbstract\n */\nfinal class TypeHintReference\n{\n    /**\n     * @param string $type\n     *\n     * @return bool\n     */\n    public function isBuiltInParamTypeHint($type)\n    {\n        switch ($type) {\n            case 'self':\n            case 'array':\n            case 'callable':\n            case 'bool':\n            case 'float':\n            case 'int':\n            case 'string':\n            case 'iterable':\n            case 'object':\n            case 'mixed':\n                return true;\n\n            default:\n                return false;\n        }\n    }\n\n    /**\n     * @param string $type\n     *\n     * @return bool\n     */\n    public function isBuiltInReturnTypeHint($type)\n    {\n        if ($type === 'void') {\n            return true;\n        }\n\n        return $this->isBuiltInParamTypeHint($type);\n    }\n}\n"
  },
  {
    "path": "src/Prophecy/Doubler/LazyDouble.php",
    "content": "<?php\n\n/*\n * This file is part of the Prophecy.\n * (c) Konstantin Kudryashov <ever.zet@gmail.com>\n *     Marcello Duarte <marcello.duarte@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Prophecy\\Doubler;\n\nuse Prophecy\\Exception\\Doubler\\DoubleException;\nuse Prophecy\\Exception\\Doubler\\ClassNotFoundException;\nuse Prophecy\\Exception\\Doubler\\InterfaceNotFoundException;\nuse ReflectionClass;\n\n/**\n * Lazy double.\n * Gives simple interface to describe double before creating it.\n *\n * @template T of object\n *\n * @author Konstantin Kudryashov <ever.zet@gmail.com>\n */\nclass LazyDouble\n{\n    private $doubler;\n    /**\n     * @var ReflectionClass<T>|null\n     */\n    private $class;\n    /**\n     * @var list<ReflectionClass<object>>\n     */\n    private $interfaces = array();\n    /**\n     * @var array<mixed>|null\n     */\n    private $arguments  = null;\n    /**\n     * @var (T&DoubleInterface)|null\n     */\n    private $double;\n\n    public function __construct(Doubler $doubler)\n    {\n        $this->doubler = $doubler;\n    }\n\n    /**\n     * Tells doubler to use specific class as parent one for double.\n     *\n     * @param class-string|ReflectionClass<object> $class\n     *\n     * @return void\n     *\n     * @template U of object\n     * @phpstan-param class-string<U>|ReflectionClass<U> $class\n     * @phpstan-this-out static<U>\n     *\n     * @throws ClassNotFoundException\n     * @throws DoubleException\n     */\n    public function setParentClass($class)\n    {\n        if (null !== $this->double) {\n            throw new DoubleException('Can not extend class with already instantiated double.');\n        }\n\n        if (!$class instanceof ReflectionClass) {\n            if (!class_exists($class)) {\n                throw new ClassNotFoundException(sprintf('Class %s not found.', $class), $class);\n            }\n\n            $class = new ReflectionClass($class);\n        }\n\n        /** @var static<U> $this */\n\n        $this->class = $class;\n    }\n\n    /**\n     * Tells doubler to implement specific interface with double.\n     *\n     * @param class-string|ReflectionClass<object> $interface\n     *\n     * @return void\n     *\n     * @template U of object\n     * @phpstan-param class-string<U>|ReflectionClass<U> $interface\n     * @phpstan-this-out static<T&U>\n     *\n     * @throws InterfaceNotFoundException\n     * @throws DoubleException\n     */\n    public function addInterface($interface)\n    {\n        if (null !== $this->double) {\n            throw new DoubleException(\n                'Can not implement interface with already instantiated double.'\n            );\n        }\n\n        if (!$interface instanceof ReflectionClass) {\n            if (!interface_exists($interface)) {\n                throw new InterfaceNotFoundException(\n                    sprintf('Interface %s not found.', $interface),\n                    $interface\n                );\n            }\n\n            $interface = new ReflectionClass($interface);\n        }\n\n        $this->interfaces[] = $interface;\n    }\n\n    /**\n     * Sets constructor arguments.\n     *\n     * @param array<mixed>|null $arguments\n     *\n     * @return void\n     */\n    public function setArguments(?array $arguments = null)\n    {\n        $this->arguments = $arguments;\n    }\n\n    /**\n     * Creates double instance or returns already created one.\n     *\n     * @return T&DoubleInterface\n     */\n    public function getInstance()\n    {\n        if (null === $this->double) {\n            if (null !== $this->arguments) {\n                return $this->double = $this->doubler->double(\n                    $this->class, $this->interfaces, $this->arguments\n                );\n            }\n\n            $this->double = $this->doubler->double($this->class, $this->interfaces);\n        }\n\n        return $this->double;\n    }\n}\n"
  },
  {
    "path": "src/Prophecy/Doubler/NameGenerator.php",
    "content": "<?php\n\n/*\n * This file is part of the Prophecy.\n * (c) Konstantin Kudryashov <ever.zet@gmail.com>\n *     Marcello Duarte <marcello.duarte@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Prophecy\\Doubler;\n\nuse ReflectionClass;\n\n/**\n * Name generator.\n * Generates classname for double.\n *\n * @author Konstantin Kudryashov <ever.zet@gmail.com>\n */\nclass NameGenerator\n{\n    /**\n     * @var int\n     */\n    private static $counter = 1;\n\n    /**\n     * Generates name.\n     *\n     * @param ReflectionClass<object>|null $class\n     * @param ReflectionClass<object>[]    $interfaces\n     *\n     * @return string\n     */\n    public function name(?ReflectionClass $class, array $interfaces)\n    {\n        $parts = array();\n\n        if (null !== $class) {\n            $parts[] = $class->getName();\n        } else {\n            foreach ($interfaces as $interface) {\n                $parts[] = $interface->getShortName();\n            }\n        }\n\n        if (!count($parts)) {\n            $parts[] = 'stdClass';\n        }\n\n        return sprintf('Double\\%s\\P%d', implode('\\\\', $parts), self::$counter++);\n    }\n}\n"
  },
  {
    "path": "src/Prophecy/Exception/Call/UnexpectedCallException.php",
    "content": "<?php\n\n/*\n * This file is part of the Prophecy.\n * (c) Konstantin Kudryashov <ever.zet@gmail.com>\n *     Marcello Duarte <marcello.duarte@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Prophecy\\Exception\\Call;\n\nuse Prophecy\\Exception\\Prophecy\\ObjectProphecyException;\nuse Prophecy\\Prophecy\\ObjectProphecy;\n\nclass UnexpectedCallException extends ObjectProphecyException\n{\n    private $methodName;\n    private $arguments;\n\n    /**\n     * @param string                 $message\n     * @param ObjectProphecy<object> $objectProphecy\n     * @param string                 $methodName\n     * @param array<mixed>           $arguments\n     */\n    public function __construct($message, ObjectProphecy $objectProphecy,\n        $methodName, array $arguments)\n    {\n        parent::__construct($message, $objectProphecy);\n\n        $this->methodName = $methodName;\n        $this->arguments = $arguments;\n    }\n\n    /**\n     * @return string\n     */\n    public function getMethodName()\n    {\n        return $this->methodName;\n    }\n\n    /**\n     * @return array<mixed>\n     */\n    public function getArguments()\n    {\n        return $this->arguments;\n    }\n}\n"
  },
  {
    "path": "src/Prophecy/Exception/Doubler/ClassCreatorException.php",
    "content": "<?php\n\n/*\n * This file is part of the Prophecy.\n * (c) Konstantin Kudryashov <ever.zet@gmail.com>\n *     Marcello Duarte <marcello.duarte@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Prophecy\\Exception\\Doubler;\n\nuse Prophecy\\Doubler\\Generator\\Node\\ClassNode;\n\nclass ClassCreatorException extends \\RuntimeException implements DoublerException\n{\n    private $node;\n\n    /**\n     * @param string    $message\n     * @param ClassNode $node\n     */\n    public function __construct($message, ClassNode $node)\n    {\n        parent::__construct($message);\n\n        $this->node = $node;\n    }\n\n    /**\n     * @return ClassNode\n     */\n    public function getClassNode()\n    {\n        return $this->node;\n    }\n}\n"
  },
  {
    "path": "src/Prophecy/Exception/Doubler/ClassMirrorException.php",
    "content": "<?php\n\n/*\n * This file is part of the Prophecy.\n * (c) Konstantin Kudryashov <ever.zet@gmail.com>\n *     Marcello Duarte <marcello.duarte@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Prophecy\\Exception\\Doubler;\n\nuse ReflectionClass;\n\nclass ClassMirrorException extends \\RuntimeException implements DoublerException\n{\n    private $class;\n\n    /**\n     * @param string                  $message\n     * @param ReflectionClass<object> $class\n     */\n    public function __construct($message, ReflectionClass $class)\n    {\n        parent::__construct($message);\n\n        $this->class = $class;\n    }\n\n    /**\n     * @return ReflectionClass<object>\n     */\n    public function getReflectedClass()\n    {\n        return $this->class;\n    }\n}\n"
  },
  {
    "path": "src/Prophecy/Exception/Doubler/ClassNotFoundException.php",
    "content": "<?php\n\n/*\n * This file is part of the Prophecy.\n * (c) Konstantin Kudryashov <ever.zet@gmail.com>\n *     Marcello Duarte <marcello.duarte@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Prophecy\\Exception\\Doubler;\n\nclass ClassNotFoundException extends DoubleException\n{\n    private $classname;\n\n    /**\n     * @param string $message\n     * @param string $classname\n     */\n    public function __construct($message, $classname)\n    {\n        parent::__construct($message);\n\n        $this->classname = $classname;\n    }\n\n    /**\n     * @return string\n     */\n    public function getClassname()\n    {\n        return $this->classname;\n    }\n}\n"
  },
  {
    "path": "src/Prophecy/Exception/Doubler/DoubleException.php",
    "content": "<?php\n\n/*\n * This file is part of the Prophecy.\n * (c) Konstantin Kudryashov <ever.zet@gmail.com>\n *     Marcello Duarte <marcello.duarte@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Prophecy\\Exception\\Doubler;\n\nuse RuntimeException;\n\nclass DoubleException extends RuntimeException implements DoublerException {}\n"
  },
  {
    "path": "src/Prophecy/Exception/Doubler/DoublerException.php",
    "content": "<?php\n\n/*\n * This file is part of the Prophecy.\n * (c) Konstantin Kudryashov <ever.zet@gmail.com>\n *     Marcello Duarte <marcello.duarte@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Prophecy\\Exception\\Doubler;\n\nuse Prophecy\\Exception\\Exception;\n\ninterface DoublerException extends Exception {}\n"
  },
  {
    "path": "src/Prophecy/Exception/Doubler/InterfaceNotFoundException.php",
    "content": "<?php\n\n/*\n * This file is part of the Prophecy.\n * (c) Konstantin Kudryashov <ever.zet@gmail.com>\n *     Marcello Duarte <marcello.duarte@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Prophecy\\Exception\\Doubler;\n\nclass InterfaceNotFoundException extends ClassNotFoundException\n{\n    /**\n     * @return string\n     */\n    public function getInterfaceName()\n    {\n        return $this->getClassname();\n    }\n}\n"
  },
  {
    "path": "src/Prophecy/Exception/Doubler/MethodNotExtendableException.php",
    "content": "<?php\n\nnamespace Prophecy\\Exception\\Doubler;\n\nclass MethodNotExtendableException extends DoubleException\n{\n    private $methodName;\n\n    private $className;\n\n    /**\n     * @param string $message\n     * @param string $className\n     * @param string $methodName\n     */\n    public function __construct($message, $className, $methodName)\n    {\n        parent::__construct($message);\n\n        $this->methodName = $methodName;\n        $this->className = $className;\n    }\n\n\n    /**\n     * @return string\n     */\n    public function getMethodName()\n    {\n        return $this->methodName;\n    }\n\n    /**\n     * @return string\n     */\n    public function getClassName()\n    {\n        return $this->className;\n    }\n\n}\n"
  },
  {
    "path": "src/Prophecy/Exception/Doubler/MethodNotFoundException.php",
    "content": "<?php\n\n/*\n * This file is part of the Prophecy.\n * (c) Konstantin Kudryashov <ever.zet@gmail.com>\n *     Marcello Duarte <marcello.duarte@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Prophecy\\Exception\\Doubler;\n\nuse Prophecy\\Argument\\ArgumentsWildcard;\n\nclass MethodNotFoundException extends DoubleException\n{\n    /**\n     * @var string|object\n     */\n    private $classname;\n\n    /**\n     * @var string\n     */\n    private $methodName;\n\n    /**\n     * @var null|ArgumentsWildcard|array<mixed>\n     */\n    private $arguments;\n\n    /**\n     * @param string $message\n     * @param string|object $classname\n     * @param string $methodName\n     * @param null|ArgumentsWildcard|array<mixed> $arguments\n     */\n    public function __construct($message, $classname, $methodName, $arguments = null)\n    {\n        parent::__construct($message);\n\n        $this->classname  = $classname;\n        $this->methodName = $methodName;\n        $this->arguments = $arguments;\n    }\n\n    /**\n     * @return object|string\n     */\n    public function getClassname()\n    {\n        return $this->classname;\n    }\n\n    /**\n     * @return string\n     */\n    public function getMethodName()\n    {\n        return $this->methodName;\n    }\n\n    /**\n     * @return null|ArgumentsWildcard|array<mixed>\n     */\n    public function getArguments()\n    {\n        return $this->arguments;\n    }\n}\n"
  },
  {
    "path": "src/Prophecy/Exception/Doubler/ReturnByReferenceException.php",
    "content": "<?php\n\n/*\n * This file is part of the Prophecy.\n * (c) Konstantin Kudryashov <ever.zet@gmail.com>\n *     Marcello Duarte <marcello.duarte@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Prophecy\\Exception\\Doubler;\n\nclass ReturnByReferenceException extends DoubleException\n{\n    private $classname;\n    private $methodName;\n\n    /**\n     * @param string $message\n     * @param string $classname\n     * @param string $methodName\n     */\n    public function __construct($message, $classname, $methodName)\n    {\n        parent::__construct($message);\n\n        $this->classname  = $classname;\n        $this->methodName = $methodName;\n    }\n\n    /**\n     * @return string\n     */\n    public function getClassname()\n    {\n        return $this->classname;\n    }\n\n    /**\n     * @return string\n     */\n    public function getMethodName()\n    {\n        return $this->methodName;\n    }\n}\n"
  },
  {
    "path": "src/Prophecy/Exception/Exception.php",
    "content": "<?php\n\n/*\n * This file is part of the Prophecy.\n * (c) Konstantin Kudryashov <ever.zet@gmail.com>\n *     Marcello Duarte <marcello.duarte@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Prophecy\\Exception;\n\n/**\n * Core Prophecy exception interface.\n * All Prophecy exceptions implement it.\n *\n * @author Konstantin Kudryashov <ever.zet@gmail.com>\n */\ninterface Exception extends \\Throwable {}\n"
  },
  {
    "path": "src/Prophecy/Exception/InvalidArgumentException.php",
    "content": "<?php\n\n/*\n * This file is part of the Prophecy.\n * (c) Konstantin Kudryashov <ever.zet@gmail.com>\n *     Marcello Duarte <marcello.duarte@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Prophecy\\Exception;\n\nclass InvalidArgumentException extends \\InvalidArgumentException implements Exception {}\n"
  },
  {
    "path": "src/Prophecy/Exception/Prediction/AggregateException.php",
    "content": "<?php\n\n/*\n * This file is part of the Prophecy.\n * (c) Konstantin Kudryashov <ever.zet@gmail.com>\n *     Marcello Duarte <marcello.duarte@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Prophecy\\Exception\\Prediction;\n\nuse Prophecy\\Prophecy\\ObjectProphecy;\n\nclass AggregateException extends \\RuntimeException implements PredictionException\n{\n    /**\n     * @var list<PredictionException>\n     */\n    private $exceptions = array();\n    /**\n     * @var ObjectProphecy<object>|null\n     */\n    private $objectProphecy;\n\n    /**\n     * @return void\n     */\n    public function append(PredictionException $exception)\n    {\n        $message = $exception->getMessage();\n        $message = strtr($message, array(\"\\n\" => \"\\n  \")).\"\\n\";\n        $message = empty($this->exceptions) ? $message : \"\\n\".$message;\n\n        $this->message      = rtrim($this->message.$message);\n        $this->exceptions[] = $exception;\n    }\n\n    /**\n     * @return list<PredictionException>\n     */\n    public function getExceptions()\n    {\n        return $this->exceptions;\n    }\n\n    /**\n     * @param ObjectProphecy<object> $objectProphecy\n     *\n     * @return void\n     */\n    public function setObjectProphecy(ObjectProphecy $objectProphecy)\n    {\n        $this->objectProphecy = $objectProphecy;\n    }\n\n    /**\n     * @return ObjectProphecy<object>|null\n     */\n    public function getObjectProphecy()\n    {\n        return $this->objectProphecy;\n    }\n}\n"
  },
  {
    "path": "src/Prophecy/Exception/Prediction/FailedPredictionException.php",
    "content": "<?php\n\n/*\n * This file is part of the Prophecy.\n * (c) Konstantin Kudryashov <ever.zet@gmail.com>\n *     Marcello Duarte <marcello.duarte@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Prophecy\\Exception\\Prediction;\n\nuse RuntimeException;\n\n/**\n * Basic failed prediction exception.\n * Use it for custom prediction failures.\n *\n * @author Konstantin Kudryashov <ever.zet@gmail.com>\n */\nclass FailedPredictionException extends RuntimeException implements PredictionException {}\n"
  },
  {
    "path": "src/Prophecy/Exception/Prediction/NoCallsException.php",
    "content": "<?php\n\n/*\n * This file is part of the Prophecy.\n * (c) Konstantin Kudryashov <ever.zet@gmail.com>\n *     Marcello Duarte <marcello.duarte@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Prophecy\\Exception\\Prediction;\n\nuse Prophecy\\Exception\\Prophecy\\MethodProphecyException;\n\nclass NoCallsException extends MethodProphecyException implements PredictionException {}\n"
  },
  {
    "path": "src/Prophecy/Exception/Prediction/PredictionException.php",
    "content": "<?php\n\n/*\n * This file is part of the Prophecy.\n * (c) Konstantin Kudryashov <ever.zet@gmail.com>\n *     Marcello Duarte <marcello.duarte@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Prophecy\\Exception\\Prediction;\n\nuse Prophecy\\Exception\\Exception;\n\ninterface PredictionException extends Exception {}\n"
  },
  {
    "path": "src/Prophecy/Exception/Prediction/UnexpectedCallsCountException.php",
    "content": "<?php\n\n/*\n * This file is part of the Prophecy.\n * (c) Konstantin Kudryashov <ever.zet@gmail.com>\n *     Marcello Duarte <marcello.duarte@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Prophecy\\Exception\\Prediction;\n\nuse Prophecy\\Call\\Call;\nuse Prophecy\\Prophecy\\MethodProphecy;\n\nclass UnexpectedCallsCountException extends UnexpectedCallsException\n{\n    private $expectedCount;\n\n    /**\n     * @param string         $message\n     * @param MethodProphecy $methodProphecy\n     * @param int            $count\n     * @param array<Call>     $calls\n     */\n    public function __construct($message, MethodProphecy $methodProphecy, $count, array $calls)\n    {\n        parent::__construct($message, $methodProphecy, $calls);\n\n        $this->expectedCount = intval($count);\n    }\n\n    /**\n     * @return int\n     */\n    public function getExpectedCount()\n    {\n        return $this->expectedCount;\n    }\n}\n"
  },
  {
    "path": "src/Prophecy/Exception/Prediction/UnexpectedCallsException.php",
    "content": "<?php\n\n/*\n * This file is part of the Prophecy.\n * (c) Konstantin Kudryashov <ever.zet@gmail.com>\n *     Marcello Duarte <marcello.duarte@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Prophecy\\Exception\\Prediction;\n\nuse Prophecy\\Call\\Call;\nuse Prophecy\\Prophecy\\MethodProphecy;\nuse Prophecy\\Exception\\Prophecy\\MethodProphecyException;\n\nclass UnexpectedCallsException extends MethodProphecyException implements PredictionException\n{\n    /** @var list<Call> */\n    private $calls;\n\n    /**\n     * @param string         $message\n     * @param MethodProphecy $methodProphecy\n     * @param array<Call>     $calls\n     */\n    public function __construct($message, MethodProphecy $methodProphecy, array $calls)\n    {\n        parent::__construct($message, $methodProphecy);\n\n        $this->calls = array_values($calls);\n    }\n\n    /**\n     * @return list<Call>\n     */\n    public function getCalls()\n    {\n        return $this->calls;\n    }\n}\n"
  },
  {
    "path": "src/Prophecy/Exception/Prophecy/MethodProphecyException.php",
    "content": "<?php\n\n/*\n * This file is part of the Prophecy.\n * (c) Konstantin Kudryashov <ever.zet@gmail.com>\n *     Marcello Duarte <marcello.duarte@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Prophecy\\Exception\\Prophecy;\n\nuse Prophecy\\Prophecy\\MethodProphecy;\n\nclass MethodProphecyException extends ObjectProphecyException\n{\n    private $methodProphecy;\n\n    /**\n     * @param string $message\n     */\n    public function __construct($message, MethodProphecy $methodProphecy, ?\\Throwable $previous = null)\n    {\n        parent::__construct($message, $methodProphecy->getObjectProphecy(), $previous);\n\n        $this->methodProphecy = $methodProphecy;\n    }\n\n    /**\n     * @return MethodProphecy\n     */\n    public function getMethodProphecy()\n    {\n        return $this->methodProphecy;\n    }\n}\n"
  },
  {
    "path": "src/Prophecy/Exception/Prophecy/ObjectProphecyException.php",
    "content": "<?php\n\n/*\n * This file is part of the Prophecy.\n * (c) Konstantin Kudryashov <ever.zet@gmail.com>\n *     Marcello Duarte <marcello.duarte@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Prophecy\\Exception\\Prophecy;\n\nuse Prophecy\\Prophecy\\ObjectProphecy;\n\nclass ObjectProphecyException extends \\RuntimeException implements ProphecyException\n{\n    private $objectProphecy;\n\n    /**\n     * @param string                 $message\n     * @param ObjectProphecy<object> $objectProphecy\n     */\n    public function __construct($message, ObjectProphecy $objectProphecy, ?\\Throwable $previous = null)\n    {\n        parent::__construct($message, 0, $previous);\n\n        $this->objectProphecy = $objectProphecy;\n    }\n\n    /**\n     * @return ObjectProphecy<object>\n     */\n    public function getObjectProphecy()\n    {\n        return $this->objectProphecy;\n    }\n}\n"
  },
  {
    "path": "src/Prophecy/Exception/Prophecy/ProphecyException.php",
    "content": "<?php\n\n/*\n * This file is part of the Prophecy.\n * (c) Konstantin Kudryashov <ever.zet@gmail.com>\n *     Marcello Duarte <marcello.duarte@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Prophecy\\Exception\\Prophecy;\n\nuse Prophecy\\Exception\\Exception;\n\ninterface ProphecyException extends Exception {}\n"
  },
  {
    "path": "src/Prophecy/PhpDocumentor/ClassAndInterfaceTagRetriever.php",
    "content": "<?php\n\n/*\n * This file is part of the Prophecy.\n * (c) Konstantin Kudryashov <ever.zet@gmail.com>\n *     Marcello Duarte <marcello.duarte@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Prophecy\\PhpDocumentor;\n\nuse phpDocumentor\\Reflection\\DocBlock\\Tags\\Method;\n\n/**\n * @author Théo FIDRY <theo.fidry@gmail.com>\n *\n * @internal\n */\nfinal class ClassAndInterfaceTagRetriever implements MethodTagRetrieverInterface\n{\n    /**\n     * @var MethodTagRetrieverInterface\n     */\n    private $classRetriever;\n\n    public function __construct(?MethodTagRetrieverInterface $classRetriever = null)\n    {\n        if (null !== $classRetriever) {\n            $this->classRetriever = $classRetriever;\n\n            return;\n        }\n\n        $this->classRetriever = new ClassTagRetriever();\n    }\n\n    public function getTagList(\\ReflectionClass $reflectionClass)\n    {\n        return array_merge(\n            $this->classRetriever->getTagList($reflectionClass),\n            $this->getInterfacesTagList($reflectionClass)\n        );\n    }\n\n    /**\n     * @param \\ReflectionClass<object> $reflectionClass\n     *\n     * @return list<Method>\n     */\n    private function getInterfacesTagList(\\ReflectionClass $reflectionClass)\n    {\n        $interfaces = $reflectionClass->getInterfaces();\n        $tagList = array();\n\n        foreach ($interfaces as $interface) {\n            $tagList = array_merge($tagList, $this->classRetriever->getTagList($interface));\n        }\n\n        return $tagList;\n    }\n}\n"
  },
  {
    "path": "src/Prophecy/PhpDocumentor/ClassTagRetriever.php",
    "content": "<?php\n\n/*\n * This file is part of the Prophecy.\n * (c) Konstantin Kudryashov <ever.zet@gmail.com>\n *     Marcello Duarte <marcello.duarte@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Prophecy\\PhpDocumentor;\n\nuse phpDocumentor\\Reflection\\DocBlock\\Tags\\Method;\nuse phpDocumentor\\Reflection\\DocBlockFactory;\nuse phpDocumentor\\Reflection\\Types\\ContextFactory;\n\n/**\n * @author Théo FIDRY <theo.fidry@gmail.com>\n *\n * @internal\n */\nfinal class ClassTagRetriever implements MethodTagRetrieverInterface\n{\n    private $docBlockFactory;\n    private $contextFactory;\n\n    public function __construct()\n    {\n        $this->docBlockFactory = DocBlockFactory::createInstance();\n        $this->contextFactory = new ContextFactory();\n    }\n\n    public function getTagList(\\ReflectionClass $reflectionClass)\n    {\n        try {\n            $phpdoc = $this->docBlockFactory->create(\n                $reflectionClass,\n                $this->contextFactory->createFromReflector($reflectionClass)\n            );\n\n            $methods = array();\n\n            foreach ($phpdoc->getTagsByName('method') as $tag) {\n                if ($tag instanceof Method) {\n                    $methods[] = $tag;\n                }\n            }\n\n            return $methods;\n        } catch (\\InvalidArgumentException $e) {\n            return array();\n        }\n    }\n}\n"
  },
  {
    "path": "src/Prophecy/PhpDocumentor/MethodTagRetrieverInterface.php",
    "content": "<?php\n\n/*\n * This file is part of the Prophecy.\n * (c) Konstantin Kudryashov <ever.zet@gmail.com>\n *     Marcello Duarte <marcello.duarte@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Prophecy\\PhpDocumentor;\n\nuse phpDocumentor\\Reflection\\DocBlock\\Tags\\Method;\n\n/**\n * @author Théo FIDRY <theo.fidry@gmail.com>\n *\n * @internal\n */\ninterface MethodTagRetrieverInterface\n{\n    /**\n     * @param \\ReflectionClass<object> $reflectionClass\n     *\n     * @return list<Method>\n     */\n    public function getTagList(\\ReflectionClass $reflectionClass);\n}\n"
  },
  {
    "path": "src/Prophecy/Prediction/CallPrediction.php",
    "content": "<?php\n\n/*\n * This file is part of the Prophecy.\n * (c) Konstantin Kudryashov <ever.zet@gmail.com>\n *     Marcello Duarte <marcello.duarte@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Prophecy\\Prediction;\n\nuse Prophecy\\Call\\Call;\nuse Prophecy\\Prophecy\\ObjectProphecy;\nuse Prophecy\\Prophecy\\MethodProphecy;\nuse Prophecy\\Argument\\ArgumentsWildcard;\nuse Prophecy\\Argument\\Token\\AnyValuesToken;\nuse Prophecy\\Util\\StringUtil;\nuse Prophecy\\Exception\\Prediction\\NoCallsException;\n\n/**\n * Tests that there was at least one call.\n *\n * @author Konstantin Kudryashov <ever.zet@gmail.com>\n */\nclass CallPrediction implements PredictionInterface\n{\n    private $util;\n\n    public function __construct(?StringUtil $util = null)\n    {\n        $this->util = $util ?: new StringUtil();\n    }\n\n    public function check(array $calls, ObjectProphecy $object, MethodProphecy $method)\n    {\n        if (count($calls)) {\n            return;\n        }\n\n        $methodCalls = $object->findProphecyMethodCalls(\n            $method->getMethodName(),\n            new ArgumentsWildcard(array(new AnyValuesToken()))\n        );\n\n        if (count($methodCalls)) {\n            throw new NoCallsException(sprintf(\n                \"No calls have been made that match:\\n\"\n                .\"  %s->%s(%s)\\n\"\n                .\"but expected at least one.\\n\"\n                .\"Recorded `%s(...)` calls:\\n%s\",\n\n                get_class($object->reveal()),\n                $method->getMethodName(),\n                $method->getArgumentsWildcard(),\n                $method->getMethodName(),\n                $this->util->stringifyCalls($methodCalls)\n            ), $method);\n        }\n\n        throw new NoCallsException(sprintf(\n            \"No calls have been made that match:\\n\"\n            .\"  %s->%s(%s)\\n\"\n            .\"but expected at least one.\",\n\n            get_class($object->reveal()),\n            $method->getMethodName(),\n            $method->getArgumentsWildcard()\n        ), $method);\n    }\n}\n"
  },
  {
    "path": "src/Prophecy/Prediction/CallTimesPrediction.php",
    "content": "<?php\n\n/*\n * This file is part of the Prophecy.\n * (c) Konstantin Kudryashov <ever.zet@gmail.com>\n *     Marcello Duarte <marcello.duarte@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Prophecy\\Prediction;\n\nuse Prophecy\\Prophecy\\ObjectProphecy;\nuse Prophecy\\Prophecy\\MethodProphecy;\nuse Prophecy\\Argument\\ArgumentsWildcard;\nuse Prophecy\\Argument\\Token\\AnyValuesToken;\nuse Prophecy\\Util\\StringUtil;\nuse Prophecy\\Exception\\Prediction\\UnexpectedCallsCountException;\n\n/**\n * Tests that there was exact amount of calls made.\n *\n * @author Konstantin Kudryashov <ever.zet@gmail.com>\n */\nclass CallTimesPrediction implements PredictionInterface\n{\n    private $times;\n    private $util;\n\n    /**\n     * @param int        $times\n     */\n    public function __construct($times, ?StringUtil $util = null)\n    {\n        $this->times = intval($times);\n        $this->util  = $util ?: new StringUtil();\n    }\n\n    public function check(array $calls, ObjectProphecy $object, MethodProphecy $method)\n    {\n        if ($this->times == count($calls)) {\n            return;\n        }\n\n        $methodCalls = $object->findProphecyMethodCalls(\n            $method->getMethodName(),\n            new ArgumentsWildcard(array(new AnyValuesToken()))\n        );\n\n        if (count($calls)) {\n            $message = sprintf(\n                \"Expected exactly %d calls that match:\\n\"\n                .\"  %s->%s(%s)\\n\"\n                .\"but %d were made:\\n%s\",\n\n                $this->times,\n                get_class($object->reveal()),\n                $method->getMethodName(),\n                $method->getArgumentsWildcard(),\n                count($calls),\n                $this->util->stringifyCalls($calls)\n            );\n        } elseif (count($methodCalls)) {\n            $message = sprintf(\n                \"Expected exactly %d calls that match:\\n\"\n                .\"  %s->%s(%s)\\n\"\n                .\"but none were made.\\n\"\n                .\"Recorded `%s(...)` calls:\\n%s\",\n\n                $this->times,\n                get_class($object->reveal()),\n                $method->getMethodName(),\n                $method->getArgumentsWildcard(),\n                $method->getMethodName(),\n                $this->util->stringifyCalls($methodCalls)\n            );\n        } else {\n            $message = sprintf(\n                \"Expected exactly %d calls that match:\\n\"\n                .\"  %s->%s(%s)\\n\"\n                .\"but none were made.\",\n\n                $this->times,\n                get_class($object->reveal()),\n                $method->getMethodName(),\n                $method->getArgumentsWildcard()\n            );\n        }\n\n        throw new UnexpectedCallsCountException($message, $method, $this->times, $calls);\n    }\n}\n"
  },
  {
    "path": "src/Prophecy/Prediction/CallbackPrediction.php",
    "content": "<?php\n\n/*\n * This file is part of the Prophecy.\n * (c) Konstantin Kudryashov <ever.zet@gmail.com>\n *     Marcello Duarte <marcello.duarte@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Prophecy\\Prediction;\n\nuse Prophecy\\Prophecy\\ObjectProphecy;\nuse Prophecy\\Prophecy\\MethodProphecy;\nuse Prophecy\\Exception\\InvalidArgumentException;\nuse Closure;\nuse ReflectionFunction;\n\n/**\n * Executes preset callback.\n *\n * @author Konstantin Kudryashov <ever.zet@gmail.com>\n */\nclass CallbackPrediction implements PredictionInterface\n{\n    private $callback;\n\n    /**\n     * @param callable $callback Custom callback\n     *\n     * @throws \\Prophecy\\Exception\\InvalidArgumentException\n     */\n    public function __construct($callback)\n    {\n        if (!is_callable($callback)) {\n            throw new InvalidArgumentException(sprintf(\n                'Callable expected as an argument to CallbackPrediction, but got %s.',\n                gettype($callback)\n            ));\n        }\n\n        $this->callback = $callback;\n    }\n\n    public function check(array $calls, ObjectProphecy $object, MethodProphecy $method)\n    {\n        $callback = $this->callback;\n\n        if ($callback instanceof Closure && (new ReflectionFunction($callback))->getClosureThis() !== null) {\n            $callback = Closure::bind($callback, $object) ?? $this->callback;\n        }\n\n        call_user_func($callback, $calls, $object, $method);\n    }\n}\n"
  },
  {
    "path": "src/Prophecy/Prediction/NoCallsPrediction.php",
    "content": "<?php\n\n/*\n * This file is part of the Prophecy.\n * (c) Konstantin Kudryashov <ever.zet@gmail.com>\n *     Marcello Duarte <marcello.duarte@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Prophecy\\Prediction;\n\nuse Prophecy\\Prophecy\\ObjectProphecy;\nuse Prophecy\\Prophecy\\MethodProphecy;\nuse Prophecy\\Util\\StringUtil;\nuse Prophecy\\Exception\\Prediction\\UnexpectedCallsException;\n\n/**\n * Tests that there were no calls made.\n *\n * @author Konstantin Kudryashov <ever.zet@gmail.com>\n */\nclass NoCallsPrediction implements PredictionInterface\n{\n    private $util;\n\n    public function __construct(?StringUtil $util = null)\n    {\n        $this->util = $util ?: new StringUtil();\n    }\n\n    public function check(array $calls, ObjectProphecy $object, MethodProphecy $method)\n    {\n        if (!count($calls)) {\n            return;\n        }\n\n        $verb = count($calls) === 1 ? 'was' : 'were';\n\n        throw new UnexpectedCallsException(sprintf(\n            \"No calls expected that match:\\n\"\n            .\"  %s->%s(%s)\\n\"\n            .\"but %d %s made:\\n%s\",\n            get_class($object->reveal()),\n            $method->getMethodName(),\n            $method->getArgumentsWildcard(),\n            count($calls),\n            $verb,\n            $this->util->stringifyCalls($calls)\n        ), $method, $calls);\n    }\n}\n"
  },
  {
    "path": "src/Prophecy/Prediction/PredictionInterface.php",
    "content": "<?php\n\n/*\n * This file is part of the Prophecy.\n * (c) Konstantin Kudryashov <ever.zet@gmail.com>\n *     Marcello Duarte <marcello.duarte@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Prophecy\\Prediction;\n\nuse Prophecy\\Call\\Call;\nuse Prophecy\\Exception\\Prediction\\PredictionException;\nuse Prophecy\\Prophecy\\ObjectProphecy;\nuse Prophecy\\Prophecy\\MethodProphecy;\n\n/**\n * Prediction interface.\n * Predictions are logical test blocks, tied to `should...` keyword.\n *\n * @author Konstantin Kudryashov <ever.zet@gmail.com>\n */\ninterface PredictionInterface\n{\n    /**\n     * Tests that double fulfilled prediction.\n     *\n     * @param Call[]        $calls\n     * @param ObjectProphecy<object> $object\n     * @param MethodProphecy $method\n     *\n     * @throws PredictionException\n     * @return void\n     */\n    public function check(array $calls, ObjectProphecy $object, MethodProphecy $method);\n}\n"
  },
  {
    "path": "src/Prophecy/Promise/CallbackPromise.php",
    "content": "<?php\n\n/*\n * This file is part of the Prophecy.\n * (c) Konstantin Kudryashov <ever.zet@gmail.com>\n *     Marcello Duarte <marcello.duarte@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Prophecy\\Promise;\n\nuse Prophecy\\Prophecy\\ObjectProphecy;\nuse Prophecy\\Prophecy\\MethodProphecy;\nuse Prophecy\\Exception\\InvalidArgumentException;\nuse Closure;\nuse ReflectionFunction;\n\n/**\n * Evaluates promise callback.\n *\n * @author Konstantin Kudryashov <ever.zet@gmail.com>\n */\nclass CallbackPromise implements PromiseInterface\n{\n    private $callback;\n\n    /**\n     * Initializes callback promise.\n     *\n     * @param callable $callback Custom callback\n     *\n     * @throws \\Prophecy\\Exception\\InvalidArgumentException\n     */\n    public function __construct($callback)\n    {\n        if (!is_callable($callback)) {\n            throw new InvalidArgumentException(sprintf(\n                'Callable expected as an argument to CallbackPromise, but got %s.',\n                gettype($callback)\n            ));\n        }\n\n        $this->callback = $callback;\n    }\n\n    public function execute(array $args, ObjectProphecy $object, MethodProphecy $method)\n    {\n        $callback = $this->callback;\n\n        if ($callback instanceof Closure && (new ReflectionFunction($callback))->getClosureThis() !== null) {\n            $callback = Closure::bind($callback, $object) ?? $this->callback;\n        }\n\n        return call_user_func($callback, $args, $object, $method);\n    }\n}\n"
  },
  {
    "path": "src/Prophecy/Promise/PromiseInterface.php",
    "content": "<?php\n\n/*\n * This file is part of the Prophecy.\n * (c) Konstantin Kudryashov <ever.zet@gmail.com>\n *     Marcello Duarte <marcello.duarte@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Prophecy\\Promise;\n\nuse Prophecy\\Prophecy\\ObjectProphecy;\nuse Prophecy\\Prophecy\\MethodProphecy;\n\n/**\n * Promise interface.\n * Promises are logical blocks, tied to `will...` keyword.\n *\n * @author Konstantin Kudryashov <ever.zet@gmail.com>\n */\ninterface PromiseInterface\n{\n    /**\n     * Evaluates promise.\n     *\n     * @param array<mixed>           $args\n     * @param ObjectProphecy<object> $object\n     * @param MethodProphecy         $method\n     *\n     * @return mixed\n     */\n    public function execute(array $args, ObjectProphecy $object, MethodProphecy $method);\n}\n"
  },
  {
    "path": "src/Prophecy/Promise/ReturnArgumentPromise.php",
    "content": "<?php\n\n/*\n * This file is part of the Prophecy.\n * (c) Konstantin Kudryashov <ever.zet@gmail.com>\n *     Marcello Duarte <marcello.duarte@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Prophecy\\Promise;\n\nuse Prophecy\\Exception\\InvalidArgumentException;\nuse Prophecy\\Prophecy\\ObjectProphecy;\nuse Prophecy\\Prophecy\\MethodProphecy;\n\n/**\n * Returns nth argument if has one, null otherwise.\n *\n * @author Konstantin Kudryashov <ever.zet@gmail.com>\n */\nclass ReturnArgumentPromise implements PromiseInterface\n{\n    /**\n     * @var int\n     */\n    private $index;\n\n    /**\n     * Initializes callback promise.\n     *\n     * @param int $index The zero-indexed number of the argument to return\n     *\n     * @throws \\Prophecy\\Exception\\InvalidArgumentException\n     */\n    public function __construct($index = 0)\n    {\n        if (!is_int($index) || $index < 0) {\n            throw new InvalidArgumentException(sprintf(\n                'Zero-based index expected as argument to ReturnArgumentPromise, but got %s.',\n                $index\n            ));\n        }\n        $this->index = $index;\n    }\n\n    public function execute(array $args, ObjectProphecy $object, MethodProphecy $method)\n    {\n        return count($args) > $this->index ? $args[$this->index] : null;\n    }\n}\n"
  },
  {
    "path": "src/Prophecy/Promise/ReturnPromise.php",
    "content": "<?php\n\n/*\n * This file is part of the Prophecy.\n * (c) Konstantin Kudryashov <ever.zet@gmail.com>\n *     Marcello Duarte <marcello.duarte@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Prophecy\\Promise;\n\nuse Prophecy\\Prophecy\\ObjectProphecy;\nuse Prophecy\\Prophecy\\MethodProphecy;\n\n/**\n * Returns saved values one by one until last one, then continuously returns last value.\n *\n * @author Konstantin Kudryashov <ever.zet@gmail.com>\n */\nclass ReturnPromise implements PromiseInterface\n{\n    private $returnValues = array();\n\n    /**\n     * Initializes promise.\n     *\n     * @param array<mixed> $returnValues Array of values\n     */\n    public function __construct(array $returnValues)\n    {\n        $this->returnValues = $returnValues;\n    }\n\n    public function execute(array $args, ObjectProphecy $object, MethodProphecy $method)\n    {\n        $value = array_shift($this->returnValues);\n\n        if (!count($this->returnValues)) {\n            $this->returnValues[] = $value;\n        }\n\n        return $value;\n    }\n}\n"
  },
  {
    "path": "src/Prophecy/Promise/ThrowPromise.php",
    "content": "<?php\n\n/*\n * This file is part of the Prophecy.\n * (c) Konstantin Kudryashov <ever.zet@gmail.com>\n *     Marcello Duarte <marcello.duarte@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Prophecy\\Promise;\n\nuse Doctrine\\Instantiator\\Instantiator;\nuse Prophecy\\Prophecy\\ObjectProphecy;\nuse Prophecy\\Prophecy\\MethodProphecy;\nuse Prophecy\\Exception\\InvalidArgumentException;\nuse ReflectionClass;\n\n/**\n * Throws predefined exception.\n *\n * @author Konstantin Kudryashov <ever.zet@gmail.com>\n */\nclass ThrowPromise implements PromiseInterface\n{\n    private $exception;\n\n    /**\n     * @var Instantiator|null\n     */\n    private $instantiator;\n\n    /**\n     * Initializes promise.\n     *\n     * @param string|\\Throwable $exception Exception class name or instance\n     *\n     * @throws \\Prophecy\\Exception\\InvalidArgumentException\n     *\n     * @phpstan-param class-string<\\Throwable>|\\Throwable $exception\n     */\n    public function __construct($exception)\n    {\n        if (is_string($exception)) {\n            if ((!class_exists($exception) && !interface_exists($exception)) || !$this->isAValidThrowable($exception)) {\n                throw new InvalidArgumentException(sprintf(\n                    'Exception / Throwable class or instance expected as argument to ThrowPromise, but got %s.',\n                    $exception\n                ));\n            }\n        } elseif (!$exception instanceof \\Exception && !$exception instanceof \\Throwable) {\n            throw new InvalidArgumentException(sprintf(\n                'Exception / Throwable class or instance expected as argument to ThrowPromise, but got %s.',\n                is_object($exception) ? get_class($exception) : gettype($exception)\n            ));\n        }\n\n        $this->exception = $exception;\n    }\n\n    public function execute(array $args, ObjectProphecy $object, MethodProphecy $method)\n    {\n        if (is_string($this->exception)) {\n            $classname   = $this->exception;\n            $reflection  = new ReflectionClass($classname);\n            $constructor = $reflection->getConstructor();\n\n            if ($constructor === null || $constructor->isPublic() && 0 == $constructor->getNumberOfRequiredParameters()) {\n                throw $reflection->newInstance();\n            }\n\n            if (!$this->instantiator) {\n                $this->instantiator = new Instantiator();\n            }\n\n            throw $this->instantiator->instantiate($classname);\n        }\n\n        throw $this->exception;\n    }\n\n    /**\n     * @param string $exception\n     *\n     * @return bool\n     */\n    private function isAValidThrowable($exception)\n    {\n        return is_a($exception, 'Exception', true)\n            || is_a($exception, 'Throwable', true);\n    }\n}\n"
  },
  {
    "path": "src/Prophecy/Prophecy/MethodProphecy.php",
    "content": "<?php\n\n/*\n * This file is part of the Prophecy.\n * (c) Konstantin Kudryashov <ever.zet@gmail.com>\n *     Marcello Duarte <marcello.duarte@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Prophecy\\Prophecy;\n\nuse Prophecy\\Argument;\nuse Prophecy\\Exception\\Doubler\\ClassMirrorException;\nuse Prophecy\\Exception\\Prediction\\PredictionException;\nuse Prophecy\\Prophet;\nuse Prophecy\\Promise;\nuse Prophecy\\Prediction;\nuse Prophecy\\Exception\\Doubler\\MethodNotFoundException;\nuse Prophecy\\Exception\\InvalidArgumentException;\nuse Prophecy\\Exception\\Prophecy\\MethodProphecyException;\nuse ReflectionNamedType;\nuse ReflectionUnionType;\n\n/**\n * Method prophecy.\n *\n * @author Konstantin Kudryashov <ever.zet@gmail.com>\n */\nclass MethodProphecy\n{\n    private $objectProphecy;\n    private $methodName;\n    /**\n     * @var Argument\\ArgumentsWildcard\n     */\n    private $argumentsWildcard;\n    /**\n     * @var Promise\\PromiseInterface|null\n     */\n    private $promise;\n    /**\n     * @var Prediction\\PredictionInterface|null\n     */\n    private $prediction;\n    /**\n     * @var list<Prediction\\PredictionInterface>\n     */\n    private $checkedPredictions = array();\n    /**\n     * @var bool\n     */\n    private $bound = false;\n    /**\n     * @var bool\n     */\n    private $voidReturnType = false;\n\n    /**\n     * @param ObjectProphecy<object>                  $objectProphecy\n     * @param string                                  $methodName\n     * @param Argument\\ArgumentsWildcard|array<mixed> $arguments\n     *\n     * @throws \\Prophecy\\Exception\\Doubler\\MethodNotFoundException If method not found\n     *\n     * @internal\n     */\n    public function __construct(ObjectProphecy $objectProphecy, $methodName, $arguments)\n    {\n        $double = $objectProphecy->reveal();\n        if (!method_exists($double, $methodName)) {\n            throw new MethodNotFoundException(sprintf(\n                'Method `%s::%s()` is not defined.', get_class($double), $methodName\n            ), get_class($double), $methodName, $arguments);\n        }\n\n        $this->objectProphecy = $objectProphecy;\n        $this->methodName     = $methodName;\n\n        $reflectedMethod = new \\ReflectionMethod($double, $methodName);\n        if ($reflectedMethod->isFinal()) {\n            throw new MethodProphecyException(sprintf(\n                \"Can not add prophecy for a method `%s::%s()`\\n\"\n                .\"as it is a final method.\",\n                get_class($double),\n                $methodName\n            ), $this);\n        }\n\n        $this->withArguments($arguments);\n\n        $hasTentativeReturnType = method_exists($reflectedMethod, 'hasTentativeReturnType')\n            && $reflectedMethod->hasTentativeReturnType();\n\n        if (true === $reflectedMethod->hasReturnType() || $hasTentativeReturnType) {\n            if ($hasTentativeReturnType) {\n                $reflectionType = $reflectedMethod->getTentativeReturnType();\n            } else {\n                $reflectionType = $reflectedMethod->getReturnType();\n            }\n\n            if ($reflectionType instanceof ReflectionNamedType) {\n                $types = [$reflectionType];\n            } elseif ($reflectionType instanceof ReflectionUnionType) {\n                $types = $reflectionType->getTypes();\n            } else {\n                throw new MethodProphecyException(sprintf(\n                    \"Can not add prophecy for a method `%s::%s()`\\nas its return type is not supported by Prophecy yet.\",\n                    get_class($double),\n                    $methodName\n                ), $this);\n            }\n\n            $types = array_map(\n                function (ReflectionNamedType $type) { return $type->getName(); },\n                $types\n            );\n\n            usort(\n                $types,\n                static function (string $type1, string $type2) {\n\n                    // null is lowest priority\n                    if ($type2 == 'null') {\n                        return -1;\n                    } elseif ($type1 == 'null') {\n                        return 1;\n                    }\n\n                    // objects are higher priority than scalars\n                    $isObject = static function ($type) {\n                        return class_exists($type) || interface_exists($type);\n                    };\n\n                    if ($isObject($type1) && !$isObject($type2)) {\n                        return -1;\n                    } elseif (!$isObject($type1) && $isObject($type2)) {\n                        return 1;\n                    }\n\n                    // don't sort both-scalars or both-objects\n                    return 0;\n                }\n            );\n\n            $defaultType = $types[0];\n\n            if ('void' === $defaultType) {\n                $this->voidReturnType = true;\n            }\n\n            $this->will(function ($args, ObjectProphecy $object, MethodProphecy $method) use ($defaultType) {\n                switch ($defaultType) {\n                    case 'void': return;\n                    case 'string': return '';\n                    case 'float':  return 0.0;\n                    case 'int':    return 0;\n                    case 'bool':   return false;\n                    case 'array':  return array();\n                    case 'true': return true;\n                    case 'false': return false;\n                    case 'null': return null;\n\n                    case 'callable':\n                    case 'Closure':\n                        return function () {};\n\n                    case 'Traversable':\n                    case 'Generator':\n                        return (function () { yield; })();\n\n                    case 'object':\n                        $prophet = new Prophet();\n                        return $prophet->prophesize()->reveal();\n\n                    default:\n                        if (!class_exists($defaultType) && !interface_exists($defaultType)) {\n                            throw new MethodProphecyException(sprintf('Cannot create a return value for the method as the type \"%s\" is not supported. Configure an explicit return value instead.', $defaultType), $method);\n                        }\n\n                        $prophet = new Prophet();\n\n                        try {\n                            return $prophet->prophesize($defaultType)->reveal();\n                        } catch (ClassMirrorException $e) {\n                            throw new MethodProphecyException(\\sprintf('Cannot create a return value for the method. Configure an explicit return value instead.'), $method, $e);\n                        }\n                }\n            });\n        }\n    }\n\n    /**\n     * Sets argument wildcard.\n     *\n     * @param array<mixed>|Argument\\ArgumentsWildcard $arguments\n     *\n     * @return $this\n     *\n     * @throws \\Prophecy\\Exception\\InvalidArgumentException\n     */\n    public function withArguments($arguments)\n    {\n        if (is_array($arguments)) {\n            $arguments = new Argument\\ArgumentsWildcard($arguments);\n        }\n\n        if (!$arguments instanceof Argument\\ArgumentsWildcard) {\n            throw new InvalidArgumentException(sprintf(\n                \"Either an array or an instance of ArgumentsWildcard expected as\\n\"\n                .'a `MethodProphecy::withArguments()` argument, but got %s.',\n                gettype($arguments)\n            ));\n        }\n\n        $this->argumentsWildcard = $arguments;\n\n        return $this;\n    }\n\n    /**\n     * Sets custom promise to the prophecy.\n     *\n     * @param callable|Promise\\PromiseInterface $promise\n     *\n     * @return $this\n     *\n     * @throws \\Prophecy\\Exception\\InvalidArgumentException\n     */\n    public function will($promise)\n    {\n        if (is_callable($promise)) {\n            $promise = new Promise\\CallbackPromise($promise);\n        }\n\n        if (!$promise instanceof Promise\\PromiseInterface) {\n            throw new InvalidArgumentException(sprintf(\n                'Expected callable or instance of PromiseInterface, but got %s.',\n                gettype($promise)\n            ));\n        }\n\n        $this->bindToObjectProphecy();\n        $this->promise = $promise;\n\n        return $this;\n    }\n\n    /**\n     * Sets return promise to the prophecy.\n     *\n     * @see \\Prophecy\\Promise\\ReturnPromise\n     *\n     * @param mixed ...$return a list of return values\n     *\n     * @return $this\n     */\n    public function willReturn(...$return)\n    {\n        if ($this->voidReturnType) {\n            throw new MethodProphecyException(\n                \"The method \\\"$this->methodName\\\" has a void return type, and so cannot return anything\",\n                $this\n            );\n        }\n\n        return $this->will(new Promise\\ReturnPromise($return));\n    }\n\n    /**\n     * @param array<mixed> $items\n     * @param mixed $return\n     *\n     * @return $this\n     *\n     * @throws \\Prophecy\\Exception\\InvalidArgumentException\n     */\n    public function willYield($items, $return = null)\n    {\n        if ($this->voidReturnType) {\n            throw new MethodProphecyException(\n                \"The method \\\"$this->methodName\\\" has a void return type, and so cannot yield anything\",\n                $this\n            );\n        }\n\n        if (!is_array($items)) {\n            throw new InvalidArgumentException(sprintf(\n                'Expected array, but got %s.',\n                gettype($items)\n            ));\n        }\n\n        $generator =  function () use ($items, $return) {\n            yield from $items;\n\n            return $return;\n        };\n\n        return $this->will($generator);\n    }\n\n    /**\n     * Sets return argument promise to the prophecy.\n     *\n     * @param int $index The zero-indexed number of the argument to return\n     *\n     * @see \\Prophecy\\Promise\\ReturnArgumentPromise\n     *\n     * @return $this\n     */\n    public function willReturnArgument($index = 0)\n    {\n        if ($this->voidReturnType) {\n            throw new MethodProphecyException(\"The method \\\"$this->methodName\\\" has a void return type\", $this);\n        }\n\n        return $this->will(new Promise\\ReturnArgumentPromise($index));\n    }\n\n    /**\n     * Sets throw promise to the prophecy.\n     *\n     * @see \\Prophecy\\Promise\\ThrowPromise\n     *\n     * @param string|\\Throwable $exception Exception class or instance\n     *\n     * @return $this\n     *\n     * @phpstan-param class-string<\\Throwable>|\\Throwable $exception\n     */\n    public function willThrow($exception)\n    {\n        return $this->will(new Promise\\ThrowPromise($exception));\n    }\n\n    /**\n     * Sets custom prediction to the prophecy.\n     *\n     * @param callable|Prediction\\PredictionInterface $prediction\n     *\n     * @return $this\n     *\n     * @throws \\Prophecy\\Exception\\InvalidArgumentException\n     */\n    public function should($prediction)\n    {\n        if (is_callable($prediction)) {\n            $prediction = new Prediction\\CallbackPrediction($prediction);\n        }\n\n        if (!$prediction instanceof Prediction\\PredictionInterface) {\n            throw new InvalidArgumentException(sprintf(\n                'Expected callable or instance of PredictionInterface, but got %s.',\n                gettype($prediction)\n            ));\n        }\n\n        $this->bindToObjectProphecy();\n        $this->prediction = $prediction;\n\n        return $this;\n    }\n\n    /**\n     * Sets call prediction to the prophecy.\n     *\n     * @see \\Prophecy\\Prediction\\CallPrediction\n     *\n     * @return $this\n     */\n    public function shouldBeCalled()\n    {\n        return $this->should(new Prediction\\CallPrediction());\n    }\n\n    /**\n     * Sets no calls prediction to the prophecy.\n     *\n     * @see \\Prophecy\\Prediction\\NoCallsPrediction\n     *\n     * @return $this\n     */\n    public function shouldNotBeCalled()\n    {\n        return $this->should(new Prediction\\NoCallsPrediction());\n    }\n\n    /**\n     * Sets call times prediction to the prophecy.\n     *\n     * @see \\Prophecy\\Prediction\\CallTimesPrediction\n     *\n     * @param int $count\n     *\n     * @return $this\n     */\n    public function shouldBeCalledTimes($count)\n    {\n        return $this->should(new Prediction\\CallTimesPrediction($count));\n    }\n\n    /**\n     * Sets call times prediction to the prophecy.\n     *\n     * @see \\Prophecy\\Prediction\\CallTimesPrediction\n     *\n     * @return $this\n     */\n    public function shouldBeCalledOnce()\n    {\n        return $this->shouldBeCalledTimes(1);\n    }\n\n    /**\n     * Checks provided prediction immediately.\n     *\n     * @param callable|Prediction\\PredictionInterface $prediction\n     *\n     * @return $this\n     *\n     * @throws \\Prophecy\\Exception\\InvalidArgumentException\n     * @throws PredictionException\n     */\n    public function shouldHave($prediction)\n    {\n        if (is_callable($prediction)) {\n            $prediction = new Prediction\\CallbackPrediction($prediction);\n        }\n\n        if (!$prediction instanceof Prediction\\PredictionInterface) {\n            throw new InvalidArgumentException(sprintf(\n                'Expected callable or instance of PredictionInterface, but got %s.',\n                gettype($prediction)\n            ));\n        }\n\n        if (null === $this->promise && !$this->voidReturnType) {\n            $this->willReturn();\n        }\n\n        $calls = $this->getObjectProphecy()->findProphecyMethodCalls(\n            $this->getMethodName(),\n            $this->getArgumentsWildcard()\n        );\n\n        try {\n            $prediction->check($calls, $this->getObjectProphecy(), $this);\n            $this->checkedPredictions[] = $prediction;\n        } catch (\\Exception $e) {\n            $this->checkedPredictions[] = $prediction;\n\n            throw $e;\n        }\n\n        return $this;\n    }\n\n    /**\n     * Checks call prediction.\n     *\n     * @see \\Prophecy\\Prediction\\CallPrediction\n     *\n     * @return $this\n     *\n     * @throws PredictionException\n     */\n    public function shouldHaveBeenCalled()\n    {\n        return $this->shouldHave(new Prediction\\CallPrediction());\n    }\n\n    /**\n     * Checks no calls prediction.\n     *\n     * @see \\Prophecy\\Prediction\\NoCallsPrediction\n     *\n     * @return $this\n     *\n     * @throws PredictionException\n     */\n    public function shouldNotHaveBeenCalled()\n    {\n        return $this->shouldHave(new Prediction\\NoCallsPrediction());\n    }\n\n    /**\n     * Checks no calls prediction.\n     *\n     * @see \\Prophecy\\Prediction\\NoCallsPrediction\n     * @deprecated\n     *\n     * @return $this\n     */\n    public function shouldNotBeenCalled()\n    {\n        return $this->shouldNotHaveBeenCalled();\n    }\n\n    /**\n     * Checks call times prediction.\n     *\n     * @see \\Prophecy\\Prediction\\CallTimesPrediction\n     *\n     * @param int $count\n     *\n     * @return $this\n     */\n    public function shouldHaveBeenCalledTimes($count)\n    {\n        return $this->shouldHave(new Prediction\\CallTimesPrediction($count));\n    }\n\n    /**\n     * Checks call times prediction.\n     *\n     * @see \\Prophecy\\Prediction\\CallTimesPrediction\n     *\n     * @return $this\n     */\n    public function shouldHaveBeenCalledOnce()\n    {\n        return $this->shouldHaveBeenCalledTimes(1);\n    }\n\n    /**\n     * Checks currently registered [with should(...)] prediction.\n     *\n     * @return void\n     *\n     * @throws PredictionException\n     */\n    public function checkPrediction()\n    {\n        if (null === $this->prediction) {\n            return;\n        }\n\n        $this->shouldHave($this->prediction);\n    }\n\n    /**\n     * Returns currently registered promise.\n     *\n     * @return null|Promise\\PromiseInterface\n     */\n    public function getPromise()\n    {\n        return $this->promise;\n    }\n\n    /**\n     * Returns currently registered prediction.\n     *\n     * @return null|Prediction\\PredictionInterface\n     */\n    public function getPrediction()\n    {\n        return $this->prediction;\n    }\n\n    /**\n     * Returns predictions that were checked on this object.\n     *\n     * @return list<Prediction\\PredictionInterface>\n     */\n    public function getCheckedPredictions()\n    {\n        return $this->checkedPredictions;\n    }\n\n    /**\n     * Returns object prophecy this method prophecy is tied to.\n     *\n     * @return ObjectProphecy<object>\n     */\n    public function getObjectProphecy()\n    {\n        return $this->objectProphecy;\n    }\n\n    /**\n     * Returns method name.\n     *\n     * @return string\n     */\n    public function getMethodName()\n    {\n        return $this->methodName;\n    }\n\n    /**\n     * Returns arguments wildcard.\n     *\n     * @return Argument\\ArgumentsWildcard\n     */\n    public function getArgumentsWildcard()\n    {\n        return $this->argumentsWildcard;\n    }\n\n    /**\n     * @return bool\n     */\n    public function hasReturnVoid()\n    {\n        return $this->voidReturnType;\n    }\n\n    /**\n     * @return void\n     */\n    private function bindToObjectProphecy()\n    {\n        if ($this->bound) {\n            return;\n        }\n\n        $this->getObjectProphecy()->addMethodProphecy($this);\n        $this->bound = true;\n    }\n}\n"
  },
  {
    "path": "src/Prophecy/Prophecy/ObjectProphecy.php",
    "content": "<?php\n\n/*\n * This file is part of the Prophecy.\n * (c) Konstantin Kudryashov <ever.zet@gmail.com>\n *     Marcello Duarte <marcello.duarte@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Prophecy\\Prophecy;\n\nuse Prophecy\\Comparator\\FactoryProvider;\nuse SebastianBergmann\\Comparator\\ComparisonFailure;\nuse SebastianBergmann\\Comparator\\Factory as ComparatorFactory;\nuse Prophecy\\Call\\Call;\nuse Prophecy\\Doubler\\LazyDouble;\nuse Prophecy\\Argument\\ArgumentsWildcard;\nuse Prophecy\\Call\\CallCenter;\nuse Prophecy\\Exception\\Prophecy\\ObjectProphecyException;\nuse Prophecy\\Exception\\Prediction\\AggregateException;\nuse Prophecy\\Exception\\Prediction\\PredictionException;\n\n/**\n * @author Konstantin Kudryashov <ever.zet@gmail.com>\n *\n * @template-covariant T of object\n * @template-implements ProphecyInterface<T>\n */\nclass ObjectProphecy implements ProphecyInterface\n{\n    /**\n     * @var LazyDouble<T>\n     */\n    private $lazyDouble;\n    private $callCenter;\n    private $revealer;\n    private $comparatorFactory;\n\n    /**\n     * @var array<string, list<MethodProphecy>>\n     */\n    private $methodProphecies = array();\n\n    /**\n     * @param LazyDouble<T> $lazyDouble\n     */\n    public function __construct(\n        LazyDouble $lazyDouble,\n        ?CallCenter $callCenter = null,\n        ?RevealerInterface $revealer = null,\n        ?ComparatorFactory $comparatorFactory = null\n    ) {\n        $this->lazyDouble = $lazyDouble;\n        $this->callCenter = $callCenter ?: new CallCenter();\n        $this->revealer   = $revealer ?: new Revealer();\n\n        $this->comparatorFactory = $comparatorFactory ?: FactoryProvider::getInstance();\n    }\n\n    /**\n     * Forces double to extend specific class.\n     *\n     * @param string $class\n     *\n     * @return $this\n     *\n     * @template U of object\n     * @phpstan-param class-string<U> $class\n     * @phpstan-this-out static<T&U>\n     */\n    public function willExtend($class)\n    {\n        $this->lazyDouble->setParentClass($class);\n\n        return $this;\n    }\n\n    /**\n     * Forces double to implement specific interface.\n     *\n     * @param string $interface\n     *\n     * @return $this\n     *\n     * @template U of object\n     * @phpstan-param class-string<U> $interface\n     * @phpstan-this-out static<T&U>\n     */\n    public function willImplement($interface)\n    {\n        $this->lazyDouble->addInterface($interface);\n\n        return $this;\n    }\n\n    /**\n     * Sets constructor arguments.\n     *\n     * @param array<mixed> $arguments\n     *\n     * @return $this\n     */\n    public function willBeConstructedWith(?array $arguments = null)\n    {\n        $this->lazyDouble->setArguments($arguments);\n\n        return $this;\n    }\n\n    /**\n     * Reveals double.\n     *\n     * @return object\n     *\n     * @throws \\Prophecy\\Exception\\Prophecy\\ObjectProphecyException If double doesn't implement needed interface\n     *\n     * @phpstan-return T\n     */\n    public function reveal()\n    {\n        $double = $this->lazyDouble->getInstance();\n\n        if (!$double instanceof ProphecySubjectInterface) {\n            throw new ObjectProphecyException(\n                \"Generated double must implement ProphecySubjectInterface, but it does not.\\n\"\n                .'It seems you have wrongly configured doubler without required ClassPatch.',\n                $this\n            );\n        }\n\n        $double->setProphecy($this);\n\n        return $double;\n    }\n\n    /**\n     * Adds method prophecy to object prophecy.\n     *\n     * @param MethodProphecy $methodProphecy\n     *\n     * @return void\n     */\n    public function addMethodProphecy(MethodProphecy $methodProphecy)\n    {\n        $methodName = strtolower($methodProphecy->getMethodName());\n\n        if (!isset($this->methodProphecies[$methodName])) {\n            $this->methodProphecies[$methodName] = [];\n        }\n\n        $this->methodProphecies[$methodName][] = $methodProphecy;\n    }\n\n    /**\n     * Returns either all or related to single method prophecies.\n     *\n     * @param null|string $methodName\n     *\n     * @return MethodProphecy[]|array<string, MethodProphecy[]>\n     *\n     * @phpstan-return ($methodName is string ? list<MethodProphecy> : array<string, list<MethodProphecy>>)\n     */\n    public function getMethodProphecies($methodName = null)\n    {\n        if (null === $methodName) {\n            return $this->methodProphecies;\n        }\n\n        $methodName = strtolower($methodName);\n\n        if (!isset($this->methodProphecies[$methodName])) {\n            return [];\n        }\n\n        return $this->methodProphecies[$methodName];\n    }\n\n    /**\n     * Makes specific method call.\n     *\n     * @param string $methodName\n     * @param array<mixed> $arguments\n     *\n     * @return mixed\n     */\n    public function makeProphecyMethodCall($methodName, array $arguments)\n    {\n        $arguments = $this->revealer->reveal($arguments);\n        \\assert(\\is_array($arguments));\n        $return    = $this->callCenter->makeCall($this, $methodName, $arguments);\n\n        return $this->revealer->reveal($return);\n    }\n\n    /**\n     * Finds calls by method name & arguments wildcard.\n     *\n     * @param string            $methodName\n     * @param ArgumentsWildcard $wildcard\n     *\n     * @return list<Call>\n     */\n    public function findProphecyMethodCalls($methodName, ArgumentsWildcard $wildcard)\n    {\n        return $this->callCenter->findCalls($methodName, $wildcard);\n    }\n\n    /**\n     * Checks that registered method predictions do not fail.\n     *\n     * @return void\n     *\n     * @throws \\Prophecy\\Exception\\Prediction\\AggregateException If any of registered predictions fail\n     * @throws \\Prophecy\\Exception\\Call\\UnexpectedCallException\n     */\n    public function checkProphecyMethodsPredictions()\n    {\n        $exception = new AggregateException(sprintf(\"%s:\\n\", get_class($this->reveal())));\n        $exception->setObjectProphecy($this);\n\n        $this->callCenter->checkUnexpectedCalls();\n\n        foreach ($this->methodProphecies as $prophecies) {\n            foreach ($prophecies as $prophecy) {\n                try {\n                    $prophecy->checkPrediction();\n                } catch (PredictionException $e) {\n                    $exception->append($e);\n                }\n            }\n        }\n\n        if (count($exception->getExceptions())) {\n            throw $exception;\n        }\n    }\n\n    /**\n     * Creates new method prophecy using specified method name and arguments.\n     *\n     * @param string $methodName\n     * @param array<mixed> $arguments\n     *\n     * @return MethodProphecy\n     */\n    public function __call($methodName, array $arguments)\n    {\n        $arguments = $this->revealer->reveal($arguments);\n        \\assert(\\is_array($arguments));\n        $arguments = new ArgumentsWildcard($arguments);\n\n        foreach ($this->getMethodProphecies($methodName) as $prophecy) {\n            $argumentsWildcard = $prophecy->getArgumentsWildcard();\n            $comparator = $this->comparatorFactory->getComparatorFor(\n                $argumentsWildcard, $arguments\n            );\n\n            try {\n                $comparator->assertEquals($argumentsWildcard, $arguments);\n                return $prophecy;\n            } catch (ComparisonFailure $failure) {\n            }\n        }\n\n        return new MethodProphecy($this, $methodName, $arguments);\n    }\n\n    /**\n     * Tries to get property value from double.\n     *\n     * @param string $name\n     *\n     * @return mixed\n     */\n    public function __get($name)\n    {\n        return $this->reveal()->$name;\n    }\n\n    /**\n     * Tries to set property value to double.\n     *\n     * @param string $name\n     * @param mixed  $value\n     *\n     * @return void\n     */\n    public function __set($name, $value)\n    {\n        $this->reveal()->$name = $this->revealer->reveal($value);\n    }\n}\n"
  },
  {
    "path": "src/Prophecy/Prophecy/ProphecyInterface.php",
    "content": "<?php\n\n/*\n * This file is part of the Prophecy.\n * (c) Konstantin Kudryashov <ever.zet@gmail.com>\n *     Marcello Duarte <marcello.duarte@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Prophecy\\Prophecy;\n\n/**\n * Core Prophecy interface.\n *\n * @author Konstantin Kudryashov <ever.zet@gmail.com>\n *\n * @template-covariant T of object\n */\ninterface ProphecyInterface\n{\n    /**\n     * Reveals prophecy object (double) .\n     *\n     * @return object\n     *\n     * @phpstan-return T\n     */\n    public function reveal();\n}\n"
  },
  {
    "path": "src/Prophecy/Prophecy/ProphecySubjectInterface.php",
    "content": "<?php\n\n/*\n * This file is part of the Prophecy.\n * (c) Konstantin Kudryashov <ever.zet@gmail.com>\n *     Marcello Duarte <marcello.duarte@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Prophecy\\Prophecy;\n\n/**\n * Controllable doubles interface.\n *\n * @author Konstantin Kudryashov <ever.zet@gmail.com>\n */\ninterface ProphecySubjectInterface\n{\n    /**\n     * Sets subject prophecy.\n     *\n     * @param ProphecyInterface<object> $prophecy\n     *\n     * @return void\n     */\n    public function setProphecy(ProphecyInterface $prophecy);\n\n    /**\n     * Returns subject prophecy.\n     *\n     * @return ProphecyInterface<object>\n     */\n    public function getProphecy();\n}\n"
  },
  {
    "path": "src/Prophecy/Prophecy/Revealer.php",
    "content": "<?php\n\n/*\n * This file is part of the Prophecy.\n * (c) Konstantin Kudryashov <ever.zet@gmail.com>\n *     Marcello Duarte <marcello.duarte@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Prophecy\\Prophecy;\n\n/**\n * Basic prophecies revealer.\n *\n * @author Konstantin Kudryashov <ever.zet@gmail.com>\n */\nclass Revealer implements RevealerInterface\n{\n    /**\n     * Unwraps value(s).\n     *\n     * @param mixed $value\n     *\n     * @return mixed\n     */\n    public function reveal($value)\n    {\n        if (is_array($value)) {\n            return array_map(array($this, __FUNCTION__), $value);\n        }\n\n        if (!is_object($value)) {\n            return $value;\n        }\n\n        if ($value instanceof ProphecyInterface) {\n            $value = $value->reveal();\n        }\n\n        return $value;\n    }\n}\n"
  },
  {
    "path": "src/Prophecy/Prophecy/RevealerInterface.php",
    "content": "<?php\n\n/*\n * This file is part of the Prophecy.\n * (c) Konstantin Kudryashov <ever.zet@gmail.com>\n *     Marcello Duarte <marcello.duarte@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Prophecy\\Prophecy;\n\n/**\n * Prophecies revealer interface.\n *\n * @author Konstantin Kudryashov <ever.zet@gmail.com>\n */\ninterface RevealerInterface\n{\n    /**\n     * Unwraps value(s).\n     *\n     * @param mixed $value\n     *\n     * @return mixed\n     */\n    public function reveal($value);\n}\n"
  },
  {
    "path": "src/Prophecy/Prophet.php",
    "content": "<?php\n\n/*\n * This file is part of the Prophecy.\n * (c) Konstantin Kudryashov <ever.zet@gmail.com>\n *     Marcello Duarte <marcello.duarte@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Prophecy;\n\nuse Prophecy\\Doubler\\CachedDoubler;\nuse Prophecy\\Doubler\\Doubler;\nuse Prophecy\\Doubler\\LazyDouble;\nuse Prophecy\\Doubler\\ClassPatch;\nuse Prophecy\\Exception\\Doubler\\ClassNotFoundException;\nuse Prophecy\\Prophecy\\ObjectProphecy;\nuse Prophecy\\Prophecy\\RevealerInterface;\nuse Prophecy\\Prophecy\\Revealer;\nuse Prophecy\\Call\\CallCenter;\nuse Prophecy\\Util\\StringUtil;\nuse Prophecy\\Exception\\Prediction\\PredictionException;\nuse Prophecy\\Exception\\Prediction\\AggregateException;\n\n/**\n * Prophet creates prophecies.\n *\n * @author Konstantin Kudryashov <ever.zet@gmail.com>\n */\nclass Prophet\n{\n    /**\n     * @var Doubler\n     */\n    private $doubler;\n    private $revealer;\n    private $util;\n\n    /**\n     * @var list<ObjectProphecy<object>>\n     */\n    private $prophecies = array();\n\n    public function __construct(\n        ?Doubler $doubler = null,\n        ?RevealerInterface $revealer = null,\n        ?StringUtil $util = null\n    ) {\n        if (null === $doubler) {\n            $doubler = new CachedDoubler();\n            $doubler->registerClassPatch(new ClassPatch\\SplFileInfoPatch());\n            $doubler->registerClassPatch(new ClassPatch\\TraversablePatch());\n            $doubler->registerClassPatch(new ClassPatch\\ThrowablePatch());\n            $doubler->registerClassPatch(new ClassPatch\\DisableConstructorPatch());\n            $doubler->registerClassPatch(new ClassPatch\\ProphecySubjectPatch());\n            $doubler->registerClassPatch(new ClassPatch\\ReflectionClassNewInstancePatch());\n            $doubler->registerClassPatch(new ClassPatch\\MagicCallPatch());\n            $doubler->registerClassPatch(new ClassPatch\\KeywordPatch());\n        }\n\n        $this->doubler  = $doubler;\n        $this->revealer = $revealer ?: new Revealer();\n        $this->util     = $util ?: new StringUtil();\n    }\n\n    /**\n     * Creates new object prophecy.\n     *\n     * @param null|string $classOrInterface Class or interface name\n     *\n     * @return ObjectProphecy\n     *\n     * @template T of object\n     * @phpstan-param class-string<T>|null $classOrInterface\n     * @phpstan-return ($classOrInterface is null ? ObjectProphecy<object> : ObjectProphecy<T>)\n     */\n    public function prophesize($classOrInterface = null)\n    {\n        $this->prophecies[] = $prophecy = new ObjectProphecy(\n            new LazyDouble($this->doubler),\n            new CallCenter($this->util),\n            $this->revealer\n        );\n\n        if ($classOrInterface) {\n            if (class_exists($classOrInterface)) {\n                return $prophecy->willExtend($classOrInterface);\n            }\n\n            if (interface_exists($classOrInterface)) {\n                return $prophecy->willImplement($classOrInterface);\n            }\n\n            throw new ClassNotFoundException(sprintf(\n                'Cannot prophesize class %s, because it cannot be found.',\n                $classOrInterface\n            ), $classOrInterface);\n        }\n\n        return $prophecy;\n    }\n\n    /**\n     * Returns all created object prophecies.\n     *\n     * @return list<ObjectProphecy<object>>\n     */\n    public function getProphecies()\n    {\n        return $this->prophecies;\n    }\n\n    /**\n     * Returns Doubler instance assigned to this Prophet.\n     *\n     * @return Doubler\n     */\n    public function getDoubler()\n    {\n        return $this->doubler;\n    }\n\n    /**\n     * Checks all predictions defined by prophecies of this Prophet.\n     *\n     * @return void\n     *\n     * @throws Exception\\Prediction\\AggregateException If any prediction fails\n     */\n    public function checkPredictions()\n    {\n        $exception = new AggregateException(\"Some predictions failed:\\n\");\n        foreach ($this->prophecies as $prophecy) {\n            try {\n                $prophecy->checkProphecyMethodsPredictions();\n            } catch (PredictionException $e) {\n                $exception->append($e);\n            }\n        }\n\n        if (count($exception->getExceptions())) {\n            throw $exception;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Prophecy/Util/ExportUtil.php",
    "content": "<?php\n\nnamespace Prophecy\\Util;\n\nuse SebastianBergmann\\RecursionContext\\Context;\n\n/*\n * This file is part of the Prophecy.\n * (c) Konstantin Kudryashov <ever.zet@gmail.com>\n *     Marcello Duarte <marcello.duarte@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/**\n * This class is a modification from sebastianbergmann/exporter\n * @see https://github.com/sebastianbergmann/exporter\n */\nclass ExportUtil\n{\n    /**\n     * Exports a value as a string\n     *\n     * The output of this method is similar to the output of print_r(), but\n     * improved in various aspects:\n     *\n     *  - NULL is rendered as \"null\" (instead of \"\")\n     *  - TRUE is rendered as \"true\" (instead of \"1\")\n     *  - FALSE is rendered as \"false\" (instead of \"\")\n     *  - Strings are always quoted with single quotes\n     *  - Carriage returns and newlines are normalized to \\n\n     *  - Recursion and repeated rendering is treated properly\n     *\n     * @param  mixed  $value\n     * @param  int    $indentation The indentation level of the 2nd+ line\n     * @return string\n     */\n    public static function export($value, $indentation = 0)\n    {\n        return self::recursiveExport($value, $indentation);\n    }\n\n    /**\n     * Converts an object to an array containing all of its private, protected\n     * and public properties.\n     *\n     * @param  mixed $value\n     * @return array<mixed>\n     */\n    public static function toArray($value)\n    {\n        if (!is_object($value)) {\n            return (array) $value;\n        }\n\n        $array = array();\n\n        foreach ((array) $value as $key => $val) {\n            // properties are transformed to keys in the following way:\n            // private   $property => \"\\0Classname\\0property\"\n            // protected $property => \"\\0*\\0property\"\n            // public    $property => \"property\"\n            if (preg_match('/^\\0.+\\0(.+)$/', $key, $matches)) {\n                $key = $matches[1];\n            }\n\n            // See https://github.com/php/php-src/commit/5721132\n            if ($key === \"\\0gcdata\") {\n                continue;\n            }\n\n            $array[$key] = $val;\n        }\n\n        // Some internal classes like SplObjectStorage don't work with the\n        // above (fast) mechanism nor with reflection in Zend.\n        // Format the output similarly to print_r() in this case\n        if ($value instanceof \\SplObjectStorage) {\n            foreach ($value as $key => $val) {\n                // Use the same identifier that would be printed alongside the object's representation elsewhere.\n                $array[spl_object_id($val)] = array(\n                    'obj' => $val,\n                    'inf' => $value->getInfo(),\n                );\n            }\n        }\n\n        return $array;\n    }\n\n    /**\n     * Recursive implementation of export\n     *\n     * @param  mixed                                       $value       The value to export\n     * @param  int                                         $indentation The indentation level of the 2nd+ line\n     * @param  \\SebastianBergmann\\RecursionContext\\Context $processed   Previously processed objects\n     * @return string\n     * @see    SebastianBergmann\\Exporter\\Exporter::export\n     */\n    protected static function recursiveExport(&$value, $indentation, $processed = null)\n    {\n        if ($value === null) {\n            return 'null';\n        }\n\n        if ($value === true) {\n            return 'true';\n        }\n\n        if ($value === false) {\n            return 'false';\n        }\n\n        if (is_float($value) && floatval(intval($value)) === $value) {\n            return \"$value.0\";\n        }\n\n        if (is_resource($value)) {\n            return sprintf(\n                'resource(%d) of type (%s)',\n                (int) $value,\n                get_resource_type($value)\n            );\n        }\n\n        if (is_string($value)) {\n            // Match for most non printable chars somewhat taking multibyte chars into account\n            if (preg_match('/[^\\x09-\\x0d\\x20-\\xff]/', $value)) {\n                return 'Binary String: 0x'.bin2hex($value);\n            }\n\n            return \"'\"\n            .str_replace(array(\"\\r\\n\", \"\\n\\r\", \"\\r\"), array(\"\\n\", \"\\n\", \"\\n\"), $value)\n            .\"'\";\n        }\n\n        $whitespace = str_repeat(' ', 4 * $indentation);\n\n        if (!$processed) {\n            $processed = new Context();\n        }\n\n        if (is_array($value)) {\n            if (($key = $processed->contains($value)) !== false) {\n                return 'Array &'.$key;\n            }\n\n            $array  = $value;\n            $key    = $processed->add($value);\n            $values = '';\n\n            if (count($array) > 0) {\n                foreach ($array as $k => $v) {\n                    $values .= sprintf(\n                        '%s    %s => %s'.\"\\n\",\n                        $whitespace,\n                        self::recursiveExport($k, $indentation),\n                        self::recursiveExport($value[$k], $indentation + 1, $processed)\n                    );\n                }\n\n                $values = \"\\n\".$values.$whitespace;\n            }\n\n            return sprintf('Array &%s (%s)', $key, $values);\n        }\n\n        if (is_object($value)) {\n            $class = get_class($value);\n\n            if ($processed->contains($value)) {\n                return sprintf('%s#%d Object', $class, spl_object_id($value));\n            }\n\n            $processed->add($value);\n            $values = '';\n            $array  = self::toArray($value);\n\n            if (count($array) > 0) {\n                foreach ($array as $k => $v) {\n                    $values .= sprintf(\n                        '%s    %s => %s'.\"\\n\",\n                        $whitespace,\n                        self::recursiveExport($k, $indentation),\n                        self::recursiveExport($v, $indentation + 1, $processed)\n                    );\n                }\n\n                $values = \"\\n\".$values.$whitespace;\n            }\n\n            return sprintf('%s#%d Object (%s)', $class, spl_object_id($value), $values);\n        }\n\n        return var_export($value, true);\n    }\n}\n"
  },
  {
    "path": "src/Prophecy/Util/StringUtil.php",
    "content": "<?php\n\n/*\n * This file is part of the Prophecy.\n * (c) Konstantin Kudryashov <ever.zet@gmail.com>\n *     Marcello Duarte <marcello.duarte@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Prophecy\\Util;\n\nuse Prophecy\\Call\\Call;\n\n/**\n * String utility.\n *\n * @author Konstantin Kudryashov <ever.zet@gmail.com>\n */\nclass StringUtil\n{\n    private $verbose;\n\n    /**\n     * @param bool $verbose\n     */\n    public function __construct($verbose = true)\n    {\n        $this->verbose = $verbose;\n    }\n\n    /**\n     * Stringifies any provided value.\n     *\n     * @param mixed   $value\n     * @param boolean $exportObject\n     *\n     * @return string\n     */\n    public function stringify($value, $exportObject = true)\n    {\n        if (\\is_array($value)) {\n            if (range(0, count($value) - 1) === array_keys($value)) {\n                return '['.implode(', ', array_map(array($this, __FUNCTION__), $value)).']';\n            }\n\n            $stringify = array($this, __FUNCTION__);\n\n            return '['.implode(', ', array_map(function ($item, $key) use ($stringify) {\n                return (is_integer($key) ? $key : '\"'.$key.'\"')\n                    .' => '.call_user_func($stringify, $item);\n            }, $value, array_keys($value))).']';\n        }\n        if (\\is_resource($value)) {\n            return get_resource_type($value).':'.$value;\n        }\n        if (\\is_object($value)) {\n            return $exportObject ? ExportUtil::export($value) : sprintf('%s#%s', get_class($value), spl_object_id($value));\n        }\n        if (\\is_bool($value)) {\n            return $value ? 'true' : 'false';\n        }\n        if (\\is_string($value)) {\n            $str = sprintf('\"%s\"', str_replace(\"\\n\", '\\\\n', $value));\n\n            if (!$this->verbose && 50 <= strlen($str)) {\n                return substr($str, 0, 50).'\"...';\n            }\n\n            return $str;\n        }\n        if (null === $value) {\n            return 'null';\n        }\n\n        \\assert(\\is_int($value) || \\is_float($value));\n\n        return (string) $value;\n    }\n\n    /**\n     * Stringifies provided array of calls.\n     *\n     * @param Call[] $calls Array of Call instances\n     *\n     * @return string\n     */\n    public function stringifyCalls(array $calls)\n    {\n        $self = $this;\n\n        return implode(PHP_EOL, array_map(function (Call $call) use ($self) {\n            return sprintf('  - %s(%s) @ %s',\n                $call->getMethodName(),\n                implode(', ', array_map(array($self, 'stringify'), $call->getArguments())),\n                str_replace(GETCWD().DIRECTORY_SEPARATOR, '', $call->getCallPlace())\n            );\n        }, $calls));\n    }\n}\n"
  },
  {
    "path": "tests/Argument/Token/ExactValueTokenTest.php",
    "content": "<?php\n\nnamespace Tests\\Prophecy\\Argument\\Token;\n\nuse PHPUnit\\Framework\\Attributes\\Test;\nuse PHPUnit\\Framework\\TestCase;\nuse Prophecy\\Argument\\Token\\ExactValueToken;\n\nclass ExactValueTokenTest extends TestCase\n{\n    /**\n     * @see https://github.com/phpspec/prophecy/issues/268\n     * @see https://stackoverflow.com/a/19097159/2424814\n     */\n    #[Test]\n    public function does_not_trigger_nesting_error(): void\n    {\n        $child1 = new ChildClass('A', new ParentClass());\n        $child2 = new ChildClass('B', new ParentClass());\n\n        $exactValueToken = new ExactValueToken($child1);\n        self::assertEquals(false, $exactValueToken->scoreArgument($child2));\n    }\n\n    #[Test]\n    public function scores_10_for_objects_with_same_fields(): void\n    {\n        $child1 = new ChildClass('A', new ParentClass());\n        $child2 = new ChildClass('A', new ParentClass());\n\n        $exactValueToken = new ExactValueToken($child1);\n        self::assertEquals(10, $exactValueToken->scoreArgument($child2));\n    }\n\n    #[Test]\n    public function scores_10_for_matching_callables(): void\n    {\n        $callable = function () {};\n\n        $exactValueToken = new ExactValueToken($callable);\n        self::assertEquals(10, $exactValueToken->scoreArgument($callable));\n    }\n\n    #[Test]\n    public function scores_false_for_object_and_string(): void\n    {\n        $child1 = new ChildClass('A', new ParentClass());\n\n        $exactValueToken = new ExactValueToken($child1);\n        self::assertEquals(false, $exactValueToken->scoreArgument(\"A\"));\n    }\n\n    #[Test]\n    public function scores_false_for_object_and_int(): void\n    {\n        $child1 = new ChildClass('A', new ParentClass());\n\n        $exactValueToken = new ExactValueToken($child1);\n        self::assertEquals(false, $exactValueToken->scoreArgument(100));\n    }\n\n    #[Test]\n    public function scores_false_for_object_and_stdclass(): void\n    {\n        $child1 = new ChildClass('A', new ParentClass());\n\n        $exactValueToken = new ExactValueToken($child1);\n        self::assertEquals(false, $exactValueToken->scoreArgument(new \\stdClass()));\n    }\n\n    #[Test]\n    public function scores_false_for_object_and_null(): void\n    {\n        $child1 = new ChildClass('A', new ParentClass());\n\n        $exactValueToken = new ExactValueToken($child1);\n        self::assertEquals(false, $exactValueToken->scoreArgument(null));\n    }\n}\n\n\nclass ParentClass\n{\n    public $children = array();\n\n    public function addChild($child)\n    {\n        $this->children[] = $child;\n    }\n}\n\nclass ChildClass\n{\n    public $parent = null;\n    public $name = null;\n\n    public function __construct($name, $parent)\n    {\n        $this->name = $name;\n        $this->parent = $parent;\n        $this->parent->addChild($this);\n    }\n\n}\n"
  },
  {
    "path": "tests/Comparator/FactoryProviderTest.php",
    "content": "<?php\n\nnamespace Tests\\Prophecy\\Comparator;\n\nuse PHPUnit\\Framework\\Attributes\\Test;\nuse Prophecy\\Comparator\\ClosureComparator;\nuse Prophecy\\Comparator\\FactoryProvider;\nuse PHPUnit\\Framework\\TestCase;\n\nclass FactoryProviderTest extends TestCase\n{\n    #[Test]\n    function it_should_have_ClosureComparator_registered(): void\n    {\n        $comparator = FactoryProvider::getInstance()->getComparatorFor(function () {}, function () {});\n\n        $this->assertInstanceOf(ClosureComparator::class, $comparator);\n    }\n}\n"
  },
  {
    "path": "tests/Doubler/ClassPatch/MagicCallPatchTest.php",
    "content": "<?php\n\nnamespace Tests\\Prophecy\\Doubler\\ClassPatch;\n\nuse PHPUnit\\Framework\\Attributes\\Test;\nuse PHPUnit\\Framework\\TestCase;\nuse Prophecy\\Doubler\\ClassPatch\\MagicCallPatch;\nuse Prophecy\\Doubler\\Generator\\ClassMirror;\nuse Prophecy\\Doubler\\Generator\\Node\\ArgumentNode;\nuse Prophecy\\Doubler\\Generator\\Node\\ClassNode;\n\nclass MagicCallPatchTest extends TestCase\n{\n    #[Test]\n    public function it_supports_classes_with_invalid_tags(): void\n    {\n        $class = new \\ReflectionClass('Fixtures\\Prophecy\\WithPhpdocClass');\n\n        $classNode = $this->applyPatchTo($class);\n\n        // Newer phpDocumentor versions allow reading valid method tags, even when some other tags are invalid\n        // Some older versions might also have this method due to not considering the method tag invalid as rule evolved, but we don't track that.\n        if (class_exists('phpDocumentor\\Reflection\\DocBlock\\Tags\\InvalidTag')) {\n            $this->assertTrue($classNode->hasMethod('name'));\n        }\n\n        // We expect no error when processing the class patch. But we still need to increment the assertion count.\n        $this->assertTrue(true);\n    }\n\n    #[Test]\n    public function it_supports_arguments_for_magic_methods(): void\n    {\n        $class = new \\ReflectionClass('Fixtures\\Prophecy\\WithPhpdocClass');\n\n        $classNode = $this->applyPatchTo($class);\n\n        $method = $classNode->getMethod('__unserialize');\n        if (method_exists($method, 'getParameters')) {\n            // Reflection Docblock 5.4.0+.\n            $args = $method->getParameters();\n        } else {\n            // Reflection Docblock < 5.4.0.\n            $args = $method->getArguments();\n        }\n\n        $this->assertEquals([new ArgumentNode('data')], $args);\n    }\n\n    private function applyPatchTo(\\ReflectionClass $class): ClassNode\n    {\n        $mirror = new ClassMirror();\n        $classNode = $mirror->reflect($class, array());\n\n        $patch = new MagicCallPatch();\n\n        $patch->apply($classNode);\n        return $classNode;\n    }\n}\n"
  },
  {
    "path": "tests/Doubler/Generator/ClassMirrorTest.php",
    "content": "<?php\n\nnamespace Tests\\Prophecy\\Doubler\\Generator;\n\nuse Fixtures\\Prophecy\\SelfReferencing;\nuse PHPUnit\\Framework\\Attributes\\Test;\nuse PHPUnit\\Framework\\TestCase;\nuse Prophecy\\Doubler\\Generator\\ClassMirror;\nuse Prophecy\\Doubler\\Generator\\Node\\ArgumentTypeNode;\nuse Prophecy\\Doubler\\Generator\\Node\\ReturnTypeNode;\nuse Prophecy\\Doubler\\Generator\\Node\\Type\\BuiltinType;\nuse Prophecy\\Doubler\\Generator\\Node\\Type\\IntersectionType;\nuse Prophecy\\Doubler\\Generator\\Node\\Type\\ObjectType;\nuse Prophecy\\Doubler\\Generator\\Node\\Type\\UnionType;\nuse Prophecy\\Exception\\Doubler\\ClassMirrorException;\nuse Prophecy\\Exception\\InvalidArgumentException;\nuse Prophecy\\Prophet;\n\nclass ClassMirrorTest extends TestCase\n{\n    #[Test]\n    public function it_reflects_allowed_magic_methods(): void\n    {\n        $class = new \\ReflectionClass('Fixtures\\Prophecy\\SpecialMethods');\n\n        $mirror = new ClassMirror();\n\n        $node = $mirror->reflect($class, array());\n\n        $this->assertCount(7, $node->getMethods());\n    }\n\n    #[Test]\n    public function it_reflects_protected_abstract_methods(): void\n    {\n        $class = new \\ReflectionClass('Fixtures\\Prophecy\\WithProtectedAbstractMethod');\n\n        $mirror = new ClassMirror();\n\n        $classNode = $mirror->reflect($class, array());\n\n        $this->assertEquals('Fixtures\\Prophecy\\WithProtectedAbstractMethod', $classNode->getParentClass());\n\n        $methodNodes = $classNode->getMethods();\n        $this->assertCount(1, $methodNodes);\n\n        $this->assertEquals('protected', $methodNodes['innerDetail']->getVisibility());\n    }\n\n    #[Test]\n    public function it_reflects_public_static_methods(): void\n    {\n        $class = new \\ReflectionClass('Fixtures\\Prophecy\\WithStaticMethod');\n\n        $mirror = new ClassMirror();\n\n        $classNode = $mirror->reflect($class, array());\n\n        $this->assertEquals('Fixtures\\Prophecy\\WithStaticMethod', $classNode->getParentClass());\n\n        $methodNodes = $classNode->getMethods();\n        $this->assertCount(1, $methodNodes);\n\n        $this->assertTrue($methodNodes['innerDetail']->isStatic());\n    }\n\n    #[Test]\n    public function it_marks_required_args_without_types_as_not_optional(): void\n    {\n        $class = new \\ReflectionClass('Fixtures\\Prophecy\\WithArguments');\n\n        $mirror = new ClassMirror();\n\n        $classNode = $mirror->reflect($class, array());\n        $methodNode = $classNode->getMethod('methodWithoutTypeHints');\n        $argNodes = $methodNode->getArguments();\n\n        $this->assertCount(1, $argNodes);\n\n        $this->assertEquals('arg', $argNodes[0]->getName());\n        $this->assertEquals(new ArgumentTypeNode(), $argNodes[0]->getTypeNode());\n        $this->assertFalse($argNodes[0]->isOptional());\n        $this->assertNull($argNodes[0]->getDefault());\n        $this->assertFalse($argNodes[0]->isPassedByReference());\n        $this->assertFalse($argNodes[0]->isVariadic());\n    }\n\n    #[Test]\n    public function it_properly_reads_methods_arguments_with_types(): void\n    {\n        $class = new \\ReflectionClass('Fixtures\\Prophecy\\WithArguments');\n\n        $mirror = new ClassMirror();\n\n        $classNode = $mirror->reflect($class, array());\n        $methodNode = $classNode->getMethod('methodWithArgs');\n        $argNodes = $methodNode->getArguments();\n\n        $this->assertCount(3, $argNodes);\n\n\n        $this->assertEquals('arg_1', $argNodes[0]->getName());\n        $this->assertEquals(new ArgumentTypeNode(new ObjectType('ArrayAccess')), $argNodes[0]->getTypeNode());\n        $this->assertFalse($argNodes[0]->isOptional());\n\n        $this->assertEquals('arg_2', $argNodes[1]->getName());\n        $this->assertEquals(new ArgumentTypeNode(new BuiltinType('array')), $argNodes[1]->getTypeNode());\n        $this->assertTrue($argNodes[1]->isOptional());\n        $this->assertEquals(array(), $argNodes[1]->getDefault());\n        $this->assertFalse($argNodes[1]->isPassedByReference());\n        $this->assertFalse($argNodes[1]->isVariadic());\n\n        $this->assertEquals('arg_3', $argNodes[2]->getName());\n        $this->assertEquals(new ArgumentTypeNode(new UnionType([\n            new BuiltinType('null'),\n            new ObjectType('ArrayAccess'),\n        ])), $argNodes[2]->getTypeNode());\n        $this->assertTrue($argNodes[2]->isOptional());\n        $this->assertNull($argNodes[2]->getDefault());\n        $this->assertFalse($argNodes[2]->isPassedByReference());\n        $this->assertFalse($argNodes[2]->isVariadic());\n    }\n\n    #[Test]\n    public function it_properly_reads_methods_arguments_with_callable_types(): void\n    {\n        $class = new \\ReflectionClass('Fixtures\\Prophecy\\WithCallableArgument');\n\n        $mirror = new ClassMirror();\n\n        $classNode = $mirror->reflect($class, array());\n        $methodNode = $classNode->getMethod('methodWithArgs');\n        $argNodes = $methodNode->getArguments();\n\n        $this->assertCount(2, $argNodes);\n\n        $this->assertEquals('arg_1', $argNodes[0]->getName());\n        $this->assertEquals(new ArgumentTypeNode(new BuiltinType('callable')), $argNodes[0]->getTypeNode());\n        $this->assertFalse($argNodes[0]->isOptional());\n        $this->assertFalse($argNodes[0]->isPassedByReference());\n        $this->assertFalse($argNodes[0]->isVariadic());\n\n        $this->assertEquals('arg_2', $argNodes[1]->getName());\n        $this->assertEquals(new ArgumentTypeNode(new UnionType([\n            new BuiltinType('null'),\n            new BuiltinType('callable'),\n        ])), $argNodes[1]->getTypeNode());\n        $this->assertTrue($argNodes[1]->isOptional());\n        $this->assertNull($argNodes[1]->getDefault());\n        $this->assertFalse($argNodes[1]->isPassedByReference());\n        $this->assertFalse($argNodes[1]->isVariadic());\n    }\n\n    #[Test]\n    public function it_properly_reads_methods_variadic_arguments(): void\n    {\n        $class = new \\ReflectionClass('Fixtures\\Prophecy\\WithVariadicArgument');\n\n        $mirror = new ClassMirror();\n\n        $classNode = $mirror->reflect($class, array());\n        $methodNode = $classNode->getMethod('methodWithArgs');\n        $argNodes = $methodNode->getArguments();\n\n        $this->assertCount(1, $argNodes);\n\n        $this->assertEquals('args', $argNodes[0]->getName());\n        $this->assertEquals(new ArgumentTypeNode(), $argNodes[0]->getTypeNode());\n        $this->assertFalse($argNodes[0]->isOptional());\n        $this->assertFalse($argNodes[0]->isPassedByReference());\n        $this->assertTrue($argNodes[0]->isVariadic());\n    }\n\n    #[Test]\n    public function it_properly_reads_methods_typehinted_variadic_arguments(): void\n    {\n        $class = new \\ReflectionClass('Fixtures\\Prophecy\\WithTypehintedVariadicArgument');\n\n        $mirror = new ClassMirror();\n\n        $classNode = $mirror->reflect($class, array());\n        $methodNode = $classNode->getMethod('methodWithTypeHintedArgs');\n        $argNodes = $methodNode->getArguments();\n\n        $this->assertCount(1, $argNodes);\n\n        $this->assertEquals('args', $argNodes[0]->getName());\n        $this->assertEquals(new ArgumentTypeNode(new BuiltinType('array')), $argNodes[0]->getTypeNode());\n        $this->assertFalse($argNodes[0]->isOptional());\n        $this->assertFalse($argNodes[0]->isPassedByReference());\n        $this->assertTrue($argNodes[0]->isVariadic());\n    }\n\n    #[Test]\n    public function it_marks_passed_by_reference_args_as_passed_by_reference(): void\n    {\n        $class = new \\ReflectionClass('Fixtures\\Prophecy\\WithReferences');\n\n        $mirror = new ClassMirror();\n\n        $classNode = $mirror->reflect($class, array());\n\n        $this->assertTrue($classNode->hasMethod('methodWithReferenceArgument'));\n\n        $argNodes = $classNode->getMethod('methodWithReferenceArgument')->getArguments();\n\n        $this->assertCount(2, $argNodes);\n\n        $this->assertTrue($argNodes[0]->isPassedByReference());\n        $this->assertTrue($argNodes[1]->isPassedByReference());\n    }\n\n    #[Test]\n    public function it_throws_an_exception_if_class_is_final(): void\n    {\n        $class = new \\ReflectionClass('Fixtures\\Prophecy\\FinalClass');\n\n        $mirror = new ClassMirror();\n\n        $this->expectException(ClassMirrorException::class);\n\n        $mirror->reflect($class, array());\n    }\n\n    #[Test]\n    public function it_ignores_final_methods(): void\n    {\n        $class = new \\ReflectionClass('Fixtures\\Prophecy\\WithFinalMethod');\n\n        $mirror = new ClassMirror();\n\n        $classNode = $mirror->reflect($class, array());\n\n        $this->assertCount(0, $classNode->getMethods());\n    }\n\n    #[Test]\n    public function it_marks_final_methods_as_unextendable(): void\n    {\n        $class = new \\ReflectionClass('Fixtures\\Prophecy\\WithFinalMethod');\n\n        $mirror = new ClassMirror();\n\n        $classNode = $mirror->reflect($class, array());\n\n        $this->assertCount(1, $classNode->getUnextendableMethods());\n        $this->assertFalse($classNode->isExtendable('finalImplementation'));\n    }\n\n    #[Test]\n    public function it_throws_an_exception_if_interface_provided_instead_of_class(): void\n    {\n        $class = new \\ReflectionClass('Fixtures\\Prophecy\\EmptyInterface');\n\n        $mirror = new ClassMirror();\n\n        $this->expectException(InvalidArgumentException::class);\n\n        $mirror->reflect($class, array());\n    }\n\n    #[Test]\n    public function it_reflects_all_interfaces_methods(): void\n    {\n        $mirror = new ClassMirror();\n\n        $classNode = $mirror->reflect(null, array(\n            new \\ReflectionClass('Fixtures\\Prophecy\\Named'),\n            new \\ReflectionClass('Fixtures\\Prophecy\\ModifierInterface'),\n        ));\n\n        $this->assertEquals('stdClass', $classNode->getParentClass());\n        $this->assertEquals(array(\n            'Prophecy\\Doubler\\Generator\\ReflectionInterface',\n            'Fixtures\\Prophecy\\ModifierInterface',\n            'Fixtures\\Prophecy\\Named',\n        ), $classNode->getInterfaces());\n\n        $this->assertCount(3, $classNode->getMethods());\n        $this->assertTrue($classNode->hasMethod('getName'));\n        $this->assertTrue($classNode->hasMethod('isAbstract'));\n        $this->assertTrue($classNode->hasMethod('getVisibility'));\n    }\n\n    #[Test]\n    public function it_ignores_virtually_private_methods(): void\n    {\n        $class = new \\ReflectionClass('Fixtures\\Prophecy\\WithVirtuallyPrivateMethod');\n\n        $mirror = new ClassMirror();\n\n        $classNode = $mirror->reflect($class, array());\n\n        $this->assertCount(2, $classNode->getMethods());\n        $this->assertTrue($classNode->hasMethod('isAbstract'));\n        $this->assertTrue($classNode->hasMethod('__toString'));\n        $this->assertFalse($classNode->hasMethod('_getName'));\n    }\n\n    #[Test]\n    public function it_does_not_throw_exception_for_virtually_private_finals(): void\n    {\n        $class = new \\ReflectionClass('Fixtures\\Prophecy\\WithFinalVirtuallyPrivateMethod');\n\n        $mirror = new ClassMirror();\n\n        $classNode = $mirror->reflect($class, array());\n\n        $this->assertCount(0, $classNode->getMethods());\n    }\n\n    #[Test]\n    public function it_reflects_return_typehints(): void\n    {\n        $class = new \\ReflectionClass('Fixtures\\Prophecy\\WithReturnTypehints');\n\n        $mirror = new ClassMirror();\n\n        $classNode = $mirror->reflect($class, array());\n\n        $this->assertCount(3, $classNode->getMethods());\n        $this->assertTrue($classNode->hasMethod('getName'));\n        $this->assertTrue($classNode->hasMethod('getSelf'));\n        $this->assertTrue($classNode->hasMethod('getParent'));\n\n        $this->assertEquals(new ReturnTypeNode(new BuiltinType('string')), $classNode->getMethod('getName')->getReturnTypeNode());\n        $this->assertEquals(new ReturnTypeNode(new ObjectType('Fixtures\\Prophecy\\WithReturnTypehints')), $classNode->getMethod('getSelf')->getReturnTypeNode());\n        $this->assertEquals(new ReturnTypeNode(new ObjectType('Fixtures\\Prophecy\\EmptyClass')), $classNode->getMethod('getParent')->getReturnTypeNode());\n    }\n\n    #[Test]\n    public function it_throws_an_exception_if_class_provided_in_interfaces_list(): void\n    {\n        $class = new \\ReflectionClass('Fixtures\\Prophecy\\EmptyClass');\n\n        $mirror = new ClassMirror();\n\n        $this->expectException(\\InvalidArgumentException::class);\n\n        $mirror->reflect(null, array($class));\n    }\n\n    #[Test]\n    public function it_throws_an_exception_if_not_reflection_provided_as_interface(): void\n    {\n        $mirror = new ClassMirror();\n\n        $this->expectException(\\InvalidArgumentException::class);\n\n        $mirror->reflect(null, array(null));\n    }\n\n    #[Test]\n    public function it_doesnt_fail_to_typehint_nonexistent_FQCN(): void\n    {\n        $mirror = new ClassMirror();\n\n        $classNode = $mirror->reflect(new \\ReflectionClass('Fixtures\\Prophecy\\OptionalDepsClass'), array());\n        $method = $classNode->getMethod('iHaveAStrangeTypeHintedArg');\n        $arguments = $method->getArguments();\n        $this->assertEquals(new ArgumentTypeNode('I\\Simply\\Am\\Nonexistent'), $arguments[0]->getTypeNode());\n    }\n\n    #[Test]\n    public function it_doesnt_fail_on_array_nullable_parameter_with_not_null_default_value(): void\n    {\n        $mirror = new ClassMirror();\n\n        $classNode = $mirror->reflect(new \\ReflectionClass('Fixtures\\Prophecy\\NullableArrayParameter'), array());\n        $method = $classNode->getMethod('iHaveNullableArrayParameterWithNotNullDefaultValue');\n        $arguments = $method->getArguments();\n        $this->assertEquals(new ArgumentTypeNode(new UnionType([\n            new BuiltinType('null'),\n            new BuiltinType('array'),\n        ])), $arguments[0]->getTypeNode());\n    }\n\n    #[Test]\n    public function it_doesnt_fail_to_typehint_nonexistent_RQCN(): void\n    {\n        $mirror = new ClassMirror();\n\n        $classNode = $mirror->reflect(new \\ReflectionClass('Fixtures\\Prophecy\\OptionalDepsClass'), array());\n        $method = $classNode->getMethod('iHaveAnEvenStrangerTypeHintedArg');\n        $arguments = $method->getArguments();\n        $this->assertEquals(new ArgumentTypeNode('I\\Simply\\Am\\Not'), $arguments[0]->getTypeNode());\n    }\n\n    #[Test]\n    function it_doesnt_fail_when_method_is_extended_with_more_params(): void\n    {\n        $mirror = new ClassMirror();\n\n        $classNode = $mirror->reflect(\n            new \\ReflectionClass('Fixtures\\Prophecy\\MethodWithAdditionalParam'),\n            array(new \\ReflectionClass('Fixtures\\Prophecy\\Named'))\n        );\n        $method = $classNode->getMethod('getName');\n        $this->assertCount(1, $method->getArguments());\n\n        $method = $classNode->getMethod('methodWithoutTypeHints');\n        $this->assertCount(2, $method->getArguments());\n    }\n\n    #[Test]\n    function it_doesnt_fail_to_mock_self_referencing_interface(): void\n    {\n        $mirror = new ClassMirror();\n\n        $classNode = $mirror->reflect(null, array(new \\ReflectionClass(SelfReferencing::class)));\n\n        $method = $classNode->getMethod('__invoke');\n        $this->assertCount(1, $method->getArguments());\n\n        $this->assertEquals(new ArgumentTypeNode(SelfReferencing::class), $method->getArguments()[0]->getTypeNode());\n\n        $this->assertEquals(new ReturnTypeNode(SelfReferencing::class), $method->getReturnTypeNode());\n    }\n\n    #[Test]\n    function it_changes_argument_names_if_they_are_varying(): void\n    {\n        // Use test doubles in this test, as arguments named ... in the Reflection API can only happen for internal classes\n        $prophet = new Prophet();\n        $class = $prophet->prophesize('ReflectionClass');\n        $method = $prophet->prophesize('ReflectionMethod');\n        $parameter = $prophet->prophesize('ReflectionParameter');\n\n        if (PHP_VERSION_ID >= 80200) {\n            $class->isReadOnly()->willReturn(false);\n        }\n        $class->getName()->willReturn('Custom\\ClassName');\n        $class->isInterface()->willReturn(false);\n        $class->isFinal()->willReturn(false);\n        $class->getMethods(\\ReflectionMethod::IS_PUBLIC)->willReturn(array($method));\n        $class->getMethods(\\ReflectionMethod::IS_ABSTRACT)->willReturn(array());\n\n        $method->getParameters()->willReturn(array($parameter));\n        $method->getName()->willReturn('methodName');\n        $method->isFinal()->willReturn(false);\n        $method->isProtected()->willReturn(false);\n        $method->isStatic()->willReturn(false);\n        $method->returnsReference()->willReturn(false);\n        $method->hasReturnType()->willReturn(false);\n        $method->getDeclaringClass()->willReturn($class);\n\n        if (\\PHP_VERSION_ID >= 80100) {\n            $method->hasTentativeReturnType()->willReturn(false);\n        }\n\n        $parameter->getName()->willReturn('...');\n        $parameter->isDefaultValueAvailable()->willReturn(true);\n        $parameter->getDefaultValue()->willReturn(null);\n        $parameter->isPassedByReference()->willReturn(false);\n        $parameter->allowsNull()->willReturn(true);\n        $parameter->getClass()->willReturn($class);\n        $parameter->getType()->willReturn(null);\n        $parameter->hasType()->willReturn(false);\n        $parameter->isVariadic()->willReturn(false);\n\n        $mirror = new ClassMirror();\n\n        $classNode = $mirror->reflect($class->reveal(), array());\n\n        $methodNodes = $classNode->getMethods();\n\n        $argumentNodes = $methodNodes['methodName']->getArguments();\n        $argumentNode = $argumentNodes[0];\n\n        $this->assertEquals('__dot_dot_dot__', $argumentNode->getName());\n    }\n\n    #[Test]\n    public function it_can_double_a_class_with_union_return_types(): void\n    {\n        if (PHP_VERSION_ID < 80000) {\n            $this->markTestSkipped('Union types are not supported in this PHP version');\n        }\n\n        $classNode = (new ClassMirror())->reflect(new \\ReflectionClass('Fixtures\\Prophecy\\UnionReturnTypes'), []);\n        $methodNode = $classNode->getMethods()['doSomething'];\n\n\n        $this->assertEquals(new UnionType([\n            new ObjectType('stdClass'),\n            new BuiltinType('bool'),\n        ]), $methodNode->getReturnTypeNode()->getType());\n    }\n\n    #[Test]\n    public function it_can_double_a_class_with_union_return_type_with_false(): void\n    {\n        if (PHP_VERSION_ID < 80000) {\n            $this->markTestSkipped('Union types with false are not supported in this PHP version');\n        }\n\n        $classNode = (new ClassMirror())->reflect(new \\ReflectionClass('Fixtures\\Prophecy\\UnionReturnTypeFalse'), []);\n        $methodNode = $classNode->getMethods()['method'];\n\n        $this->assertEquals(new UnionType([\n            new ObjectType('stdClass'),\n            new BuiltinType('false'),\n        ]), $methodNode->getReturnTypeNode()->getType());\n    }\n\n    #[Test]\n    public function it_can_double_a_class_with_union_argument_types(): void\n    {\n        if (PHP_VERSION_ID < 80000) {\n            $this->markTestSkipped('Union types are not supported in this PHP version');\n        }\n\n        $classNode = (new ClassMirror())->reflect(new \\ReflectionClass('Fixtures\\Prophecy\\UnionArgumentTypes'), []);\n        $methodNode = $classNode->getMethods()['doSomething'];\n\n        $this->assertEquals(new ArgumentTypeNode(\\stdClass::class, 'bool'), $methodNode->getArguments()[0]->getTypeNode());\n    }\n\n    #[Test]\n    public function it_can_double_a_class_with_union_argument_type_with_false(): void\n    {\n        if (PHP_VERSION_ID < 80000) {\n            $this->markTestSkipped('Union types with false are not supported in this PHP version');\n        }\n\n        $classNode = (new ClassMirror())->reflect(new \\ReflectionClass('Fixtures\\Prophecy\\UnionArgumentTypeFalse'), []);\n        $methodNode = $classNode->getMethods()['method'];\n\n        $this->assertEquals(new ArgumentTypeNode(\\stdClass::class, 'false'), $methodNode->getArguments()[0]->getTypeNode());\n    }\n\n    #[Test]\n    public function it_can_double_a_class_with_mixed_types(): void\n    {\n        if (PHP_VERSION_ID < 80000) {\n            $this->markTestSkipped('Mixed type is not supported in this PHP version');\n        }\n\n        $classNode = (new ClassMirror())->reflect(new \\ReflectionClass('Fixtures\\Prophecy\\MixedTypes'), []);\n        $methodNode = $classNode->getMethods()['doSomething'];\n\n        $this->assertEquals(new ArgumentTypeNode('mixed'), $methodNode->getArguments()[0]->getTypeNode());\n        $this->assertEquals(new ReturnTypeNode('mixed'), $methodNode->getReturnTypeNode());\n    }\n\n    #[Test]\n    public function it_can_double_inherited_self_return_type(): void\n    {\n        $classNode = (new ClassMirror())->reflect(new \\ReflectionClass('Fixtures\\Prophecy\\ClassExtendAbstractWithMethodWithReturnType'), []);\n        $methodNode = $classNode->getMethods()['returnSelf'];\n\n        $this->assertEquals(new ReturnTypeNode('Fixtures\\Prophecy\\AbstractBaseClassWithMethodWithReturnType'), $methodNode->getReturnTypeNode());\n    }\n\n    #[Test]\n    public function it_can_double_never_return_type(): void\n    {\n        if (PHP_VERSION_ID < 80100) {\n            $this->markTestSkipped('Never type is not supported in this PHP version');\n        }\n\n        $classNode = (new ClassMirror())->reflect(new \\ReflectionClass('Fixtures\\Prophecy\\NeverType'), []);\n        $methodNode = $classNode->getMethods()['doSomething'];\n\n        $this->assertEquals(new ReturnTypeNode('never'), $methodNode->getReturnTypeNode());\n\n    }\n\n    #[Test]\n    public function it_can_not_double_an_enum(): void\n    {\n        if (PHP_VERSION_ID < 80100) {\n            $this->markTestSkipped('Enums are not supported in this PHP version');\n        }\n\n        $this->expectException(ClassMirrorException::class);\n\n        $classNode = (new ClassMirror())->reflect(new \\ReflectionClass('Fixtures\\Prophecy\\Enum'), []);\n    }\n\n    #[Test]\n    public function it_can_double_intersection_return_types(): void\n    {\n        if (PHP_VERSION_ID < 80100) {\n            $this->markTestSkipped('Intersection types are not supported in this PHP version');\n        }\n\n        $classNode = (new ClassMirror())->reflect(new \\ReflectionClass('Fixtures\\Prophecy\\IntersectionReturnType'), []);\n\n        $method = $classNode->getMethod('doSomething');\n        $returnType = $method->getReturnTypeNode();\n\n        $this->assertEquals(\n            new IntersectionType([\n                new ObjectType('Fixtures\\Prophecy\\Bar'),\n                new ObjectType('Fixtures\\Prophecy\\Baz'),\n            ]),\n            $returnType->getType()\n        );\n    }\n\n    #[Test]\n    public function it_can_double_intersection_argument_types(): void\n    {\n        if (PHP_VERSION_ID < 80100) {\n            $this->markTestSkipped('Intersection types are not supported in this PHP version');\n        }\n\n        $classNode = (new ClassMirror())->reflect(new \\ReflectionClass('Fixtures\\Prophecy\\IntersectionArgumentType'), []);\n\n        $method = $classNode->getMethod('doSomething');\n        $argType = $method->getArguments()[0]->getTypeNode();\n\n        $this->assertEquals(\n            new IntersectionType([\n                new ObjectType('Fixtures\\Prophecy\\Bar'),\n                new ObjectType('Fixtures\\Prophecy\\Baz'),\n            ]),\n            $argType->getType()\n        );\n    }\n\n    #[Test]\n    public function it_can_double_a_standalone_return_type_of_false(): void\n    {\n        if (PHP_VERSION_ID < 80200) {\n            $this->markTestSkipped('Standalone return type of false is not supported in this PHP version');\n        }\n\n        $classNode = (new ClassMirror())->reflect(new \\ReflectionClass('Fixtures\\Prophecy\\StandaloneReturnTypeFalse'), []);\n        $methodNode = $classNode->getMethods()['method'];\n\n        $this->assertEquals(new ReturnTypeNode('false'), $methodNode->getReturnTypeNode());\n    }\n\n    #[Test]\n    public function it_can_double_a_standalone_parameter_type_of_false(): void\n    {\n        if (PHP_VERSION_ID < 80200) {\n            $this->markTestSkipped('Standalone parameter type of false is not supported in this PHP version');\n        }\n\n        $classNode = (new ClassMirror())->reflect(new \\ReflectionClass('Fixtures\\Prophecy\\StandaloneParameterTypeFalse'), []);\n        $method = $classNode->getMethod('method');\n        $arguments = $method->getArguments();\n\n        $this->assertEquals(new ArgumentTypeNode('false'), $arguments[0]->getTypeNode());\n    }\n\n    #[Test]\n    public function it_can_double_a_nullable_return_type_of_false(): void\n    {\n        if (PHP_VERSION_ID < 80200) {\n            $this->markTestSkipped('Nullable return type of false is not supported in this PHP version');\n        }\n\n        $classNode = (new ClassMirror())->reflect(new \\ReflectionClass('Fixtures\\Prophecy\\NullableReturnTypeFalse'), []);\n        $methodNode = $classNode->getMethods()['method'];\n\n        $this->assertEquals(new ReturnTypeNode('null', 'false'), $methodNode->getReturnTypeNode());\n    }\n\n    #[Test]\n    public function it_can_double_a_nullable_parameter_type_of_false(): void\n    {\n        if (PHP_VERSION_ID < 80200) {\n            $this->markTestSkipped('Nullable parameter type of false is not supported in this PHP version');\n        }\n\n        $classNode = (new ClassMirror())->reflect(new \\ReflectionClass('Fixtures\\Prophecy\\NullableParameterTypeFalse'), []);\n        $method = $classNode->getMethod('method');\n        $arguments = $method->getArguments();\n\n        $this->assertEquals(new ArgumentTypeNode(new UnionType([\n            new BuiltinType('null'),\n            new BuiltinType('false'),\n        ])), $arguments[0]->getTypeNode());\n    }\n\n    #[Test]\n    public function it_can_not_double_dnf_intersection_argument_types(): void\n    {\n        if (PHP_VERSION_ID < 80200) {\n            $this->markTestSkipped('DNF intersection types are not supported in this PHP version');\n        }\n\n        $classNode = (new ClassMirror())->reflect(new \\ReflectionClass('Fixtures\\Prophecy\\DnfArgumentType'), []);\n\n\n        $method = $classNode->getMethod('doSomething');\n        $argType = $method->getArguments()[0]->getTypeNode();\n\n        $this->assertEquals(\n            new UnionType([\n                new IntersectionType([\n                    new ObjectType('Fixtures\\Prophecy\\A'),\n                    new ObjectType('Fixtures\\Prophecy\\B'),\n                ]),\n                new ObjectType('Fixtures\\Prophecy\\C'),\n            ]),\n            $argType->getType()\n        );\n    }\n\n    #[Test]\n    public function it_can_double_dnf_intersection_return_types(): void\n    {\n        $classNode = (new ClassMirror())->reflect(new \\ReflectionClass('Fixtures\\Prophecy\\DnfReturnType'), []);\n\n        $method = $classNode->getMethod('doSomething');\n        $returnType = $method->getReturnTypeNode();\n\n        $this->assertEquals(\n            new UnionType([\n                new IntersectionType([\n                    new ObjectType('Fixtures\\Prophecy\\A'),\n                    new ObjectType('Fixtures\\Prophecy\\B'),\n                ]),\n                new ObjectType('Fixtures\\Prophecy\\C'),\n            ]),\n            $returnType->getType()\n        );\n    }\n\n    #[Test]\n    public function it_can_double_a_standalone_return_type_of_true(): void\n    {\n        if (PHP_VERSION_ID < 80200) {\n            $this->markTestSkipped('Standalone return type of true is not supported in this PHP version');\n        }\n\n        $classNode = (new ClassMirror())->reflect(new \\ReflectionClass('Fixtures\\Prophecy\\StandaloneReturnTypeTrue'), []);\n        $methodNode = $classNode->getMethods()['method'];\n\n        $this->assertEquals(new ReturnTypeNode('true'), $methodNode->getReturnTypeNode());\n    }\n\n    #[Test]\n    public function it_reflects_non_read_only_class(): void\n    {\n        $classNode = (new ClassMirror())->reflect(\n            new \\ReflectionClass('Fixtures\\Prophecy\\EmptyClass'),\n            []\n        );\n\n        $this->assertFalse($classNode->isReadOnly());\n    }\n\n    #[Test]\n    public function it_can_double_a_standalone_parameter_type_of_true(): void\n    {\n        if (PHP_VERSION_ID < 80200) {\n            $this->markTestSkipped('Standalone parameter type of true is not supported in this PHP version');\n        }\n\n        $classNode = (new ClassMirror())->reflect(new \\ReflectionClass('Fixtures\\Prophecy\\StandaloneParameterTypeTrue'), []);\n        $method = $classNode->getMethod('method');\n        $arguments = $method->getArguments();\n\n        $this->assertEquals(new ArgumentTypeNode('true'), $arguments[0]->getTypeNode());\n    }\n\n    #[Test]\n    public function it_can_double_a_nullable_return_type_of_true(): void\n    {\n        if (PHP_VERSION_ID < 80200) {\n            $this->markTestSkipped('Nullable return type of true is not supported in this PHP version');\n        }\n\n        $classNode = (new ClassMirror())->reflect(new \\ReflectionClass('Fixtures\\Prophecy\\NullableReturnTypeTrue'), []);\n        $methodNode = $classNode->getMethods()['method'];\n\n        $this->assertEquals(new ReturnTypeNode('null', 'true'), $methodNode->getReturnTypeNode());\n    }\n\n    #[Test]\n    public function it_can_double_a_nullable_parameter_type_of_true(): void\n    {\n        if (PHP_VERSION_ID < 80200) {\n            $this->markTestSkipped('Nullable parameter type of true is not supported in this PHP version');\n        }\n\n        $classNode = (new ClassMirror())->reflect(new \\ReflectionClass('Fixtures\\Prophecy\\NullableParameterTypeTrue'), []);\n        $method = $classNode->getMethod('method');\n        $arguments = $method->getArguments();\n\n        $this->assertEquals(new ArgumentTypeNode(new UnionType([\n            new BuiltinType('null'),\n            new BuiltinType('true'),\n        ])), $arguments[0]->getTypeNode());\n    }\n\n    #[Test]\n    public function it_can_double_a_standalone_return_type_of_null(): void\n    {\n        if (PHP_VERSION_ID < 80200) {\n            $this->markTestSkipped('Standalone return type of null is not supported in this PHP version');\n        }\n\n        $classNode = (new ClassMirror())->reflect(new \\ReflectionClass('Fixtures\\Prophecy\\StandaloneReturnTypeNull'), []);\n        $methodNode = $classNode->getMethods()['method'];\n\n        $this->assertEquals(new ReturnTypeNode('null'), $methodNode->getReturnTypeNode());\n    }\n\n    #[Test]\n    public function it_can_double_a_standalone_parameter_type_of_null(): void\n    {\n        if (PHP_VERSION_ID < 80200) {\n            $this->markTestSkipped('Standalone parameter type of null is not supported in this PHP version');\n        }\n\n        $classNode = (new ClassMirror())->reflect(new \\ReflectionClass('Fixtures\\Prophecy\\StandaloneParameterTypeNull'), []);\n        $method = $classNode->getMethod('method');\n        $arguments = $method->getArguments();\n\n        $this->assertEquals(new ArgumentTypeNode('null'), $arguments[0]->getTypeNode());\n    }\n\n    #[Test]\n    public function it_reflects_read_only_class(): void\n    {\n        if (PHP_VERSION_ID < 80200) {\n            $this->markTestSkipped('Read only classes are not supported in this PHP version');\n        }\n\n        $classNode = (new ClassMirror())->reflect(\n            new \\ReflectionClass('Fixtures\\Prophecy\\ReadOnlyClass'),\n            []\n        );\n\n        $this->assertTrue($classNode->isReadOnly());\n    }\n}\n"
  },
  {
    "path": "tests/Doubler/Generator/Node/TypeNodeAbstractTest.php",
    "content": "<?php\n\nnamespace Tests\\Prophecy\\Doubler\\Generator\\Node;\n\nuse PHPUnit\\Framework\\Attributes\\DataProvider;\nuse PHPUnit\\Framework\\Attributes\\Test;\nuse PHPUnit\\Framework\\TestCase;\nuse Prophecy\\Doubler\\Generator\\Node\\ArgumentTypeNode;\nuse Prophecy\\Doubler\\Generator\\Node\\ReturnTypeNode;\nuse Prophecy\\Doubler\\Generator\\Node\\TypeNodeAbstract;\n\nclass TypeNodeAbstractTest extends TestCase\n{\n    /**\n     * @return \\Generator<array{0: TypeNodeAbstract, 1?: bool}>\n     */\n    public static function childClassDataProvider(): \\Generator\n    {\n        $typesCombination = [\n            ['bool', 'null'],\n            ['int', 'bool', 'null'],\n        ];\n\n        if (PHP_VERSION_ID >= 80200) {\n            $typesCombination[] = ['null'];\n        }\n\n        foreach ($typesCombination as $types) {\n            $count = count($types);\n            $expected = $count === 2;\n\n            yield $count.' return types' => [new ReturnTypeNode(...$types), $expected];\n            yield $count.' argument types' => [new ArgumentTypeNode(...$types), $expected];\n        }\n    }\n\n    #[DataProvider('childClassDataProvider')]\n    #[Test]\n    public function it_can_use_null_shorthand_only_with_two_types(TypeNodeAbstract $node, bool $expected): void\n    {\n        $this->assertSame($expected, $node->canUseNullShorthand());\n    }\n}\n"
  },
  {
    "path": "tests/FunctionalTest.php",
    "content": "<?php\n\nnamespace Tests\\Prophecy;\n\nuse Fixtures\\Prophecy\\ReturningFinalClass;\nuse PHPUnit\\Framework\\Attributes\\Test;\nuse PHPUnit\\Framework\\TestCase;\nuse Prophecy\\Doubler\\DoubleInterface;\nuse Prophecy\\Exception\\Prophecy\\MethodProphecyException;\nuse Prophecy\\Prophecy\\ProphecySubjectInterface;\nuse Prophecy\\Prophet;\n\nclass FunctionalTest extends TestCase\n{\n    #[Test]\n    public function case_insensitive_method_names(): void\n    {\n        $prophet = new Prophet();\n        $prophecy = $prophet->prophesize('ArrayObject');\n        $prophecy->offsetGet(1)->willReturn(1)->shouldBeCalledTimes(1);\n        $prophecy->offsetget(2)->willReturn(2)->shouldBeCalledTimes(1);\n        $prophecy->OffsetGet(3)->willReturn(3)->shouldBeCalledTimes(1);\n\n        $arrayObject = $prophecy->reveal();\n        self::assertSame(1, $arrayObject->offsetGet(1));\n        self::assertSame(2, $arrayObject->offsetGet(2));\n        self::assertSame(3, $arrayObject->offsetGet(3));\n    }\n\n    #[Test]\n    public function it_implements_the_double_interface(): void\n    {\n        $prophet = new Prophet();\n        $object = $prophet->prophesize('stdClass')->reveal();\n\n        $this->assertInstanceOf(DoubleInterface::class, $object);\n    }\n\n    #[Test]\n    public function it_implements_the_prophecy_subject_interface(): void\n    {\n        $prophet = new Prophet();\n        $object = $prophet->prophesize('stdClass')->reveal();\n\n        $this->assertInstanceOf(ProphecySubjectInterface::class, $object);\n    }\n\n    public function testUnconfiguredFinalReturnType(): void\n    {\n        $prophet = new Prophet();\n        $object = $prophet->prophesize(ReturningFinalClass::class);\n\n        $object->doSomething()->shouldBeCalled();\n\n        $double = $object->reveal();\n\n        $this->expectException(MethodProphecyException::class);\n        $this->expectExceptionMessage('Cannot create a return value for the method. Configure an explicit return value instead.');\n\n        $double->doSomething();\n    }\n}\n"
  }
]