diff --git a/.gitignore b/.gitignore index 7278a54..36b6252 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ vendor/ -composer.lock .idea/ state/*-* build/* phpunit.xml +.php_cs.cache +.php_cs.result.cache diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php new file mode 100644 index 0000000..f2388aa --- /dev/null +++ b/.php-cs-fixer.dist.php @@ -0,0 +1,19 @@ +in(__DIR__ . '/src') + ->in(__DIR__ . '/tests'); + +return (new PhpCsFixer\Config()) + ->setRules([ + '@Symfony' => true, + 'array_syntax' => ['syntax' => 'short'], + 'combine_consecutive_unsets' => true, + 'concat_space' => ['spacing' => 'one'], + 'return_type_declaration' => ['space_before' => 'one'], + 'no_unreachable_default_argument_value' => false, + 'yoda_style' => false, + 'ordered_imports' => ['sort_algorithm' => 'alpha'], + 'increment_style' => ['style' => 'post'] + ]) + ->setFinder($finder); diff --git a/.php_cs.dist b/.php_cs.dist new file mode 100644 index 0000000..f07918d --- /dev/null +++ b/.php_cs.dist @@ -0,0 +1,19 @@ +in(__DIR__ . '/src') + ->in(__DIR__ . '/tests'); + +return PhpCsFixer\Config::create() + ->setRules([ + '@Symfony' => true, + 'array_syntax' => ['syntax' => 'short'], + 'combine_consecutive_unsets' => true, + 'concat_space' => ['spacing' => 'one'], + 'return_type_declaration' => ['space_before' => 'one'], + 'no_unreachable_default_argument_value' => false, + 'yoda_style' => false, + 'ordered_imports' => ['sortAlgorithm' => 'alpha'], + 'pre_increment' => false, + ]) + ->setFinder($finder); diff --git a/.travis.yml b/.travis.yml index 4974134..47fe754 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,9 +1,9 @@ language: php php: - - 7.1 - 7.2 - 7.3 + - 7.4 before_script: - composer install @@ -11,5 +11,5 @@ before_script: sudo: false script: - - ./vendor/bin/phpcs --standard=vendor/internations/kodierungsregelwerksammlung/ruleset.xml ./src/ + - composer lint:check - ./vendor/bin/phpunit diff --git a/composer.json b/composer.json index fd71746..e4b2ece 100644 --- a/composer.json +++ b/composer.json @@ -1,6 +1,6 @@ { "name": "internations/http-mock", - "description": "Mock HTTP requests on the server side in your PHP unit tests", + "description": "Mock HTTP requests on the server side in your PHP unit tests, PSR/7 Fork of internations version", "license": "MIT", "authors": [ { @@ -10,25 +10,54 @@ { "name": "Max Beutel", "email": "max.beutel@internations.org" + }, + { + "name": "Joshua Eichorn", + "email": "joshua.eichorn@pagely.com" } ], - "require": { - "php": "~7.1", - "silex/silex": "~2.0", - "guzzle/guzzle": ">=3.8", - "symfony/process": "~3|~4", + "require": { + "php": "~7.2", + "ext-json": "*", + "symfony/process": "~3|~4|~5", "jeremeamia/superclosure": "~2", - "lstrojny/hmmmath": ">=0.5.0" + "lstrojny/hmmmath": ">=0.5.0", + "guzzlehttp/guzzle": "^6.3|~7", + "slim/slim": "^3.12", + "friendsofphp/php-cs-fixer": "3.4.0" }, "require-dev": { - "internations/kodierungsregelwerksammlung": "~0.23.0", - "internations/testing-component": "1.0.1", + "internations/testing-component": "1.3.0", "phpunit/phpunit": "^7" }, "autoload": { - "psr-4": {"InterNations\\Component\\HttpMock\\": "src/"} + "psr-4": { + "InterNations\\Component\\HttpMock\\": "src/" + } }, "autoload-dev": { - "psr-4": {"InterNations\\Component\\HttpMock\\Tests\\": "tests/"} + "psr-4": { + "InterNations\\Component\\HttpMock\\Tests\\": "tests/" + } + }, + "scripts": { + "auto-scripts": [ + "@security-check" + ], + "post-install-cmd": [ + "@auto-scripts" + ], + "post-update-cmd": [ + "@auto-scripts" + ], + "lint": [ + "php-cs-fixer fix --ansi --verbose --show-progress=dots" + ], + "lint:check": [ + "@lint --dry-run" + ], + "security-check": [ + "local-php-security-checker-installer && local-php-security-checker" + ] } } diff --git a/composer.lock b/composer.lock new file mode 100644 index 0000000..21fa161 --- /dev/null +++ b/composer.lock @@ -0,0 +1,4743 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", + "This file is @generated automatically" + ], + "content-hash": "d436ff32fe1a31062076b35a557341b9", + "packages": [ + { + "name": "composer/pcre", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/composer/pcre.git", + "reference": "67a32d7d6f9f560b726ab25a061b38ff3a80c560" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer/pcre/zipball/67a32d7d6f9f560b726ab25a061b38ff3a80c560", + "reference": "67a32d7d6f9f560b726ab25a061b38ff3a80c560", + "shasum": "" + }, + "require": { + "php": "^5.3.2 || ^7.0 || ^8.0" + }, + "require-dev": { + "phpstan/phpstan": "^1.3", + "phpstan/phpstan-strict-rules": "^1.1", + "symfony/phpunit-bridge": "^4.2 || ^5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Composer\\Pcre\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be" + } + ], + "description": "PCRE wrapping library that offers type-safe preg_* replacements.", + "keywords": [ + "PCRE", + "preg", + "regex", + "regular expression" + ], + "support": { + "issues": "https://github.com/composer/pcre/issues", + "source": "https://github.com/composer/pcre/tree/1.0.1" + }, + "funding": [ + { + "url": "https://packagist.com", + "type": "custom" + }, + { + "url": "https://github.com/composer", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/composer/composer", + "type": "tidelift" + } + ], + "time": "2022-01-21T20:24:37+00:00" + }, + { + "name": "composer/semver", + "version": "3.3.2", + "source": { + "type": "git", + "url": "https://github.com/composer/semver.git", + "reference": "3953f23262f2bff1919fc82183ad9acb13ff62c9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer/semver/zipball/3953f23262f2bff1919fc82183ad9acb13ff62c9", + "reference": "3953f23262f2bff1919fc82183ad9acb13ff62c9", + "shasum": "" + }, + "require": { + "php": "^5.3.2 || ^7.0 || ^8.0" + }, + "require-dev": { + "phpstan/phpstan": "^1.4", + "symfony/phpunit-bridge": "^4.2 || ^5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Composer\\Semver\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nils Adermann", + "email": "naderman@naderman.de", + "homepage": "http://www.naderman.de" + }, + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be" + }, + { + "name": "Rob Bast", + "email": "rob.bast@gmail.com", + "homepage": "http://robbast.nl" + } + ], + "description": "Semver library that offers utilities, version constraint parsing and validation.", + "keywords": [ + "semantic", + "semver", + "validation", + "versioning" + ], + "support": { + "irc": "irc://irc.freenode.org/composer", + "issues": "https://github.com/composer/semver/issues", + "source": "https://github.com/composer/semver/tree/3.3.2" + }, + "funding": [ + { + "url": "https://packagist.com", + "type": "custom" + }, + { + "url": "https://github.com/composer", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/composer/composer", + "type": "tidelift" + } + ], + "time": "2022-04-01T19:23:25+00:00" + }, + { + "name": "composer/xdebug-handler", + "version": "2.0.5", + "source": { + "type": "git", + "url": "https://github.com/composer/xdebug-handler.git", + "reference": "9e36aeed4616366d2b690bdce11f71e9178c579a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/9e36aeed4616366d2b690bdce11f71e9178c579a", + "reference": "9e36aeed4616366d2b690bdce11f71e9178c579a", + "shasum": "" + }, + "require": { + "composer/pcre": "^1", + "php": "^5.3.2 || ^7.0 || ^8.0", + "psr/log": "^1 || ^2 || ^3" + }, + "require-dev": { + "phpstan/phpstan": "^1.0", + "phpstan/phpstan-strict-rules": "^1.1", + "symfony/phpunit-bridge": "^4.2 || ^5.0 || ^6.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Composer\\XdebugHandler\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "John Stevenson", + "email": "john-stevenson@blueyonder.co.uk" + } + ], + "description": "Restarts a process without Xdebug.", + "keywords": [ + "Xdebug", + "performance" + ], + "support": { + "irc": "irc://irc.freenode.org/composer", + "issues": "https://github.com/composer/xdebug-handler/issues", + "source": "https://github.com/composer/xdebug-handler/tree/2.0.5" + }, + "funding": [ + { + "url": "https://packagist.com", + "type": "custom" + }, + { + "url": "https://github.com/composer", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/composer/composer", + "type": "tidelift" + } + ], + "time": "2022-02-24T20:20:32+00:00" + }, + { + "name": "doctrine/annotations", + "version": "1.13.2", + "source": { + "type": "git", + "url": "https://github.com/doctrine/annotations.git", + "reference": "5b668aef16090008790395c02c893b1ba13f7e08" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/annotations/zipball/5b668aef16090008790395c02c893b1ba13f7e08", + "reference": "5b668aef16090008790395c02c893b1ba13f7e08", + "shasum": "" + }, + "require": { + "doctrine/lexer": "1.*", + "ext-tokenizer": "*", + "php": "^7.1 || ^8.0", + "psr/cache": "^1 || ^2 || ^3" + }, + "require-dev": { + "doctrine/cache": "^1.11 || ^2.0", + "doctrine/coding-standard": "^6.0 || ^8.1", + "phpstan/phpstan": "^0.12.20", + "phpunit/phpunit": "^7.5 || ^8.0 || ^9.1.5", + "symfony/cache": "^4.4 || ^5.2" + }, + "type": "library", + "autoload": { + "psr-4": { + "Doctrine\\Common\\Annotations\\": "lib/Doctrine/Common/Annotations" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "Docblock Annotations Parser", + "homepage": "https://www.doctrine-project.org/projects/annotations.html", + "keywords": [ + "annotations", + "docblock", + "parser" + ], + "support": { + "issues": "https://github.com/doctrine/annotations/issues", + "source": "https://github.com/doctrine/annotations/tree/1.13.2" + }, + "time": "2021-08-05T19:00:23+00:00" + }, + { + "name": "doctrine/lexer", + "version": "1.2.3", + "source": { + "type": "git", + "url": "https://github.com/doctrine/lexer.git", + "reference": "c268e882d4dbdd85e36e4ad69e02dc284f89d229" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/lexer/zipball/c268e882d4dbdd85e36e4ad69e02dc284f89d229", + "reference": "c268e882d4dbdd85e36e4ad69e02dc284f89d229", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0" + }, + "require-dev": { + "doctrine/coding-standard": "^9.0", + "phpstan/phpstan": "^1.3", + "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", + "vimeo/psalm": "^4.11" + }, + "type": "library", + "autoload": { + "psr-4": { + "Doctrine\\Common\\Lexer\\": "lib/Doctrine/Common/Lexer" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "PHP Doctrine Lexer parser library that can be used in Top-Down, Recursive Descent Parsers.", + "homepage": "https://www.doctrine-project.org/projects/lexer.html", + "keywords": [ + "annotations", + "docblock", + "lexer", + "parser", + "php" + ], + "support": { + "issues": "https://github.com/doctrine/lexer/issues", + "source": "https://github.com/doctrine/lexer/tree/1.2.3" + }, + "funding": [ + { + "url": "https://www.doctrine-project.org/sponsorship.html", + "type": "custom" + }, + { + "url": "https://www.patreon.com/phpdoctrine", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/doctrine%2Flexer", + "type": "tidelift" + } + ], + "time": "2022-02-28T11:07:21+00:00" + }, + { + "name": "friendsofphp/php-cs-fixer", + "version": "v3.4.0", + "source": { + "type": "git", + "url": "https://github.com/FriendsOfPHP/PHP-CS-Fixer.git", + "reference": "47177af1cfb9dab5d1cc4daf91b7179c2efe7fad" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/FriendsOfPHP/PHP-CS-Fixer/zipball/47177af1cfb9dab5d1cc4daf91b7179c2efe7fad", + "reference": "47177af1cfb9dab5d1cc4daf91b7179c2efe7fad", + "shasum": "" + }, + "require": { + "composer/semver": "^3.2", + "composer/xdebug-handler": "^2.0", + "doctrine/annotations": "^1.12", + "ext-json": "*", + "ext-tokenizer": "*", + "php": "^7.2.5 || ^8.0", + "php-cs-fixer/diff": "^2.0", + "symfony/console": "^4.4.20 || ^5.1.3 || ^6.0", + "symfony/event-dispatcher": "^4.4.20 || ^5.0 || ^6.0", + "symfony/filesystem": "^4.4.20 || ^5.0 || ^6.0", + "symfony/finder": "^4.4.20 || ^5.0 || ^6.0", + "symfony/options-resolver": "^4.4.20 || ^5.0 || ^6.0", + "symfony/polyfill-mbstring": "^1.23", + "symfony/polyfill-php80": "^1.23", + "symfony/polyfill-php81": "^1.23", + "symfony/process": "^4.4.20 || ^5.0 || ^6.0", + "symfony/stopwatch": "^4.4.20 || ^5.0 || ^6.0" + }, + "require-dev": { + "justinrainbow/json-schema": "^5.2", + "keradus/cli-executor": "^1.5", + "mikey179/vfsstream": "^1.6.8", + "php-coveralls/php-coveralls": "^2.5.2", + "php-cs-fixer/accessible-object": "^1.1", + "php-cs-fixer/phpunit-constraint-isidenticalstring": "^1.2", + "php-cs-fixer/phpunit-constraint-xmlmatchesxsd": "^1.2.1", + "phpspec/prophecy": "^1.15", + "phpspec/prophecy-phpunit": "^1.1 || ^2.0", + "phpunit/phpunit": "^8.5.21 || ^9.5", + "phpunitgoodpractices/polyfill": "^1.5", + "phpunitgoodpractices/traits": "^1.9.1", + "symfony/phpunit-bridge": "^5.2.4 || ^6.0", + "symfony/yaml": "^4.4.20 || ^5.0 || ^6.0" + }, + "suggest": { + "ext-dom": "For handling output formats in XML", + "ext-mbstring": "For handling non-UTF8 characters." + }, + "bin": [ + "php-cs-fixer" + ], + "type": "application", + "autoload": { + "psr-4": { + "PhpCsFixer\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Dariusz Rumiński", + "email": "dariusz.ruminski@gmail.com" + } + ], + "description": "A tool to automatically fix PHP code style", + "support": { + "issues": "https://github.com/FriendsOfPHP/PHP-CS-Fixer/issues", + "source": "https://github.com/FriendsOfPHP/PHP-CS-Fixer/tree/v3.4.0" + }, + "funding": [ + { + "url": "https://github.com/keradus", + "type": "github" + } + ], + "time": "2021-12-11T16:25:08+00:00" + }, + { + "name": "guzzlehttp/guzzle", + "version": "7.4.4", + "source": { + "type": "git", + "url": "https://github.com/guzzle/guzzle.git", + "reference": "e3ff079b22820c2029d4c2a87796b6a0b8716ad8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/e3ff079b22820c2029d4c2a87796b6a0b8716ad8", + "reference": "e3ff079b22820c2029d4c2a87796b6a0b8716ad8", + "shasum": "" + }, + "require": { + "ext-json": "*", + "guzzlehttp/promises": "^1.5", + "guzzlehttp/psr7": "^1.8.3 || ^2.1", + "php": "^7.2.5 || ^8.0", + "psr/http-client": "^1.0", + "symfony/deprecation-contracts": "^2.2 || ^3.0" + }, + "provide": { + "psr/http-client-implementation": "1.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.4.1", + "ext-curl": "*", + "php-http/client-integration-tests": "^3.0", + "phpunit/phpunit": "^8.5.5 || ^9.3.5", + "psr/log": "^1.1 || ^2.0 || ^3.0" + }, + "suggest": { + "ext-curl": "Required for CURL handler support", + "ext-intl": "Required for Internationalized Domain Name (IDN) support", + "psr/log": "Required for using the Log middleware" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "7.4-dev" + } + }, + "autoload": { + "files": [ + "src/functions_include.php" + ], + "psr-4": { + "GuzzleHttp\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "Jeremy Lindblom", + "email": "jeremeamia@gmail.com", + "homepage": "https://github.com/jeremeamia" + }, + { + "name": "George Mponos", + "email": "gmponos@gmail.com", + "homepage": "https://github.com/gmponos" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://github.com/sagikazarmark" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" + } + ], + "description": "Guzzle is a PHP HTTP client library", + "keywords": [ + "client", + "curl", + "framework", + "http", + "http client", + "psr-18", + "psr-7", + "rest", + "web service" + ], + "support": { + "issues": "https://github.com/guzzle/guzzle/issues", + "source": "https://github.com/guzzle/guzzle/tree/7.4.4" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/guzzle", + "type": "tidelift" + } + ], + "time": "2022-06-09T21:39:15+00:00" + }, + { + "name": "guzzlehttp/promises", + "version": "1.5.1", + "source": { + "type": "git", + "url": "https://github.com/guzzle/promises.git", + "reference": "fe752aedc9fd8fcca3fe7ad05d419d32998a06da" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/promises/zipball/fe752aedc9fd8fcca3fe7ad05d419d32998a06da", + "reference": "fe752aedc9fd8fcca3fe7ad05d419d32998a06da", + "shasum": "" + }, + "require": { + "php": ">=5.5" + }, + "require-dev": { + "symfony/phpunit-bridge": "^4.4 || ^5.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.5-dev" + } + }, + "autoload": { + "files": [ + "src/functions_include.php" + ], + "psr-4": { + "GuzzleHttp\\Promise\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" + } + ], + "description": "Guzzle promises library", + "keywords": [ + "promise" + ], + "support": { + "issues": "https://github.com/guzzle/promises/issues", + "source": "https://github.com/guzzle/promises/tree/1.5.1" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/promises", + "type": "tidelift" + } + ], + "time": "2021-10-22T20:56:57+00:00" + }, + { + "name": "guzzlehttp/psr7", + "version": "2.3.0", + "source": { + "type": "git", + "url": "https://github.com/guzzle/psr7.git", + "reference": "83260bb50b8fc753c72d14dc1621a2dac31877ee" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/83260bb50b8fc753c72d14dc1621a2dac31877ee", + "reference": "83260bb50b8fc753c72d14dc1621a2dac31877ee", + "shasum": "" + }, + "require": { + "php": "^7.2.5 || ^8.0", + "psr/http-factory": "^1.0", + "psr/http-message": "^1.0", + "ralouphie/getallheaders": "^3.0" + }, + "provide": { + "psr/http-factory-implementation": "1.0", + "psr/http-message-implementation": "1.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.4.1", + "http-interop/http-factory-tests": "^0.9", + "phpunit/phpunit": "^8.5.8 || ^9.3.10" + }, + "suggest": { + "laminas/laminas-httphandlerrunner": "Emit PSR-7 responses" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.3-dev" + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\Psr7\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "George Mponos", + "email": "gmponos@gmail.com", + "homepage": "https://github.com/gmponos" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://github.com/sagikazarmark" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://sagikazarmark.hu" + } + ], + "description": "PSR-7 message implementation that also provides common utility methods", + "keywords": [ + "http", + "message", + "psr-7", + "request", + "response", + "stream", + "uri", + "url" + ], + "support": { + "issues": "https://github.com/guzzle/psr7/issues", + "source": "https://github.com/guzzle/psr7/tree/2.3.0" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/psr7", + "type": "tidelift" + } + ], + "time": "2022-06-09T08:26:02+00:00" + }, + { + "name": "jeremeamia/superclosure", + "version": "2.4.0", + "source": { + "type": "git", + "url": "https://github.com/jeremeamia/super_closure.git", + "reference": "5707d5821b30b9a07acfb4d76949784aaa0e9ce9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/jeremeamia/super_closure/zipball/5707d5821b30b9a07acfb4d76949784aaa0e9ce9", + "reference": "5707d5821b30b9a07acfb4d76949784aaa0e9ce9", + "shasum": "" + }, + "require": { + "nikic/php-parser": "^1.2|^2.0|^3.0|^4.0", + "php": ">=5.4", + "symfony/polyfill-php56": "^1.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.0|^5.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.4-dev" + } + }, + "autoload": { + "psr-4": { + "SuperClosure\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jeremy Lindblom", + "email": "jeremeamia@gmail.com", + "homepage": "https://github.com/jeremeamia", + "role": "Developer" + } + ], + "description": "Serialize Closure objects, including their context and binding", + "homepage": "https://github.com/jeremeamia/super_closure", + "keywords": [ + "closure", + "function", + "lambda", + "parser", + "serializable", + "serialize", + "tokenizer" + ], + "support": { + "issues": "https://github.com/jeremeamia/super_closure/issues", + "source": "https://github.com/jeremeamia/super_closure/tree/master" + }, + "abandoned": "opis/closure", + "time": "2018-03-21T22:21:57+00:00" + }, + { + "name": "lstrojny/hmmmath", + "version": "0.8.0", + "source": { + "type": "git", + "url": "https://github.com/lstrojny/hmmmath.git", + "reference": "8e562c70f89b5580ed99674b849e3587b52f704b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/lstrojny/hmmmath/zipball/8e562c70f89b5580ed99674b849e3587b52f704b", + "reference": "8e562c70f89b5580ed99674b849e3587b52f704b", + "shasum": "" + }, + "require": { + "php": "^7.2|^8.0" + }, + "require-dev": { + "phpunit/phpunit": "^8.5" + }, + "type": "library", + "autoload": { + "psr-0": { + "hmmmath\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Lars Strojny", + "email": "lars@strojny.net" + } + ], + "description": "Collection of math related PHP functions", + "support": { + "issues": "https://github.com/lstrojny/hmmmath/issues", + "source": "https://github.com/lstrojny/hmmmath/tree/0.8.0" + }, + "time": "2020-12-17T11:21:54+00:00" + }, + { + "name": "nikic/fast-route", + "version": "v1.3.0", + "source": { + "type": "git", + "url": "https://github.com/nikic/FastRoute.git", + "reference": "181d480e08d9476e61381e04a71b34dc0432e812" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nikic/FastRoute/zipball/181d480e08d9476e61381e04a71b34dc0432e812", + "reference": "181d480e08d9476e61381e04a71b34dc0432e812", + "shasum": "" + }, + "require": { + "php": ">=5.4.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.8.35|~5.7" + }, + "type": "library", + "autoload": { + "files": [ + "src/functions.php" + ], + "psr-4": { + "FastRoute\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Nikita Popov", + "email": "nikic@php.net" + } + ], + "description": "Fast request router for PHP", + "keywords": [ + "router", + "routing" + ], + "support": { + "issues": "https://github.com/nikic/FastRoute/issues", + "source": "https://github.com/nikic/FastRoute/tree/master" + }, + "time": "2018-02-13T20:26:39+00:00" + }, + { + "name": "nikic/php-parser", + "version": "v4.14.0", + "source": { + "type": "git", + "url": "https://github.com/nikic/PHP-Parser.git", + "reference": "34bea19b6e03d8153165d8f30bba4c3be86184c1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/34bea19b6e03d8153165d8f30bba4c3be86184c1", + "reference": "34bea19b6e03d8153165d8f30bba4c3be86184c1", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "php": ">=7.0" + }, + "require-dev": { + "ircmaxell/php-yacc": "^0.0.7", + "phpunit/phpunit": "^6.5 || ^7.0 || ^8.0 || ^9.0" + }, + "bin": [ + "bin/php-parse" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.9-dev" + } + }, + "autoload": { + "psr-4": { + "PhpParser\\": "lib/PhpParser" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Nikita Popov" + } + ], + "description": "A PHP parser written in PHP", + "keywords": [ + "parser", + "php" + ], + "support": { + "issues": "https://github.com/nikic/PHP-Parser/issues", + "source": "https://github.com/nikic/PHP-Parser/tree/v4.14.0" + }, + "time": "2022-05-31T20:59:12+00:00" + }, + { + "name": "php-cs-fixer/diff", + "version": "v2.0.2", + "source": { + "type": "git", + "url": "https://github.com/PHP-CS-Fixer/diff.git", + "reference": "29dc0d507e838c4580d018bd8b5cb412474f7ec3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/PHP-CS-Fixer/diff/zipball/29dc0d507e838c4580d018bd8b5cb412474f7ec3", + "reference": "29dc0d507e838c4580d018bd8b5cb412474f7ec3", + "shasum": "" + }, + "require": { + "php": "^5.6 || ^7.0 || ^8.0" + }, + "require-dev": { + "phpunit/phpunit": "^5.7.23 || ^6.4.3 || ^7.0", + "symfony/process": "^3.3" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Kore Nordmann", + "email": "mail@kore-nordmann.de" + } + ], + "description": "sebastian/diff v3 backport support for PHP 5.6+", + "homepage": "https://github.com/PHP-CS-Fixer", + "keywords": [ + "diff" + ], + "support": { + "issues": "https://github.com/PHP-CS-Fixer/diff/issues", + "source": "https://github.com/PHP-CS-Fixer/diff/tree/v2.0.2" + }, + "time": "2020-10-14T08:32:19+00:00" + }, + { + "name": "pimple/pimple", + "version": "v3.5.0", + "source": { + "type": "git", + "url": "https://github.com/silexphp/Pimple.git", + "reference": "a94b3a4db7fb774b3d78dad2315ddc07629e1bed" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/silexphp/Pimple/zipball/a94b3a4db7fb774b3d78dad2315ddc07629e1bed", + "reference": "a94b3a4db7fb774b3d78dad2315ddc07629e1bed", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "psr/container": "^1.1 || ^2.0" + }, + "require-dev": { + "symfony/phpunit-bridge": "^5.4@dev" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.4.x-dev" + } + }, + "autoload": { + "psr-0": { + "Pimple": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + } + ], + "description": "Pimple, a simple Dependency Injection Container", + "homepage": "https://pimple.symfony.com", + "keywords": [ + "container", + "dependency injection" + ], + "support": { + "source": "https://github.com/silexphp/Pimple/tree/v3.5.0" + }, + "time": "2021-10-28T11:13:42+00:00" + }, + { + "name": "psr/cache", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/cache.git", + "reference": "d11b50ad223250cf17b86e38383413f5a6764bf8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/cache/zipball/d11b50ad223250cf17b86e38383413f5a6764bf8", + "reference": "d11b50ad223250cf17b86e38383413f5a6764bf8", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Cache\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for caching libraries", + "keywords": [ + "cache", + "psr", + "psr-6" + ], + "support": { + "source": "https://github.com/php-fig/cache/tree/master" + }, + "time": "2016-08-06T20:24:11+00:00" + }, + { + "name": "psr/container", + "version": "1.1.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/container.git", + "reference": "8622567409010282b7aeebe4bb841fe98b58dcaf" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/container/zipball/8622567409010282b7aeebe4bb841fe98b58dcaf", + "reference": "8622567409010282b7aeebe4bb841fe98b58dcaf", + "shasum": "" + }, + "require": { + "php": ">=7.2.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Psr\\Container\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common Container Interface (PHP FIG PSR-11)", + "homepage": "https://github.com/php-fig/container", + "keywords": [ + "PSR-11", + "container", + "container-interface", + "container-interop", + "psr" + ], + "support": { + "issues": "https://github.com/php-fig/container/issues", + "source": "https://github.com/php-fig/container/tree/1.1.1" + }, + "time": "2021-03-05T17:36:06+00:00" + }, + { + "name": "psr/event-dispatcher", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/event-dispatcher.git", + "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/event-dispatcher/zipball/dbefd12671e8a14ec7f180cab83036ed26714bb0", + "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0", + "shasum": "" + }, + "require": { + "php": ">=7.2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\EventDispatcher\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Standard interfaces for event handling.", + "keywords": [ + "events", + "psr", + "psr-14" + ], + "support": { + "issues": "https://github.com/php-fig/event-dispatcher/issues", + "source": "https://github.com/php-fig/event-dispatcher/tree/1.0.0" + }, + "time": "2019-01-08T18:20:26+00:00" + }, + { + "name": "psr/http-client", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-client.git", + "reference": "2dfb5f6c5eff0e91e20e913f8c5452ed95b86621" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-client/zipball/2dfb5f6c5eff0e91e20e913f8c5452ed95b86621", + "reference": "2dfb5f6c5eff0e91e20e913f8c5452ed95b86621", + "shasum": "" + }, + "require": { + "php": "^7.0 || ^8.0", + "psr/http-message": "^1.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Client\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP clients", + "homepage": "https://github.com/php-fig/http-client", + "keywords": [ + "http", + "http-client", + "psr", + "psr-18" + ], + "support": { + "source": "https://github.com/php-fig/http-client/tree/master" + }, + "time": "2020-06-29T06:28:15+00:00" + }, + { + "name": "psr/http-factory", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-factory.git", + "reference": "12ac7fcd07e5b077433f5f2bee95b3a771bf61be" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-factory/zipball/12ac7fcd07e5b077433f5f2bee95b3a771bf61be", + "reference": "12ac7fcd07e5b077433f5f2bee95b3a771bf61be", + "shasum": "" + }, + "require": { + "php": ">=7.0.0", + "psr/http-message": "^1.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interfaces for PSR-7 HTTP message factories", + "keywords": [ + "factory", + "http", + "message", + "psr", + "psr-17", + "psr-7", + "request", + "response" + ], + "support": { + "source": "https://github.com/php-fig/http-factory/tree/master" + }, + "time": "2019-04-30T12:38:16+00:00" + }, + { + "name": "psr/http-message", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-message.git", + "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-message/zipball/f6561bf28d520154e4b0ec72be95418abe6d9363", + "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP messages", + "homepage": "https://github.com/php-fig/http-message", + "keywords": [ + "http", + "http-message", + "psr", + "psr-7", + "request", + "response" + ], + "support": { + "source": "https://github.com/php-fig/http-message/tree/master" + }, + "time": "2016-08-06T14:39:51+00:00" + }, + { + "name": "psr/log", + "version": "1.1.4", + "source": { + "type": "git", + "url": "https://github.com/php-fig/log.git", + "reference": "d49695b909c3b7628b6289db5479a1c204601f11" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/log/zipball/d49695b909c3b7628b6289db5479a1c204601f11", + "reference": "d49695b909c3b7628b6289db5479a1c204601f11", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Log\\": "Psr/Log/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for logging libraries", + "homepage": "https://github.com/php-fig/log", + "keywords": [ + "log", + "psr", + "psr-3" + ], + "support": { + "source": "https://github.com/php-fig/log/tree/1.1.4" + }, + "time": "2021-05-03T11:20:27+00:00" + }, + { + "name": "ralouphie/getallheaders", + "version": "3.0.3", + "source": { + "type": "git", + "url": "https://github.com/ralouphie/getallheaders.git", + "reference": "120b605dfeb996808c31b6477290a714d356e822" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ralouphie/getallheaders/zipball/120b605dfeb996808c31b6477290a714d356e822", + "reference": "120b605dfeb996808c31b6477290a714d356e822", + "shasum": "" + }, + "require": { + "php": ">=5.6" + }, + "require-dev": { + "php-coveralls/php-coveralls": "^2.1", + "phpunit/phpunit": "^5 || ^6.5" + }, + "type": "library", + "autoload": { + "files": [ + "src/getallheaders.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ralph Khattar", + "email": "ralph.khattar@gmail.com" + } + ], + "description": "A polyfill for getallheaders.", + "support": { + "issues": "https://github.com/ralouphie/getallheaders/issues", + "source": "https://github.com/ralouphie/getallheaders/tree/develop" + }, + "time": "2019-03-08T08:55:37+00:00" + }, + { + "name": "slim/slim", + "version": "3.12.3", + "source": { + "type": "git", + "url": "https://github.com/slimphp/Slim.git", + "reference": "1c9318a84ffb890900901136d620b4f03a59da38" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/slimphp/Slim/zipball/1c9318a84ffb890900901136d620b4f03a59da38", + "reference": "1c9318a84ffb890900901136d620b4f03a59da38", + "shasum": "" + }, + "require": { + "ext-json": "*", + "ext-libxml": "*", + "ext-simplexml": "*", + "nikic/fast-route": "^1.0", + "php": ">=5.5.0", + "pimple/pimple": "^3.0", + "psr/container": "^1.0", + "psr/http-message": "^1.0" + }, + "provide": { + "psr/http-message-implementation": "1.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.0", + "squizlabs/php_codesniffer": "^2.5" + }, + "type": "library", + "autoload": { + "psr-4": { + "Slim\\": "Slim" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Josh Lockhart", + "email": "hello@joshlockhart.com", + "homepage": "https://joshlockhart.com" + }, + { + "name": "Andrew Smith", + "email": "a.smith@silentworks.co.uk", + "homepage": "http://silentworks.co.uk" + }, + { + "name": "Rob Allen", + "email": "rob@akrabat.com", + "homepage": "http://akrabat.com" + }, + { + "name": "Gabriel Manricks", + "email": "gmanricks@me.com", + "homepage": "http://gabrielmanricks.com" + } + ], + "description": "Slim is a PHP micro framework that helps you quickly write simple yet powerful web applications and APIs", + "homepage": "https://slimframework.com", + "keywords": [ + "api", + "framework", + "micro", + "router" + ], + "support": { + "issues": "https://github.com/slimphp/Slim/issues", + "source": "https://github.com/slimphp/Slim/tree/3.x" + }, + "time": "2019-11-28T17:40:33+00:00" + }, + { + "name": "symfony/console", + "version": "v5.4.9", + "source": { + "type": "git", + "url": "https://github.com/symfony/console.git", + "reference": "829d5d1bf60b2efeb0887b7436873becc71a45eb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/console/zipball/829d5d1bf60b2efeb0887b7436873becc71a45eb", + "reference": "829d5d1bf60b2efeb0887b7436873becc71a45eb", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/deprecation-contracts": "^2.1|^3", + "symfony/polyfill-mbstring": "~1.0", + "symfony/polyfill-php73": "^1.9", + "symfony/polyfill-php80": "^1.16", + "symfony/service-contracts": "^1.1|^2|^3", + "symfony/string": "^5.1|^6.0" + }, + "conflict": { + "psr/log": ">=3", + "symfony/dependency-injection": "<4.4", + "symfony/dotenv": "<5.1", + "symfony/event-dispatcher": "<4.4", + "symfony/lock": "<4.4", + "symfony/process": "<4.4" + }, + "provide": { + "psr/log-implementation": "1.0|2.0" + }, + "require-dev": { + "psr/log": "^1|^2", + "symfony/config": "^4.4|^5.0|^6.0", + "symfony/dependency-injection": "^4.4|^5.0|^6.0", + "symfony/event-dispatcher": "^4.4|^5.0|^6.0", + "symfony/lock": "^4.4|^5.0|^6.0", + "symfony/process": "^4.4|^5.0|^6.0", + "symfony/var-dumper": "^4.4|^5.0|^6.0" + }, + "suggest": { + "psr/log": "For using the console logger", + "symfony/event-dispatcher": "", + "symfony/lock": "", + "symfony/process": "" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Console\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Eases the creation of beautiful and testable command line interfaces", + "homepage": "https://symfony.com", + "keywords": [ + "cli", + "command line", + "console", + "terminal" + ], + "support": { + "source": "https://github.com/symfony/console/tree/v5.4.9" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-05-18T06:17:34+00:00" + }, + { + "name": "symfony/deprecation-contracts", + "version": "v2.5.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/deprecation-contracts.git", + "reference": "e8b495ea28c1d97b5e0c121748d6f9b53d075c66" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/e8b495ea28c1d97b5e0c121748d6f9b53d075c66", + "reference": "e8b495ea28c1d97b5e0c121748d6f9b53d075c66", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "2.5-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "autoload": { + "files": [ + "function.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "A generic function and convention to trigger deprecation notices", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/deprecation-contracts/tree/v2.5.1" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-01-02T09:53:40+00:00" + }, + { + "name": "symfony/event-dispatcher", + "version": "v5.4.9", + "source": { + "type": "git", + "url": "https://github.com/symfony/event-dispatcher.git", + "reference": "8e6ce1cc0279e3ff3c8ff0f43813bc88d21ca1bc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/8e6ce1cc0279e3ff3c8ff0f43813bc88d21ca1bc", + "reference": "8e6ce1cc0279e3ff3c8ff0f43813bc88d21ca1bc", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/deprecation-contracts": "^2.1|^3", + "symfony/event-dispatcher-contracts": "^2|^3", + "symfony/polyfill-php80": "^1.16" + }, + "conflict": { + "symfony/dependency-injection": "<4.4" + }, + "provide": { + "psr/event-dispatcher-implementation": "1.0", + "symfony/event-dispatcher-implementation": "2.0" + }, + "require-dev": { + "psr/log": "^1|^2|^3", + "symfony/config": "^4.4|^5.0|^6.0", + "symfony/dependency-injection": "^4.4|^5.0|^6.0", + "symfony/error-handler": "^4.4|^5.0|^6.0", + "symfony/expression-language": "^4.4|^5.0|^6.0", + "symfony/http-foundation": "^4.4|^5.0|^6.0", + "symfony/service-contracts": "^1.1|^2|^3", + "symfony/stopwatch": "^4.4|^5.0|^6.0" + }, + "suggest": { + "symfony/dependency-injection": "", + "symfony/http-kernel": "" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\EventDispatcher\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/event-dispatcher/tree/v5.4.9" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-05-05T16:45:39+00:00" + }, + { + "name": "symfony/event-dispatcher-contracts", + "version": "v2.5.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/event-dispatcher-contracts.git", + "reference": "f98b54df6ad059855739db6fcbc2d36995283fe1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/f98b54df6ad059855739db6fcbc2d36995283fe1", + "reference": "f98b54df6ad059855739db6fcbc2d36995283fe1", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "psr/event-dispatcher": "^1" + }, + "suggest": { + "symfony/event-dispatcher-implementation": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "2.5-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\EventDispatcher\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to dispatching event", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v2.5.1" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-01-02T09:53:40+00:00" + }, + { + "name": "symfony/filesystem", + "version": "v5.4.9", + "source": { + "type": "git", + "url": "https://github.com/symfony/filesystem.git", + "reference": "36a017fa4cce1eff1b8e8129ff53513abcef05ba" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/36a017fa4cce1eff1b8e8129ff53513abcef05ba", + "reference": "36a017fa4cce1eff1b8e8129ff53513abcef05ba", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-mbstring": "~1.8", + "symfony/polyfill-php80": "^1.16" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Filesystem\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides basic utilities for the filesystem", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/filesystem/tree/v5.4.9" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-05-20T13:55:35+00:00" + }, + { + "name": "symfony/finder", + "version": "v5.4.8", + "source": { + "type": "git", + "url": "https://github.com/symfony/finder.git", + "reference": "9b630f3427f3ebe7cd346c277a1408b00249dad9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/finder/zipball/9b630f3427f3ebe7cd346c277a1408b00249dad9", + "reference": "9b630f3427f3ebe7cd346c277a1408b00249dad9", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/deprecation-contracts": "^2.1|^3", + "symfony/polyfill-php80": "^1.16" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Finder\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Finds files and directories via an intuitive fluent interface", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/finder/tree/v5.4.8" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-04-15T08:07:45+00:00" + }, + { + "name": "symfony/options-resolver", + "version": "v5.4.3", + "source": { + "type": "git", + "url": "https://github.com/symfony/options-resolver.git", + "reference": "cc1147cb11af1b43f503ac18f31aa3bec213aba8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/options-resolver/zipball/cc1147cb11af1b43f503ac18f31aa3bec213aba8", + "reference": "cc1147cb11af1b43f503ac18f31aa3bec213aba8", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/deprecation-contracts": "^2.1|^3", + "symfony/polyfill-php73": "~1.0", + "symfony/polyfill-php80": "^1.16" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\OptionsResolver\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides an improved replacement for the array_replace PHP function", + "homepage": "https://symfony.com", + "keywords": [ + "config", + "configuration", + "options" + ], + "support": { + "source": "https://github.com/symfony/options-resolver/tree/v5.4.3" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-01-02T09:53:40+00:00" + }, + { + "name": "symfony/polyfill-ctype", + "version": "v1.26.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-ctype.git", + "reference": "6fd1b9a79f6e3cf65f9e679b23af304cd9e010d4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/6fd1b9a79f6e3cf65f9e679b23af304cd9e010d4", + "reference": "6fd1b9a79f6e3cf65f9e679b23af304cd9e010d4", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "provide": { + "ext-ctype": "*" + }, + "suggest": { + "ext-ctype": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.26-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Ctype\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Gert de Pagter", + "email": "BackEndTea@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for ctype functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "ctype", + "polyfill", + "portable" + ], + "support": { + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.26.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-05-24T11:49:31+00:00" + }, + { + "name": "symfony/polyfill-intl-grapheme", + "version": "v1.26.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-grapheme.git", + "reference": "433d05519ce6990bf3530fba6957499d327395c2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/433d05519ce6990bf3530fba6957499d327395c2", + "reference": "433d05519ce6990bf3530fba6957499d327395c2", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.26-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Intl\\Grapheme\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for intl's grapheme_* functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "grapheme", + "intl", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.26.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-05-24T11:49:31+00:00" + }, + { + "name": "symfony/polyfill-intl-normalizer", + "version": "v1.26.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-normalizer.git", + "reference": "219aa369ceff116e673852dce47c3a41794c14bd" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/219aa369ceff116e673852dce47c3a41794c14bd", + "reference": "219aa369ceff116e673852dce47c3a41794c14bd", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.26-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Intl\\Normalizer\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for intl's Normalizer class and related functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "intl", + "normalizer", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.26.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-05-24T11:49:31+00:00" + }, + { + "name": "symfony/polyfill-mbstring", + "version": "v1.26.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-mbstring.git", + "reference": "9344f9cb97f3b19424af1a21a3b0e75b0a7d8d7e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/9344f9cb97f3b19424af1a21a3b0e75b0a7d8d7e", + "reference": "9344f9cb97f3b19424af1a21a3b0e75b0a7d8d7e", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "provide": { + "ext-mbstring": "*" + }, + "suggest": { + "ext-mbstring": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.26-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Mbstring\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for the Mbstring extension", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "mbstring", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.26.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-05-24T11:49:31+00:00" + }, + { + "name": "symfony/polyfill-php56", + "version": "v1.20.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php56.git", + "reference": "54b8cd7e6c1643d78d011f3be89f3ef1f9f4c675" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php56/zipball/54b8cd7e6c1643d78d011f3be89f3ef1f9f4c675", + "reference": "54b8cd7e6c1643d78d011f3be89f3ef1f9f4c675", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "type": "metapackage", + "extra": { + "branch-alias": { + "dev-main": "1.20-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 5.6+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php56/tree/v1.20.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-10-23T14:02:19+00:00" + }, + { + "name": "symfony/polyfill-php73", + "version": "v1.26.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php73.git", + "reference": "e440d35fa0286f77fb45b79a03fedbeda9307e85" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/e440d35fa0286f77fb45b79a03fedbeda9307e85", + "reference": "e440d35fa0286f77fb45b79a03fedbeda9307e85", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.26-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php73\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 7.3+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php73/tree/v1.26.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-05-24T11:49:31+00:00" + }, + { + "name": "symfony/polyfill-php80", + "version": "v1.26.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php80.git", + "reference": "cfa0ae98841b9e461207c13ab093d76b0fa7bace" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/cfa0ae98841b9e461207c13ab093d76b0fa7bace", + "reference": "cfa0ae98841b9e461207c13ab093d76b0fa7bace", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.26-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php80\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ion Bazan", + "email": "ion.bazan@gmail.com" + }, + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php80/tree/v1.26.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-05-10T07:21:04+00:00" + }, + { + "name": "symfony/polyfill-php81", + "version": "v1.26.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php81.git", + "reference": "13f6d1271c663dc5ae9fb843a8f16521db7687a1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/13f6d1271c663dc5ae9fb843a8f16521db7687a1", + "reference": "13f6d1271c663dc5ae9fb843a8f16521db7687a1", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.26-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php81\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 8.1+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php81/tree/v1.26.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-05-24T11:49:31+00:00" + }, + { + "name": "symfony/process", + "version": "v5.4.8", + "source": { + "type": "git", + "url": "https://github.com/symfony/process.git", + "reference": "597f3fff8e3e91836bb0bd38f5718b56ddbde2f3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/process/zipball/597f3fff8e3e91836bb0bd38f5718b56ddbde2f3", + "reference": "597f3fff8e3e91836bb0bd38f5718b56ddbde2f3", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/polyfill-php80": "^1.16" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Process\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Executes commands in sub-processes", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/process/tree/v5.4.8" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-04-08T05:07:18+00:00" + }, + { + "name": "symfony/service-contracts", + "version": "v2.5.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/service-contracts.git", + "reference": "24d9dc654b83e91aa59f9d167b131bc3b5bea24c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/24d9dc654b83e91aa59f9d167b131bc3b5bea24c", + "reference": "24d9dc654b83e91aa59f9d167b131bc3b5bea24c", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "psr/container": "^1.1", + "symfony/deprecation-contracts": "^2.1|^3" + }, + "conflict": { + "ext-psr": "<1.1|>=2" + }, + "suggest": { + "symfony/service-implementation": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "2.5-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\Service\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to writing services", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/service-contracts/tree/v2.5.1" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-03-13T20:07:29+00:00" + }, + { + "name": "symfony/stopwatch", + "version": "v5.4.5", + "source": { + "type": "git", + "url": "https://github.com/symfony/stopwatch.git", + "reference": "4d04b5c24f3c9a1a168a131f6cbe297155bc0d30" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/stopwatch/zipball/4d04b5c24f3c9a1a168a131f6cbe297155bc0d30", + "reference": "4d04b5c24f3c9a1a168a131f6cbe297155bc0d30", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/service-contracts": "^1|^2|^3" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Stopwatch\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides a way to profile code", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/stopwatch/tree/v5.4.5" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-02-18T16:06:09+00:00" + }, + { + "name": "symfony/string", + "version": "v5.4.9", + "source": { + "type": "git", + "url": "https://github.com/symfony/string.git", + "reference": "985e6a9703ef5ce32ba617c9c7d97873bb7b2a99" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/string/zipball/985e6a9703ef5ce32ba617c9c7d97873bb7b2a99", + "reference": "985e6a9703ef5ce32ba617c9c7d97873bb7b2a99", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-intl-grapheme": "~1.0", + "symfony/polyfill-intl-normalizer": "~1.0", + "symfony/polyfill-mbstring": "~1.0", + "symfony/polyfill-php80": "~1.15" + }, + "conflict": { + "symfony/translation-contracts": ">=3.0" + }, + "require-dev": { + "symfony/error-handler": "^4.4|^5.0|^6.0", + "symfony/http-client": "^4.4|^5.0|^6.0", + "symfony/translation-contracts": "^1.1|^2", + "symfony/var-exporter": "^4.4|^5.0|^6.0" + }, + "type": "library", + "autoload": { + "files": [ + "Resources/functions.php" + ], + "psr-4": { + "Symfony\\Component\\String\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides an object-oriented API to strings and deals with bytes, UTF-8 code points and grapheme clusters in a unified way", + "homepage": "https://symfony.com", + "keywords": [ + "grapheme", + "i18n", + "string", + "unicode", + "utf-8", + "utf8" + ], + "support": { + "source": "https://github.com/symfony/string/tree/v5.4.9" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-04-19T10:40:37+00:00" + } + ], + "packages-dev": [ + { + "name": "doctrine/instantiator", + "version": "1.4.1", + "source": { + "type": "git", + "url": "https://github.com/doctrine/instantiator.git", + "reference": "10dcfce151b967d20fde1b34ae6640712c3891bc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/instantiator/zipball/10dcfce151b967d20fde1b34ae6640712c3891bc", + "reference": "10dcfce151b967d20fde1b34ae6640712c3891bc", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0" + }, + "require-dev": { + "doctrine/coding-standard": "^9", + "ext-pdo": "*", + "ext-phar": "*", + "phpbench/phpbench": "^0.16 || ^1", + "phpstan/phpstan": "^1.4", + "phpstan/phpstan-phpunit": "^1", + "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", + "vimeo/psalm": "^4.22" + }, + "type": "library", + "autoload": { + "psr-4": { + "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Marco Pivetta", + "email": "ocramius@gmail.com", + "homepage": "https://ocramius.github.io/" + } + ], + "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", + "homepage": "https://www.doctrine-project.org/projects/instantiator.html", + "keywords": [ + "constructor", + "instantiate" + ], + "support": { + "issues": "https://github.com/doctrine/instantiator/issues", + "source": "https://github.com/doctrine/instantiator/tree/1.4.1" + }, + "funding": [ + { + "url": "https://www.doctrine-project.org/sponsorship.html", + "type": "custom" + }, + { + "url": "https://www.patreon.com/phpdoctrine", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/doctrine%2Finstantiator", + "type": "tidelift" + } + ], + "time": "2022-03-03T08:28:38+00:00" + }, + { + "name": "internations/testing-component", + "version": "1.3.0", + "source": { + "type": "git", + "url": "https://github.com/InterNations/TestingComponent.git", + "reference": "7125a34eff7088ce0f2c178daea2d498ae8c0f3a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/InterNations/TestingComponent/zipball/7125a34eff7088ce0f2c178daea2d498ae8c0f3a", + "reference": "7125a34eff7088ce0f2c178daea2d498ae8c0f3a", + "shasum": "" + }, + "require": { + "php": "~7.1" + }, + "require-dev": { + "doctrine/annotations": "^1.2", + "internations/kodierungsregelwerksammlung": "dev-master", + "phpunit/phpunit": "~6", + "symfony/config": "^4.0", + "symfony/css-selector": "~3", + "symfony/dependency-injection": "^4.0", + "symfony/dom-crawler": "~3", + "symfony/framework-bundle": "^4.0", + "symfony/http-kernel": "^4.0", + "symfony/validator": "~3" + }, + "suggest": { + "symfony/css-selector": "Dependency for symfony/dom-crawler", + "symfony/dom-crawler": "Necessary to use DomCrawlerAssertionTrait" + }, + "type": "library", + "autoload": { + "psr-0": { + "InterNations\\Component\\Testing": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Lars Strojny", + "email": "lars.strojny@internations.org" + }, + { + "name": "Max Beutel", + "email": "max.beutel@internations.org" + }, + { + "name": "Michael Weinrich", + "email": "michael.weinrich@internations.org" + }, + { + "name": "Marc Jakubowski", + "email": "marc.jakubowski@internations.org" + }, + { + "name": "Hans Bernhard Streit", + "email": "hans.streit@internations.org" + } + ], + "description": "A collection of test helpers for Symfony 3 projects", + "support": { + "issues": "https://github.com/InterNations/TestingComponent/issues", + "source": "https://github.com/InterNations/TestingComponent/tree/master" + }, + "time": "2018-12-09T16:20:22+00:00" + }, + { + "name": "myclabs/deep-copy", + "version": "1.11.0", + "source": { + "type": "git", + "url": "https://github.com/myclabs/DeepCopy.git", + "reference": "14daed4296fae74d9e3201d2c4925d1acb7aa614" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/14daed4296fae74d9e3201d2c4925d1acb7aa614", + "reference": "14daed4296fae74d9e3201d2c4925d1acb7aa614", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0" + }, + "conflict": { + "doctrine/collections": "<1.6.8", + "doctrine/common": "<2.13.3 || >=3,<3.2.2" + }, + "require-dev": { + "doctrine/collections": "^1.6.8", + "doctrine/common": "^2.13.3 || ^3.2.2", + "phpunit/phpunit": "^7.5.20 || ^8.5.23 || ^9.5.13" + }, + "type": "library", + "autoload": { + "files": [ + "src/DeepCopy/deep_copy.php" + ], + "psr-4": { + "DeepCopy\\": "src/DeepCopy/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Create deep copies (clones) of your objects", + "keywords": [ + "clone", + "copy", + "duplicate", + "object", + "object graph" + ], + "support": { + "issues": "https://github.com/myclabs/DeepCopy/issues", + "source": "https://github.com/myclabs/DeepCopy/tree/1.11.0" + }, + "funding": [ + { + "url": "https://tidelift.com/funding/github/packagist/myclabs/deep-copy", + "type": "tidelift" + } + ], + "time": "2022-03-03T13:19:32+00:00" + }, + { + "name": "phar-io/manifest", + "version": "1.0.3", + "source": { + "type": "git", + "url": "https://github.com/phar-io/manifest.git", + "reference": "7761fcacf03b4d4f16e7ccb606d4879ca431fcf4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phar-io/manifest/zipball/7761fcacf03b4d4f16e7ccb606d4879ca431fcf4", + "reference": "7761fcacf03b4d4f16e7ccb606d4879ca431fcf4", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-phar": "*", + "phar-io/version": "^2.0", + "php": "^5.6 || ^7.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + }, + { + "name": "Sebastian Heuer", + "email": "sebastian@phpeople.de", + "role": "Developer" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "Developer" + } + ], + "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", + "support": { + "issues": "https://github.com/phar-io/manifest/issues", + "source": "https://github.com/phar-io/manifest/tree/master" + }, + "time": "2018-07-08T19:23:20+00:00" + }, + { + "name": "phar-io/version", + "version": "2.0.1", + "source": { + "type": "git", + "url": "https://github.com/phar-io/version.git", + "reference": "45a2ec53a73c70ce41d55cedef9063630abaf1b6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phar-io/version/zipball/45a2ec53a73c70ce41d55cedef9063630abaf1b6", + "reference": "45a2ec53a73c70ce41d55cedef9063630abaf1b6", + "shasum": "" + }, + "require": { + "php": "^5.6 || ^7.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + }, + { + "name": "Sebastian Heuer", + "email": "sebastian@phpeople.de", + "role": "Developer" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "Developer" + } + ], + "description": "Library for handling version information and constraints", + "support": { + "issues": "https://github.com/phar-io/version/issues", + "source": "https://github.com/phar-io/version/tree/master" + }, + "time": "2018-07-08T19:19:57+00:00" + }, + { + "name": "phpdocumentor/reflection-common", + "version": "2.2.0", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/ReflectionCommon.git", + "reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/1d01c49d4ed62f25aa84a747ad35d5a16924662b", + "reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-2.x": "2.x-dev" + } + }, + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jaap van Otterdijk", + "email": "opensource@ijaap.nl" + } + ], + "description": "Common reflection classes used by phpdocumentor to reflect the code structure", + "homepage": "http://www.phpdoc.org", + "keywords": [ + "FQSEN", + "phpDocumentor", + "phpdoc", + "reflection", + "static analysis" + ], + "support": { + "issues": "https://github.com/phpDocumentor/ReflectionCommon/issues", + "source": "https://github.com/phpDocumentor/ReflectionCommon/tree/2.x" + }, + "time": "2020-06-27T09:03:43+00:00" + }, + { + "name": "phpdocumentor/reflection-docblock", + "version": "5.3.0", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", + "reference": "622548b623e81ca6d78b721c5e029f4ce664f170" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/622548b623e81ca6d78b721c5e029f4ce664f170", + "reference": "622548b623e81ca6d78b721c5e029f4ce664f170", + "shasum": "" + }, + "require": { + "ext-filter": "*", + "php": "^7.2 || ^8.0", + "phpdocumentor/reflection-common": "^2.2", + "phpdocumentor/type-resolver": "^1.3", + "webmozart/assert": "^1.9.1" + }, + "require-dev": { + "mockery/mockery": "~1.3.2", + "psalm/phar": "^4.8" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.x-dev" + } + }, + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mike van Riel", + "email": "me@mikevanriel.com" + }, + { + "name": "Jaap van Otterdijk", + "email": "account@ijaap.nl" + } + ], + "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", + "support": { + "issues": "https://github.com/phpDocumentor/ReflectionDocBlock/issues", + "source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/5.3.0" + }, + "time": "2021-10-19T17:43:47+00:00" + }, + { + "name": "phpdocumentor/type-resolver", + "version": "1.6.1", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/TypeResolver.git", + "reference": "77a32518733312af16a44300404e945338981de3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/77a32518733312af16a44300404e945338981de3", + "reference": "77a32518733312af16a44300404e945338981de3", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0", + "phpdocumentor/reflection-common": "^2.0" + }, + "require-dev": { + "ext-tokenizer": "*", + "psalm/phar": "^4.8" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-1.x": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mike van Riel", + "email": "me@mikevanriel.com" + } + ], + "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names", + "support": { + "issues": "https://github.com/phpDocumentor/TypeResolver/issues", + "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.6.1" + }, + "time": "2022-03-15T21:29:03+00:00" + }, + { + "name": "phpspec/prophecy", + "version": "v1.15.0", + "source": { + "type": "git", + "url": "https://github.com/phpspec/prophecy.git", + "reference": "bbcd7380b0ebf3961ee21409db7b38bc31d69a13" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpspec/prophecy/zipball/bbcd7380b0ebf3961ee21409db7b38bc31d69a13", + "reference": "bbcd7380b0ebf3961ee21409db7b38bc31d69a13", + "shasum": "" + }, + "require": { + "doctrine/instantiator": "^1.2", + "php": "^7.2 || ~8.0, <8.2", + "phpdocumentor/reflection-docblock": "^5.2", + "sebastian/comparator": "^3.0 || ^4.0", + "sebastian/recursion-context": "^3.0 || ^4.0" + }, + "require-dev": { + "phpspec/phpspec": "^6.0 || ^7.0", + "phpunit/phpunit": "^8.0 || ^9.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Prophecy\\": "src/Prophecy" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Konstantin Kudryashov", + "email": "ever.zet@gmail.com", + "homepage": "http://everzet.com" + }, + { + "name": "Marcello Duarte", + "email": "marcello.duarte@gmail.com" + } + ], + "description": "Highly opinionated mocking framework for PHP 5.3+", + "homepage": "https://github.com/phpspec/prophecy", + "keywords": [ + "Double", + "Dummy", + "fake", + "mock", + "spy", + "stub" + ], + "support": { + "issues": "https://github.com/phpspec/prophecy/issues", + "source": "https://github.com/phpspec/prophecy/tree/v1.15.0" + }, + "time": "2021-12-08T12:19:24+00:00" + }, + { + "name": "phpunit/php-code-coverage", + "version": "6.1.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-code-coverage.git", + "reference": "807e6013b00af69b6c5d9ceb4282d0393dbb9d8d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/807e6013b00af69b6c5d9ceb4282d0393dbb9d8d", + "reference": "807e6013b00af69b6c5d9ceb4282d0393dbb9d8d", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-xmlwriter": "*", + "php": "^7.1", + "phpunit/php-file-iterator": "^2.0", + "phpunit/php-text-template": "^1.2.1", + "phpunit/php-token-stream": "^3.0", + "sebastian/code-unit-reverse-lookup": "^1.0.1", + "sebastian/environment": "^3.1 || ^4.0", + "sebastian/version": "^2.0.1", + "theseer/tokenizer": "^1.1" + }, + "require-dev": { + "phpunit/phpunit": "^7.0" + }, + "suggest": { + "ext-xdebug": "^2.6.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "6.1-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", + "homepage": "https://github.com/sebastianbergmann/php-code-coverage", + "keywords": [ + "coverage", + "testing", + "xunit" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/master" + }, + "time": "2018-10-31T16:06:48+00:00" + }, + { + "name": "phpunit/php-file-iterator", + "version": "2.0.5", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-file-iterator.git", + "reference": "42c5ba5220e6904cbfe8b1a1bda7c0cfdc8c12f5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/42c5ba5220e6904cbfe8b1a1bda7c0cfdc8c12f5", + "reference": "42c5ba5220e6904cbfe8b1a1bda7c0cfdc8c12f5", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "require-dev": { + "phpunit/phpunit": "^8.5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "FilterIterator implementation that filters files based on a list of suffixes.", + "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", + "keywords": [ + "filesystem", + "iterator" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-file-iterator/issues", + "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/2.0.5" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2021-12-02T12:42:26+00:00" + }, + { + "name": "phpunit/php-text-template", + "version": "1.2.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-text-template.git", + "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/31f8b717e51d9a2afca6c9f046f5d69fc27c8686", + "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Simple template engine.", + "homepage": "https://github.com/sebastianbergmann/php-text-template/", + "keywords": [ + "template" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-text-template/issues", + "source": "https://github.com/sebastianbergmann/php-text-template/tree/1.2.1" + }, + "time": "2015-06-21T13:50:34+00:00" + }, + { + "name": "phpunit/php-timer", + "version": "2.1.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-timer.git", + "reference": "2454ae1765516d20c4ffe103d85a58a9a3bd5662" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/2454ae1765516d20c4ffe103d85a58a9a3bd5662", + "reference": "2454ae1765516d20c4ffe103d85a58a9a3bd5662", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "require-dev": { + "phpunit/phpunit": "^8.5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.1-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Utility class for timing", + "homepage": "https://github.com/sebastianbergmann/php-timer/", + "keywords": [ + "timer" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-timer/issues", + "source": "https://github.com/sebastianbergmann/php-timer/tree/2.1.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-11-30T08:20:02+00:00" + }, + { + "name": "phpunit/php-token-stream", + "version": "3.1.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-token-stream.git", + "reference": "9c1da83261628cb24b6a6df371b6e312b3954768" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/9c1da83261628cb24b6a6df371b6e312b3954768", + "reference": "9c1da83261628cb24b6a6df371b6e312b3954768", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "php": ">=7.1" + }, + "require-dev": { + "phpunit/phpunit": "^7.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.1-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Wrapper around PHP's tokenizer extension.", + "homepage": "https://github.com/sebastianbergmann/php-token-stream/", + "keywords": [ + "tokenizer" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-token-stream/issues", + "source": "https://github.com/sebastianbergmann/php-token-stream/tree/3.1.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "abandoned": true, + "time": "2021-07-26T12:15:06+00:00" + }, + { + "name": "phpunit/phpunit", + "version": "7.5.20", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit.git", + "reference": "9467db479d1b0487c99733bb1e7944d32deded2c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/9467db479d1b0487c99733bb1e7944d32deded2c", + "reference": "9467db479d1b0487c99733bb1e7944d32deded2c", + "shasum": "" + }, + "require": { + "doctrine/instantiator": "^1.1", + "ext-dom": "*", + "ext-json": "*", + "ext-libxml": "*", + "ext-mbstring": "*", + "ext-xml": "*", + "myclabs/deep-copy": "^1.7", + "phar-io/manifest": "^1.0.2", + "phar-io/version": "^2.0", + "php": "^7.1", + "phpspec/prophecy": "^1.7", + "phpunit/php-code-coverage": "^6.0.7", + "phpunit/php-file-iterator": "^2.0.1", + "phpunit/php-text-template": "^1.2.1", + "phpunit/php-timer": "^2.1", + "sebastian/comparator": "^3.0", + "sebastian/diff": "^3.0", + "sebastian/environment": "^4.0", + "sebastian/exporter": "^3.1", + "sebastian/global-state": "^2.0", + "sebastian/object-enumerator": "^3.0.3", + "sebastian/resource-operations": "^2.0", + "sebastian/version": "^2.0.1" + }, + "conflict": { + "phpunit/phpunit-mock-objects": "*" + }, + "require-dev": { + "ext-pdo": "*" + }, + "suggest": { + "ext-soap": "*", + "ext-xdebug": "*", + "phpunit/php-invoker": "^2.0" + }, + "bin": [ + "phpunit" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "7.5-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "The PHP Unit Testing framework.", + "homepage": "https://phpunit.de/", + "keywords": [ + "phpunit", + "testing", + "xunit" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/phpunit/issues", + "source": "https://github.com/sebastianbergmann/phpunit/tree/7.5.20" + }, + "time": "2020-01-08T08:45:45+00:00" + }, + { + "name": "sebastian/code-unit-reverse-lookup", + "version": "1.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", + "reference": "1de8cd5c010cb153fcd68b8d0f64606f523f7619" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/1de8cd5c010cb153fcd68b8d0f64606f523f7619", + "reference": "1de8cd5c010cb153fcd68b8d0f64606f523f7619", + "shasum": "" + }, + "require": { + "php": ">=5.6" + }, + "require-dev": { + "phpunit/phpunit": "^8.5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Looks up which function or method a line of code belongs to", + "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", + "support": { + "issues": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/issues", + "source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/1.0.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-11-30T08:15:22+00:00" + }, + { + "name": "sebastian/comparator", + "version": "3.0.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/comparator.git", + "reference": "1071dfcef776a57013124ff35e1fc41ccd294758" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/1071dfcef776a57013124ff35e1fc41ccd294758", + "reference": "1071dfcef776a57013124ff35e1fc41ccd294758", + "shasum": "" + }, + "require": { + "php": ">=7.1", + "sebastian/diff": "^3.0", + "sebastian/exporter": "^3.1" + }, + "require-dev": { + "phpunit/phpunit": "^8.5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@2bepublished.at" + } + ], + "description": "Provides the functionality to compare PHP values for equality", + "homepage": "https://github.com/sebastianbergmann/comparator", + "keywords": [ + "comparator", + "compare", + "equality" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/comparator/issues", + "source": "https://github.com/sebastianbergmann/comparator/tree/3.0.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-11-30T08:04:30+00:00" + }, + { + "name": "sebastian/diff", + "version": "3.0.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/diff.git", + "reference": "14f72dd46eaf2f2293cbe79c93cc0bc43161a211" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/14f72dd46eaf2f2293cbe79c93cc0bc43161a211", + "reference": "14f72dd46eaf2f2293cbe79c93cc0bc43161a211", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "require-dev": { + "phpunit/phpunit": "^7.5 || ^8.0", + "symfony/process": "^2 || ^3.3 || ^4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Kore Nordmann", + "email": "mail@kore-nordmann.de" + } + ], + "description": "Diff implementation", + "homepage": "https://github.com/sebastianbergmann/diff", + "keywords": [ + "diff", + "udiff", + "unidiff", + "unified diff" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/diff/issues", + "source": "https://github.com/sebastianbergmann/diff/tree/3.0.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-11-30T07:59:04+00:00" + }, + { + "name": "sebastian/environment", + "version": "4.2.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/environment.git", + "reference": "d47bbbad83711771f167c72d4e3f25f7fcc1f8b0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/d47bbbad83711771f167c72d4e3f25f7fcc1f8b0", + "reference": "d47bbbad83711771f167c72d4e3f25f7fcc1f8b0", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "require-dev": { + "phpunit/phpunit": "^7.5" + }, + "suggest": { + "ext-posix": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.2-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides functionality to handle HHVM/PHP environments", + "homepage": "http://www.github.com/sebastianbergmann/environment", + "keywords": [ + "Xdebug", + "environment", + "hhvm" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/environment/issues", + "source": "https://github.com/sebastianbergmann/environment/tree/4.2.4" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-11-30T07:53:42+00:00" + }, + { + "name": "sebastian/exporter", + "version": "3.1.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/exporter.git", + "reference": "0c32ea2e40dbf59de29f3b49bf375176ce7dd8db" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/0c32ea2e40dbf59de29f3b49bf375176ce7dd8db", + "reference": "0c32ea2e40dbf59de29f3b49bf375176ce7dd8db", + "shasum": "" + }, + "require": { + "php": ">=7.0", + "sebastian/recursion-context": "^3.0" + }, + "require-dev": { + "ext-mbstring": "*", + "phpunit/phpunit": "^8.5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.1.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + } + ], + "description": "Provides the functionality to export PHP variables for visualization", + "homepage": "http://www.github.com/sebastianbergmann/exporter", + "keywords": [ + "export", + "exporter" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/exporter/issues", + "source": "https://github.com/sebastianbergmann/exporter/tree/3.1.4" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2021-11-11T13:51:24+00:00" + }, + { + "name": "sebastian/global-state", + "version": "2.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/global-state.git", + "reference": "e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4", + "reference": "e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4", + "shasum": "" + }, + "require": { + "php": "^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^6.0" + }, + "suggest": { + "ext-uopz": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Snapshotting of global state", + "homepage": "http://www.github.com/sebastianbergmann/global-state", + "keywords": [ + "global state" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/global-state/issues", + "source": "https://github.com/sebastianbergmann/global-state/tree/2.0.0" + }, + "time": "2017-04-27T15:39:26+00:00" + }, + { + "name": "sebastian/object-enumerator", + "version": "3.0.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/object-enumerator.git", + "reference": "e67f6d32ebd0c749cf9d1dbd9f226c727043cdf2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/e67f6d32ebd0c749cf9d1dbd9f226c727043cdf2", + "reference": "e67f6d32ebd0c749cf9d1dbd9f226c727043cdf2", + "shasum": "" + }, + "require": { + "php": ">=7.0", + "sebastian/object-reflector": "^1.1.1", + "sebastian/recursion-context": "^3.0" + }, + "require-dev": { + "phpunit/phpunit": "^6.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Traverses array structures and object graphs to enumerate all referenced objects", + "homepage": "https://github.com/sebastianbergmann/object-enumerator/", + "support": { + "issues": "https://github.com/sebastianbergmann/object-enumerator/issues", + "source": "https://github.com/sebastianbergmann/object-enumerator/tree/3.0.4" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-11-30T07:40:27+00:00" + }, + { + "name": "sebastian/object-reflector", + "version": "1.1.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/object-reflector.git", + "reference": "9b8772b9cbd456ab45d4a598d2dd1a1bced6363d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/9b8772b9cbd456ab45d4a598d2dd1a1bced6363d", + "reference": "9b8772b9cbd456ab45d4a598d2dd1a1bced6363d", + "shasum": "" + }, + "require": { + "php": ">=7.0" + }, + "require-dev": { + "phpunit/phpunit": "^6.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Allows reflection of object attributes, including inherited and non-public ones", + "homepage": "https://github.com/sebastianbergmann/object-reflector/", + "support": { + "issues": "https://github.com/sebastianbergmann/object-reflector/issues", + "source": "https://github.com/sebastianbergmann/object-reflector/tree/1.1.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-11-30T07:37:18+00:00" + }, + { + "name": "sebastian/recursion-context", + "version": "3.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/recursion-context.git", + "reference": "367dcba38d6e1977be014dc4b22f47a484dac7fb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/367dcba38d6e1977be014dc4b22f47a484dac7fb", + "reference": "367dcba38d6e1977be014dc4b22f47a484dac7fb", + "shasum": "" + }, + "require": { + "php": ">=7.0" + }, + "require-dev": { + "phpunit/phpunit": "^6.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + } + ], + "description": "Provides functionality to recursively process PHP variables", + "homepage": "http://www.github.com/sebastianbergmann/recursion-context", + "support": { + "issues": "https://github.com/sebastianbergmann/recursion-context/issues", + "source": "https://github.com/sebastianbergmann/recursion-context/tree/3.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-11-30T07:34:24+00:00" + }, + { + "name": "sebastian/resource-operations", + "version": "2.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/resource-operations.git", + "reference": "31d35ca87926450c44eae7e2611d45a7a65ea8b3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/31d35ca87926450c44eae7e2611d45a7a65ea8b3", + "reference": "31d35ca87926450c44eae7e2611d45a7a65ea8b3", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides a list of PHP built-in functions that operate on resources", + "homepage": "https://www.github.com/sebastianbergmann/resource-operations", + "support": { + "issues": "https://github.com/sebastianbergmann/resource-operations/issues", + "source": "https://github.com/sebastianbergmann/resource-operations/tree/2.0.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-11-30T07:30:19+00:00" + }, + { + "name": "sebastian/version", + "version": "2.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/version.git", + "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/99732be0ddb3361e16ad77b68ba41efc8e979019", + "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019", + "shasum": "" + }, + "require": { + "php": ">=5.6" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library that helps with managing the version number of Git-hosted PHP projects", + "homepage": "https://github.com/sebastianbergmann/version", + "support": { + "issues": "https://github.com/sebastianbergmann/version/issues", + "source": "https://github.com/sebastianbergmann/version/tree/master" + }, + "time": "2016-10-03T07:35:21+00:00" + }, + { + "name": "theseer/tokenizer", + "version": "1.2.1", + "source": { + "type": "git", + "url": "https://github.com/theseer/tokenizer.git", + "reference": "34a41e998c2183e22995f158c581e7b5e755ab9e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/theseer/tokenizer/zipball/34a41e998c2183e22995f158c581e7b5e755ab9e", + "reference": "34a41e998c2183e22995f158c581e7b5e755ab9e", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-tokenizer": "*", + "ext-xmlwriter": "*", + "php": "^7.2 || ^8.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + } + ], + "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", + "support": { + "issues": "https://github.com/theseer/tokenizer/issues", + "source": "https://github.com/theseer/tokenizer/tree/1.2.1" + }, + "funding": [ + { + "url": "https://github.com/theseer", + "type": "github" + } + ], + "time": "2021-07-28T10:34:58+00:00" + }, + { + "name": "webmozart/assert", + "version": "1.11.0", + "source": { + "type": "git", + "url": "https://github.com/webmozarts/assert.git", + "reference": "11cb2199493b2f8a3b53e7f19068fc6aac760991" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/webmozarts/assert/zipball/11cb2199493b2f8a3b53e7f19068fc6aac760991", + "reference": "11cb2199493b2f8a3b53e7f19068fc6aac760991", + "shasum": "" + }, + "require": { + "ext-ctype": "*", + "php": "^7.2 || ^8.0" + }, + "conflict": { + "phpstan/phpstan": "<0.12.20", + "vimeo/psalm": "<4.6.1 || 4.6.2" + }, + "require-dev": { + "phpunit/phpunit": "^8.5.13" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.10-dev" + } + }, + "autoload": { + "psr-4": { + "Webmozart\\Assert\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + } + ], + "description": "Assertions to validate method input/output with nice error messages.", + "keywords": [ + "assert", + "check", + "validate" + ], + "support": { + "issues": "https://github.com/webmozarts/assert/issues", + "source": "https://github.com/webmozarts/assert/tree/1.11.0" + }, + "time": "2022-06-03T18:03:27+00:00" + } + ], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": [], + "prefer-stable": false, + "prefer-lowest": false, + "platform": { + "php": "~7.2", + "ext-json": "*" + }, + "platform-dev": [], + "plugin-api-version": "2.3.0" +} diff --git a/doc/recording.md b/doc/recording.md index 892e045..10c03c4 100644 --- a/doc/recording.md +++ b/doc/recording.md @@ -2,7 +2,7 @@ Once a SUT (system under test) has fired HTTP requests, we often want to validate that our assumption about the nature of those requests are valid. For that purpose HTTP mock stores every request for later inspection. The recorded requests -are presented as an instance of `InterNations\Component\HttpMock\Request\UnifiedRequest`. +are presented as an instance of `Slim\Http\Response`. ```php $this->http->mock diff --git a/doc/server.md b/doc/server.md index a1059f4..c3dc689 100644 --- a/doc/server.md +++ b/doc/server.md @@ -6,7 +6,8 @@ Overview of the internal server functionality ``` POST /_expectation { - response (required): serialized Symfony response + response (required): stringified http respopnse + responseCallback (optional): serialized closure that is passed in the response, and can return a new Response matcher (optional): serialized list of closures limiter (optional): serialized closure that limits the validity of the expectation } diff --git a/doc/start.md b/doc/start.md index b972367..5731841 100644 --- a/doc/start.md +++ b/doc/start.md @@ -58,10 +58,10 @@ class ExampleTest extends PHPUnit_Framework_TestCase ->end(); $this->http->setUp(); - $this->assertSame('mocked body', $this->http->client->post('http://localhost:8082/foo')->send()->getBody(true)); + $this->assertSame('mocked body', (string)$this->http->client->post('http://localhost:8082/foo')->getBody()); $this->assertSame('POST', $this->http->requests->latest()->getMethod()); - $this->assertSame('/foo', $this->http->requests->latest()->getPath()); + $this->assertSame('/foo', $this->http->requests->latest()->getUri()->getPath()); } } ``` diff --git a/doc/stubbing.md b/doc/stubbing.md index c779181..8ef97e8 100644 --- a/doc/stubbing.md +++ b/doc/stubbing.md @@ -24,8 +24,8 @@ The example above say: when we see a `GET` request asking for `/resource` respon What we see here is internally syntactic sugar for the following, more verbose, example using plain callbacks. ```php -use Symfony\Component\HttpFoundation\Request; -use Symfony\Component\HttpFoundation\Response; +use Psr\Http\Message\RequestInterface as Request; +use Psr\Http\Message\ResponseInterface as Response; $this->http->mock ->when() @@ -43,21 +43,20 @@ $this->http->mock ->end(); ``` -What we can see above is that we use standard Symfony HTTP foundation `Request` and `Response` objects. If you want to -learn more about it, look at -[Symfony’s documentation](https://symfony.com/doc/current/components/http_foundation/introduction.html). +What we can see above is that we use standard PSR/7 Request Response, we use the Guzzle implementation on the Client and the Slim implementation on the server side, hurrah standards Let’s have a look what we can do with matching and response building shortcuts: ```php -use Symfony\Component\HttpFoundation\Response; +use Psr\Http\Message\ResponseInterface as Response; +use Slim\Http\StatusCode; $this->http->mock ->when() ->methodIs('GET') ->pathIs('/resource') ->then() - ->statusCode(Response::HTTP_NOT_FOUND) + ->statusCode(StatusCode::HTTP_NOT_FOUND) ->header('X-Custom-Header', 'Header Value') ->body('response') ->end();` diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 51c72a8..9c7409b 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -1,10 +1,6 @@ - - + diff --git a/public/index.php b/public/index.php index d9d901e..f10e911 100644 --- a/public/index.php +++ b/public/index.php @@ -1,4 +1,8 @@ matcherFactory = $matcherFactory; $this->responseBuilder = new ResponseBuilder($mockBuilder); $this->extractorFactory = $extractorFactory; @@ -142,6 +142,11 @@ public function getResponse() return $this->responseBuilder->getResponse(); } + public function getResponseCallback() + { + return $this->responseBuilder->getResponseCallback(); + } + public function getLimiter() { return new SerializableClosure($this->limiter); diff --git a/src/Matcher/AbstractMatcher.php b/src/Matcher/AbstractMatcher.php index 429d60b..dbbc577 100644 --- a/src/Matcher/AbstractMatcher.php +++ b/src/Matcher/AbstractMatcher.php @@ -1,9 +1,10 @@ basePath; return static function (Request $request) use ($basePath) { - return substr_replace($request->getPathInfo(), '', 0, strlen($basePath)); + return substr_replace($request->getUri()->getPath(), '', 0, strlen($basePath)); }; } @@ -31,28 +32,33 @@ public function createMethodExtractor() public function createParamExtractor($param) { return static function (Request $request) use ($param) { - return $request->query->get($param); + return $request->getParam($param); }; } public function createParamExistsExtractor($param) { return static function (Request $request) use ($param) { - return $request->query->has($param); + return $request->getParam($param, false) !== false; }; } public function createHeaderExtractor($header) { return static function (Request $request) use ($header) { - return $request->headers->get($header); + $r = $request->getHeaderLine($header); + if (empty($r)) { + return null; + } + + return $r; }; } public function createHeaderExistsExtractor($header) { return static function (Request $request) use ($header) { - return $request->headers->has($header); + return $request->hasHeader($header); }; } } diff --git a/src/Matcher/MatcherFactory.php b/src/Matcher/MatcherFactory.php index 34d5461..5e76388 100644 --- a/src/Matcher/MatcherFactory.php +++ b/src/Matcher/MatcherFactory.php @@ -1,4 +1,5 @@ http[\'%s\']->%1$s->…', - $property, - implode('", "', array_keys($this->facadeMap)), - current(array_keys($this->facadeMap)) - ) - ); + throw new OutOfBoundsException(sprintf('Tried to access facade property "%1$s" on facade map. First select one of the facades from ' . 'the map. Defined facades: "%2$s", try $this->http[\'%s\']->%1$s->…', $property, implode('", "', array_keys($this->facadeMap)), current(array_keys($this->facadeMap)))); } - throw new OutOfBoundsException( - sprintf( - 'Tried to access property "%1$s". This is a map of facades, try $this->http[\'%1$s\'] instead.', - $property - ) - ); + throw new OutOfBoundsException(sprintf('Tried to access property "%1$s". This is a map of facades, try $this->http[\'%1$s\'] instead.', $property)); } public function all() diff --git a/src/PHPUnit/HttpMockTrait.php b/src/PHPUnit/HttpMockTrait.php index 51afa3d..f976a08 100644 --- a/src/PHPUnit/HttpMockTrait.php +++ b/src/PHPUnit/HttpMockTrait.php @@ -1,4 +1,5 @@ wrapped = $wrapped; - $this->init($params); - } - - /** - * Get the user agent of the request - * - * @return string - */ - public function getUserAgent() - { - return $this->userAgent; - } - - /** - * Get the body of the request if set - * - * @return EntityBodyInterface|null - */ - public function getBody() - { - return $this->invokeWrappedIfEntityEnclosed(__FUNCTION__, func_get_args()); - } - - /** - * Get a POST field from the request - * - * @param string $field Field to retrieve - * - * @return mixed|null - */ - public function getPostField($field) - { - return $this->invokeWrappedIfEntityEnclosed(__FUNCTION__, func_get_args()); - } - - /** - * Get the post fields that will be used in the request - * - * @return QueryString - */ - public function getPostFields() - { - return $this->invokeWrappedIfEntityEnclosed(__FUNCTION__, func_get_args()); - } - - /** - * Returns an associative array of POST field names to PostFileInterface objects - * - * @return array - */ - public function getPostFiles() - { - return $this->invokeWrappedIfEntityEnclosed(__FUNCTION__, func_get_args()); - } - - /** - * Get a POST file from the request - * - * @param string $fieldName POST fields to retrieve - * - * @return array|null Returns an array wrapping an array of PostFileInterface objects - */ - public function getPostFile($fieldName) - { - return $this->invokeWrappedIfEntityEnclosed(__FUNCTION__, func_get_args()); - } - - /** - * Get application and plugin specific parameters set on the message. - * - * @return Collection - */ - public function getParams() - { - return $this->wrapped->getParams(); - } - - /** - * Retrieve an HTTP header by name. Performs a case-insensitive search of all headers. - * - * @param string $header Header to retrieve. - * - * @return Header|null Returns NULL if no matching header is found. - * Returns a Header object if found. - */ - public function getHeader($header) - { - return $this->wrapped->getHeader($header); - } - - /** - * Get all headers as a collection - * - * @return HeaderCollection - */ - public function getHeaders() - { - return $this->wrapped->getHeaders(); - } - - /** - * Get an array of message header lines - * - * @return array - */ - public function getHeaderLines() - { - return $this->wrapped->getHeaderLines(); - } - - /** - * Check if the specified header is present. - * - * @param string $header The header to check. - * - * @return boolean Returns TRUE or FALSE if the header is present - */ - public function hasHeader($header) - { - return $this->wrapped->hasHeader($header); - } - - /** - * Get the raw message headers as a string - * - * @return string - */ - public function getRawHeaders() - { - return $this->wrapped->getRawHeaders(); - } - - /** - * Get the collection of key value pairs that will be used as the query - * string in the request - * - * @return QueryString - */ - public function getQuery() - { - return $this->wrapped->getQuery(); - } - - /** - * Get the HTTP method of the request - * - * @return string - */ - public function getMethod() - { - return $this->wrapped->getMethod(); - } - - /** - * Get the URI scheme of the request (http, https, ftp, etc) - * - * @return string - */ - public function getScheme() - { - return $this->wrapped->getScheme(); - } - - /** - * Get the host of the request - * - * @return string - */ - public function getHost() - { - return $this->wrapped->getHost(); - } - - /** - * Get the HTTP protocol version of the request - * - * @return string - */ - public function getProtocolVersion() - { - return $this->wrapped->getProtocolVersion(); - } - - /** - * Get the path of the request (e.g. '/', '/index.html') - * - * @return string - */ - public function getPath() - { - return $this->wrapped->getPath(); - } - - /** - * Get the port that the request will be sent on if it has been set - * - * @return integer|null - */ - public function getPort() - { - return $this->wrapped->getPort(); - } - - /** - * Get the username to pass in the URL if set - * - * @return string|null - */ - public function getUsername() - { - return $this->wrapped->getUsername(); - } - - /** - * Get the password to pass in the URL if set - * - * @return string|null - */ - public function getPassword() - { - return $this->wrapped->getPassword(); - } - - /** - * Get the full URL of the request (e.g. 'http://www.guzzle-project.com/') - * scheme://username:password@domain:port/path?query_string#fragment - * - * @param boolean $asObject Set to TRUE to retrieve the URL as a clone of the URL object owned by the request. - * - * @return string|Url - */ - public function getUrl($asObject = false) - { - return $this->wrapped->getUrl($asObject); - } - - /** - * Get an array of Cookies - * - * @return array - */ - public function getCookies() - { - return $this->wrapped->getCookies(); - } - - /** - * Get a cookie value by name - * - * @param string $name Cookie to retrieve - * - * @return null|string - */ - public function getCookie($name) - { - return $this->wrapped->getCookie($name); - } - - protected function invokeWrappedIfEntityEnclosed($method, array $params = []) - { - if (!$this->wrapped instanceof EntityEnclosingRequestInterface) { - throw new BadMethodCallException( - sprintf( - 'Cannot call method "%s" on a request that does not enclose an entity.' - . ' Did you expect a POST/PUT request instead of %s %s?', - $method, - $this->wrapped->getMethod(), - $this->wrapped->getPath() - ) - ); - } - - return call_user_func_array([$this->wrapped, $method], $params); - } - - private function init(array $params) - { - foreach ($params as $property => $value) { - if (property_exists($this, $property)) { - $this->{$property} = $value; - } - } - } -} diff --git a/src/RequestCollectionFacade.php b/src/RequestCollectionFacade.php index e185902..33f78c9 100644 --- a/src/RequestCollectionFacade.php +++ b/src/RequestCollectionFacade.php @@ -1,69 +1,50 @@ client = $client; } - /** - * @return UnifiedRequest - */ - public function latest() + public function latest() : RequestInterface { return $this->getRecordedRequest('/_request/last'); } - /** - * @return UnifiedRequest - */ - public function last() + public function last() : RequestInterface { return $this->getRecordedRequest('/_request/last'); } - /** - * @return UnifiedRequest - */ - public function first() + public function first() : RequestInterface { return $this->getRecordedRequest('/_request/first'); } - /** - * @param integer $position - * @return UnifiedRequest - */ - public function at($position) + public function at($position) : RequestInterface { - return $this->getRecordedRequest('/_request/' . $position); + return $this->getRecordedRequest('/_request/' . $position); } - /** - * @return UnifiedRequest - */ - public function pop() + public function pop() : RequestInterface { return $this->deleteRecordedRequest('/_request/last'); } - /** - * @return UnifiedRequest - */ - public function shift() + public function shift() : RequestInterface { return $this->deleteRecordedRequest('/_request/first'); } @@ -71,72 +52,27 @@ public function shift() public function count() { $response = $this->client - ->get('/_request/count') - ->send(); + ->get('/_request/count'); - return (int) $response->getBody(true); + return (int) $response->getBody()->getContents(); } - /** - * @param Response $response - * @param string $path - * @throws UnexpectedValueException - * @return UnifiedRequest - */ - private function parseRequestFromResponse(Response $response, $path) + private function parseRequestFromResponse(ResponseInterface $response, $path) : Request { try { - $requestInfo = Util::deserialize($response->getBody()); + $contents = $response->getBody()->getContents(); + $requestInfo = Util::deserialize($contents); } catch (UnexpectedValueException $e) { - throw new UnexpectedValueException( - sprintf('Cannot deserialize response from "%s": "%s"', $path, $response->getBody()), - null, - $e - ); - } - - $request = RequestFactory::getInstance()->fromMessage($requestInfo['request']); - $params = $this->configureRequest( - $request, - $requestInfo['server'], - isset($requestInfo['enclosure']) ? $requestInfo['enclosure'] : [] - ); - - return new UnifiedRequest($request, $params); - } - - private function configureRequest(RequestInterface $request, array $server, array $enclosure) - { - if (isset($server['HTTP_HOST'])) { - $request->setHost($server['HTTP_HOST']); - } - - if (isset($server['HTTP_PORT'])) { - $request->setPort($server['HTTP_PORT']); - } - - if (isset($server['PHP_AUTH_USER'])) { - $request->setAuth($server['PHP_AUTH_USER'], isset($server['PHP_AUTH_PW']) ? $server['PHP_AUTH_PW'] : null); - } - - $params = []; - - if (isset($server['HTTP_USER_AGENT'])) { - $params['userAgent'] = $server['HTTP_USER_AGENT']; - } - - if ($request instanceof EntityEnclosingRequestInterface) { - $request->addPostFields($enclosure); + throw new UnexpectedValueException(sprintf('Cannot deserialize response from "%s": "%s"', $path, $contents), null, $e); } - return $params; + return parse_request($requestInfo['request']); } private function getRecordedRequest($path) { $response = $this->client - ->get($path) - ->send(); + ->get($path); return $this->parseResponse($response, $path); } @@ -144,30 +80,25 @@ private function getRecordedRequest($path) private function deleteRecordedRequest($path) { $response = $this->client - ->delete($path) - ->send(); + ->delete($path); return $this->parseResponse($response, $path); } - private function parseResponse(Response $response, $path) + private function parseResponse(ResponseInterface $response, $path) { $statusCode = $response->getStatusCode(); if ($statusCode !== 200) { - throw new UnexpectedValueException( - sprintf('Expected status code 200 from "%s", got %d', $path, $statusCode) - ); + throw new UnexpectedValueException(sprintf('Expected status code 200 from "%s", got %d', $path, $statusCode)); } $contentType = $response->hasHeader('content-type') - ? $response->getContentType() + ? $response->getHeaderLine('content-type') : ''; if (substr($contentType, 0, 10) !== 'text/plain') { - throw new UnexpectedValueException( - sprintf('Expected content type "text/plain" from "%s", got "%s"', $path, $contentType) - ); + throw new UnexpectedValueException(sprintf('Expected content type "text/plain" from "%s", got "%s"', $path, $contentType)); } return $this->parseRequestFromResponse($response, $path); diff --git a/src/RequestStorage.php b/src/RequestStorage.php index f2838f8..0191d7d 100644 --- a/src/RequestStorage.php +++ b/src/RequestStorage.php @@ -1,7 +1,8 @@ directory . $this->pid . '-' . $name . '-' . $request->server->get('SERVER_PORT'); + return $this->directory . $this->pid . '-' . $name . '-' . $request->getUri()->getPort(); } public function clear(Request $request, $name) diff --git a/src/Response/CallbackResponse.php b/src/Response/CallbackResponse.php deleted file mode 100644 index 025979c..0000000 --- a/src/Response/CallbackResponse.php +++ /dev/null @@ -1,28 +0,0 @@ -callback = $callback; - } - - public function sendCallback() - { - if ($this->callback) { - $callback = $this->callback; - $callback($this); - } - } - - public function send() - { - $this->sendCallback(); - parent::send(); - } -} diff --git a/src/ResponseBuilder.php b/src/ResponseBuilder.php index 62890ba..8d8d108 100644 --- a/src/ResponseBuilder.php +++ b/src/ResponseBuilder.php @@ -1,59 +1,71 @@ mockBuilder = $mockBuilder; - $this->response = new CallbackResponse(); + $this->response = new Response(); } - public function statusCode($statusCode) + public function statusCode(int $statusCode) : self { - $this->response->setStatusCode($statusCode); + $this->response = $this->response->withStatus($statusCode); return $this; } - public function body($body) + public function body(string $body) : self { - $this->response->setContent($body); + $this->response = $this->response->withBody(stream_for($body)); return $this; } - public function callback(Closure $callback) + public function callback(Closure $callback) : self { - $this->response->setCallback(new SerializableClosure($callback)); + $this->responseCallback = new SerializableClosure($callback); return $this; } - public function header($header, $value) + public function header(string $header, string $value) : self { - $this->response->headers->set($header, $value); + $this->response = $this->response->withHeader($header, $value); return $this; } - public function end() + public function end() : MockBuilder { return $this->mockBuilder; } - public function getResponse() + public function getResponse() : ResponseInterface { return $this->response; } + + public function getResponseCallback() + { + return $this->responseCallback; + } } diff --git a/src/Server.php b/src/Server.php index 24cd15f..47743d0 100644 --- a/src/Server.php +++ b/src/Server.php @@ -1,19 +1,21 @@ getBaseUrl()); - $client->getEventDispatcher()->addListener( - 'request.error', - static function (Event $event) { - $event->stopPropagation(); - } - ); - - return $client; + return new Client(['base_uri' => $this->getBaseUrl(), 'http_errors' => false]); } public function getBaseUrl() @@ -76,6 +70,7 @@ public function getConnectionString() /** * @param Expectation[] $expectations + * * @throws RuntimeException */ public function setUp(array $expectations) @@ -84,16 +79,16 @@ public function setUp(array $expectations) foreach ($expectations as $expectation) { $response = $this->getClient()->post( '/_expectation', - null, - [ - 'matcher' => serialize($expectation->getMatcherClosures()), - 'limiter' => serialize($expectation->getLimiter()), - 'response' => serialize($expectation->getResponse()), - ] - )->send(); + ['json' => [ + 'matcher' => serialize($expectation->getMatcherClosures()), + 'limiter' => serialize($expectation->getLimiter()), + 'response' => Util::serializePsrMessage($expectation->getResponse()), + 'responseCallback' => serialize($expectation->getResponseCallback()), + ]] + ); if ($response->getStatusCode() !== 201) { - throw new RuntimeException('Could not set up expectations'); + throw new RuntimeException('Could not set up expectations: ' . $response->getBody()->getContents()); } } } @@ -104,7 +99,7 @@ public function clean() $this->start(); } - $this->getClient()->delete('/_all')->send(); + $this->getClient()->delete('/_all'); } private function pollWait() @@ -112,11 +107,53 @@ private function pollWait() foreach (FibonacciFactory::sequence(50000, 10000) as $sleepTime) { try { usleep($sleepTime); - $this->getClient()->head('/_me')->send(); + $this->getClient()->head('/_me'); break; - } catch (CurlException $e) { + } catch (\Exception $e) { continue; } } } + + public function getIncrementalErrorOutput() + { + return self::cleanErrorOutput(parent::getIncrementalErrorOutput()); + } + + public function getErrorOutput() + { + return self::cleanErrorOutput(parent::getErrorOutput()); + } + + private static function cleanErrorOutput($output) + { + if (!trim($output)) { + return ''; + } + + $errorLines = []; + + foreach (explode(PHP_EOL, $output) as $line) { + if (!$line) { + continue; + } + + if (!self::stringEndsWithAny($line, ['Accepted', 'Closing', ' started'])) { + $errorLines[] = $line; + } + } + + return $errorLines ? implode(PHP_EOL, $errorLines) : ''; + } + + private static function stringEndsWithAny($haystack, array $needles) + { + foreach ($needles as $needle) { + if (substr($haystack, (-1 * strlen($needle))) === $needle) { + return true; + } + } + + return false; + } } diff --git a/src/Util.php b/src/Util.php index 6437a41..b0283f9 100644 --- a/src/Util.php +++ b/src/Util.php @@ -1,6 +1,9 @@ getHeaders(); + foreach ($headers as $key => $list) { + foreach ($list as $value) { + if (substr($key, 0, 5) === 'HTTP_') { + $newKey = substr($key, 5); + $newKey = str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', $newKey)))); + $message = $message->withoutHeader($key)->withHeader($newKey, $value); + } + } + } + + if (!$message->hasHeader('cache-control')) { + $message->withHeader('cache-control', 'no-cache, private'); + } + + return str($message); + } } diff --git a/src/app.php b/src/app.php index 4df7419..0c6075a 100644 --- a/src/app.php +++ b/src/app.php @@ -1,13 +1,17 @@ - [ + 'displayErrorDetails' => true, + ], +]); +$container['storage'] = new RequestStorage(getmypid(), __DIR__ . '/../state/'); +$app = new App($container); $app->delete( '/_expectation', - static function (Request $request) use ($app) { - $app['storage']->clear($request, 'expectations'); + function (Request $request, Response $response) use ($container) { + $container['storage']->clear($request, 'expectations'); - return new Response('', Response::HTTP_OK); + return $response->withStatus(StatusCode::HTTP_OK); } ); $app->post( '/_expectation', - static function (Request $request) use ($app) { - + function (Request $request, Response $response) use ($container) { + $data = json_decode($request->getBody()->getContents(), true); $matcher = []; - if ($request->request->has('matcher')) { - $matcher = Util::silentDeserialize($request->request->get('matcher')); - $validator = static function ($closure) { + if (!empty($data['matcher'])) { + $matcher = Util::silentDeserialize($data['matcher']); + $validator = function ($closure) { return is_callable($closure); }; if (!is_array($matcher) || count(array_filter($matcher, $validator)) !== count($matcher)) { - return new Response( - 'POST data key "matcher" must be a serialized list of closures', - Response::HTTP_EXPECTATION_FAILED + return $response->withStatus(StatusCode::HTTP_EXPECTATION_FAILED)->write( + 'POST data key "matcher" must be a serialized list of closures' ); } } - if (!$request->request->has('response')) { - return new Response('POST data key "response" not found in POST data', Response::HTTP_EXPECTATION_FAILED); + if (empty($data['response'])) { + return $response->withStatus(StatusCode::HTTP_EXPECTATION_FAILED)->write( + 'POST data key "response" not found in POST data' + ); } - $response = Util::silentDeserialize($request->request->get('response')); - - if (!$response instanceof Response) { - return new Response( - 'POST data key "response" must be a serialized Symfony response', - Response::HTTP_EXPECTATION_FAILED + try { + $responseToSave = Util::responseDeserialize($data['response']); + } catch (Exception $e) { + return $response->withStatus(StatusCode::HTTP_EXPECTATION_FAILED)->write( + 'POST data key "response" must be an http response message in text form' ); } $limiter = null; - if ($request->request->has('limiter')) { - $limiter = Util::silentDeserialize($request->request->get('limiter')); + if (!empty($data['limiter'])) { + $limiter = Util::silentDeserialize($data['limiter']); if (!is_callable($limiter)) { - return new Response( - 'POST data key "limiter" must be a serialized closure', - Response::HTTP_EXPECTATION_FAILED + return $response->withStatus(StatusCode::HTTP_EXPECTATION_FAILED)->write( + 'POST data key "limiter" must be a serialized closure' ); } } // Fix issue with silex default error handling - $response->headers->set('X-Status-Code', $response->getStatusCode()); + // not sure if this is need anymore + $response = $response->withHeader('X-Status-Code', $response->getStatusCode()); + + $responseCallback = null; + if (!empty($data['responseCallback'])) { + $responseCallback = Util::silentDeserialize($data['responseCallback']); + + if ($responseCallback !== null && !is_callable($responseCallback)) { + return $response->withStatus(StatusCode::HTTP_EXPECTATION_FAILED)->write( + 'POST data key "responseCallback" must be a serialized closure: ' + . print_r($data['responseCallback'], true) + ); + } + } - $app['storage']->prepend( + $container['storage']->prepend( $request, 'expectations', - ['matcher' => $matcher, 'response' => $response, 'limiter' => $limiter, 'runs' => 0] + [ + 'matcher' => $matcher, + 'response' => $data['response'], + 'limiter' => $limiter, + 'responseCallback' => $responseCallback, + 'runs' => 0, + ] ); - return new Response('', Response::HTTP_CREATED); + return $response->withStatus(StatusCode::HTTP_CREATED); } ); -$app->error( - static function (Exception $e, Request $request, $code, GetResponseForExceptionEvent $event = null) use ($app) { - if ($e instanceof NotFoundHttpException) { - $app['storage']->append( - $request, - 'requests', - serialize( - [ - 'server' => $request->server->all(), - 'request' => (string) $request, - 'enclosure' => $request->request->all(), - ] - ) - ); +$container['phpErrorHandler'] = function ($container) { + return function (Request $request, Response $response, Error $e) { + return $response->withStatus(500) + ->withHeader('Content-Type', 'text/plain') + ->write($e->getMessage() . "\n" . $e->getTraceAsString() . "\n"); + }; +}; + +$container['notFoundHandler'] = function ($container) { + return function (Request $request, Response $response) use ($container) { + $container['storage']->append( + $request, + 'requests', + serialize( + [ + 'request' => Util::serializePsrMessage($request), + 'server' => $request->getServerParams(), + ] + ) + ); - $notFoundResponse = new Response('No matching expectation found', Response::HTTP_NOT_FOUND); + $notFoundResponse = $response->withStatus(StatusCode::HTTP_NOT_FOUND); - $expectations = $app['storage']->read($request, 'expectations'); + $expectations = $container['storage']->read($request, 'expectations'); - foreach ($expectations as $pos => $expectation) { - foreach ($expectation['matcher'] as $matcher) { - if (!$matcher($request)) { - continue 2; - } + foreach ($expectations as $pos => $expectation) { + foreach ($expectation['matcher'] as $matcher) { + if (!$matcher($request)) { + continue 2; } + } - if (isset($expectation['limiter']) && !$expectation['limiter']($expectation['runs'])) { - $notFoundResponse = new Response('Expectation no longer applicable', Response::HTTP_GONE); - continue; + if (isset($expectation['limiter']) && !$expectation['limiter']($expectation['runs'])) { + if ($notFoundResponse->getStatusCode() != StatusCode::HTTP_GONE) { + $notFoundResponse = $response->withStatus(StatusCode::HTTP_GONE) + ->write('Expectation no longer applicable'); } + continue; + } - ++$expectations[$pos]['runs']; - $app['storage']->store($request, 'expectations', $expectations); + $expectations[$pos]['runs']++; + $container['storage']->store($request, 'expectations', $expectations); - if (method_exists($event, 'allowCustomResponseCode')) { - $event->allowCustomResponseCode(); - } + $r = Util::responseDeserialize($expectation['response']); + if (!empty($expectation['responseCallback'])) { + $callback = $expectation['responseCallback']; - return $expectation['response']; + return $callback($r); } - return $notFoundResponse; + return $r; } - return new Response('Server error: ' . $e->getMessage(), $code); - } -); + if ($notFoundResponse->getStatusCode() == StatusCode::HTTP_NOT_FOUND) { + $notFoundResponse = $notFoundResponse->write('No matching expectation found'); + } + + return $notFoundResponse; + }; +}; + +$container['errorHandler'] = function ($container) { + return function (Request $request, Response $response, Exception $e) { + return $response->withStatus(StatusCode::HTTP_INTERNAL_SERVER_ERROR)->write( + 'Server error: ' . $e->getMessage()); + }; +}; $app->get( '/_request/count', - static function (Request $request) use ($app) { - return count($app['storage']->read($request, 'requests')); + function (Request $request, Response $response) use ($container) { + $count = count($container['storage']->read($request, 'requests')); + + return $response->withStatus(StatusCode::HTTP_OK) + ->write($count) + ->withHeader('Content-Type', 'text/plain'); } ); $app->get( - '/_request/{index}', - static function (Request $request, $index) use ($app) { - $requestData = $app['storage']->read($request, 'requests'); + '/_request/{index:[0-9]+}', + function (Request $request, Response $response, $args) use ($container) { + $index = (int) $args['index']; + $requestData = $container['storage']->read($request, 'requests'); if (!isset($requestData[$index])) { - return new Response('Index ' . $index . ' not found', Response::HTTP_NOT_FOUND); + return $response->withStatus(StatusCode::HTTP_NOT_FOUND)->write( + 'Index ' . $index . ' not found'); } - return new Response($requestData[$index], Response::HTTP_OK, ['Content-Type' => 'text/plain']); + return $response->withStatus(StatusCode::HTTP_OK) + ->write($requestData[$index]) + ->withHeader('Content-Type', 'text/plain'); } -)->assert('index', '\d+'); +); $app->delete( - '/_request/{action}', - static function (Request $request, $action) use ($app) { - $requestData = $app['storage']->read($request, 'requests'); - $fn = 'array_' . ($action === 'last' ? 'pop' : 'shift'); + '/_request/{action:last|latest|first}', + function (Request $request, Response $response, $args) use ($container) { + $action = $args['action']; + + $requestData = $container['storage']->read($request, 'requests'); + $fn = 'array_' . ($action === 'last' || $action === 'latest' ? 'pop' : 'shift'); $requestString = $fn($requestData); - $app['storage']->store($request, 'requests', $requestData); + $container['storage']->store($request, 'requests', $requestData); if (!$requestString) { - return new Response($action . ' not possible', Response::HTTP_NOT_FOUND); + return $response->withStatus(StatusCode::HTTP_NOT_FOUND)->write( + $action . ' not possible' + ); } - return new Response($requestString, Response::HTTP_OK, ['Content-Type' => 'text/plain']); + return $response->withStatus(StatusCode::HTTP_OK) + ->write($requestString) + ->withHeader('Content-Type', 'text/plain'); } -)->assert('index', '(last|first)'); +); $app->get( - '/_request/{action}', - static function (Request $request, $action) use ($app) { - $requestData = $app['storage']->read($request, 'requests'); - $fn = 'array_' . ($action === 'last' ? 'pop' : 'shift'); + '/_request/{action:last|latest|first}', + function (Request $request, Response $response, $args) use ($container) { + $action = $args['action']; + $requestData = $container['storage']->read($request, 'requests'); + $fn = 'array_' . ($action === 'last' || $action === 'latest' ? 'pop' : 'shift'); $requestString = $fn($requestData); if (!$requestString) { - return new Response($action . ' not available', Response::HTTP_NOT_FOUND); + return $response->withStatus(StatusCode::HTTP_NOT_FOUND)->write( + $action . ' not available' + ); } - return new Response($requestString, Response::HTTP_OK, ['Content-Type' => 'text/plain']); + return $response->withStatus(StatusCode::HTTP_OK) + ->withHeader('Content-Type', 'text/plain') + ->write($requestString); } -)->assert('index', '(last|first)'); +); $app->delete( '/_request', - static function (Request $request) use ($app) { - $app['storage']->store($request, 'requests', []); + function (Request $request, Response $response) use ($container) { + $container['storage']->store($request, 'requests', []); - return new Response('', Response::HTTP_OK); + return $response->withStatus(StatusCode::HTTP_OK); } ); $app->delete( '/_all', - static function (Request $request) use ($app) { - $app['storage']->store($request, 'requests', []); - $app['storage']->store($request, 'expectations', []); + function (Request $request, Response $response) use ($container) { + $container['storage']->store($request, 'requests', []); + $container['storage']->store($request, 'expectations', []); - return new Response('', Response::HTTP_OK); + return $response->withStatus(StatusCode::HTTP_OK); } ); $app->get( '/_me', - static function () { - return new Response('O RLY?', Response::HTTP_I_AM_A_TEAPOT, ['Content-Type' => 'text/plain']); + function (Request $request, Response $response) { + return $response->withStatus(StatusCode::HTTP_IM_A_TEAPOT) + ->write('O RLY?') + ->withHeader('Content-Type', 'text/plain'); } ); diff --git a/tests/AppIntegrationTest.php b/tests/AppIntegrationTest.php index 491cfe3..a63e6a4 100644 --- a/tests/AppIntegrationTest.php +++ b/tests/AppIntegrationTest.php @@ -1,16 +1,14 @@ getOutput(), (string) static::$server1->getOutput()); - static::assertSame('', (string) static::$server1->getErrorOutput(), (string) static::$server1->getErrorOutput()); + $out = (string) static::$server1->getOutput(); + static::assertSame('', $out, $out); + + $out = (string) static::$server1->getErrorOutput(); + //static::assertSame('', $out, $out); + echo $out . "\n"; + static::$server1->stop(); } @@ -49,110 +52,135 @@ public function setUp() public function testSimpleUseCase() { - $response = $this->client->post( - '/_expectation', - null, - $this->createExpectationParams( - [ - static function ($request) { - return $request instanceof Request; - } - ], - new Response('fake body', 200) - ) - )->send(); + $params = $this->createExpectationParams( + [ + static function ($request) { + return $request instanceof RequestInterface; + }, + ], + new Response(200, ['Host' => 'localhost'], 'fake body') + ); + + $response = $this->client->post('/_expectation', ['json' => $params]); $this->assertSame('', (string) $response->getBody()); $this->assertSame(201, $response->getStatusCode()); - $response = $this->client->post('/foobar', ['X-Special' => 1], ['post' => 'data'])->send(); + $response = $this->client->post('/foobar', [ + 'headers' => ['X-Special' => 1], + 'form_params' => ['post' => 'data'], + ]); $this->assertSame(200, $response->getStatusCode()); $this->assertSame('fake body', (string) $response->getBody()); - $response = $this->client->get('/_request/latest')->send(); + $response = $this->client->get('/_request/latest'); - /** @var EntityEnclosingRequest $request */ $request = $this->parseRequestFromResponse($response); - $this->assertSame('1', (string) $request->getHeader('X-Special')); + $this->assertSame('1', (string) $request->getHeaderLine('X-Special')); $this->assertSame('post=data', (string) $request->getBody()); + + // should be the same as latest + $response = $this->client->get('/_request/last'); + $request = $this->parseRequestFromResponse($response); + $this->assertSame('1', (string) $request->getHeaderLine('X-Special')); } public function testRecording() { - $this->client->delete('/_all')->send(); + $this->client->delete('/_all'); - $this->assertSame(404, $this->client->get('/_request/latest')->send()->getStatusCode()); - $this->assertSame(404, $this->client->get('/_request/0')->send()->getStatusCode()); - $this->assertSame(404, $this->client->get('/_request/first')->send()->getStatusCode()); - $this->assertSame(404, $this->client->get('/_request/last')->send()->getStatusCode()); + $this->assertSame(404, $this->client->get('/_request/latest')->getStatusCode()); + $this->assertSame(404, $this->client->get('/_request/0')->getStatusCode()); + $this->assertSame(404, $this->client->get('/_request/first')->getStatusCode()); + $this->assertSame(404, $this->client->get('/_request/last')->getStatusCode()); - $this->client->get('/req/0')->send(); - $this->client->get('/req/1')->send(); - $this->client->get('/req/2')->send(); - $this->client->get('/req/3')->send(); + $this->client->get('/req/0'); + $this->client->get('/req/1'); + $this->client->get('/req/2'); + $this->client->get('/req/3'); $this->assertSame( '/req/3', - $this->parseRequestFromResponse($this->client->get('/_request/last')->send())->getPath() + $this->parseRequestFromResponse($this->client->get('/_request/last'))->getUri()->getPath() ); $this->assertSame( '/req/0', - $this->parseRequestFromResponse($this->client->get('/_request/0')->send())->getPath() + $this->parseRequestFromResponse($this->client->get('/_request/0'))->getUri()->getPath() ); $this->assertSame( '/req/1', - $this->parseRequestFromResponse($this->client->get('/_request/1')->send())->getPath() + $this->parseRequestFromResponse($this->client->get('/_request/1'))->getUri()->getPath() ); $this->assertSame( '/req/2', - $this->parseRequestFromResponse($this->client->get('/_request/2')->send())->getPath() + $this->parseRequestFromResponse($this->client->get('/_request/2'))->getUri()->getPath() ); $this->assertSame( '/req/3', - $this->parseRequestFromResponse($this->client->get('/_request/3')->send())->getPath() + $this->parseRequestFromResponse($this->client->get('/_request/3'))->getUri()->getPath() ); - $this->assertSame(404, $this->client->get('/_request/4')->send()->getStatusCode()); + $this->assertSame(404, $this->client->get('/_request/4')->getStatusCode()); $this->assertSame( '/req/3', - $this->parseRequestFromResponse($this->client->delete('/_request/last')->send())->getPath() + $this->parseRequestFromResponse($this->client->delete('/_request/last'))->getUri()->getPath() ); $this->assertSame( '/req/0', - $this->parseRequestFromResponse($this->client->delete('/_request/first')->send())->getPath() + $this->parseRequestFromResponse($this->client->delete('/_request/first'))->getUri()->getPath() ); $this->assertSame( '/req/1', - $this->parseRequestFromResponse($this->client->get('/_request/0')->send())->getPath() + $this->parseRequestFromResponse($this->client->get('/_request/0'))->getUri()->getPath() ); $this->assertSame( '/req/2', - $this->parseRequestFromResponse($this->client->get('/_request/1')->send())->getPath() + $this->parseRequestFromResponse($this->client->get('/_request/1'))->getUri()->getPath() ); - $this->assertSame(404, $this->client->get('/_request/2')->send()->getStatusCode()); + $this->assertSame(404, $this->client->get('/_request/2')->getStatusCode()); } public function testErrorHandling() { - $this->client->delete('/_all')->send(); + $this->client->delete('/_all'); + + $tester = function ($matcher, $response = null, $limiter = null) { + $payload = []; + if ($response === null) { + $payload['response'] = \GuzzleHttp\Psr7\str(new Response(200, [], 'foo')); + } elseif ($response !== false) { + $payload['response'] = $response; + } + if ($matcher === null) { + $matcher['matcher'] = serialize([new SerializableClosure(function () { return true; })]); + } elseif ($matcher !== false) { + $payload['matcher'] = $matcher; + } - $response = $this->client->post('/_expectation', null, ['matcher' => ''])->send(); + if ($limiter !== false && $limiter !== null) { + $payload['limiter'] = $limiter; + } + + return $this->client->post('/_expectation', ['json' => $payload]); + }; + + $response = $tester('hi'); $this->assertSame(417, $response->getStatusCode()); $this->assertSame('POST data key "matcher" must be a serialized list of closures', (string) $response->getBody()); - $response = $this->client->post('/_expectation', null, ['matcher' => ['foo']])->send(); + $response = $tester(['foo']); $this->assertSame(417, $response->getStatusCode()); $this->assertSame('POST data key "matcher" must be a serialized list of closures', (string) $response->getBody()); - $response = $this->client->post('/_expectation', null, [])->send(); + $response = $tester(null, false); $this->assertSame(417, $response->getStatusCode()); $this->assertSame('POST data key "response" not found in POST data', (string) $response->getBody()); - $response = $this->client->post('/_expectation', null, ['response' => ''])->send(); + $response = $tester(null, 'foo'); $this->assertSame(417, $response->getStatusCode()); - $this->assertSame('POST data key "response" must be a serialized Symfony response', (string) $response->getBody()); + $this->assertSame('POST data key "response" must be an http response message in text form', (string) $response->getBody()); - $response = $this->client->post('/_expectation', null, ['response' => serialize(new Response()), 'limiter' => 'foo'])->send(); + $response = $tester(null, null, 'foo'); $this->assertSame(417, $response->getStatusCode()); $this->assertSame('POST data key "limiter" must be a serialized closure', (string) $response->getBody()); } @@ -160,13 +188,15 @@ public function testErrorHandling() public function testServerParamsAreRecorded() { $this->client - ->setUserAgent('CUSTOM UA') - ->get('/foo') - ->setAuth('username', 'password') - ->setProtocolVersion('1.0') - ->send(); + ->get('/foo', [ + 'headers' => [ + 'User-Agent' => 'CUSTOM UA', + ], + 'auth' => ['username', 'password'], + 'version' => '1.0', + ]); - $latestRequest = unserialize($this->client->get('/_request/latest')->send()->getBody()); + $latestRequest = unserialize($this->client->get('/_request/latest')->getBody()); $this->assertSame(HTTP_MOCK_HOST, $latestRequest['server']['SERVER_NAME']); $this->assertSame(HTTP_MOCK_PORT, $latestRequest['server']['SERVER_PORT']); @@ -180,38 +210,52 @@ public function testNewestExpectationsAreFirstEvaluated() { $this->client->post( '/_expectation', - null, - $this->createExpectationParams( + ['json' => $this->createExpectationParams( [ static function ($request) { - return $request instanceof Request; - } + return $request instanceof RequestInterface; + }, ], - new Response('first', 200) - ) - )->send(); - $this->assertSame('first', $this->client->get('/')->send()->getBody(true)); + new Response(200, [], 'first') + )] + ); + $this->assertSame('first', $this->client->get('/')->getBody()->getContents()); $this->client->post( '/_expectation', - null, - $this->createExpectationParams( + ['json' => $this->createExpectationParams( [ static function ($request) { - return $request instanceof Request; - } + return $request instanceof RequestInterface; + }, ], - new Response('second', 200) - ) - )->send(); - $this->assertSame('second', $this->client->get('/')->send()->getBody(true)); + new Response(200, [], 'second') + )] + ); + $this->assertSame('second', $this->client->get('/')->getBody()->getContents()); + } + + public function testServerLogsAreNotInErrorOutput() + { + $this->client->delete('/_all'); + + $expectedServerErrorOutput = '[404]: (null) / - No such file or directory'; + + self::$server1->addErrorOutput('PHP 7.4.2 Development Server (http://localhost:8086) started' . PHP_EOL); + self::$server1->addErrorOutput('Accepted' . PHP_EOL); + self::$server1->addErrorOutput($expectedServerErrorOutput . PHP_EOL); + self::$server1->addErrorOutput('Closing' . PHP_EOL); + + $actualServerErrorOutput = self::$server1->getErrorOutput(); + + $this->assertEquals($expectedServerErrorOutput, $actualServerErrorOutput); } - private function parseRequestFromResponse(GuzzleResponse $response) + private function parseRequestFromResponse(ResponseInterface $response) { $body = unserialize($response->getBody()); - return RequestFactory::getInstance()->fromMessage($body['request']); + return \GuzzleHttp\Psr7\parse_request($body['request']); } private function createExpectationParams(array $closures, Response $response) @@ -221,8 +265,8 @@ private function createExpectationParams(array $closures, Response $response) } return [ - 'matcher' => serialize($closures), - 'response' => serialize($response), + 'matcher' => serialize($closures), + 'response' => \GuzzleHttp\Psr7\str($response), ]; } } diff --git a/tests/Fixtures/Request.php b/tests/Fixtures/Request.php index b6d746e..2f09d81 100644 --- a/tests/Fixtures/Request.php +++ b/tests/Fixtures/Request.php @@ -1,10 +1,21 @@ requestUri = $requestUri; diff --git a/tests/Matcher/ExtractorFactoryTest.php b/tests/Matcher/ExtractorFactoryTest.php index c71dd42..16ca88e 100644 --- a/tests/Matcher/ExtractorFactoryTest.php +++ b/tests/Matcher/ExtractorFactoryTest.php @@ -1,9 +1,10 @@ extractorFactory = new ExtractorFactory(); - $this->request = $this->createMock('Symfony\Component\HttpFoundation\Request'); } public function testGetMethod() { - $this->request - ->expects($this->once()) - ->method('getMethod') - ->will($this->returnValue('POST')); + $request = new Request( + 'POST', + '/' + ); $extractor = $this->extractorFactory->createMethodExtractor(); - $this->assertSame('POST', $extractor($this->request)); + $this->assertSame('POST', $extractor($request)); } public function testGetPath() { - $this->request - ->expects($this->once()) - ->method('getPathInfo') - ->will($this->returnValue('/foo/bar')); + $request = new Request( + 'GET', + '/foo/bar' + ); $extractor = $this->extractorFactory->createPathExtractor(); - $this->assertSame('/foo/bar', $extractor($this->request)); + $this->assertSame('/foo/bar', $extractor($request)); } public function testGetPathWithBasePath() { - $this->request - ->expects($this->once()) - ->method('getPathInfo') - ->will($this->returnValue('/foo/bar')); + $request = new Request( + 'GET', + '/foo/bar' + ); $extractorFactory = new ExtractorFactory('/foo'); $extractor = $extractorFactory->createPathExtractor(); - $this->assertSame('/bar', $extractor($this->request)); + $this->assertSame('/bar', $extractor($request)); } public function testGetPathWithBasePathTrailingSlash() { - $this->request - ->expects($this->once()) - ->method('getPathInfo') - ->will($this->returnValue('/foo/bar')); + $request = new Request( + 'GET', + '/foo/bar' + ); $extractorFactory = new ExtractorFactory('/foo/'); $extractor = $extractorFactory->createPathExtractor(); - $this->assertSame('/bar', $extractor($this->request)); + $this->assertSame('/bar', $extractor($request)); } public function testGetPathWithBasePathThatDoesNotMatch() { - $this->request - ->expects($this->once()) - ->method('getPathInfo') - ->will($this->returnValue('/bar')); + $request = new Request( + 'GET', + '/bar' + ); $extractorFactory = new ExtractorFactory('/foo'); $extractor = $extractorFactory->createPathExtractor(); - $this->assertSame('', $extractor($this->request)); + $this->assertSame('', $extractor($request)); } public function testGetHeaderWithExistingHeader() { $request = new Request( - [], - [], - [], - [], - [], - ['HTTP_CONTENT_TYPE' => 'application/json'] + 'GET', + '/', + ['Content-Type' => 'application/json'] ); $extractorFactory = new ExtractorFactory('/foo'); @@ -101,12 +98,9 @@ public function testGetHeaderWithExistingHeader() public function testGetHeaderWithNonExistingHeader() { $request = new Request( - [], - [], - [], - [], - [], - ['HTTP_X_FOO' => 'bar'] + 'GET', + '/', + ['X-Foo' => 'bar'] ); $extractorFactory = new ExtractorFactory('/foo'); @@ -118,12 +112,9 @@ public function testGetHeaderWithNonExistingHeader() public function testHeaderExistsWithExistingHeader() { $request = new Request( - [], - [], - [], - [], - [], - ['HTTP_CONTENT_TYPE' => 'application/json'] + 'GET', + '/', + ['Content-Type' => 'application/json'] ); $extractorFactory = new ExtractorFactory('/foo'); @@ -135,12 +126,9 @@ public function testHeaderExistsWithExistingHeader() public function testHeaderExistsWithNonExistingHeader() { $request = new Request( - [], - [], - [], - [], - [], - ['HTTP_X_FOO' => 'bar'] + 'GET', + '/', + ['X-Foo' => 'bar'] ); $extractorFactory = new ExtractorFactory('/foo'); diff --git a/tests/Matcher/StringMatcherTest.php b/tests/Matcher/StringMatcherTest.php index 32df60c..f9cbca9 100644 --- a/tests/Matcher/StringMatcherTest.php +++ b/tests/Matcher/StringMatcherTest.php @@ -1,18 +1,19 @@ setExtractor(static function() { - return 0; + $matcher->setExtractor(static function () { + return 0; }); - self::assertTrue($matcher->getMatcher()(new Request())); + self::assertTrue($matcher->getMatcher()(new Request('GET', '/'))); } } diff --git a/tests/MockBuilderIntegrationTest.php b/tests/MockBuilderIntegrationTest.php index 9b64c27..3a29d71 100644 --- a/tests/MockBuilderIntegrationTest.php +++ b/tests/MockBuilderIntegrationTest.php @@ -1,4 +1,5 @@ pathIs('/foo') ->methodIs($this->matches->regex('/POST/')) ->callback(static function (Request $request) { - error_log('CLOSURE MATCHER: ' . $request->getMethod() . ' ' . $request->getPathInfo()); + error_log('CLOSURE MATCHER: ' . $request->getMethod() . ' ' . $request->getUri()->getPath()); + return true; }) ->then() @@ -65,9 +65,7 @@ public function testCreateExpectation() /** @var Expectation $expectation */ $expectation = current($expectations); - $request = new TestRequest(); - $request->setMethod('POST'); - $request->setRequestUri('/foo'); + $request = new TestRequest('POST', '/foo'); $run = 0; $oldValue = ini_set('error_log', '/dev/null'); @@ -82,16 +80,11 @@ public function testCreateExpectation() ini_set('error_log', $oldValue); $this->assertSame(3, $run); - $expectation->getResponse()->setDate(new DateTime('2012-11-10 09:08:07', new DateTimeZone('UTC'))); - $response = "HTTP/1.0 401 Unauthorized\r\nCache-Control: no-cache, private\r\nDate: Sat, 10 Nov 2012 09:08:07 GMT\r\nX-Foo: Bar\r\n\r\nresponse body"; - $this->assertSame($response, (string)$expectation->getResponse()); - - $this->server->setUp($expectations); $client = $this->server->getClient(); - $this->assertSame('response body', (string) $client->post('/foo')->send()->getBody()); + $this->assertSame('response body', (string) $client->post('/foo')->getBody()); $this->assertContains('CLOSURE MATCHER: POST /foo', $this->server->getErrorOutput()); } @@ -118,9 +111,9 @@ public function testCreateTwoExpectationsAfterEachOther() ->end(); $this->server->setUp($this->builder->flushExpectations()); - $this->assertSame('POST 1', (string) $this->server->getClient()->post('/post-resource-1')->send()->getBody()); - $this->assertSame('POST 2', (string) $this->server->getClient()->post('/post-resource-2')->send()->getBody()); - $this->assertSame('POST 1', (string) $this->server->getClient()->post('/post-resource-1')->send()->getBody()); - $this->assertSame('POST 2', (string) $this->server->getClient()->post('/post-resource-2')->send()->getBody()); + $this->assertSame('POST 1', (string) $this->server->getClient()->post('/post-resource-1')->getBody()); + $this->assertSame('POST 2', (string) $this->server->getClient()->post('/post-resource-2')->getBody()); + $this->assertSame('POST 1', (string) $this->server->getClient()->post('/post-resource-1')->getBody()); + $this->assertSame('POST 2', (string) $this->server->getClient()->post('/post-resource-2')->getBody()); } } diff --git a/tests/PHPUnit/HttpMockMultiPHPUnitIntegrationTest.php b/tests/PHPUnit/HttpMockMultiPHPUnitIntegrationTest.php index d4561ef..639f88b 100644 --- a/tests/PHPUnit/HttpMockMultiPHPUnitIntegrationTest.php +++ b/tests/PHPUnit/HttpMockMultiPHPUnitIntegrationTest.php @@ -1,10 +1,11 @@ end(); $this->http['firstNamedServer']->setUp(); - $this->assertSame($path . ' body', (string) $this->http['firstNamedServer']->client->get($path)->send()->getBody()); + $this->assertSame($path . ' body', (string) $this->http['firstNamedServer']->client->get($path)->getBody()); $request = $this->http['firstNamedServer']->requests->latest(); $this->assertSame('GET', $request->getMethod()); - $this->assertSame($path, $request->getPath()); + $this->assertSame($path, $request->getUri()->getPath()); $request = $this->http['firstNamedServer']->requests->last(); $this->assertSame('GET', $request->getMethod()); - $this->assertSame($path, $request->getPath()); + $this->assertSame($path, $request->getUri()->getPath()); $request = $this->http['firstNamedServer']->requests->first(); $this->assertSame('GET', $request->getMethod()); - $this->assertSame($path, $request->getPath()); + $this->assertSame($path, $request->getUri()->getPath()); $request = $this->http['firstNamedServer']->requests->at(0); $this->assertSame('GET', $request->getMethod()); - $this->assertSame($path, $request->getPath()); + $this->assertSame($path, $request->getUri()->getPath()); $request = $this->http['firstNamedServer']->requests->pop(); $this->assertSame('GET', $request->getMethod()); - $this->assertSame($path, $request->getPath()); + $this->assertSame($path, $request->getUri()->getPath()); - $this->assertSame($path . ' body', (string) $this->http['firstNamedServer']->client->get($path)->send()->getBody()); + $this->assertSame($path . ' body', (string) $this->http['firstNamedServer']->client->get($path)->getBody()); $request = $this->http['firstNamedServer']->requests->shift(); $this->assertSame('GET', $request->getMethod()); - $this->assertSame($path, $request->getPath()); + $this->assertSame($path, $request->getUri()->getPath()); $this->expectException('UnexpectedValueException'); @@ -91,12 +92,12 @@ public function testErrorLogOutput() { $this->http['firstNamedServer']->mock ->when() - ->callback(static function () {error_log('error output');}) + ->callback(static function () {error_log('error output'); }) ->then() ->end(); $this->http['firstNamedServer']->setUp(); - $this->http['firstNamedServer']->client->get('/foo')->send(); + $this->http['firstNamedServer']->client->get('/foo'); // Should fail during tear down as we have an error_log() on the server side try { @@ -109,7 +110,7 @@ public function testErrorLogOutput() public function testFailedRequest() { - $response = $this->http['firstNamedServer']->client->get('/foo')->send(); + $response = $this->http['firstNamedServer']->client->get('/foo'); $this->assertSame(404, $response->getStatusCode()); $this->assertSame('No matching expectation found', (string) $response->getBody()); } @@ -122,7 +123,7 @@ public function testStopServer() /** @depends testStopServer */ public function testHttpServerIsRestartedIfATestStopsIt() { - $response = $this->http['firstNamedServer']->client->get('/')->send(); + $response = $this->http['firstNamedServer']->client->get('/'); $this->assertSame(404, $response->getStatusCode()); } @@ -136,11 +137,11 @@ public function testLimitDurationOfAResponse() ->body('POST METHOD') ->end(); $this->http['firstNamedServer']->setUp(); - $firstResponse = $this->http['firstNamedServer']->client->post('/')->send(); + $firstResponse = $this->http['firstNamedServer']->client->post('/'); $this->assertSame(200, $firstResponse->getStatusCode()); - $secondResponse = $this->http['firstNamedServer']->client->post('/')->send(); + $secondResponse = $this->http['firstNamedServer']->client->post('/'); $this->assertSame(410, $secondResponse->getStatusCode()); - $this->assertSame('Expectation no longer applicable', $secondResponse->getBody(true)); + $this->assertSame('Expectation no longer applicable', $secondResponse->getBody()->getContents()); $this->http['firstNamedServer']->mock ->exactly(2) @@ -150,13 +151,13 @@ public function testLimitDurationOfAResponse() ->body('POST METHOD') ->end(); $this->http['firstNamedServer']->setUp(); - $firstResponse = $this->http['firstNamedServer']->client->post('/')->send(); + $firstResponse = $this->http['firstNamedServer']->client->post('/'); $this->assertSame(200, $firstResponse->getStatusCode()); - $secondResponse = $this->http['firstNamedServer']->client->post('/')->send(); + $secondResponse = $this->http['firstNamedServer']->client->post('/'); $this->assertSame(200, $secondResponse->getStatusCode()); - $thirdResponse = $this->http['firstNamedServer']->client->post('/')->send(); + $thirdResponse = $this->http['firstNamedServer']->client->post('/'); $this->assertSame(410, $thirdResponse->getStatusCode()); - $this->assertSame('Expectation no longer applicable', $thirdResponse->getBody(true)); + $this->assertSame('Expectation no longer applicable', (string) $thirdResponse->getBody()); $this->http['firstNamedServer']->mock ->any() @@ -166,11 +167,11 @@ public function testLimitDurationOfAResponse() ->body('POST METHOD') ->end(); $this->http['firstNamedServer']->setUp(); - $firstResponse = $this->http['firstNamedServer']->client->post('/')->send(); + $firstResponse = $this->http['firstNamedServer']->client->post('/'); $this->assertSame(200, $firstResponse->getStatusCode()); - $secondResponse = $this->http['firstNamedServer']->client->post('/')->send(); + $secondResponse = $this->http['firstNamedServer']->client->post('/'); $this->assertSame(200, $secondResponse->getStatusCode()); - $thirdResponse = $this->http['firstNamedServer']->client->post('/')->send(); + $thirdResponse = $this->http['firstNamedServer']->client->post('/'); $this->assertSame(200, $thirdResponse->getStatusCode()); } @@ -180,10 +181,10 @@ public function testCallbackOnResponse() ->when() ->methodIs('POST') ->then() - ->callback(static function(Response $response) {$response->setContent('CALLBACK');}) + ->callback(static function (Response $response) {return $response->withBody(\GuzzleHttp\Psr7\stream_for('CALLBACK')); }) ->end(); $this->http['firstNamedServer']->setUp(); - $this->assertSame('CALLBACK', $this->http['firstNamedServer']->client->post('/')->send()->getBody(true)); + $this->assertSame('CALLBACK', (string) $this->http['firstNamedServer']->client->post('/')->getBody()); } public function testComplexResponse() @@ -198,11 +199,16 @@ public function testComplexResponse() ->end(); $this->http['firstNamedServer']->setUp(); $response = $this->http['firstNamedServer']->client - ->post('/', ['x-client-header' => 'header-value'], ['post-key' => 'post-value'])->send(); - $this->assertSame('BODY', $response->getBody(true)); + ->post('/', [ + 'headers' => ['x-client-header' => 'header-value'], + 'form_params' => ['post-key' => 'post-value'], + ]); + $this->assertSame('BODY', (string) $response->getBody()); $this->assertSame(201, $response->getStatusCode()); - $this->assertSame('Bar', (string) $response->getHeader('X-Foo')); - $this->assertSame('post-value', $this->http['firstNamedServer']->requests->latest()->getPostField('post-key')); + $this->assertSame('Bar', (string) $response->getHeaderLine('X-Foo')); + + parse_str($this->http['firstNamedServer']->requests->latest()->getBody()->getContents(), $body); + $this->assertSame('post-value', $body['post-key']); } public function testPutRequest() @@ -217,11 +223,15 @@ public function testPutRequest() ->end(); $this->http['firstNamedServer']->setUp(); $response = $this->http['firstNamedServer']->client - ->put('/', ['x-client-header' => 'header-value'], ['put-key' => 'put-value'])->send(); - $this->assertSame('BODY', $response->getBody(true)); + ->put('/', [ + 'headers' => ['x-client-header' => 'header-value'], + 'form_params' => ['put-key' => 'put-value'], + ]); + $this->assertSame('BODY', (string) $response->getBody()); $this->assertSame(201, $response->getStatusCode()); - $this->assertSame('Bar', (string) $response->getHeader('X-Foo')); - $this->assertSame('put-value', $this->http['firstNamedServer']->requests->latest()->getPostField('put-key')); + $this->assertSame('Bar', (string) $response->getHeaderLine('X-Foo')); + parse_str($this->http['firstNamedServer']->requests->latest()->getBody()->getContents(), $body); + $this->assertSame('put-value', $body['put-key']); } public function testPostRequest() @@ -236,11 +246,15 @@ public function testPostRequest() ->end(); $this->http['firstNamedServer']->setUp(); $response = $this->http['firstNamedServer']->client - ->post('/', ['x-client-header' => 'header-value'], ['post-key' => 'post-value'])->send(); - $this->assertSame('BODY', $response->getBody(true)); + ->post('/', [ + 'headers' => ['x-client-header' => 'header-value'], + 'form_params' => ['post-key' => 'post-value'], + ]); + $this->assertSame('BODY', (string) $response->getBody()); $this->assertSame(201, $response->getStatusCode()); - $this->assertSame('Bar', (string) $response->getHeader('X-Foo')); - $this->assertSame('post-value', $this->http['firstNamedServer']->requests->latest()->getPostField('post-key')); + $this->assertSame('Bar', (string) $response->getHeaderLine('X-Foo')); + parse_str($this->http['firstNamedServer']->requests->latest()->getBody()->getContents(), $body); + $this->assertSame('post-value', $body['post-key']); } public function testFatalError() diff --git a/tests/PHPUnit/HttpMockPHPUnitIntegrationBasePathTest.php b/tests/PHPUnit/HttpMockPHPUnitIntegrationBasePathTest.php index 8cc8199..4718c37 100644 --- a/tests/PHPUnit/HttpMockPHPUnitIntegrationBasePathTest.php +++ b/tests/PHPUnit/HttpMockPHPUnitIntegrationBasePathTest.php @@ -1,8 +1,9 @@ end(); $this->http->setUp(); - $this->assertSame('/foo body', (string) $this->http->client->get('/custom-base-path/foo')->send()->getBody()); + $this->assertSame('/foo body', (string) $this->http->client->get('/custom-base-path/foo')->getBody()); $request = $this->http->requests->latest(); $this->assertSame('GET', $request->getMethod()); - $this->assertSame('/custom-base-path/foo', $request->getPath()); + $this->assertSame('/custom-base-path/foo', $request->getUri()->getPath()); } } diff --git a/tests/PHPUnit/HttpMockPHPUnitIntegrationTest.php b/tests/PHPUnit/HttpMockPHPUnitIntegrationTest.php index 806e420..50a8bd5 100644 --- a/tests/PHPUnit/HttpMockPHPUnitIntegrationTest.php +++ b/tests/PHPUnit/HttpMockPHPUnitIntegrationTest.php @@ -1,11 +1,13 @@ end(); $this->http->setUp(); - $this->assertSame($path . ' body', (string) $this->http->client->get($path)->send()->getBody()); + $this->assertSame($path . ' body', (string) $this->http->client->get($path)->getBody()); $request = $this->http->requests->latest(); $this->assertSame('GET', $request->getMethod()); - $this->assertSame($path, $request->getPath()); + $this->assertSame($path, $request->getUri()->getPath()); $request = $this->http->requests->last(); $this->assertSame('GET', $request->getMethod()); - $this->assertSame($path, $request->getPath()); + $this->assertSame($path, $request->getUri()->getPath()); $request = $this->http->requests->first(); $this->assertSame('GET', $request->getMethod()); - $this->assertSame($path, $request->getPath()); + $this->assertSame($path, $request->getUri()->getPath()); $request = $this->http->requests->at(0); $this->assertSame('GET', $request->getMethod()); - $this->assertSame($path, $request->getPath()); + $this->assertSame($path, $request->getUri()->getPath()); $request = $this->http->requests->pop(); $this->assertSame('GET', $request->getMethod()); - $this->assertSame($path, $request->getPath()); + $this->assertSame($path, $request->getUri()->getPath()); - $this->assertSame($path . ' body', (string) $this->http->client->get($path)->send()->getBody()); + $this->assertSame($path . ' body', (string) $this->http->client->get($path)->getBody()); $request = $this->http->requests->shift(); $this->assertSame('GET', $request->getMethod()); - $this->assertSame($path, $request->getPath()); + $this->assertSame($path, $request->getUri()->getPath()); $this->expectException('UnexpectedValueException'); @@ -91,12 +93,12 @@ public function testErrorLogOutput() { $this->http->mock ->when() - ->callback(static function () {error_log('error output');}) + ->callback(static function () {error_log('error output'); }) ->then() ->end(); $this->http->setUp(); - $this->http->client->get('/foo')->send(); + $this->http->client->get('/foo'); // Should fail during tear down as we have an error_log() on the server side try { @@ -109,7 +111,7 @@ public function testErrorLogOutput() public function testFailedRequest() { - $response = $this->http->client->get('/foo')->send(); + $response = $this->http->client->get('/foo'); $this->assertSame(404, $response->getStatusCode()); $this->assertSame('No matching expectation found', (string) $response->getBody()); } @@ -122,7 +124,7 @@ public function testStopServer() /** @depends testStopServer */ public function testHttpServerIsRestartedIfATestStopsIt() { - $response = $this->http->client->get('/')->send(); + $response = $this->http->client->get('/'); $this->assertSame(404, $response->getStatusCode()); } @@ -136,11 +138,11 @@ public function testLimitDurationOfAResponse() ->body('POST METHOD') ->end(); $this->http->setUp(); - $firstResponse = $this->http->client->post('/')->send(); + $firstResponse = $this->http->client->post('/'); $this->assertSame(200, $firstResponse->getStatusCode()); - $secondResponse = $this->http->client->post('/')->send(); + $secondResponse = $this->http->client->post('/'); $this->assertSame(410, $secondResponse->getStatusCode()); - $this->assertSame('Expectation no longer applicable', $secondResponse->getBody(true)); + $this->assertSame('Expectation no longer applicable', (string) $secondResponse->getBody()); $this->http->mock ->exactly(2) @@ -150,13 +152,13 @@ public function testLimitDurationOfAResponse() ->body('POST METHOD') ->end(); $this->http->setUp(); - $firstResponse = $this->http->client->post('/')->send(); + $firstResponse = $this->http->client->post('/'); $this->assertSame(200, $firstResponse->getStatusCode()); - $secondResponse = $this->http->client->post('/')->send(); + $secondResponse = $this->http->client->post('/'); $this->assertSame(200, $secondResponse->getStatusCode()); - $thirdResponse = $this->http->client->post('/')->send(); + $thirdResponse = $this->http->client->post('/'); $this->assertSame(410, $thirdResponse->getStatusCode()); - $this->assertSame('Expectation no longer applicable', $thirdResponse->getBody(true)); + $this->assertSame('Expectation no longer applicable', (string) $thirdResponse->getBody()); $this->http->mock ->any() @@ -166,11 +168,11 @@ public function testLimitDurationOfAResponse() ->body('POST METHOD') ->end(); $this->http->setUp(); - $firstResponse = $this->http->client->post('/')->send(); + $firstResponse = $this->http->client->post('/'); $this->assertSame(200, $firstResponse->getStatusCode()); - $secondResponse = $this->http->client->post('/')->send(); + $secondResponse = $this->http->client->post('/'); $this->assertSame(200, $secondResponse->getStatusCode()); - $thirdResponse = $this->http->client->post('/')->send(); + $thirdResponse = $this->http->client->post('/'); $this->assertSame(200, $thirdResponse->getStatusCode()); } @@ -180,10 +182,12 @@ public function testCallbackOnResponse() ->when() ->methodIs('POST') ->then() - ->callback(static function(Response $response) {$response->setContent('CALLBACK');}) + ->callback(static function (Response $response) { + return $response->withBody(\GuzzleHttp\Psr7\stream_For('CALLBACK')); + }) ->end(); $this->http->setUp(); - $this->assertSame('CALLBACK', $this->http->client->post('/')->send()->getBody(true)); + $this->assertSame('CALLBACK', (string) $this->http->client->post('/')->getBody()); } public function testComplexResponse() @@ -198,11 +202,15 @@ public function testComplexResponse() ->end(); $this->http->setUp(); $response = $this->http->client - ->post('/', ['x-client-header' => 'header-value'], ['post-key' => 'post-value'])->send(); - $this->assertSame('BODY', $response->getBody(true)); + ->post('/', [ + 'headers' => ['x-client-header' => 'header-value'], + 'form_params' => ['post-key' => 'post-value'], + ]); + $this->assertSame('BODY', (string) $response->getBody()); $this->assertSame(201, $response->getStatusCode()); - $this->assertSame('Bar', (string) $response->getHeader('X-Foo')); - $this->assertSame('post-value', $this->http->requests->latest()->getPostField('post-key')); + $this->assertSame('Bar', (string) $response->getHeaderLine('X-Foo')); + parse_str($this->http->requests->latest()->getBody()->getContents(), $body); + $this->assertSame('post-value', $body['post-key']); } public function testPutRequest() @@ -217,11 +225,15 @@ public function testPutRequest() ->end(); $this->http->setUp(); $response = $this->http->client - ->put('/', ['x-client-header' => 'header-value'], ['put-key' => 'put-value'])->send(); - $this->assertSame('BODY', $response->getBody(true)); + ->put('/', [ + 'headers' => ['x-client-header' => 'header-value'], + 'form_params' => ['put-key' => 'put-value'], + ]); + $this->assertSame('BODY', (string) $response->getBody()); $this->assertSame(201, $response->getStatusCode()); - $this->assertSame('Bar', (string) $response->getHeader('X-Foo')); - $this->assertSame('put-value', $this->http->requests->latest()->getPostField('put-key')); + $this->assertSame('Bar', (string) $response->getHeaderLine('X-Foo')); + parse_str($this->http->requests->latest()->getBody()->getContents(), $body); + $this->assertSame('put-value', $body['put-key']); } public function testPostRequest() @@ -236,11 +248,15 @@ public function testPostRequest() ->end(); $this->http->setUp(); $response = $this->http->client - ->post('/', ['x-client-header' => 'header-value'], ['post-key' => 'post-value'])->send(); - $this->assertSame('BODY', $response->getBody(true)); + ->post('/', [ + 'headers' => ['x-client-header' => 'header-value'], + 'form_params' => ['post-key' => 'post-value'], + ]); + $this->assertSame('BODY', (string) $response->getBody()); $this->assertSame(201, $response->getStatusCode()); - $this->assertSame('Bar', (string) $response->getHeader('X-Foo')); - $this->assertSame('post-value', $this->http->requests->latest()->getPostField('post-key')); + $this->assertSame('Bar', (string) $response->getHeaderLine('X-Foo')); + parse_str($this->http->requests->latest()->getBody()->getContents(), $body); + $this->assertSame('post-value', $body['post-key']); } public function testCountRequests() @@ -254,7 +270,7 @@ public function testCountRequests() $this->http->setUp(); $this->assertCount(0, $this->http->requests); - $this->assertSame('resource body', (string) $this->http->client->get('/resource')->send()->getBody()); + $this->assertSame('resource body', (string) $this->http->client->get('/resource')->getBody()); $this->assertCount(1, $this->http->requests); } @@ -264,7 +280,9 @@ public function testMatchQueryString() ->when() ->callback( function (Request $request) { - return $request->query->has('key1'); + parse_str($request->getUri()->getQuery(), $query); + + return isset($query['key1']); } ) ->methodIs('GET') @@ -273,10 +291,10 @@ function (Request $request) { ->end(); $this->http->setUp(); - $this->assertSame('query string', (string) $this->http->client->get('/?key1=')->send()->getBody()); + $this->assertSame('query string', (string) $this->http->client->get('/?key1=')->getBody()); - $this->assertEquals(Response::HTTP_NOT_FOUND, (string) $this->http->client->get('/')->send()->getStatusCode()); - $this->assertEquals(Response::HTTP_NOT_FOUND, (string) $this->http->client->post('/')->send()->getStatusCode()); + $this->assertEquals(StatusCode::HTTP_NOT_FOUND, (string) $this->http->client->get('/')->getStatusCode()); + $this->assertEquals(StatusCode::HTTP_NOT_FOUND, (string) $this->http->client->post('/')->getStatusCode()); } public function testMatchRegex() @@ -289,8 +307,8 @@ public function testMatchRegex() ->end(); $this->http->setUp(); - $this->assertSame('response', (string) $this->http->client->get('/')->send()->getBody()); - $this->assertSame('response', (string) $this->http->client->get('/')->send()->getBody()); + $this->assertSame('response', (string) $this->http->client->get('/')->getBody()); + $this->assertSame('response', (string) $this->http->client->get('/')->getBody()); } public function testMatchQueryParams() @@ -310,19 +328,19 @@ public function testMatchQueryParams() $this->assertSame( 'response', - (string) $this->http->client->get('/?p1=&p2=v2&p4=any&p5=v5&p6=v6')->send()->getBody() + (string) $this->http->client->get('/?p1=&p2=v2&p4=any&p5=v5&p6=v6')->getBody() ); $this->assertEquals( - Response::HTTP_NOT_FOUND, - (string) $this->http->client->get('/?p1=&p2=v2&p3=foo')->send()->getStatusCode() + StatusCode::HTTP_NOT_FOUND, + (string) $this->http->client->get('/?p1=&p2=v2&p3=foo')->getStatusCode() ); $this->assertEquals( - Response::HTTP_NOT_FOUND, - (string) $this->http->client->get('/?p1=')->send()->getStatusCode() + StatusCode::HTTP_NOT_FOUND, + (string) $this->http->client->get('/?p1=')->getStatusCode() ); $this->assertEquals( - Response::HTTP_NOT_FOUND, - (string) $this->http->client->get('/?p3=foo')->send()->getStatusCode() + StatusCode::HTTP_NOT_FOUND, + (string) $this->http->client->get('/?p3=foo')->getStatusCode() ); } diff --git a/tests/Request/UnifiedRequestTest.php b/tests/Request/UnifiedRequestTest.php deleted file mode 100644 index 479a384..0000000 --- a/tests/Request/UnifiedRequestTest.php +++ /dev/null @@ -1,134 +0,0 @@ -wrappedRequest = $this->createMock('Guzzle\Http\Message\RequestInterface'); - $this->wrappedEntityEnclosingRequest = $this->createMock('Guzzle\Http\Message\EntityEnclosingRequestInterface'); - $this->unifiedRequest = new UnifiedRequest($this->wrappedRequest); - $this->unifiedEnclosingEntityRequest = new UnifiedRequest($this->wrappedEntityEnclosingRequest); - } - - public static function provideMethods() - { - return [ - ['getParams'], - ['getHeaders'], - ['getHeaderLines'], - ['getRawHeaders'], - ['getQuery'], - ['getMethod'], - ['getScheme'], - ['getHost'], - ['getProtocolVersion'], - ['getPath'], - ['getPort'], - ['getUsername'], - ['getPassword'], - ['getUrl'], - ['getCookies'], - ['getHeader', ['header']], - ['hasHeader', ['header']], - ['getUrl', [false]], - ['getUrl', [true]], - ['getCookie', ['cookieName']], - ]; - } - - public static function provideEntityEnclosingInterfaceMethods() - { - return [ - ['getBody'], - ['getPostField', ['postField']], - ['getPostFields'], - ['getPostFiles'], - ['getPostFile', ['fileName']], - ]; - } - - /** @dataProvider provideMethods */ - public function testMethodsFromRequestInterface($method, array $params = []) - { - $this->wrappedRequest - ->expects($this->once()) - ->method($method) - ->will($this->returnValue('REQ')) - ->with(...$params); - $this->assertSame('REQ', call_user_func_array([$this->unifiedRequest, $method], $params)); - - - $this->wrappedEntityEnclosingRequest - ->expects($this->once()) - ->method($method) - ->will($this->returnValue('ENTITY_ENCL_REQ')) - ->with(...$params); - $this->assertSame( - 'ENTITY_ENCL_REQ', - call_user_func_array([$this->unifiedEnclosingEntityRequest, $method], $params) - ); - } - - /** @dataProvider provideEntityEnclosingInterfaceMethods */ - public function testEntityEnclosingInterfaceMethods($method, array $params = []) - { - $this->wrappedEntityEnclosingRequest - ->expects($this->once()) - ->method($method) - ->will($this->returnValue('ENTITY_ENCL_REQ')) - ->with(...$params); - - $this->assertSame( - 'ENTITY_ENCL_REQ', - call_user_func_array([$this->unifiedEnclosingEntityRequest, $method], $params) - ); - - $this->wrappedRequest - ->expects($this->any()) - ->method('getMethod') - ->will($this->returnValue('METHOD')); - $this->wrappedRequest - ->expects($this->any()) - ->method('getPath') - ->will($this->returnValue('/foo')); - - $this->expectException('BadMethodCallException'); - - $this->expectExceptionMessage( - - sprintf( - 'Cannot call method "%s" on a request that does not enclose an entity. Did you expect a POST/PUT request instead of METHOD /foo?', - $method - ) - - ); - call_user_func_array([$this->unifiedRequest, $method], $params); - } - - public function testUserAgent() - { - $this->assertNull($this->unifiedRequest->getUserAgent()); - - $unifiedRequest = new UnifiedRequest($this->wrappedRequest, ['userAgent' => 'UA']); - $this->assertSame('UA', $unifiedRequest->getUserAgent()); - } -} diff --git a/tests/RequestCollectionFacadeTest.php b/tests/RequestCollectionFacadeTest.php index e111263..5f4cc92 100644 --- a/tests/RequestCollectionFacadeTest.php +++ b/tests/RequestCollectionFacadeTest.php @@ -1,13 +1,15 @@ client = $this->createMock('Guzzle\Http\ClientInterface'); + $this->client = $this->createMock(Client::class); $this->facade = new RequestCollectionFacade($this->client); $this->request = new Request('GET', '/_request/last'); - $this->request->setClient($this->client); } public static function provideMethodAndUrls() @@ -48,7 +49,7 @@ public function testRequestingLatestRequest($method, $path, array $args = [], $h $request = call_user_func_array([$this->facade, $method], $args); $this->assertSame('POST', $request->getMethod()); - $this->assertSame('/foo', $request->getPath()); + $this->assertSame('/foo', $request->getUri()->getPath()); $this->assertSame('RECORDED=1', (string) $request->getBody()); } @@ -60,17 +61,15 @@ public function testRequestLatestResponseWithHttpAuth($method, $path, array $arg $request = call_user_func_array([$this->facade, $method], $args); $this->assertSame('POST', $request->getMethod()); - $this->assertSame('/foo', $request->getPath()); + $this->assertSame('/foo', $request->getUri()->getPath()); $this->assertSame('RECORDED=1', (string) $request->getBody()); - $this->assertSame('host', $request->getHost()); - $this->assertSame(1234, $request->getPort()); - $this->assertSame('username', $request->getUsername()); - $this->assertSame('password', $request->getPassword()); - $this->assertSame('CUSTOM UA', $request->getUserAgent()); + $this->assertSame('localhost', $request->getUri()->getHost()); + $this->assertSame(1234, $request->getUri()->getPort()); + $this->assertSame('CUSTOM UA', $request->getHeaderLine(('User-Agent'))); } /** @dataProvider provideMethodAndUrls */ - public function testRequestResponse_InvalidStatusCode($method, $path, array $args = [], $httpMethod = 'get') + public function testRequestResponseInvalidStatusCode($method, $path, array $args = [], $httpMethod = 'get') { $this->mockClient($path, $this->createResponseWithInvalidStatusCode(), $httpMethod); @@ -81,7 +80,7 @@ public function testRequestResponse_InvalidStatusCode($method, $path, array $arg } /** @dataProvider provideMethodAndUrls */ - public function testRequestResponse_EmptyContentType($method, $path, array $args = [], $httpMethod = 'get') + public function testRequestResponseEmptyContentType($method, $path, array $args = [], $httpMethod = 'get') { $this->mockClient($path, $this->createResponseWithEmptyContentType(), $httpMethod); @@ -92,7 +91,7 @@ public function testRequestResponse_EmptyContentType($method, $path, array $args } /** @dataProvider provideMethodAndUrls */ - public function testRequestResponse_InvalidContentType($method, $path, array $args = [], $httpMethod = 'get') + public function testRequestResponseInvalidContentType($method, $path, array $args = [], $httpMethod = 'get') { $this->mockClient($path, $this->createResponseWithInvalidContentType(), $httpMethod); @@ -103,7 +102,7 @@ public function testRequestResponse_InvalidContentType($method, $path, array $ar } /** @dataProvider provideMethodAndUrls */ - public function testRequestResponse_DeserializationError($method, $path, array $args = [], $httpMethod = 'get') + public function testRequestResponseDeserializationError($method, $path, array $args = [], $httpMethod = 'get') { $this->mockClient($path, $this->createResponseThatCannotBeDeserialized(), $httpMethod); @@ -117,23 +116,19 @@ private function mockClient($path, Response $response, $method) { $this->client ->expects($this->once()) - ->method($method) - ->with($path) - ->will($this->returnValue($this->request)); - - $this->client - ->expects($this->once()) - ->method('send') - ->with($this->request) + ->method('__call') + ->with($method, [$path]) ->will($this->returnValue($response)); } private function createSimpleResponse() { - $recordedRequest = new TestRequest(); - $recordedRequest->setMethod('POST'); - $recordedRequest->setRequestUri('/foo'); - $recordedRequest->setContent('RECORDED=1'); + $recordedRequest = new TestRequest( + 'POST', + 'http://localhost/foo', + [], + 'RECORDED=1' + ); return new Response( '200', @@ -141,7 +136,7 @@ private function createSimpleResponse() serialize( [ 'server' => [], - 'request' => (string) $recordedRequest, + 'request' => Util::serializePsrMessage($recordedRequest), ] ) ); @@ -149,27 +144,23 @@ private function createSimpleResponse() private function createComplexResponse() { - $recordedRequest = new TestRequest(); - $recordedRequest->setMethod('POST'); - $recordedRequest->setRequestUri('/foo'); - $recordedRequest->setContent('RECORDED=1'); - $recordedRequest->headers->set('Php-Auth-User', 'ignored'); - $recordedRequest->headers->set('Php-Auth-Pw', 'ignored'); - $recordedRequest->headers->set('User-Agent', 'ignored'); + $recordedRequest = new TestRequest( + 'POST', + 'http://localhost:1234/foo', + [ + 'Php-Auth-User' => 'username', + 'Php-Auth-Pw' => 'password', + 'User-Agent' => 'CUSTOM UA', + ], + 'RECORDED=1' + ); return new Response( '200', ['Content-Type' => 'text/plain; charset=UTF-8'], serialize( [ - 'server' => [ - 'HTTP_HOST' => 'host', - 'HTTP_PORT' => 1234, - 'PHP_AUTH_USER' => 'username', - 'PHP_AUTH_PW' => 'password', - 'HTTP_USER_AGENT' => 'CUSTOM UA', - ], - 'request' => (string) $recordedRequest, + 'request' => Util::serializePsrMessage($recordedRequest), ] ) );