From 3d57e87a1d44128cef8814c6fb731181433f8594 Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Wed, 2 Sep 2020 15:14:33 +0200 Subject: [PATCH 01/14] Initial scope of work, limitations and stability promises --- README.md | 92 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 92 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..38ad4dc --- /dev/null +++ b/README.md @@ -0,0 +1,92 @@ +# Infection Static Analysis Plugin + +This plugin is designed to run static analysis on top of [`infection/infection`](https://github.com/infection/infection) +test runs in order to discover if [escaped mutants](https://en.wikipedia.org/wiki/Mutation_testing) +are valid mutations, or if they do not respect the type signature of your +program. + +## Usage + +```sh +composer require roave/infection-static-analysis-plugin + +vendor/bin/roave-infection-static-analysis-plugin +``` + +## Background + +If you come from a statically typed language with AoT compilers, you may be +confused about the scope of this project, but in the PHP ecosystem, producing +runnable code that does not respect the type system is very easy, and mutation +testing tools do this all the time. + +Take for example following snippet: + +```php +/** + * @template T + * @param array $values + * @return list + */ +function makeAList(array $values): array +{ + return array_values($values); +} +``` + +Given a valid test as follows: + +```php +function test_makes_a_list(): void +{ + $list = makeAList(['a' => 'b', 'c' => 'd']); + + assert(count($list) === 2); + assert(in_array('b', $list, true)); + assert(in_array('d', $list, true)); +} +``` + +The mutation testing framework will produce following mutation, since we +failed to verify the output in a more precise way: + +```diff +/** + * @template T + * @param array $values + * @return list + */ +function makeAList(array $values): array +{ +- return array_values($values); ++ return $values; +} +``` + +The code above is valid PHP, but not valid according to our type declarations. +While we can indeed write a test for this, such test would probably be +unnecessary, as existing type checkers can detect that our actual return value is +no longer a `list`, but a map of `array`, which is in conflict +with what we declared. + +This plugin detects such mutations, and prevents them from making you write +unnecessary tests, leveraging the full power of existing PHP type checkers +such as [phpstan](https://github.com/phpstan/phpstan) and [psalm](https://github.com/vimeo/psalm). + +## Stability + +Since [`infection/infection`](https://github.com/infection/infection) is not yet +designed to support plugins, this tool uses a very aggressive approach to bootstrap +itself, and relies on internal details of the underlying runner. + +To prevent compatibility issues, it therefore always pins to a very specific version +of `infection/infection`, so please be patient when you wish to use the latest and +greatest version of `infection/infection`, as we may still be catching up to it. + +Eventually, we will contribute patches to `infection/infection` so that there is a +proper way to design and use plugins, without the need for dirty hacks. + +## PHPStan? Psalm? Where's my favourite static analysis tool? + +Our initial scope of work for `1.0.x` is to provide `vimeo/psalm` support as a start, +while other static analysers will be included at a later point in time. From d6e556acef29c02e0ca04fc014112207739ddcaf Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Wed, 2 Sep 2020 15:25:06 +0200 Subject: [PATCH 02/14] Added package dependencies - we need `infection`, `psalm` and `phpunit` --- composer.json | 19 + composer.lock | 4443 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 4462 insertions(+) create mode 100644 composer.json create mode 100644 composer.lock diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..a63e25b --- /dev/null +++ b/composer.json @@ -0,0 +1,19 @@ +{ + "name": "roave/infection-static-analysis-plugin", + "description": "Static analysis on top of mutation testing - prevents escaped mutants from being invalid according to static analysis", + "type": "library", + "require": { + "infection/infection": "0.17.5", + "vimeo/psalm": "^3.15.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.2.6" + }, + "license": "MIT", + "authors": [ + { + "name": "Marco Pivetta", + "email": "ocramius@gmail.com" + } + ] +} diff --git a/composer.lock b/composer.lock new file mode 100644 index 0000000..3834dc8 --- /dev/null +++ b/composer.lock @@ -0,0 +1,4443 @@ +{ + "_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": "37d292672b14a096ef164860da8efade", + "packages": [ + { + "name": "amphp/amp", + "version": "v2.5.0", + "source": { + "type": "git", + "url": "https://github.com/amphp/amp.git", + "reference": "f220a51458bf4dd0dedebb171ac3457813c72bbc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/amphp/amp/zipball/f220a51458bf4dd0dedebb171ac3457813c72bbc", + "reference": "f220a51458bf4dd0dedebb171ac3457813c72bbc", + "shasum": "" + }, + "require": { + "php": ">=7" + }, + "require-dev": { + "amphp/php-cs-fixer-config": "dev-master", + "amphp/phpunit-util": "^1", + "ext-json": "*", + "jetbrains/phpstorm-stubs": "^2019.3", + "phpunit/phpunit": "^6.0.9 | ^7", + "psalm/phar": "^3.11@dev", + "react/promise": "^2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.x-dev" + } + }, + "autoload": { + "psr-4": { + "Amp\\": "lib" + }, + "files": [ + "lib/functions.php", + "lib/Internal/functions.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Daniel Lowrey", + "email": "rdlowrey@php.net" + }, + { + "name": "Aaron Piotrowski", + "email": "aaron@trowski.com" + }, + { + "name": "Bob Weinand", + "email": "bobwei9@hotmail.com" + }, + { + "name": "Niklas Keller", + "email": "me@kelunik.com" + } + ], + "description": "A non-blocking concurrency framework for PHP applications.", + "homepage": "http://amphp.org/amp", + "keywords": [ + "async", + "asynchronous", + "awaitable", + "concurrency", + "event", + "event-loop", + "future", + "non-blocking", + "promise" + ], + "support": { + "irc": "irc://irc.freenode.org/amphp", + "issues": "https://github.com/amphp/amp/issues", + "source": "https://github.com/amphp/amp/tree/master" + }, + "funding": [ + { + "url": "https://github.com/amphp", + "type": "github" + } + ], + "time": "2020-07-14T21:47:18+00:00" + }, + { + "name": "amphp/byte-stream", + "version": "v1.8.0", + "source": { + "type": "git", + "url": "https://github.com/amphp/byte-stream.git", + "reference": "f0c20cf598a958ba2aa8c6e5a71c697d652c7088" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/amphp/byte-stream/zipball/f0c20cf598a958ba2aa8c6e5a71c697d652c7088", + "reference": "f0c20cf598a958ba2aa8c6e5a71c697d652c7088", + "shasum": "" + }, + "require": { + "amphp/amp": "^2", + "php": ">=7.1" + }, + "require-dev": { + "amphp/php-cs-fixer-config": "dev-master", + "amphp/phpunit-util": "^1.4", + "friendsofphp/php-cs-fixer": "^2.3", + "jetbrains/phpstorm-stubs": "^2019.3", + "phpunit/phpunit": "^6 || ^7 || ^8", + "psalm/phar": "^3.11.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Amp\\ByteStream\\": "lib" + }, + "files": [ + "lib/functions.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Aaron Piotrowski", + "email": "aaron@trowski.com" + }, + { + "name": "Niklas Keller", + "email": "me@kelunik.com" + } + ], + "description": "A stream abstraction to make working with non-blocking I/O simple.", + "homepage": "http://amphp.org/byte-stream", + "keywords": [ + "amp", + "amphp", + "async", + "io", + "non-blocking", + "stream" + ], + "support": { + "irc": "irc://irc.freenode.org/amphp", + "issues": "https://github.com/amphp/byte-stream/issues", + "source": "https://github.com/amphp/byte-stream/tree/master" + }, + "time": "2020-06-29T18:35:05+00:00" + }, + { + "name": "composer/package-versions-deprecated", + "version": "1.11.99", + "source": { + "type": "git", + "url": "https://github.com/composer/package-versions-deprecated.git", + "reference": "c8c9aa8a14cc3d3bec86d0a8c3fa52ea79936855" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer/package-versions-deprecated/zipball/c8c9aa8a14cc3d3bec86d0a8c3fa52ea79936855", + "reference": "c8c9aa8a14cc3d3bec86d0a8c3fa52ea79936855", + "shasum": "" + }, + "require": { + "composer-plugin-api": "^1.1.0 || ^2.0", + "php": "^7 || ^8" + }, + "replace": { + "ocramius/package-versions": "1.11.99" + }, + "require-dev": { + "composer/composer": "^1.9.3 || ^2.0@dev", + "ext-zip": "^1.13", + "phpunit/phpunit": "^6.5 || ^7" + }, + "type": "composer-plugin", + "extra": { + "class": "PackageVersions\\Installer", + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "PackageVersions\\": "src/PackageVersions" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Marco Pivetta", + "email": "ocramius@gmail.com" + }, + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be" + } + ], + "description": "Composer plugin that provides efficient querying for installed package versions (no runtime IO)", + "support": { + "issues": "https://github.com/composer/package-versions-deprecated/issues", + "source": "https://github.com/composer/package-versions-deprecated/tree/master" + }, + "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": "2020-08-25T05:50:16+00:00" + }, + { + "name": "composer/semver", + "version": "3.0.0", + "source": { + "type": "git", + "url": "https://github.com/composer/semver.git", + "reference": "3426bd5efa8a12d230824536c42a8a4ad30b7940" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer/semver/zipball/3426bd5efa8a12d230824536c42a8a4ad30b7940", + "reference": "3426bd5efa8a12d230824536c42a8a4ad30b7940", + "shasum": "" + }, + "require": { + "php": "^5.3.2 || ^7.0 || ^8.0" + }, + "require-dev": { + "phpstan/phpstan": "^0.12.19", + "symfony/phpunit-bridge": "^4.2 || ^5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "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.0.0" + }, + "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": "2020-05-26T18:22:04+00:00" + }, + { + "name": "composer/xdebug-handler", + "version": "1.4.3", + "source": { + "type": "git", + "url": "https://github.com/composer/xdebug-handler.git", + "reference": "ebd27a9866ae8254e873866f795491f02418c5a5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/ebd27a9866ae8254e873866f795491f02418c5a5", + "reference": "ebd27a9866ae8254e873866f795491f02418c5a5", + "shasum": "" + }, + "require": { + "php": "^5.3.2 || ^7.0 || ^8.0", + "psr/log": "^1.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.8.35 || ^5.7 || 6.5 - 8" + }, + "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/1.4.3" + }, + "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": "2020-08-19T10:27:58+00:00" + }, + { + "name": "dnoegel/php-xdg-base-dir", + "version": "v0.1.1", + "source": { + "type": "git", + "url": "https://github.com/dnoegel/php-xdg-base-dir.git", + "reference": "8f8a6e48c5ecb0f991c2fdcf5f154a47d85f9ffd" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/dnoegel/php-xdg-base-dir/zipball/8f8a6e48c5ecb0f991c2fdcf5f154a47d85f9ffd", + "reference": "8f8a6e48c5ecb0f991c2fdcf5f154a47d85f9ffd", + "shasum": "" + }, + "require": { + "php": ">=5.3.2" + }, + "require-dev": { + "phpunit/phpunit": "~7.0|~6.0|~5.0|~4.8.35" + }, + "type": "library", + "autoload": { + "psr-4": { + "XdgBaseDir\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "implementation of xdg base directory specification for php", + "support": { + "issues": "https://github.com/dnoegel/php-xdg-base-dir/issues", + "source": "https://github.com/dnoegel/php-xdg-base-dir/tree/v0.1.1" + }, + "time": "2019-12-04T15:06:13+00:00" + }, + { + "name": "felixfbecker/advanced-json-rpc", + "version": "v3.1.1", + "source": { + "type": "git", + "url": "https://github.com/felixfbecker/php-advanced-json-rpc.git", + "reference": "0ed363f8de17d284d479ec813c9ad3f6834b5c40" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/felixfbecker/php-advanced-json-rpc/zipball/0ed363f8de17d284d479ec813c9ad3f6834b5c40", + "reference": "0ed363f8de17d284d479ec813c9ad3f6834b5c40", + "shasum": "" + }, + "require": { + "netresearch/jsonmapper": "^1.0 || ^2.0", + "php": ">=7.0", + "phpdocumentor/reflection-docblock": "^4.0.0 || ^5.0.0" + }, + "require-dev": { + "phpunit/phpunit": "^6.0.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "AdvancedJsonRpc\\": "lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "ISC" + ], + "authors": [ + { + "name": "Felix Becker", + "email": "felix.b@outlook.com" + } + ], + "description": "A more advanced JSONRPC implementation", + "support": { + "issues": "https://github.com/felixfbecker/php-advanced-json-rpc/issues", + "source": "https://github.com/felixfbecker/php-advanced-json-rpc/tree/master" + }, + "time": "2020-03-11T15:21:41+00:00" + }, + { + "name": "felixfbecker/language-server-protocol", + "version": "v1.4.0", + "source": { + "type": "git", + "url": "https://github.com/felixfbecker/php-language-server-protocol.git", + "reference": "378801f6139bb74ac215d81cca1272af61df9a9f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/felixfbecker/php-language-server-protocol/zipball/378801f6139bb74ac215d81cca1272af61df9a9f", + "reference": "378801f6139bb74ac215d81cca1272af61df9a9f", + "shasum": "" + }, + "require": { + "php": "^7.0" + }, + "require-dev": { + "phpstan/phpstan": "*", + "phpunit/phpunit": "^6.3", + "squizlabs/php_codesniffer": "^3.1" + }, + "type": "library", + "autoload": { + "psr-4": { + "LanguageServerProtocol\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "ISC" + ], + "authors": [ + { + "name": "Felix Becker", + "email": "felix.b@outlook.com" + } + ], + "description": "PHP classes for the Language Server Protocol", + "keywords": [ + "language", + "microsoft", + "php", + "server" + ], + "support": { + "issues": "https://github.com/felixfbecker/php-language-server-protocol/issues", + "source": "https://github.com/felixfbecker/php-language-server-protocol/tree/v1.4.0" + }, + "time": "2019-06-23T21:03:50+00:00" + }, + { + "name": "infection/abstract-testframework-adapter", + "version": "0.3.1", + "source": { + "type": "git", + "url": "https://github.com/infection/abstract-testframework-adapter.git", + "reference": "c52539339f28d6b67625ff24496289b3e6d66025" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/infection/abstract-testframework-adapter/zipball/c52539339f28d6b67625ff24496289b3e6d66025", + "reference": "c52539339f28d6b67625ff24496289b3e6d66025", + "shasum": "" + }, + "require": { + "php": "^7.3 || ^8.0" + }, + "require-dev": { + "ergebnis/composer-normalize": "^2.8", + "friendsofphp/php-cs-fixer": "^2.16", + "phpunit/phpunit": "^9.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Infection\\AbstractTestFramework\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Maks Rafalko", + "email": "maks.rafalko@gmail.com" + } + ], + "description": "Abstract Test Framework Adapter for Infection", + "support": { + "issues": "https://github.com/infection/abstract-testframework-adapter/issues", + "source": "https://github.com/infection/abstract-testframework-adapter/tree/0.3" + }, + "time": "2020-08-30T13:50:12+00:00" + }, + { + "name": "infection/extension-installer", + "version": "0.1.1", + "source": { + "type": "git", + "url": "https://github.com/infection/extension-installer.git", + "reference": "ff30c0adffcdbc747c96adf92382ccbe271d0afd" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/infection/extension-installer/zipball/ff30c0adffcdbc747c96adf92382ccbe271d0afd", + "reference": "ff30c0adffcdbc747c96adf92382ccbe271d0afd", + "shasum": "" + }, + "require": { + "composer-plugin-api": "^1.1 || ^2.0" + }, + "require-dev": { + "composer/composer": "^1.9", + "friendsofphp/php-cs-fixer": "^2.16", + "infection/infection": "^0.15.2", + "php-coveralls/php-coveralls": "^2.2", + "phpstan/extension-installer": "^1.0", + "phpstan/phpstan": "^0.12.10", + "phpstan/phpstan-phpunit": "^0.12.6", + "phpstan/phpstan-strict-rules": "^0.12.2", + "phpstan/phpstan-webmozart-assert": "^0.12.2", + "phpunit/phpunit": "^8.5", + "vimeo/psalm": "^3.8" + }, + "type": "composer-plugin", + "extra": { + "class": "Infection\\ExtensionInstaller\\Plugin" + }, + "autoload": { + "psr-4": { + "Infection\\ExtensionInstaller\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Maks Rafalko", + "email": "maks.rafalko@gmail.com" + } + ], + "description": "Infection Extension Installer", + "support": { + "issues": "https://github.com/infection/extension-installer/issues", + "source": "https://github.com/infection/extension-installer/tree/0.1.1" + }, + "time": "2020-04-25T22:40:05+00:00" + }, + { + "name": "infection/include-interceptor", + "version": "0.2.4", + "source": { + "type": "git", + "url": "https://github.com/infection/include-interceptor.git", + "reference": "e3cf9317a7fd554ab60a5587f028b16418cc4264" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/infection/include-interceptor/zipball/e3cf9317a7fd554ab60a5587f028b16418cc4264", + "reference": "e3cf9317a7fd554ab60a5587f028b16418cc4264", + "shasum": "" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^2.16", + "infection/infection": "^0.15.0", + "phan/phan": "^2.4 || ^3", + "php-coveralls/php-coveralls": "^2.2", + "phpstan/phpstan": "^0.12.8", + "phpunit/phpunit": "^8.5", + "vimeo/psalm": "^3.8" + }, + "type": "library", + "autoload": { + "psr-4": { + "Infection\\StreamWrapper\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Maks Rafalko", + "email": "maks.rafalko@gmail.com" + } + ], + "description": "Stream Wrapper: Include Interceptor. Allows to replace included (autoloaded) file with another one.", + "support": { + "issues": "https://github.com/infection/include-interceptor/issues", + "source": "https://github.com/infection/include-interceptor/tree/0.2.4" + }, + "time": "2020-08-07T22:40:37+00:00" + }, + { + "name": "infection/infection", + "version": "0.17.5", + "source": { + "type": "git", + "url": "https://github.com/infection/infection.git", + "reference": "14ff2578179588dfdc3cd05ceb8337cdedfdf5cc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/infection/infection/zipball/14ff2578179588dfdc3cd05ceb8337cdedfdf5cc", + "reference": "14ff2578179588dfdc3cd05ceb8337cdedfdf5cc", + "shasum": "" + }, + "require": { + "composer/xdebug-handler": "^1.3.3", + "ext-dom": "*", + "ext-json": "*", + "ext-libxml": "*", + "infection/abstract-testframework-adapter": "^0.3.0", + "infection/extension-installer": "^0.1.0", + "infection/include-interceptor": "^0.2.4", + "justinrainbow/json-schema": "^5.2", + "nikic/php-parser": "^4.2.2", + "ocramius/package-versions": "^1.2", + "ondram/ci-detector": "^3.3.0", + "php": "^7.3", + "sanmai/pipeline": "^3.1 || ^5.0", + "sebastian/diff": "^3.0.2 || ^4.0", + "seld/jsonlint": "^1.7", + "symfony/console": "^3.4.29 || ^4.0 || ^5.0", + "symfony/filesystem": "^3.4.29 || ^4.0 || ^5.0", + "symfony/finder": "^3.4.29 || ^4.0 || ^5.0", + "symfony/process": "^3.4.29 || ^4.0 || ^5.0", + "thecodingmachine/safe": "^1.0", + "webmozart/assert": "^1.3", + "webmozart/path-util": "^2.3" + }, + "conflict": { + "phpunit/php-code-coverage": ">9 <9.1.4", + "phpunit/phpunit": ">=9.3", + "symfony/console": "=4.1.5" + }, + "require-dev": { + "ext-simplexml": "*", + "helmich/phpunit-json-assert": "^3.0", + "phpstan/extension-installer": "^1.0", + "phpstan/phpstan": "^0.12.8", + "phpstan/phpstan-phpunit": "^0.12.6", + "phpstan/phpstan-webmozart-assert": "^0.12.2", + "phpunit/phpunit": "^8.2.5 <8.4", + "symfony/phpunit-bridge": "^4.3.4 || ^5.0", + "symfony/yaml": "^5.0", + "thecodingmachine/phpstan-safe-rule": "^1.0" + }, + "bin": [ + "bin/infection" + ], + "type": "library", + "autoload": { + "psr-4": { + "Infection\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Maks Rafalko", + "email": "maks.rafalko@gmail.com", + "homepage": "https://twitter.com/maks_rafalko" + }, + { + "name": "Oleg Zhulnev", + "homepage": "https://github.com/sidz" + }, + { + "name": "Gert de Pagter", + "homepage": "https://github.com/BackEndTea" + }, + { + "name": "Théo FIDRY", + "email": "theo.fidry@gmail.com", + "homepage": "https://twitter.com/tfidry" + }, + { + "name": "Alexey Kopytko", + "email": "alexey@kopytko.com", + "homepage": "https://www.alexeykopytko.com" + }, + { + "name": "Andreas Möller", + "email": "am@localheinz.com", + "homepage": "https://localheinz.com" + } + ], + "description": "Infection is a Mutation Testing framework for PHP. The mutation adequacy score can be used to measure the effectiveness of a test set in terms of its ability to detect faults.", + "keywords": [ + "coverage", + "mutant", + "mutation framework", + "mutation testing", + "testing", + "unit testing" + ], + "support": { + "issues": "https://github.com/infection/infection/issues", + "source": "https://github.com/infection/infection/tree/0.17.5" + }, + "time": "2020-09-01T05:23:59+00:00" + }, + { + "name": "justinrainbow/json-schema", + "version": "5.2.10", + "source": { + "type": "git", + "url": "https://github.com/justinrainbow/json-schema.git", + "reference": "2ba9c8c862ecd5510ed16c6340aa9f6eadb4f31b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/justinrainbow/json-schema/zipball/2ba9c8c862ecd5510ed16c6340aa9f6eadb4f31b", + "reference": "2ba9c8c862ecd5510ed16c6340aa9f6eadb4f31b", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "~2.2.20||~2.15.1", + "json-schema/json-schema-test-suite": "1.2.0", + "phpunit/phpunit": "^4.8.35" + }, + "bin": [ + "bin/validate-json" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "JsonSchema\\": "src/JsonSchema/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Bruno Prieto Reis", + "email": "bruno.p.reis@gmail.com" + }, + { + "name": "Justin Rainbow", + "email": "justin.rainbow@gmail.com" + }, + { + "name": "Igor Wiedler", + "email": "igor@wiedler.ch" + }, + { + "name": "Robert Schönthal", + "email": "seroscho@googlemail.com" + } + ], + "description": "A library to validate a json schema.", + "homepage": "https://github.com/justinrainbow/json-schema", + "keywords": [ + "json", + "schema" + ], + "support": { + "issues": "https://github.com/justinrainbow/json-schema/issues", + "source": "https://github.com/justinrainbow/json-schema/tree/5.2.10" + }, + "time": "2020-05-27T16:41:55+00:00" + }, + { + "name": "netresearch/jsonmapper", + "version": "v2.1.0", + "source": { + "type": "git", + "url": "https://github.com/cweiske/jsonmapper.git", + "reference": "e0f1e33a71587aca81be5cffbb9746510e1fe04e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/cweiske/jsonmapper/zipball/e0f1e33a71587aca81be5cffbb9746510e1fe04e", + "reference": "e0f1e33a71587aca81be5cffbb9746510e1fe04e", + "shasum": "" + }, + "require": { + "ext-json": "*", + "ext-pcre": "*", + "ext-reflection": "*", + "ext-spl": "*", + "php": ">=5.6" + }, + "require-dev": { + "phpunit/phpunit": "~4.8.35 || ~5.7 || ~6.4 || ~7.0", + "squizlabs/php_codesniffer": "~3.5" + }, + "type": "library", + "autoload": { + "psr-0": { + "JsonMapper": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "OSL-3.0" + ], + "authors": [ + { + "name": "Christian Weiske", + "email": "cweiske@cweiske.de", + "homepage": "http://github.com/cweiske/jsonmapper/", + "role": "Developer" + } + ], + "description": "Map nested JSON structures onto PHP classes", + "support": { + "email": "cweiske@cweiske.de", + "issues": "https://github.com/cweiske/jsonmapper/issues", + "source": "https://github.com/cweiske/jsonmapper/tree/master" + }, + "time": "2020-04-16T18:48:43+00:00" + }, + { + "name": "nikic/php-parser", + "version": "v4.9.1", + "source": { + "type": "git", + "url": "https://github.com/nikic/PHP-Parser.git", + "reference": "88e519766fc58bd46b8265561fb79b54e2e00b28" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/88e519766fc58bd46b8265561fb79b54e2e00b28", + "reference": "88e519766fc58bd46b8265561fb79b54e2e00b28", + "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.9.1" + }, + "time": "2020-08-30T16:15:20+00:00" + }, + { + "name": "ondram/ci-detector", + "version": "3.5.0", + "source": { + "type": "git", + "url": "https://github.com/OndraM/ci-detector.git", + "reference": "789e9fcc7a8c3ef6d54f645fef744ad35946e896" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/OndraM/ci-detector/zipball/789e9fcc7a8c3ef6d54f645fef744ad35946e896", + "reference": "789e9fcc7a8c3ef6d54f645fef744ad35946e896", + "shasum": "" + }, + "require": { + "php": "^7.1" + }, + "require-dev": { + "ergebnis/composer-normalize": "^2.2", + "lmc/coding-standard": "^1.3 || ^2.0", + "php-coveralls/php-coveralls": "^2.2", + "php-parallel-lint/php-parallel-lint": "^1.1", + "phpstan/extension-installer": "^1.0.3", + "phpstan/phpstan": "^0.12.0", + "phpstan/phpstan-phpunit": "^0.12.1", + "phpunit/phpunit": "^7.1 || ^8.0 || ^9.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "OndraM\\CiDetector\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ondřej Machulda", + "email": "ondrej.machulda@gmail.com" + } + ], + "description": "Detect continuous integration environment and provide unified access to properties of current build", + "keywords": [ + "CircleCI", + "Codeship", + "Wercker", + "adapter", + "appveyor", + "aws", + "aws codebuild", + "bamboo", + "bitbucket", + "buddy", + "ci-info", + "codebuild", + "continuous integration", + "continuousphp", + "drone", + "github", + "gitlab", + "interface", + "jenkins", + "teamcity", + "travis" + ], + "support": { + "issues": "https://github.com/OndraM/ci-detector/issues", + "source": "https://github.com/OndraM/ci-detector/tree/main" + }, + "time": "2020-08-25T11:58:23+00:00" + }, + { + "name": "openlss/lib-array2xml", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/nullivex/lib-array2xml.git", + "reference": "a91f18a8dfc69ffabe5f9b068bc39bb202c81d90" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nullivex/lib-array2xml/zipball/a91f18a8dfc69ffabe5f9b068bc39bb202c81d90", + "reference": "a91f18a8dfc69ffabe5f9b068bc39bb202c81d90", + "shasum": "" + }, + "require": { + "php": ">=5.3.2" + }, + "type": "library", + "autoload": { + "psr-0": { + "LSS": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Bryan Tong", + "email": "bryan@nullivex.com", + "homepage": "https://www.nullivex.com" + }, + { + "name": "Tony Butler", + "email": "spudz76@gmail.com", + "homepage": "https://www.nullivex.com" + } + ], + "description": "Array2XML conversion library credit to lalit.org", + "homepage": "https://www.nullivex.com", + "keywords": [ + "array", + "array conversion", + "xml", + "xml conversion" + ], + "support": { + "issues": "https://github.com/nullivex/lib-array2xml/issues", + "source": "https://github.com/nullivex/lib-array2xml/tree/master" + }, + "time": "2019-03-29T20:06:56+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.2.1", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", + "reference": "d870572532cd70bc3fab58f2e23ad423c8404c44" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/d870572532cd70bc3fab58f2e23ad423c8404c44", + "reference": "d870572532cd70bc3fab58f2e23ad423c8404c44", + "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" + }, + "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/master" + }, + "time": "2020-08-15T11:14:08+00:00" + }, + { + "name": "phpdocumentor/type-resolver", + "version": "1.3.0", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/TypeResolver.git", + "reference": "e878a14a65245fbe78f8080eba03b47c3b705651" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/e878a14a65245fbe78f8080eba03b47c3b705651", + "reference": "e878a14a65245fbe78f8080eba03b47c3b705651", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0", + "phpdocumentor/reflection-common": "^2.0" + }, + "require-dev": { + "ext-tokenizer": "*" + }, + "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.x" + }, + "time": "2020-06-27T10:12:23+00:00" + }, + { + "name": "psr/container", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/container.git", + "reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/container/zipball/b7ce3b176482dbbc1245ebf52b181af44c2cf55f", + "reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Container\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://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/master" + }, + "time": "2017-02-14T16:28:37+00:00" + }, + { + "name": "psr/log", + "version": "1.1.3", + "source": { + "type": "git", + "url": "https://github.com/php-fig/log.git", + "reference": "0f73288fd15629204f9d42b7055f72dacbe811fc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/log/zipball/0f73288fd15629204f9d42b7055f72dacbe811fc", + "reference": "0f73288fd15629204f9d42b7055f72dacbe811fc", + "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": "http://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.3" + }, + "time": "2020-03-23T09:12:05+00:00" + }, + { + "name": "sanmai/pipeline", + "version": "v5.0.1", + "source": { + "type": "git", + "url": "https://github.com/sanmai/pipeline.git", + "reference": "a51d82ca3653f3d417230218a8fe3738cdd207cd" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sanmai/pipeline/zipball/a51d82ca3653f3d417230218a8fe3738cdd207cd", + "reference": "a51d82ca3653f3d417230218a8fe3738cdd207cd", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^2.13", + "infection/infection": ">=0.10.5", + "league/pipeline": "^1.0 || ^0.3", + "phan/phan": "^1.1 || ^2.0", + "php-coveralls/php-coveralls": "^2.0", + "phpstan/phpstan": ">=0.10", + "phpunit/phpunit": "^7.4 || ^8.1 || ^9.0", + "vimeo/psalm": "^2.0 || ^3.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Pipeline\\": "src/" + }, + "files": [ + "src/functions.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Alexey Kopytko", + "email": "alexey@kopytko.com" + } + ], + "description": "General-purpose collections pipeline", + "support": { + "issues": "https://github.com/sanmai/pipeline/issues", + "source": "https://github.com/sanmai/pipeline/tree/v5.0.1" + }, + "funding": [ + { + "url": "https://github.com/sanmai", + "type": "github" + } + ], + "time": "2020-08-27T13:29:50+00:00" + }, + { + "name": "sebastian/diff", + "version": "4.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/diff.git", + "reference": "1e90b4cf905a7d06c420b1d2e9d11a4dc8a13113" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/1e90b4cf905a7d06c420b1d2e9d11a4dc8a13113", + "reference": "1e90b4cf905a7d06c420b1d2e9d11a4dc8a13113", + "shasum": "" + }, + "require": { + "php": "^7.3 || ^8.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.0", + "symfony/process": "^4.2 || ^5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.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/master" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-06-30T04:46:02+00:00" + }, + { + "name": "seld/jsonlint", + "version": "1.8.2", + "source": { + "type": "git", + "url": "https://github.com/Seldaek/jsonlint.git", + "reference": "590cfec960b77fd55e39b7d9246659e95dd6d337" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Seldaek/jsonlint/zipball/590cfec960b77fd55e39b7d9246659e95dd6d337", + "reference": "590cfec960b77fd55e39b7d9246659e95dd6d337", + "shasum": "" + }, + "require": { + "php": "^5.3 || ^7.0 || ^8.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0" + }, + "bin": [ + "bin/jsonlint" + ], + "type": "library", + "autoload": { + "psr-4": { + "Seld\\JsonLint\\": "src/Seld/JsonLint/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be" + } + ], + "description": "JSON Linter", + "keywords": [ + "json", + "linter", + "parser", + "validator" + ], + "support": { + "issues": "https://github.com/Seldaek/jsonlint/issues", + "source": "https://github.com/Seldaek/jsonlint/tree/master" + }, + "funding": [ + { + "url": "https://github.com/Seldaek", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/seld/jsonlint", + "type": "tidelift" + } + ], + "time": "2020-08-25T06:56:57+00:00" + }, + { + "name": "symfony/console", + "version": "v5.1.5", + "source": { + "type": "git", + "url": "https://github.com/symfony/console.git", + "reference": "186f395b256065ba9b890c0a4e48a91d598fa2cf" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/console/zipball/186f395b256065ba9b890c0a4e48a91d598fa2cf", + "reference": "186f395b256065ba9b890c0a4e48a91d598fa2cf", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/polyfill-mbstring": "~1.0", + "symfony/polyfill-php73": "^1.8", + "symfony/polyfill-php80": "^1.15", + "symfony/service-contracts": "^1.1|^2", + "symfony/string": "^5.1" + }, + "conflict": { + "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" + }, + "require-dev": { + "psr/log": "~1.0", + "symfony/config": "^4.4|^5.0", + "symfony/dependency-injection": "^4.4|^5.0", + "symfony/event-dispatcher": "^4.4|^5.0", + "symfony/lock": "^4.4|^5.0", + "symfony/process": "^4.4|^5.0", + "symfony/var-dumper": "^4.4|^5.0" + }, + "suggest": { + "psr/log": "For using the console logger", + "symfony/event-dispatcher": "", + "symfony/lock": "", + "symfony/process": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.1-dev" + } + }, + "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": "Symfony Console Component", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/console/tree/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": "2020-09-02T07:07:40+00:00" + }, + { + "name": "symfony/filesystem", + "version": "v5.1.5", + "source": { + "type": "git", + "url": "https://github.com/symfony/filesystem.git", + "reference": "f7b9ed6142a34252d219801d9767dedbd711da1a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/f7b9ed6142a34252d219801d9767dedbd711da1a", + "reference": "f7b9ed6142a34252d219801d9767dedbd711da1a", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/polyfill-ctype": "~1.8" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.1-dev" + } + }, + "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": "Symfony Filesystem Component", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/filesystem/tree/v5.1.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": "2020-08-21T17:19:47+00:00" + }, + { + "name": "symfony/finder", + "version": "v5.1.5", + "source": { + "type": "git", + "url": "https://github.com/symfony/finder.git", + "reference": "2b765f0cf6612b3636e738c0689b29aa63088d5d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/finder/zipball/2b765f0cf6612b3636e738c0689b29aa63088d5d", + "reference": "2b765f0cf6612b3636e738c0689b29aa63088d5d", + "shasum": "" + }, + "require": { + "php": ">=7.2.5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.1-dev" + } + }, + "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": "Symfony Finder Component", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/finder/tree/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": "2020-08-17T10:01:29+00:00" + }, + { + "name": "symfony/polyfill-ctype", + "version": "v1.18.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-ctype.git", + "reference": "1c302646f6efc070cd46856e600e5e0684d6b454" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/1c302646f6efc070cd46856e600e5e0684d6b454", + "reference": "1c302646f6efc070cd46856e600e5e0684d6b454", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "suggest": { + "ext-ctype": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.18-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Ctype\\": "" + }, + "files": [ + "bootstrap.php" + ] + }, + "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.18.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-07-14T12:35:20+00:00" + }, + { + "name": "symfony/polyfill-intl-grapheme", + "version": "v1.18.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-grapheme.git", + "reference": "b740103edbdcc39602239ee8860f0f45a8eb9aa5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/b740103edbdcc39602239ee8860f0f45a8eb9aa5", + "reference": "b740103edbdcc39602239ee8860f0f45a8eb9aa5", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.18-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Intl\\Grapheme\\": "" + }, + "files": [ + "bootstrap.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": "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.18.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": "2020-07-14T12:35:20+00:00" + }, + { + "name": "symfony/polyfill-intl-normalizer", + "version": "v1.18.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-normalizer.git", + "reference": "37078a8dd4a2a1e9ab0231af7c6cb671b2ed5a7e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/37078a8dd4a2a1e9ab0231af7c6cb671b2ed5a7e", + "reference": "37078a8dd4a2a1e9ab0231af7c6cb671b2ed5a7e", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.18-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Intl\\Normalizer\\": "" + }, + "files": [ + "bootstrap.php" + ], + "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.18.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": "2020-07-14T12:35:20+00:00" + }, + { + "name": "symfony/polyfill-mbstring", + "version": "v1.18.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-mbstring.git", + "reference": "a6977d63bf9a0ad4c65cd352709e230876f9904a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/a6977d63bf9a0ad4c65cd352709e230876f9904a", + "reference": "a6977d63bf9a0ad4c65cd352709e230876f9904a", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "suggest": { + "ext-mbstring": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.18-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Mbstring\\": "" + }, + "files": [ + "bootstrap.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": "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.18.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": "2020-07-14T12:35:20+00:00" + }, + { + "name": "symfony/polyfill-php73", + "version": "v1.18.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php73.git", + "reference": "fffa1a52a023e782cdcc221d781fe1ec8f87fcca" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/fffa1a52a023e782cdcc221d781fe1ec8f87fcca", + "reference": "fffa1a52a023e782cdcc221d781fe1ec8f87fcca", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.18-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Php73\\": "" + }, + "files": [ + "bootstrap.php" + ], + "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/master" + }, + "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-07-14T12:35:20+00:00" + }, + { + "name": "symfony/polyfill-php80", + "version": "v1.18.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php80.git", + "reference": "d87d5766cbf48d72388a9f6b85f280c8ad51f981" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/d87d5766cbf48d72388a9f6b85f280c8ad51f981", + "reference": "d87d5766cbf48d72388a9f6b85f280c8ad51f981", + "shasum": "" + }, + "require": { + "php": ">=7.0.8" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.18-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Php80\\": "" + }, + "files": [ + "bootstrap.php" + ], + "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/master" + }, + "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-07-14T12:35:20+00:00" + }, + { + "name": "symfony/process", + "version": "v5.1.5", + "source": { + "type": "git", + "url": "https://github.com/symfony/process.git", + "reference": "1864216226af21eb76d9477f691e7cbf198e0402" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/process/zipball/1864216226af21eb76d9477f691e7cbf198e0402", + "reference": "1864216226af21eb76d9477f691e7cbf198e0402", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/polyfill-php80": "^1.15" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.1-dev" + } + }, + "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": "Symfony Process Component", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/process/tree/v5.1.4" + }, + "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-07-23T08:36:24+00:00" + }, + { + "name": "symfony/service-contracts", + "version": "v2.1.3", + "source": { + "type": "git", + "url": "https://github.com/symfony/service-contracts.git", + "reference": "58c7475e5457c5492c26cc740cc0ad7464be9442" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/58c7475e5457c5492c26cc740cc0ad7464be9442", + "reference": "58c7475e5457c5492c26cc740cc0ad7464be9442", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "psr/container": "^1.0" + }, + "suggest": { + "symfony/service-implementation": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.1-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.1.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": "2020-07-06T13:23:11+00:00" + }, + { + "name": "symfony/string", + "version": "v5.1.5", + "source": { + "type": "git", + "url": "https://github.com/symfony/string.git", + "reference": "0de4cc1e18bb596226c06a82e2e7e9bc6001a63a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/string/zipball/0de4cc1e18bb596226c06a82e2e7e9bc6001a63a", + "reference": "0de4cc1e18bb596226c06a82e2e7e9bc6001a63a", + "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" + }, + "require-dev": { + "symfony/error-handler": "^4.4|^5.0", + "symfony/http-client": "^4.4|^5.0", + "symfony/translation-contracts": "^1.1|^2", + "symfony/var-exporter": "^4.4|^5.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.1-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\String\\": "" + }, + "files": [ + "Resources/functions.php" + ], + "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": "Symfony String component", + "homepage": "https://symfony.com", + "keywords": [ + "grapheme", + "i18n", + "string", + "unicode", + "utf-8", + "utf8" + ], + "support": { + "source": "https://github.com/symfony/string/tree/v5.1.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": "2020-08-17T07:48:54+00:00" + }, + { + "name": "thecodingmachine/safe", + "version": "v1.1.3", + "source": { + "type": "git", + "url": "https://github.com/thecodingmachine/safe.git", + "reference": "9f277171e296a3c8629c04ac93ec95ff0f208ccb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thecodingmachine/safe/zipball/9f277171e296a3c8629c04ac93ec95ff0f208ccb", + "reference": "9f277171e296a3c8629c04ac93ec95ff0f208ccb", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "require-dev": { + "phpstan/phpstan": "^0.12", + "squizlabs/php_codesniffer": "^3.2", + "thecodingmachine/phpstan-strict-rules": "^0.12" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "0.1-dev" + } + }, + "autoload": { + "psr-4": { + "Safe\\": [ + "lib/", + "generated/" + ] + }, + "files": [ + "generated/apache.php", + "generated/apc.php", + "generated/apcu.php", + "generated/array.php", + "generated/bzip2.php", + "generated/classobj.php", + "generated/com.php", + "generated/cubrid.php", + "generated/curl.php", + "generated/datetime.php", + "generated/dir.php", + "generated/eio.php", + "generated/errorfunc.php", + "generated/exec.php", + "generated/fileinfo.php", + "generated/filesystem.php", + "generated/filter.php", + "generated/fpm.php", + "generated/ftp.php", + "generated/funchand.php", + "generated/gmp.php", + "generated/gnupg.php", + "generated/hash.php", + "generated/ibase.php", + "generated/ibmDb2.php", + "generated/iconv.php", + "generated/image.php", + "generated/imap.php", + "generated/info.php", + "generated/ingres-ii.php", + "generated/inotify.php", + "generated/json.php", + "generated/ldap.php", + "generated/libevent.php", + "generated/libxml.php", + "generated/lzf.php", + "generated/mailparse.php", + "generated/mbstring.php", + "generated/misc.php", + "generated/msql.php", + "generated/mssql.php", + "generated/mysql.php", + "generated/mysqli.php", + "generated/mysqlndMs.php", + "generated/mysqlndQc.php", + "generated/network.php", + "generated/oci8.php", + "generated/opcache.php", + "generated/openssl.php", + "generated/outcontrol.php", + "generated/password.php", + "generated/pcntl.php", + "generated/pcre.php", + "generated/pdf.php", + "generated/pgsql.php", + "generated/posix.php", + "generated/ps.php", + "generated/pspell.php", + "generated/readline.php", + "generated/rpminfo.php", + "generated/rrd.php", + "generated/sem.php", + "generated/session.php", + "generated/shmop.php", + "generated/simplexml.php", + "generated/sockets.php", + "generated/sodium.php", + "generated/solr.php", + "generated/spl.php", + "generated/sqlsrv.php", + "generated/ssdeep.php", + "generated/ssh2.php", + "generated/stats.php", + "generated/stream.php", + "generated/strings.php", + "generated/swoole.php", + "generated/uodbc.php", + "generated/uopz.php", + "generated/url.php", + "generated/var.php", + "generated/xdiff.php", + "generated/xml.php", + "generated/xmlrpc.php", + "generated/yaml.php", + "generated/yaz.php", + "generated/zip.php", + "generated/zlib.php", + "lib/special_cases.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "PHP core functions that throw exceptions instead of returning FALSE on error", + "support": { + "issues": "https://github.com/thecodingmachine/safe/issues", + "source": "https://github.com/thecodingmachine/safe/tree/master" + }, + "time": "2020-07-10T09:34:29+00:00" + }, + { + "name": "vimeo/psalm", + "version": "3.15", + "source": { + "type": "git", + "url": "https://github.com/vimeo/psalm.git", + "reference": "de6e7f324f44dde540ebe7ebd4eb481b97c86f30" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/vimeo/psalm/zipball/de6e7f324f44dde540ebe7ebd4eb481b97c86f30", + "reference": "de6e7f324f44dde540ebe7ebd4eb481b97c86f30", + "shasum": "" + }, + "require": { + "amphp/amp": "^2.1", + "amphp/byte-stream": "^1.5", + "composer/package-versions-deprecated": "^1.8.0", + "composer/semver": "^1.4 || ^2.0 || ^3.0", + "composer/xdebug-handler": "^1.1", + "dnoegel/php-xdg-base-dir": "^0.1.1", + "ext-dom": "*", + "ext-json": "*", + "ext-libxml": "*", + "ext-simplexml": "*", + "ext-tokenizer": "*", + "felixfbecker/advanced-json-rpc": "^3.0.3", + "felixfbecker/language-server-protocol": "^1.4", + "netresearch/jsonmapper": "^1.0 || ^2.0 || ^3.0", + "nikic/php-parser": "4.3.* || 4.4.* || 4.5.* || 4.6.* || ^4.8", + "openlss/lib-array2xml": "^1.0", + "php": "^7.1.3|^8", + "sebastian/diff": "^3.0 || ^4.0", + "symfony/console": "^3.4.17 || ^4.1.6 || ^5.0", + "webmozart/glob": "^4.1", + "webmozart/path-util": "^2.3" + }, + "provide": { + "psalm/psalm": "self.version" + }, + "require-dev": { + "amphp/amp": "^2.4.2", + "bamarni/composer-bin-plugin": "^1.2", + "brianium/paratest": "^4.0.0", + "ext-curl": "*", + "phpdocumentor/reflection-docblock": "^4.3.4 || ^5", + "phpmyadmin/sql-parser": "5.1.0", + "phpspec/prophecy": ">=1.9.0", + "phpunit/phpunit": "^7.5.16 || ^8.5 || ^9.0", + "psalm/plugin-phpunit": "^0.11", + "slevomat/coding-standard": "^5.0", + "squizlabs/php_codesniffer": "^3.5", + "symfony/process": "^4.3", + "weirdan/prophecy-shim": "^1.0 || ^2.0" + }, + "suggest": { + "ext-igbinary": "^2.0.5" + }, + "bin": [ + "psalm", + "psalm-language-server", + "psalm-plugin", + "psalm-refactor", + "psalter" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.x-dev", + "dev-2.x": "2.x-dev", + "dev-1.x": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psalm\\": "src/Psalm/" + }, + "files": [ + "src/functions.php", + "src/spl_object_id.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Matthew Brown" + } + ], + "description": "A static analysis tool for finding errors in PHP applications", + "keywords": [ + "code", + "inspection", + "php" + ], + "support": { + "issues": "https://github.com/vimeo/psalm/issues", + "source": "https://github.com/vimeo/psalm/tree/3.x" + }, + "time": "2020-09-01T22:09:30+00:00" + }, + { + "name": "webmozart/assert", + "version": "1.9.1", + "source": { + "type": "git", + "url": "https://github.com/webmozart/assert.git", + "reference": "bafc69caeb4d49c39fd0779086c03a3738cbb389" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/webmozart/assert/zipball/bafc69caeb4d49c39fd0779086c03a3738cbb389", + "reference": "bafc69caeb4d49c39fd0779086c03a3738cbb389", + "shasum": "" + }, + "require": { + "php": "^5.3.3 || ^7.0 || ^8.0", + "symfony/polyfill-ctype": "^1.8" + }, + "conflict": { + "phpstan/phpstan": "<0.12.20", + "vimeo/psalm": "<3.9.1" + }, + "require-dev": { + "phpunit/phpunit": "^4.8.36 || ^7.5.13" + }, + "type": "library", + "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/webmozart/assert/issues", + "source": "https://github.com/webmozart/assert/tree/master" + }, + "time": "2020-07-08T17:02:28+00:00" + }, + { + "name": "webmozart/glob", + "version": "4.1.0", + "source": { + "type": "git", + "url": "https://github.com/webmozart/glob.git", + "reference": "3cbf63d4973cf9d780b93d2da8eec7e4a9e63bbe" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/webmozart/glob/zipball/3cbf63d4973cf9d780b93d2da8eec7e4a9e63bbe", + "reference": "3cbf63d4973cf9d780b93d2da8eec7e4a9e63bbe", + "shasum": "" + }, + "require": { + "php": "^5.3.3|^7.0", + "webmozart/path-util": "^2.2" + }, + "require-dev": { + "phpunit/phpunit": "^4.6", + "sebastian/version": "^1.0.1", + "symfony/filesystem": "^2.5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.1-dev" + } + }, + "autoload": { + "psr-4": { + "Webmozart\\Glob\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + } + ], + "description": "A PHP implementation of Ant's glob.", + "support": { + "issues": "https://github.com/webmozart/glob/issues", + "source": "https://github.com/webmozart/glob/tree/master" + }, + "time": "2015-12-29T11:14:33+00:00" + }, + { + "name": "webmozart/path-util", + "version": "2.3.0", + "source": { + "type": "git", + "url": "https://github.com/webmozart/path-util.git", + "reference": "d939f7edc24c9a1bb9c0dee5cb05d8e859490725" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/webmozart/path-util/zipball/d939f7edc24c9a1bb9c0dee5cb05d8e859490725", + "reference": "d939f7edc24c9a1bb9c0dee5cb05d8e859490725", + "shasum": "" + }, + "require": { + "php": ">=5.3.3", + "webmozart/assert": "~1.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.6", + "sebastian/version": "^1.0.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.3-dev" + } + }, + "autoload": { + "psr-4": { + "Webmozart\\PathUtil\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + } + ], + "description": "A robust cross-platform utility for normalizing, comparing and modifying file paths.", + "support": { + "issues": "https://github.com/webmozart/path-util/issues", + "source": "https://github.com/webmozart/path-util/tree/2.3.0" + }, + "time": "2015-12-17T08:42:14+00:00" + } + ], + "packages-dev": [ + { + "name": "doctrine/instantiator", + "version": "1.3.1", + "source": { + "type": "git", + "url": "https://github.com/doctrine/instantiator.git", + "reference": "f350df0268e904597e3bd9c4685c53e0e333feea" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/instantiator/zipball/f350df0268e904597e3bd9c4685c53e0e333feea", + "reference": "f350df0268e904597e3bd9c4685c53e0e333feea", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0" + }, + "require-dev": { + "doctrine/coding-standard": "^6.0", + "ext-pdo": "*", + "ext-phar": "*", + "phpbench/phpbench": "^0.13", + "phpstan/phpstan-phpunit": "^0.11", + "phpstan/phpstan-shim": "^0.11", + "phpunit/phpunit": "^7.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.2.x-dev" + } + }, + "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": "http://ocramius.github.com/" + } + ], + "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.3.x" + }, + "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": "2020-05-29T17:27:14+00:00" + }, + { + "name": "myclabs/deep-copy", + "version": "1.10.1", + "source": { + "type": "git", + "url": "https://github.com/myclabs/DeepCopy.git", + "reference": "969b211f9a51aa1f6c01d1d2aef56d3bd91598e5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/969b211f9a51aa1f6c01d1d2aef56d3bd91598e5", + "reference": "969b211f9a51aa1f6c01d1d2aef56d3bd91598e5", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0" + }, + "replace": { + "myclabs/deep-copy": "self.version" + }, + "require-dev": { + "doctrine/collections": "^1.0", + "doctrine/common": "^2.6", + "phpunit/phpunit": "^7.1" + }, + "type": "library", + "autoload": { + "psr-4": { + "DeepCopy\\": "src/DeepCopy/" + }, + "files": [ + "src/DeepCopy/deep_copy.php" + ] + }, + "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.x" + }, + "funding": [ + { + "url": "https://tidelift.com/funding/github/packagist/myclabs/deep-copy", + "type": "tidelift" + } + ], + "time": "2020-06-29T13:22:24+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": "phpspec/prophecy", + "version": "1.11.1", + "source": { + "type": "git", + "url": "https://github.com/phpspec/prophecy.git", + "reference": "b20034be5efcdab4fb60ca3a29cba2949aead160" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpspec/prophecy/zipball/b20034be5efcdab4fb60ca3a29cba2949aead160", + "reference": "b20034be5efcdab4fb60ca3a29cba2949aead160", + "shasum": "" + }, + "require": { + "doctrine/instantiator": "^1.2", + "php": "^7.2", + "phpdocumentor/reflection-docblock": "^5.0", + "sebastian/comparator": "^3.0 || ^4.0", + "sebastian/recursion-context": "^3.0 || ^4.0" + }, + "require-dev": { + "phpspec/phpspec": "^6.0", + "phpunit/phpunit": "^8.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.11.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/master" + }, + "time": "2020-07-08T12:44:21+00:00" + }, + { + "name": "phpunit/php-code-coverage", + "version": "8.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-code-coverage.git", + "reference": "ca6647ffddd2add025ab3f21644a441d7c146cdc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/ca6647ffddd2add025ab3f21644a441d7c146cdc", + "reference": "ca6647ffddd2add025ab3f21644a441d7c146cdc", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-xmlwriter": "*", + "php": "^7.3", + "phpunit/php-file-iterator": "^3.0", + "phpunit/php-text-template": "^2.0", + "phpunit/php-token-stream": "^4.0", + "sebastian/code-unit-reverse-lookup": "^2.0", + "sebastian/environment": "^5.0", + "sebastian/version": "^3.0", + "theseer/tokenizer": "^1.1.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.0" + }, + "suggest": { + "ext-pcov": "*", + "ext-xdebug": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "8.0-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/8.0.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-05-23T08:02:54+00:00" + }, + { + "name": "phpunit/php-file-iterator", + "version": "3.0.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-file-iterator.git", + "reference": "25fefc5b19835ca653877fe081644a3f8c1d915e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/25fefc5b19835ca653877fe081644a3f8c1d915e", + "reference": "25fefc5b19835ca653877fe081644a3f8c1d915e", + "shasum": "" + }, + "require": { + "php": "^7.3 || ^8.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.0" + }, + "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", + "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/3.0.4" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-07-11T05:18:21+00:00" + }, + { + "name": "phpunit/php-invoker", + "version": "3.1.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-invoker.git", + "reference": "7a85b66acc48cacffdf87dadd3694e7123674298" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/7a85b66acc48cacffdf87dadd3694e7123674298", + "reference": "7a85b66acc48cacffdf87dadd3694e7123674298", + "shasum": "" + }, + "require": { + "php": "^7.3 || ^8.0" + }, + "require-dev": { + "ext-pcntl": "*", + "phpunit/phpunit": "^9.0" + }, + "suggest": { + "ext-pcntl": "*" + }, + "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", + "role": "lead" + } + ], + "description": "Invoke callables with a timeout", + "homepage": "https://github.com/sebastianbergmann/php-invoker/", + "keywords": [ + "process" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-invoker/issues", + "source": "https://github.com/sebastianbergmann/php-invoker/tree/3.1.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-08-06T07:04:15+00:00" + }, + { + "name": "phpunit/php-text-template", + "version": "2.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-text-template.git", + "reference": "6ff9c8ea4d3212b88fcf74e25e516e2c51c99324" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/6ff9c8ea4d3212b88fcf74e25e516e2c51c99324", + "reference": "6ff9c8ea4d3212b88fcf74e25e516e2c51c99324", + "shasum": "" + }, + "require": { + "php": "^7.3 || ^8.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.0" + }, + "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", + "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/master" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-06-26T11:55:37+00:00" + }, + { + "name": "phpunit/php-timer", + "version": "5.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-timer.git", + "reference": "cc49734779cbb302bf51a44297dab8c4bbf941e7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/cc49734779cbb302bf51a44297dab8c4bbf941e7", + "reference": "cc49734779cbb302bf51a44297dab8c4bbf941e7", + "shasum": "" + }, + "require": { + "php": "^7.3 || ^8.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.0-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/master" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-06-26T11:58:13+00:00" + }, + { + "name": "phpunit/php-token-stream", + "version": "4.0.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-token-stream.git", + "reference": "a853a0e183b9db7eed023d7933a858fa1c8d25a3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/a853a0e183b9db7eed023d7933a858fa1c8d25a3", + "reference": "a853a0e183b9db7eed023d7933a858fa1c8d25a3", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "php": "^7.3 || ^8.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0-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/master" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "abandoned": true, + "time": "2020-08-04T08:28:15+00:00" + }, + { + "name": "phpunit/phpunit", + "version": "9.2.6", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit.git", + "reference": "1c6a9e4312e209e659f1fce3ce88dd197c2448f6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/1c6a9e4312e209e659f1fce3ce88dd197c2448f6", + "reference": "1c6a9e4312e209e659f1fce3ce88dd197c2448f6", + "shasum": "" + }, + "require": { + "doctrine/instantiator": "^1.3.1", + "ext-dom": "*", + "ext-json": "*", + "ext-libxml": "*", + "ext-mbstring": "*", + "ext-xml": "*", + "ext-xmlwriter": "*", + "myclabs/deep-copy": "^1.9.5", + "phar-io/manifest": "^1.0.3", + "phar-io/version": "^2.0.1", + "php": "^7.3", + "phpspec/prophecy": "^1.10.3", + "phpunit/php-code-coverage": "^8.0.2", + "phpunit/php-file-iterator": "^3.0.3", + "phpunit/php-invoker": "^3.0.2", + "phpunit/php-text-template": "^2.0.2", + "phpunit/php-timer": "^5.0.1", + "sebastian/code-unit": "^1.0.5", + "sebastian/comparator": "^4.0.3", + "sebastian/diff": "^4.0.1", + "sebastian/environment": "^5.1.2", + "sebastian/exporter": "^4.0.2", + "sebastian/global-state": "^4.0", + "sebastian/object-enumerator": "^4.0.2", + "sebastian/resource-operations": "^3.0.2", + "sebastian/type": "^2.1.1", + "sebastian/version": "^3.0.1" + }, + "require-dev": { + "ext-pdo": "*", + "phpspec/prophecy-phpunit": "^2.0" + }, + "suggest": { + "ext-soap": "*", + "ext-xdebug": "*" + }, + "bin": [ + "phpunit" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "9.2-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ], + "files": [ + "src/Framework/Assert/Functions.php" + ] + }, + "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/9.2.6" + }, + "funding": [ + { + "url": "https://phpunit.de/donate.html", + "type": "custom" + }, + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-07-13T17:55:55+00:00" + }, + { + "name": "sebastian/code-unit", + "version": "1.0.5", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/code-unit.git", + "reference": "c1e2df332c905079980b119c4db103117e5e5c90" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit/zipball/c1e2df332c905079980b119c4db103117e5e5c90", + "reference": "c1e2df332c905079980b119c4db103117e5e5c90", + "shasum": "" + }, + "require": { + "php": "^7.3 || ^8.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-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": "Collection of value objects that represent the PHP code units", + "homepage": "https://github.com/sebastianbergmann/code-unit", + "support": { + "issues": "https://github.com/sebastianbergmann/code-unit/issues", + "source": "https://github.com/sebastianbergmann/code-unit/tree/master" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-06-26T12:50:45+00:00" + }, + { + "name": "sebastian/code-unit-reverse-lookup", + "version": "2.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", + "reference": "ee51f9bb0c6d8a43337055db3120829fa14da819" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/ee51f9bb0c6d8a43337055db3120829fa14da819", + "reference": "ee51f9bb0c6d8a43337055db3120829fa14da819", + "shasum": "" + }, + "require": { + "php": "^7.3 || ^8.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.0" + }, + "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": "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/master" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-06-26T12:04:00+00:00" + }, + { + "name": "sebastian/comparator", + "version": "4.0.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/comparator.git", + "reference": "dcc580eadfaa4e7f9d2cf9ae1922134ea962e14f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/dcc580eadfaa4e7f9d2cf9ae1922134ea962e14f", + "reference": "dcc580eadfaa4e7f9d2cf9ae1922134ea962e14f", + "shasum": "" + }, + "require": { + "php": "^7.3 || ^8.0", + "sebastian/diff": "^4.0", + "sebastian/exporter": "^4.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.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/master" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-06-26T12:05:46+00:00" + }, + { + "name": "sebastian/environment", + "version": "5.1.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/environment.git", + "reference": "0a757cab9d5b7ef49a619f1143e6c9c1bc0fe9d2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/0a757cab9d5b7ef49a619f1143e6c9c1bc0fe9d2", + "reference": "0a757cab9d5b7ef49a619f1143e6c9c1bc0fe9d2", + "shasum": "" + }, + "require": { + "php": "^7.3 || ^8.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.0" + }, + "suggest": { + "ext-posix": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.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 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/master" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-06-26T12:07:24+00:00" + }, + { + "name": "sebastian/exporter", + "version": "4.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/exporter.git", + "reference": "571d721db4aec847a0e59690b954af33ebf9f023" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/571d721db4aec847a0e59690b954af33ebf9f023", + "reference": "571d721db4aec847a0e59690b954af33ebf9f023", + "shasum": "" + }, + "require": { + "php": "^7.3 || ^8.0", + "sebastian/recursion-context": "^4.0" + }, + "require-dev": { + "ext-mbstring": "*", + "phpunit/phpunit": "^9.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.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": "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/4.0.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-06-26T12:08:55+00:00" + }, + { + "name": "sebastian/global-state", + "version": "4.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/global-state.git", + "reference": "bdb1e7c79e592b8c82cb1699be3c8743119b8a72" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bdb1e7c79e592b8c82cb1699be3c8743119b8a72", + "reference": "bdb1e7c79e592b8c82cb1699be3c8743119b8a72", + "shasum": "" + }, + "require": { + "php": "^7.3", + "sebastian/object-reflector": "^2.0", + "sebastian/recursion-context": "^4.0" + }, + "require-dev": { + "ext-dom": "*", + "phpunit/phpunit": "^9.0" + }, + "suggest": { + "ext-uopz": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.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/master" + }, + "time": "2020-02-07T06:11:37+00:00" + }, + { + "name": "sebastian/object-enumerator", + "version": "4.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/object-enumerator.git", + "reference": "074fed2d0a6d08e1677dd8ce9d32aecb384917b8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/074fed2d0a6d08e1677dd8ce9d32aecb384917b8", + "reference": "074fed2d0a6d08e1677dd8ce9d32aecb384917b8", + "shasum": "" + }, + "require": { + "php": "^7.3 || ^8.0", + "sebastian/object-reflector": "^2.0", + "sebastian/recursion-context": "^4.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0-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/master" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-06-26T12:11:32+00:00" + }, + { + "name": "sebastian/object-reflector", + "version": "2.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/object-reflector.git", + "reference": "127a46f6b057441b201253526f81d5406d6c7840" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/127a46f6b057441b201253526f81d5406d6c7840", + "reference": "127a46f6b057441b201253526f81d5406d6c7840", + "shasum": "" + }, + "require": { + "php": "^7.3 || ^8.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.0" + }, + "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": "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/master" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-06-26T12:12:55+00:00" + }, + { + "name": "sebastian/recursion-context", + "version": "4.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/recursion-context.git", + "reference": "062231bf61d2b9448c4fa5a7643b5e1829c11d63" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/062231bf61d2b9448c4fa5a7643b5e1829c11d63", + "reference": "062231bf61d2b9448c4fa5a7643b5e1829c11d63", + "shasum": "" + }, + "require": { + "php": "^7.3 || ^8.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.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": "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/master" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-06-26T12:14:17+00:00" + }, + { + "name": "sebastian/resource-operations", + "version": "3.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/resource-operations.git", + "reference": "0653718a5a629b065e91f774595267f8dc32e213" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/0653718a5a629b065e91f774595267f8dc32e213", + "reference": "0653718a5a629b065e91f774595267f8dc32e213", + "shasum": "" + }, + "require": { + "php": "^7.3 || ^8.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.0" + }, + "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" + } + ], + "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/3.0.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-06-26T12:16:22+00:00" + }, + { + "name": "sebastian/type", + "version": "2.2.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/type.git", + "reference": "86991e2b33446cd96e648c18bcdb1e95afb2c05a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/86991e2b33446cd96e648c18bcdb1e95afb2c05a", + "reference": "86991e2b33446cd96e648c18bcdb1e95afb2c05a", + "shasum": "" + }, + "require": { + "php": "^7.3 || ^8.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.2-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": "Collection of value objects that represent the types of the PHP type system", + "homepage": "https://github.com/sebastianbergmann/type", + "support": { + "issues": "https://github.com/sebastianbergmann/type/issues", + "source": "https://github.com/sebastianbergmann/type/tree/2.2.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-07-05T08:31:53+00:00" + }, + { + "name": "sebastian/version", + "version": "3.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/version.git", + "reference": "626586115d0ed31cb71483be55beb759b5af5a3c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/626586115d0ed31cb71483be55beb759b5af5a3c", + "reference": "626586115d0ed31cb71483be55beb759b5af5a3c", + "shasum": "" + }, + "require": { + "php": "^7.3 || ^8.0" + }, + "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", + "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/3.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-06-26T12:18:43+00:00" + }, + { + "name": "theseer/tokenizer", + "version": "1.2.0", + "source": { + "type": "git", + "url": "https://github.com/theseer/tokenizer.git", + "reference": "75a63c33a8577608444246075ea0af0d052e452a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/theseer/tokenizer/zipball/75a63c33a8577608444246075ea0af0d052e452a", + "reference": "75a63c33a8577608444246075ea0af0d052e452a", + "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/master" + }, + "funding": [ + { + "url": "https://github.com/theseer", + "type": "github" + } + ], + "time": "2020-07-12T23:59:07+00:00" + } + ], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": [], + "prefer-stable": false, + "prefer-lowest": false, + "platform": [], + "platform-dev": [], + "plugin-api-version": "2.0.0" +} From 43836fd8545363288aa39bc886ca2f5d7bef1ae8 Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Wed, 2 Sep 2020 15:27:22 +0200 Subject: [PATCH 03/14] Added `doctrine/coding-standard` dependency, needed for CS checks later on --- composer.json | 6 +- composer.lock | 302 +++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 306 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index a63e25b..1d50c13 100644 --- a/composer.json +++ b/composer.json @@ -7,6 +7,7 @@ "vimeo/psalm": "^3.15.0" }, "require-dev": { + "doctrine/coding-standard": "^8.1.0", "phpunit/phpunit": "^9.2.6" }, "license": "MIT", @@ -15,5 +16,8 @@ "name": "Marco Pivetta", "email": "ocramius@gmail.com" } - ] + ], + "config": { + "sort-packages": true + } } diff --git a/composer.lock b/composer.lock index 3834dc8..363cbbf 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "37d292672b14a096ef164860da8efade", + "content-hash": "6328519dfb1a28b0a8fad050831548e8", "packages": [ { "name": "amphp/amp", @@ -2873,6 +2873,136 @@ } ], "packages-dev": [ + { + "name": "dealerdirect/phpcodesniffer-composer-installer", + "version": "v0.7.0", + "source": { + "type": "git", + "url": "https://github.com/Dealerdirect/phpcodesniffer-composer-installer.git", + "reference": "e8d808670b8f882188368faaf1144448c169c0b7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Dealerdirect/phpcodesniffer-composer-installer/zipball/e8d808670b8f882188368faaf1144448c169c0b7", + "reference": "e8d808670b8f882188368faaf1144448c169c0b7", + "shasum": "" + }, + "require": { + "composer-plugin-api": "^1.0 || ^2.0", + "php": ">=5.3", + "squizlabs/php_codesniffer": "^2 || ^3 || 4.0.x-dev" + }, + "require-dev": { + "composer/composer": "*", + "phpcompatibility/php-compatibility": "^9.0", + "sensiolabs/security-checker": "^4.1.0" + }, + "type": "composer-plugin", + "extra": { + "class": "Dealerdirect\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\Plugin" + }, + "autoload": { + "psr-4": { + "Dealerdirect\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Franck Nijhof", + "email": "franck.nijhof@dealerdirect.com", + "homepage": "http://www.frenck.nl", + "role": "Developer / IT Manager" + } + ], + "description": "PHP_CodeSniffer Standards Composer Installer Plugin", + "homepage": "http://www.dealerdirect.com", + "keywords": [ + "PHPCodeSniffer", + "PHP_CodeSniffer", + "code quality", + "codesniffer", + "composer", + "installer", + "phpcs", + "plugin", + "qa", + "quality", + "standard", + "standards", + "style guide", + "stylecheck", + "tests" + ], + "support": { + "issues": "https://github.com/dealerdirect/phpcodesniffer-composer-installer/issues", + "source": "https://github.com/dealerdirect/phpcodesniffer-composer-installer" + }, + "time": "2020-06-25T14:57:39+00:00" + }, + { + "name": "doctrine/coding-standard", + "version": "8.1.0", + "source": { + "type": "git", + "url": "https://github.com/doctrine/coding-standard.git", + "reference": "637003febec655f1b27f4301b44bf2264be57434" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/coding-standard/zipball/637003febec655f1b27f4301b44bf2264be57434", + "reference": "637003febec655f1b27f4301b44bf2264be57434", + "shasum": "" + }, + "require": { + "dealerdirect/phpcodesniffer-composer-installer": "^0.6.2 || ^0.7", + "php": "^7.2 || ^8.0", + "slevomat/coding-standard": "^6.3.9", + "squizlabs/php_codesniffer": "^3.5.5" + }, + "type": "phpcodesniffer-standard", + "extra": { + "branch-alias": { + "dev-master": "7.0.x-dev" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Steve Müller", + "email": "st.mueller@dzh-online.de" + } + ], + "description": "The Doctrine Coding Standard is a set of PHPCS rules applied to all Doctrine projects.", + "homepage": "https://www.doctrine-project.org/projects/coding-standard.html", + "keywords": [ + "checks", + "code", + "coding", + "cs", + "doctrine", + "rules", + "sniffer", + "sniffs", + "standard", + "style" + ], + "support": { + "issues": "https://github.com/doctrine/coding-standard/issues", + "source": "https://github.com/doctrine/coding-standard/tree/8.1.x" + }, + "time": "2020-07-05T20:35:22+00:00" + }, { "name": "doctrine/instantiator", "version": "1.3.1", @@ -3182,6 +3312,59 @@ }, "time": "2020-07-08T12:44:21+00:00" }, + { + "name": "phpstan/phpdoc-parser", + "version": "0.4.9", + "source": { + "type": "git", + "url": "https://github.com/phpstan/phpdoc-parser.git", + "reference": "98a088b17966bdf6ee25c8a4b634df313d8aa531" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/98a088b17966bdf6ee25c8a4b634df313d8aa531", + "reference": "98a088b17966bdf6ee25c8a4b634df313d8aa531", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0" + }, + "require-dev": { + "consistence/coding-standard": "^3.5", + "ergebnis/composer-normalize": "^2.0.2", + "jakub-onderka/php-parallel-lint": "^0.9.2", + "phing/phing": "^2.16.0", + "phpstan/extension-installer": "^1.0", + "phpstan/phpstan": "^0.12.26", + "phpstan/phpstan-strict-rules": "^0.12", + "phpunit/phpunit": "^6.3", + "slevomat/coding-standard": "^4.7.2", + "symfony/process": "^4.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "0.4-dev" + } + }, + "autoload": { + "psr-4": { + "PHPStan\\PhpDocParser\\": [ + "src/" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "PHPDoc parser with support for nullable, intersection and generic types", + "support": { + "issues": "https://github.com/phpstan/phpdoc-parser/issues", + "source": "https://github.com/phpstan/phpdoc-parser/tree/master" + }, + "time": "2020-08-03T20:32:43+00:00" + }, { "name": "phpunit/php-code-coverage", "version": "8.0.2", @@ -4381,6 +4564,123 @@ ], "time": "2020-06-26T12:18:43+00:00" }, + { + "name": "slevomat/coding-standard", + "version": "6.4.0", + "source": { + "type": "git", + "url": "https://github.com/slevomat/coding-standard.git", + "reference": "bf3a16a630d8245c350b459832a71afa55c02fd3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/slevomat/coding-standard/zipball/bf3a16a630d8245c350b459832a71afa55c02fd3", + "reference": "bf3a16a630d8245c350b459832a71afa55c02fd3", + "shasum": "" + }, + "require": { + "dealerdirect/phpcodesniffer-composer-installer": "^0.6.2 || ^0.7", + "php": "^7.1 || ^8.0", + "phpstan/phpdoc-parser": "0.4.5 - 0.4.9", + "squizlabs/php_codesniffer": "^3.5.6" + }, + "require-dev": { + "phing/phing": "2.16.3", + "php-parallel-lint/php-parallel-lint": "1.2.0", + "phpstan/phpstan": "0.12.40", + "phpstan/phpstan-deprecation-rules": "0.12.5", + "phpstan/phpstan-phpunit": "0.12.16", + "phpstan/phpstan-strict-rules": "0.12.5", + "phpunit/phpunit": "7.5.20|8.5.5|9.3.8" + }, + "type": "phpcodesniffer-standard", + "extra": { + "branch-alias": { + "dev-master": "6.x-dev" + } + }, + "autoload": { + "psr-4": { + "SlevomatCodingStandard\\": "SlevomatCodingStandard" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Slevomat Coding Standard for PHP_CodeSniffer complements Consistence Coding Standard by providing sniffs with additional checks.", + "support": { + "issues": "https://github.com/slevomat/coding-standard/issues", + "source": "https://github.com/slevomat/coding-standard/tree/6.4.0" + }, + "funding": [ + { + "url": "https://github.com/kukulich", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/slevomat/coding-standard", + "type": "tidelift" + } + ], + "time": "2020-08-31T07:02:52+00:00" + }, + { + "name": "squizlabs/php_codesniffer", + "version": "3.5.6", + "source": { + "type": "git", + "url": "https://github.com/squizlabs/PHP_CodeSniffer.git", + "reference": "e97627871a7eab2f70e59166072a6b767d5834e0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/e97627871a7eab2f70e59166072a6b767d5834e0", + "reference": "e97627871a7eab2f70e59166072a6b767d5834e0", + "shasum": "" + }, + "require": { + "ext-simplexml": "*", + "ext-tokenizer": "*", + "ext-xmlwriter": "*", + "php": ">=5.4.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0" + }, + "bin": [ + "bin/phpcs", + "bin/phpcbf" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.x-dev" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Greg Sherwood", + "role": "lead" + } + ], + "description": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.", + "homepage": "https://github.com/squizlabs/PHP_CodeSniffer", + "keywords": [ + "phpcs", + "standards" + ], + "support": { + "issues": "https://github.com/squizlabs/PHP_CodeSniffer/issues", + "source": "https://github.com/squizlabs/PHP_CodeSniffer", + "wiki": "https://github.com/squizlabs/PHP_CodeSniffer/wiki" + }, + "time": "2020-08-10T04:50:15+00:00" + }, { "name": "theseer/tokenizer", "version": "1.2.0", From a708211efa60c975490e7724fe88e83bfeced770 Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Wed, 2 Sep 2020 15:37:30 +0200 Subject: [PATCH 04/14] Added CI setup (copied from `roave/you-are-using-it-wrong`) --- .github/workflows/coding-standards.yml | 56 ++++++++++++++++ .github/workflows/mutation-tests.yml | 65 +++++++++++++++++++ .github/workflows/phpunit.yml | 63 ++++++++++++++++++ .github/workflows/psalm.yml | 56 ++++++++++++++++ .../workflows/release-on-milestone-closed.yml | 62 ++++++++++++++++++ 5 files changed, 302 insertions(+) create mode 100644 .github/workflows/coding-standards.yml create mode 100644 .github/workflows/mutation-tests.yml create mode 100644 .github/workflows/phpunit.yml create mode 100644 .github/workflows/psalm.yml create mode 100644 .github/workflows/release-on-milestone-closed.yml diff --git a/.github/workflows/coding-standards.yml b/.github/workflows/coding-standards.yml new file mode 100644 index 0000000..edfe788 --- /dev/null +++ b/.github/workflows/coding-standards.yml @@ -0,0 +1,56 @@ +name: "Check Coding Standards" + +on: + pull_request: + push: + +jobs: + coding-standards: + name: "Check Coding Standards" + + runs-on: ${{ matrix.operating-system }} + + strategy: + matrix: + dependencies: + - "locked" + php-version: + - "7.4" + operating-system: + - "ubuntu-latest" + + steps: + - name: "Checkout" + uses: "actions/checkout@v2" + + - name: "Install PHP" + uses: "shivammathur/setup-php@v2" + with: + coverage: "pcov" + php-version: "${{ matrix.php-version }}" + ini-values: memory_limit=-1 + tools: cs2pr + + - name: "Cache dependencies" + uses: "actions/cache@v2" + with: + path: | + ~/.composer/cache + vendor + key: "php-${{ matrix.php-version }}-${{ matrix.dependencies }}" + restore-keys: "php-${{ matrix.php-version }}-${{ matrix.dependencies }}" + + - name: "Install lowest dependencies" + if: ${{ matrix.dependencies == 'lowest' }} + run: "composer update --prefer-lowest --no-interaction --no-progress --no-suggest" + + - name: "Install highest dependencies" + if: ${{ matrix.dependencies == 'highest' }} + run: "composer update --no-interaction --no-progress --no-suggest" + + - name: "Install locked dependencies" + if: ${{ matrix.dependencies == 'locked' }} + run: "composer install --no-interaction --no-progress --no-suggest" + + - name: "Coding Standard" + run: "vendor/bin/phpcs -q --report=checkstyle | cs2pr" diff --git a/.github/workflows/mutation-tests.yml b/.github/workflows/mutation-tests.yml new file mode 100644 index 0000000..d309b72 --- /dev/null +++ b/.github/workflows/mutation-tests.yml @@ -0,0 +1,65 @@ +name: "Mutation tests" + +on: + pull_request: + push: + +jobs: + mutation-tests: + name: "Mutation tests" + + runs-on: ${{ matrix.operating-system }} + + strategy: + matrix: + dependencies: + - "locked" + php-version: + - "7.4" + operating-system: + - "ubuntu-latest" + + steps: + - name: "Checkout" + uses: "actions/checkout@v2" + with: + fetch-depth: 0 + + - name: "Install PHP" + uses: "shivammathur/setup-php@v2" + with: + coverage: "pcov" + php-version: "${{ matrix.php-version }}" + ini-values: memory_limit=-1 + tools: cs2pr + + - name: "Cache dependencies" + uses: "actions/cache@v2" + with: + path: | + ~/.composer/cache + vendor + key: "php-${{ matrix.php-version }}-${{ matrix.dependencies }}" + restore-keys: "php-${{ matrix.php-version }}-${{ matrix.dependencies }}" + + - name: "Install lowest dependencies" + if: ${{ matrix.dependencies == 'lowest' }} + run: "composer update --prefer-lowest --no-interaction --no-progress --no-suggest" + + - name: "Install highest dependencies" + if: ${{ matrix.dependencies == 'highest' }} + run: "composer update --no-interaction --no-progress --no-suggest" + + - name: "Install locked dependencies" + if: ${{ matrix.dependencies == 'locked' }} + run: "composer install --no-interaction --no-progress --no-suggest" + + - name: "Checkout current HEAD as a named ref" + run: "git checkout -b ci-run-branch" + + - name: "Infection" + run: "vendor/bin/infection" + env: + INFECTION_BADGE_API_KEY: ${{ secrets.INFECTION_BADGE_API_KEY }} + STRYKER_DASHBOARD_API_KEY: ${{ secrets.STRYKER_DASHBOARD_API_KEY }} + diff --git a/.github/workflows/phpunit.yml b/.github/workflows/phpunit.yml new file mode 100644 index 0000000..e9041ce --- /dev/null +++ b/.github/workflows/phpunit.yml @@ -0,0 +1,63 @@ +name: "PHPUnit tests" + +on: + pull_request: + push: + +jobs: + phpunit: + name: "PHPUnit tests" + + runs-on: ${{ matrix.operating-system }} + + strategy: + matrix: + dependencies: + - "lowest" + - "highest" + - "locked" + php-version: + - "7.4" + operating-system: + - "ubuntu-latest" + + steps: + - name: "Checkout" + uses: "actions/checkout@v2" + with: + fetch-depth: 0 + + - name: "Install PHP" + uses: "shivammathur/setup-php@v2" + with: + coverage: "pcov" + php-version: "${{ matrix.php-version }}" + ini-values: memory_limit=-1 + tools: cs2pr + + - name: "Cache dependencies" + uses: "actions/cache@v2" + with: + path: | + ~/.composer/cache + vendor + key: "php-${{ matrix.php-version }}-${{ matrix.dependencies }}" + restore-keys: "php-${{ matrix.php-version }}-${{ matrix.dependencies }}" + + - name: "Install lowest dependencies" + if: ${{ matrix.dependencies == 'lowest' }} + run: "composer update --prefer-lowest --no-interaction --no-progress --no-suggest" + + - name: "Install highest dependencies" + if: ${{ matrix.dependencies == 'highest' }} + run: "composer update --no-interaction --no-progress --no-suggest" + + - name: "Install locked dependencies" + if: ${{ matrix.dependencies == 'locked' }} + run: "composer install --no-interaction --no-progress --no-suggest" + + - name: "Checkout current HEAD as a named ref" + run: "git checkout -b ci-run-branch" + + - name: "Tests" + run: "vendor/bin/phpunit" diff --git a/.github/workflows/psalm.yml b/.github/workflows/psalm.yml new file mode 100644 index 0000000..ab866cf --- /dev/null +++ b/.github/workflows/psalm.yml @@ -0,0 +1,56 @@ +name: "Static Analysis by Psalm" + +on: + pull_request: + push: + +jobs: + static-analysis-psalm: + name: "Static Analysis by Psalm" + + runs-on: ${{ matrix.operating-system }} + + strategy: + matrix: + dependencies: + - "locked" + php-version: + - "7.4" + operating-system: + - "ubuntu-latest" + + steps: + - name: "Checkout" + uses: "actions/checkout@v2" + + - name: "Install PHP" + uses: "shivammathur/setup-php@v2" + with: + coverage: "pcov" + php-version: "${{ matrix.php-version }}" + ini-values: memory_limit=-1 + tools: cs2pr + + - name: "Cache dependencies" + uses: "actions/cache@v2" + with: + path: | + ~/.composer/cache + vendor + key: "php-${{ matrix.php-version }}-${{ matrix.dependencies }}" + restore-keys: "php-${{ matrix.php-version }}-${{ matrix.dependencies }}" + + - name: "Install lowest dependencies" + if: ${{ matrix.dependencies == 'lowest' }} + run: "composer update --prefer-lowest --no-interaction --no-progress --no-suggest" + + - name: "Install highest dependencies" + if: ${{ matrix.dependencies == 'highest' }} + run: "composer update --no-interaction --no-progress --no-suggest" + + - name: "Install locked dependencies" + if: ${{ matrix.dependencies == 'locked' }} + run: "composer install --no-interaction --no-progress --no-suggest" + + - name: "psalm" + run: "vendor/bin/psalm --output-format=github --shepherd --stats" diff --git a/.github/workflows/release-on-milestone-closed.yml b/.github/workflows/release-on-milestone-closed.yml new file mode 100644 index 0000000..5e9b09e --- /dev/null +++ b/.github/workflows/release-on-milestone-closed.yml @@ -0,0 +1,62 @@ +name: "Automatic Releases" + +on: + milestone: + types: + - "closed" + +jobs: + release: + name: "GIT tag, release & create merge-up PR" + runs-on: ubuntu-latest + + steps: + - name: "Checkout" + uses: "actions/checkout@v2" + + - name: "Release" + uses: "laminas/automatic-releases@v1" + with: + command-name: "laminas:automatic-releases:release" + env: + "GITHUB_TOKEN": ${{ secrets.GITHUB_TOKEN }} + "SIGNING_SECRET_KEY": ${{ secrets.SIGNING_SECRET_KEY }} + "GIT_AUTHOR_NAME": ${{ secrets.GIT_AUTHOR_NAME }} + "GIT_AUTHOR_EMAIL": ${{ secrets.GIT_AUTHOR_EMAIL }} + + - name: "Create Merge-Up Pull Request" + uses: "laminas/automatic-releases@v1" + with: + command-name: "laminas:automatic-releases:create-merge-up-pull-request" + env: + "GITHUB_TOKEN": ${{ secrets.GITHUB_TOKEN }} + "SIGNING_SECRET_KEY": ${{ secrets.SIGNING_SECRET_KEY }} + "GIT_AUTHOR_NAME": ${{ secrets.GIT_AUTHOR_NAME }} + "GIT_AUTHOR_EMAIL": ${{ secrets.GIT_AUTHOR_EMAIL }} + + - name: "Create and/or Switch to new Release Branch" + uses: "laminas/automatic-releases@v1" + with: + command-name: "laminas:automatic-releases:switch-default-branch-to-next-minor" + env: + "GITHUB_TOKEN": ${{ secrets.ORGANIZATION_ADMIN_TOKEN }} + "SIGNING_SECRET_KEY": ${{ secrets.SIGNING_SECRET_KEY }} + "GIT_AUTHOR_NAME": ${{ secrets.GIT_AUTHOR_NAME }} + "GIT_AUTHOR_EMAIL": ${{ secrets.GIT_AUTHOR_EMAIL }} + + - name: "Bump Changelog Version On Originating Release Branch" + uses: "laminas/automatic-releases@v1" + with: + command-name: "laminas:automatic-releases:bump-changelog" + env: + "GITHUB_TOKEN": ${{ secrets.GITHUB_TOKEN }} + + - name: "Create new milestones" + uses: "laminas/automatic-releases@v1" + with: + command-name: "laminas:automatic-releases:create-milestones" + env: + "GITHUB_TOKEN": ${{ secrets.GITHUB_TOKEN }} + "SIGNING_SECRET_KEY": ${{ secrets.SIGNING_SECRET_KEY }} + "GIT_AUTHOR_NAME": ${{ secrets.GIT_AUTHOR_NAME }} + "GIT_AUTHOR_EMAIL": ${{ secrets.GIT_AUTHOR_EMAIL }} From 203dd42ed81459955c378d6016ff2a484ee14918 Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Wed, 2 Sep 2020 15:44:55 +0200 Subject: [PATCH 05/14] Imported build config from `roave/you-are-using-it-wrong` --- .gitattributes | 8 ++++++++ LICENSE | 19 +++++++++++++++++++ infection.json.dist | 15 +++++++++++++++ phpcs.xml.dist | 21 +++++++++++++++++++++ phpunit.xml.dist | 23 +++++++++++++++++++++++ psalm.xml | 14 ++++++++++++++ 6 files changed, 100 insertions(+) create mode 100644 .gitattributes create mode 100644 LICENSE create mode 100644 infection.json.dist create mode 100644 phpcs.xml.dist create mode 100644 phpunit.xml.dist create mode 100644 psalm.xml diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..cfc2966 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,8 @@ +/test export-ignore +.gitattributes export-ignore +.gitignore export-ignore +composer.lock export-ignore +infection.json.dist export-ignore +phpcs.xml.dist export-ignore +phpunit.xml.dist export-ignore +psalm.xml export-ignore diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..1e1664d --- /dev/null +++ b/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2020 Roave, LLC. + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/infection.json.dist b/infection.json.dist new file mode 100644 index 0000000..39a9c12 --- /dev/null +++ b/infection.json.dist @@ -0,0 +1,15 @@ +{ + "source": { + "directories": [ + "src" + ] + }, + "logs": { + "text": "php://stderr", + "badge": { + "branch": "master" + } + }, + "minMsi": 84, + "minCoveredMsi": 100 +} diff --git a/phpcs.xml.dist b/phpcs.xml.dist new file mode 100644 index 0000000..5bfe1c5 --- /dev/null +++ b/phpcs.xml.dist @@ -0,0 +1,21 @@ + + + + + + + + + + + src + test + + + + + + diff --git a/phpunit.xml.dist b/phpunit.xml.dist new file mode 100644 index 0000000..ca6a244 --- /dev/null +++ b/phpunit.xml.dist @@ -0,0 +1,23 @@ + + + + + ./test/unit + + + + + ./src + + + diff --git a/psalm.xml b/psalm.xml new file mode 100644 index 0000000..21eeede --- /dev/null +++ b/psalm.xml @@ -0,0 +1,14 @@ + + + + + + + From 01cfeca4e2616245e493f2136896a60d0d247f4f Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Wed, 2 Sep 2020 15:49:01 +0200 Subject: [PATCH 06/14] Require a recent PHP 7.4 release to operate PHP 7.4.6 was massively broken, so we start from `^7.4.7` onwards. --- composer.json | 1 + composer.lock | 6 ++++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index 1d50c13..dafc373 100644 --- a/composer.json +++ b/composer.json @@ -3,6 +3,7 @@ "description": "Static analysis on top of mutation testing - prevents escaped mutants from being invalid according to static analysis", "type": "library", "require": { + "php": "^7.4.7", "infection/infection": "0.17.5", "vimeo/psalm": "^3.15.0" }, diff --git a/composer.lock b/composer.lock index 363cbbf..8602386 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "6328519dfb1a28b0a8fad050831548e8", + "content-hash": "628ba2876ffb212624efe7633f0d6997", "packages": [ { "name": "amphp/amp", @@ -4737,7 +4737,9 @@ "stability-flags": [], "prefer-stable": false, "prefer-lowest": false, - "platform": [], + "platform": { + "php": "^7.4.7" + }, "platform-dev": [], "plugin-api-version": "2.0.0" } From 01ad5af9e5b9b0c58a5192ce156fc45479b211cf Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Wed, 2 Sep 2020 18:44:49 +0200 Subject: [PATCH 07/14] Implemented first prototype of psalm-based mutant killing logic --- bin/roave-infection-static-analysis-plugin | 44 +++++++++++++++ composer.json | 26 ++++++--- composer.lock | 2 +- psalm.xml | 49 +++++++++++++++++ .../InfectionStaticAnalysis/Bootstrapper.php | 40 ++++++++++++++ .../Psalm/RunStaticAnalysisAgainstMutant.php | 49 +++++++++++++++++ .../RunStaticAnalysisAgainstEscapedMutant.php | 54 +++++++++++++++++++ .../Stub/ArrayFilter.php | 19 +++++++ .../BootstrapperTest.php | 36 +++++++++++++ .../Stub/ArrayFilterTest.php | 21 ++++++++ 10 files changed, 333 insertions(+), 7 deletions(-) create mode 100755 bin/roave-infection-static-analysis-plugin create mode 100644 src/Roave/InfectionStaticAnalysis/Bootstrapper.php create mode 100644 src/Roave/InfectionStaticAnalysis/Psalm/RunStaticAnalysisAgainstMutant.php create mode 100644 src/Roave/InfectionStaticAnalysis/RunStaticAnalysisAgainstEscapedMutant.php create mode 100644 src/Roave/InfectionStaticAnalysis/Stub/ArrayFilter.php create mode 100644 test/unit/Roave/InfectionStaticAnalysisTest/BootstrapperTest.php create mode 100644 test/unit/Roave/InfectionStaticAnalysisTest/Stub/ArrayFilterTest.php diff --git a/bin/roave-infection-static-analysis-plugin b/bin/roave-infection-static-analysis-plugin new file mode 100755 index 0000000..e7dc494 --- /dev/null +++ b/bin/roave-infection-static-analysis-plugin @@ -0,0 +1,44 @@ +#!/usr/bin/env php +setIncludeCollector(new IncludeCollector()); + + (new Application(Bootstrapper::bootstrap( + Container::create(), + new RunStaticAnalysisAgainstMutant($psalmConfig) + ))) + ->run(); +})(); diff --git a/composer.json b/composer.json index dafc373..cc5233b 100644 --- a/composer.json +++ b/composer.json @@ -2,22 +2,36 @@ "name": "roave/infection-static-analysis-plugin", "description": "Static analysis on top of mutation testing - prevents escaped mutants from being invalid according to static analysis", "type": "library", + "license": "MIT", + "authors": [ + { + "name": "Marco Pivetta", + "email": "ocramius@gmail.com" + } + ], + "bin": [ + "bin/roave-infection-static-analysis-plugin" + ], "require": { "php": "^7.4.7", "infection/infection": "0.17.5", + "ocramius/package-versions": "^1.9.0 || ^2.0.0", "vimeo/psalm": "^3.15.0" }, "require-dev": { "doctrine/coding-standard": "^8.1.0", "phpunit/phpunit": "^9.2.6" }, - "license": "MIT", - "authors": [ - { - "name": "Marco Pivetta", - "email": "ocramius@gmail.com" + "autoload": { + "psr-4": { + "Roave\\InfectionStaticAnalysis\\": "src/Roave/InfectionStaticAnalysis" } - ], + }, + "autoload-dev": { + "psr-4": { + "Roave\\InfectionStaticAnalysisTest\\": "test/unit/Roave/InfectionStaticAnalysisTest" + } + }, "config": { "sort-packages": true } diff --git a/composer.lock b/composer.lock index 8602386..de6d1f7 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "628ba2876ffb212624efe7633f0d6997", + "content-hash": "12ec27028a7bd3fd8d45ed180cefa135", "packages": [ { "name": "amphp/amp", diff --git a/psalm.xml b/psalm.xml index 21eeede..3862252 100644 --- a/psalm.xml +++ b/psalm.xml @@ -11,4 +11,53 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Roave/InfectionStaticAnalysis/Bootstrapper.php b/src/Roave/InfectionStaticAnalysis/Bootstrapper.php new file mode 100644 index 0000000..80a446c --- /dev/null +++ b/src/Roave/InfectionStaticAnalysis/Bootstrapper.php @@ -0,0 +1,40 @@ +getMutantExecutionResultFactory(); + + $reflectionOffsetSet->setAccessible(true); + $reflectionOffsetSet->invokeArgs( + $container, + [ + MutantExecutionResultFactory::class, + static function () use ($replacedService, $runStaticAnalysis): MutantExecutionResultFactory { + return new RunStaticAnalysisAgainstEscapedMutant( + $replacedService, + $runStaticAnalysis + ); + } + ] + ); + + return $container; + } +} diff --git a/src/Roave/InfectionStaticAnalysis/Psalm/RunStaticAnalysisAgainstMutant.php b/src/Roave/InfectionStaticAnalysis/Psalm/RunStaticAnalysisAgainstMutant.php new file mode 100644 index 0000000..6c70175 --- /dev/null +++ b/src/Roave/InfectionStaticAnalysis/Psalm/RunStaticAnalysisAgainstMutant.php @@ -0,0 +1,49 @@ +config = $config; + } + + /** @return bool whether the mutation is considered valid by static analysis */ + public function __invoke( + Mutant $mutant + ): bool { + $path = $mutant->getFilePath(); + $projectAnalyzer = new ProjectAnalyzer( + $this->config, + new Providers(new FileProvider()), + new ReportOptions() + ); + + $this->config->visitComposerAutoloadFiles($projectAnalyzer); + $projectAnalyzer->checkFile($path); + + return ! count( + $projectAnalyzer->getCodebase() + ->file_reference_provider + ->getExistingIssues()[$path] ?? [] + ); + } +} diff --git a/src/Roave/InfectionStaticAnalysis/RunStaticAnalysisAgainstEscapedMutant.php b/src/Roave/InfectionStaticAnalysis/RunStaticAnalysisAgainstEscapedMutant.php new file mode 100644 index 0000000..2de07a0 --- /dev/null +++ b/src/Roave/InfectionStaticAnalysis/RunStaticAnalysisAgainstEscapedMutant.php @@ -0,0 +1,54 @@ +next = $next; + $this->runStaticAnalysis = $runStaticAnalysis; + } + + public function createFromProcess(MutantProcess $mutantProcess): MutantExecutionResult + { + $result = $this->next->createFromProcess($mutantProcess); + + if ($result->getDetectionStatus() !== DetectionStatus::ESCAPED) { + return $result; + } + + if ($this->runStaticAnalysis->__invoke($mutantProcess->getMutant())) { + return $result; + } + + return new MutantExecutionResult( + $result->getProcessCommandLine(), + $result->getProcessOutput(), + DetectionStatus::KILLED, // Mutant was squished by static analysis + $result->getMutantDiff(), + $result->getMutatorName(), + $result->getOriginalFilePath(), + $result->getOriginalStartingLine(), + $result->getOriginalCode(), + $result->getMutatedCode() + ); + } +} diff --git a/src/Roave/InfectionStaticAnalysis/Stub/ArrayFilter.php b/src/Roave/InfectionStaticAnalysis/Stub/ArrayFilter.php new file mode 100644 index 0000000..a273310 --- /dev/null +++ b/src/Roave/InfectionStaticAnalysis/Stub/ArrayFilter.php @@ -0,0 +1,19 @@ + $values + * @psalm-return list + */ + public function makeAList(array $values): array + { + return array_values($values); + } +} diff --git a/test/unit/Roave/InfectionStaticAnalysisTest/BootstrapperTest.php b/test/unit/Roave/InfectionStaticAnalysisTest/BootstrapperTest.php new file mode 100644 index 0000000..5b2fdfc --- /dev/null +++ b/test/unit/Roave/InfectionStaticAnalysisTest/BootstrapperTest.php @@ -0,0 +1,36 @@ +createMock(RunStaticAnalysisAgainstMutant::class); + Bootstrapper::bootstrap( + Container::create(), + $runStaticAnalysis + ); + + self::assertInstanceOf( + RunStaticAnalysisAgainstEscapedMutant::class, + Bootstrapper::bootstrap( + Container::create(), + $runStaticAnalysis + )->getMutantExecutionResultFactory() + ); + } +} diff --git a/test/unit/Roave/InfectionStaticAnalysisTest/Stub/ArrayFilterTest.php b/test/unit/Roave/InfectionStaticAnalysisTest/Stub/ArrayFilterTest.php new file mode 100644 index 0000000..4e3b977 --- /dev/null +++ b/test/unit/Roave/InfectionStaticAnalysisTest/Stub/ArrayFilterTest.php @@ -0,0 +1,21 @@ +makeAList(['a' => 'b', 'c' => 'd']); + + self::assertCount(2, $list); + self::assertContains('b', $list); + self::assertContains('d', $list); + } +} From 973e9b96ee810deca66d91123f35ceea825c6c3c Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Wed, 2 Sep 2020 20:34:18 +0200 Subject: [PATCH 08/14] Achieved 100% mutation test score (with this plugin enabled) --- .github/workflows/mutation-tests.yml | 8 +- .../Psalm/RunStaticAnalysisAgainstMutant.php | 17 +- .../RunStaticAnalysisAgainstEscapedMutant.php | 2 +- .../RunStaticAnalysisAgainstMutantTest.php | 202 ++++++++++++++++++ ...StaticAnalysisAgainstEscapedMutantTest.php | 153 +++++++++++++ 5 files changed, 368 insertions(+), 14 deletions(-) create mode 100644 test/unit/Roave/InfectionStaticAnalysisTest/Psalm/RunStaticAnalysisAgainstMutantTest.php create mode 100644 test/unit/Roave/InfectionStaticAnalysisTest/RunStaticAnalysisAgainstEscapedMutantTest.php diff --git a/.github/workflows/mutation-tests.yml b/.github/workflows/mutation-tests.yml index d309b72..965bf37 100644 --- a/.github/workflows/mutation-tests.yml +++ b/.github/workflows/mutation-tests.yml @@ -57,9 +57,11 @@ jobs: - name: "Checkout current HEAD as a named ref" run: "git checkout -b ci-run-branch" - - name: "Infection" - run: "vendor/bin/infection" + - name: "Infection should fail (MSI threshold not reached)" + run: "! vendor/bin/infection" + + - name: "Infection + roave infection plugin (mutants squished by static analysis)" + run: "bin/roave-infection-static-analysis-plugin" env: INFECTION_BADGE_API_KEY: ${{ secrets.INFECTION_BADGE_API_KEY }} STRYKER_DASHBOARD_API_KEY: ${{ secrets.STRYKER_DASHBOARD_API_KEY }} - diff --git a/src/Roave/InfectionStaticAnalysis/Psalm/RunStaticAnalysisAgainstMutant.php b/src/Roave/InfectionStaticAnalysis/Psalm/RunStaticAnalysisAgainstMutant.php index 6c70175..dd8c76f 100644 --- a/src/Roave/InfectionStaticAnalysis/Psalm/RunStaticAnalysisAgainstMutant.php +++ b/src/Roave/InfectionStaticAnalysis/Psalm/RunStaticAnalysisAgainstMutant.php @@ -10,12 +10,11 @@ use Psalm\Internal\Provider\FileProvider; use Psalm\Internal\Provider\Providers; use Psalm\Report\ReportOptions; +use function array_key_exists; /** * @internal * @final not explicitly final because we don't yet have a uniform API for this type of analysis - * - * @TODO careful: need to check how stateful this code really is */ class RunStaticAnalysisAgainstMutant { @@ -26,24 +25,22 @@ public function __construct(Config $config) $this->config = $config; } - /** @return bool whether the mutation is considered valid by static analysis */ - public function __invoke( - Mutant $mutant - ): bool { - $path = $mutant->getFilePath(); + public function isMutantStillValidAccordingToStaticAnalysis(Mutant $mutant): bool + { + $path = $mutant->getFilePath(); $projectAnalyzer = new ProjectAnalyzer( $this->config, new Providers(new FileProvider()), new ReportOptions() ); - $this->config->visitComposerAutoloadFiles($projectAnalyzer); $projectAnalyzer->checkFile($path); - return ! count( + return ! array_key_exists( + $path, $projectAnalyzer->getCodebase() ->file_reference_provider - ->getExistingIssues()[$path] ?? [] + ->getExistingIssues() ); } } diff --git a/src/Roave/InfectionStaticAnalysis/RunStaticAnalysisAgainstEscapedMutant.php b/src/Roave/InfectionStaticAnalysis/RunStaticAnalysisAgainstEscapedMutant.php index 2de07a0..0fcd133 100644 --- a/src/Roave/InfectionStaticAnalysis/RunStaticAnalysisAgainstEscapedMutant.php +++ b/src/Roave/InfectionStaticAnalysis/RunStaticAnalysisAgainstEscapedMutant.php @@ -35,7 +35,7 @@ public function createFromProcess(MutantProcess $mutantProcess): MutantExecution return $result; } - if ($this->runStaticAnalysis->__invoke($mutantProcess->getMutant())) { + if ($this->runStaticAnalysis->isMutantStillValidAccordingToStaticAnalysis($mutantProcess->getMutant())) { return $result; } diff --git a/test/unit/Roave/InfectionStaticAnalysisTest/Psalm/RunStaticAnalysisAgainstMutantTest.php b/test/unit/Roave/InfectionStaticAnalysisTest/Psalm/RunStaticAnalysisAgainstMutantTest.php new file mode 100644 index 0000000..3c500df --- /dev/null +++ b/test/unit/Roave/InfectionStaticAnalysisTest/Psalm/RunStaticAnalysisAgainstMutantTest.php @@ -0,0 +1,202 @@ +makeAList($input)); +} +PHP; + + $validCodePath = tempnam(sys_get_temp_dir(), 'valid-code-'); + $invalidCodePath = tempnam(sys_get_temp_dir(), 'invalid-code-'); + $validCodeReferencingProjectFilesPath = tempnam(sys_get_temp_dir(), 'valid-code-referencing-project-files-'); + + file_put_contents($validCodePath, $validCode); + file_put_contents($invalidCodePath, $invalidCode); + file_put_contents($validCodeReferencingProjectFilesPath, $validCodeReferencingProjectFiles); + + $mutationAttributes = array_combine( + MutationAttributeKeys::ALL, + array_map('strlen', MutationAttributeKeys::ALL) + ); + + $this->mutantWithValidCode = new Mutant( + $validCodePath, + new Mutation( + 'foo', + [], + 'Plus', + $mutationAttributes, + '', + MutatedNode::wrap([]), + 0, + [] + ), + $validCode, + '', + '' + ); + + $this->mutantWithInvalidCode = new Mutant( + $invalidCodePath, + new Mutation( + 'foo', + [], + 'Plus', + $mutationAttributes, + '', + MutatedNode::wrap([]), + 0, + [] + ), + $invalidCode, + '', + '' + ); + + $this->mutantWithValidCodeReferencingProjectFiles = new Mutant( + $validCodeReferencingProjectFilesPath, + new Mutation( + 'foo', + [], + 'Plus', + $mutationAttributes, + '', + MutatedNode::wrap([]), + 0, + [] + ), + $validCodeReferencingProjectFiles, + '', + '' + ); + + if (! defined('PSALM_VERSION')) { + define('PSALM_VERSION', Versions::getVersion('vimeo/psalm')); + } + + if (! defined('PHP_PARSER_VERSION')) { + define('PHP_PARSER_VERSION', Versions::getVersion('nikic/php-parser')); + } + } + + protected function tearDown(): void + { + unlink($this->mutantWithValidCode->getFilePath()); + unlink($this->mutantWithInvalidCode->getFilePath()); + unlink($this->mutantWithValidCodeReferencingProjectFiles->getFilePath()); + + parent::tearDown(); + } + + public function testWillConsiderMutantValidIfNoErrorsAreDetectedByStaticAnalysis(): void + { + $psalmConfig = Config::getConfigForPath( + self::PSALM_WORKING_DIRECTORY, + self::PSALM_WORKING_DIRECTORY, + Report::TYPE_CONSOLE + ); + + $psalmConfig->setIncludeCollector(new IncludeCollector()); + + self::assertTrue( + (new RunStaticAnalysisAgainstMutant($psalmConfig)) + ->isMutantStillValidAccordingToStaticAnalysis($this->mutantWithValidCode) + ); + } + + public function testWillConsiderMutantInvalidIfErrorsAreDetectedByStaticAnalysis(): void + { + $psalmConfig = Config::getConfigForPath( + self::PSALM_WORKING_DIRECTORY, + self::PSALM_WORKING_DIRECTORY, + Report::TYPE_CONSOLE + ); + + $psalmConfig->setIncludeCollector(new IncludeCollector()); + + self::assertFalse( + (new RunStaticAnalysisAgainstMutant($psalmConfig)) + ->isMutantStillValidAccordingToStaticAnalysis($this->mutantWithInvalidCode) + ); + } + + public function testWillConsiderMutantReferencingProjectFilesAsValid(): void + { + $psalmConfig = Config::getConfigForPath( + self::PSALM_WORKING_DIRECTORY, + self::PSALM_WORKING_DIRECTORY, + Report::TYPE_CONSOLE + ); + + $psalmConfig->setIncludeCollector(new IncludeCollector()); + + self::assertTrue( + (new RunStaticAnalysisAgainstMutant($psalmConfig)) + ->isMutantStillValidAccordingToStaticAnalysis($this->mutantWithValidCode) + ); + } +} diff --git a/test/unit/Roave/InfectionStaticAnalysisTest/RunStaticAnalysisAgainstEscapedMutantTest.php b/test/unit/Roave/InfectionStaticAnalysisTest/RunStaticAnalysisAgainstEscapedMutantTest.php new file mode 100644 index 0000000..70f5a1e --- /dev/null +++ b/test/unit/Roave/InfectionStaticAnalysisTest/RunStaticAnalysisAgainstEscapedMutantTest.php @@ -0,0 +1,153 @@ +mutant = new Mutant( + '/tmp/my-code', + new Mutation( + 'foo', + [], + 'Plus', + array_combine( + MutationAttributeKeys::ALL, + array_map('strlen', MutationAttributeKeys::ALL) + ), + '', + MutatedNode::wrap([]), + 0, + [] + ), + 'code', + '', + '' + ); + + $this->process = new MutantProcess(new Process(['echo', 'hi']), $this->mutant); + $this->staticAnalysis = $this->createMock(RunStaticAnalysisAgainstMutant::class); + $this->nextFactory = $this->createMock(MutantExecutionResultFactory::class); + $this->factory = new RunStaticAnalysisAgainstEscapedMutant($this->nextFactory, $this->staticAnalysis); + } + + public function testWillSkipValidationOnAlreadyKilledMutants(): void + { + $this->staticAnalysis->expects(self::never()) + ->method('isMutantStillValidAccordingToStaticAnalysis'); + + $nextFactoryResult = new MutantExecutionResult( + 'echo hi', + 'output', + DetectionStatus::KILLED, + 'diff', + 'AssignmentEqual', + '/tmp/my-file', + 1, + 'code', + 'mutated code' + ); + + $this->nextFactory->expects(self::once()) + ->method('createFromProcess') + ->with(self::equalTo($this->process)) + ->willReturn($nextFactoryResult); + + $result = $this->factory->createFromProcess($this->process); + + self::assertEquals($nextFactoryResult, $result); + self::assertSame(DetectionStatus::KILLED, $result->getDetectionStatus()); + } + + public function testWillKillMutantsThatEscapedAndFailedStaticAnalysis(): void + { + $this->staticAnalysis->expects(self::once()) + ->method('isMutantStillValidAccordingToStaticAnalysis') + ->willReturn(false); + + $nextFactoryResult = new MutantExecutionResult( + 'echo hi', + 'output', + DetectionStatus::ESCAPED, + 'diff', + 'AssignmentEqual', + '/tmp/my-file', + 1, + 'code', + 'mutated code' + ); + + $this->nextFactory->expects(self::once()) + ->method('createFromProcess') + ->with(self::equalTo($this->process)) + ->willReturn($nextFactoryResult); + + $result = $this->factory->createFromProcess($this->process); + + self::assertEquals($nextFactoryResult->getMutatedCode(), $result->getMutatedCode()); + self::assertEquals($nextFactoryResult->getOriginalCode(), $result->getOriginalCode()); + self::assertEquals($nextFactoryResult->getOriginalStartingLine(), $result->getOriginalStartingLine()); + self::assertEquals($nextFactoryResult->getOriginalFilePath(), $result->getOriginalFilePath()); + self::assertEquals($nextFactoryResult->getMutatorName(), $result->getMutatorName()); + self::assertEquals($nextFactoryResult->getMutantDiff(), $result->getMutantDiff()); + self::assertEquals($nextFactoryResult->getProcessOutput(), $result->getProcessOutput()); + self::assertEquals($nextFactoryResult->getProcessCommandLine(), $result->getProcessCommandLine()); + self::assertSame(DetectionStatus::KILLED, $result->getDetectionStatus()); + } + + public function testWillNotKillMutantsThatEscapedAndPassedStaticAnalysis(): void + { + $this->staticAnalysis->expects(self::once()) + ->method('isMutantStillValidAccordingToStaticAnalysis') + ->willReturn(true); + + $nextFactoryResult = new MutantExecutionResult( + 'echo hi', + 'output', + DetectionStatus::ESCAPED, + 'diff', + 'AssignmentEqual', + '/tmp/my-file', + 1, + 'code', + 'mutated code' + ); + + $this->nextFactory->expects(self::once()) + ->method('createFromProcess') + ->with(self::equalTo($this->process)) + ->willReturn($nextFactoryResult); + + self::assertSame($nextFactoryResult, $this->factory->createFromProcess($this->process)); + } +} From 944c44790d21435a99a77001208923ba846cb1d6 Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Wed, 2 Sep 2020 20:35:44 +0200 Subject: [PATCH 09/14] Exclude `PackageVersions\Versions` from static analysis - class is indeed deprecated, but no way around it for now --- psalm.xml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/psalm.xml b/psalm.xml index 3862252..a43e766 100644 --- a/psalm.xml +++ b/psalm.xml @@ -59,5 +59,12 @@ + + + + + + + From 575976b5520da0bf8de24a1a8cd85bc3b77ffe3a Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Wed, 2 Sep 2020 20:37:14 +0200 Subject: [PATCH 10/14] Applied automated CS fixes --- .../InfectionStaticAnalysis/Bootstrapper.php | 19 +++++++------------ .../Psalm/RunStaticAnalysisAgainstMutant.php | 2 ++ .../RunStaticAnalysisAgainstEscapedMutant.php | 1 + .../Stub/ArrayFilter.php | 2 ++ .../BootstrapperTest.php | 4 ++-- .../RunStaticAnalysisAgainstMutantTest.php | 11 +++++++---- ...StaticAnalysisAgainstEscapedMutantTest.php | 3 ++- 7 files changed, 23 insertions(+), 19 deletions(-) diff --git a/src/Roave/InfectionStaticAnalysis/Bootstrapper.php b/src/Roave/InfectionStaticAnalysis/Bootstrapper.php index 80a446c..96cf991 100644 --- a/src/Roave/InfectionStaticAnalysis/Bootstrapper.php +++ b/src/Roave/InfectionStaticAnalysis/Bootstrapper.php @@ -20,20 +20,15 @@ public static function bootstrap( // @TODO we may want to make this one lazy, but for now this is OK $replacedService = $container->getMutantExecutionResultFactory(); + $factory = static function () use ($replacedService, $runStaticAnalysis): MutantExecutionResultFactory { + return new RunStaticAnalysisAgainstEscapedMutant( + $replacedService, + $runStaticAnalysis + ); + }; $reflectionOffsetSet->setAccessible(true); - $reflectionOffsetSet->invokeArgs( - $container, - [ - MutantExecutionResultFactory::class, - static function () use ($replacedService, $runStaticAnalysis): MutantExecutionResultFactory { - return new RunStaticAnalysisAgainstEscapedMutant( - $replacedService, - $runStaticAnalysis - ); - } - ] - ); + $reflectionOffsetSet->invokeArgs($container, [MutantExecutionResultFactory::class, $factory]); return $container; } diff --git a/src/Roave/InfectionStaticAnalysis/Psalm/RunStaticAnalysisAgainstMutant.php b/src/Roave/InfectionStaticAnalysis/Psalm/RunStaticAnalysisAgainstMutant.php index dd8c76f..a62b091 100644 --- a/src/Roave/InfectionStaticAnalysis/Psalm/RunStaticAnalysisAgainstMutant.php +++ b/src/Roave/InfectionStaticAnalysis/Psalm/RunStaticAnalysisAgainstMutant.php @@ -10,10 +10,12 @@ use Psalm\Internal\Provider\FileProvider; use Psalm\Internal\Provider\Providers; use Psalm\Report\ReportOptions; + use function array_key_exists; /** * @internal + * * @final not explicitly final because we don't yet have a uniform API for this type of analysis */ class RunStaticAnalysisAgainstMutant diff --git a/src/Roave/InfectionStaticAnalysis/RunStaticAnalysisAgainstEscapedMutant.php b/src/Roave/InfectionStaticAnalysis/RunStaticAnalysisAgainstEscapedMutant.php index 0fcd133..b333421 100644 --- a/src/Roave/InfectionStaticAnalysis/RunStaticAnalysisAgainstEscapedMutant.php +++ b/src/Roave/InfectionStaticAnalysis/RunStaticAnalysisAgainstEscapedMutant.php @@ -12,6 +12,7 @@ /** * @internal + * * @final not explicitly final because there is no interface for {@see MutantExecutionResultFactory} */ class RunStaticAnalysisAgainstEscapedMutant extends MutantExecutionResultFactory diff --git a/src/Roave/InfectionStaticAnalysis/Stub/ArrayFilter.php b/src/Roave/InfectionStaticAnalysis/Stub/ArrayFilter.php index a273310..08c480d 100644 --- a/src/Roave/InfectionStaticAnalysis/Stub/ArrayFilter.php +++ b/src/Roave/InfectionStaticAnalysis/Stub/ArrayFilter.php @@ -4,6 +4,8 @@ namespace Roave\InfectionStaticAnalysis\Stub; +use function array_values; + /** @internal this class only exists for self-testing purposes, to verify if the mutation testing plugin works */ final class ArrayFilter { diff --git a/test/unit/Roave/InfectionStaticAnalysisTest/BootstrapperTest.php b/test/unit/Roave/InfectionStaticAnalysisTest/BootstrapperTest.php index 5b2fdfc..10fc756 100644 --- a/test/unit/Roave/InfectionStaticAnalysisTest/BootstrapperTest.php +++ b/test/unit/Roave/InfectionStaticAnalysisTest/BootstrapperTest.php @@ -11,9 +11,9 @@ use Roave\InfectionStaticAnalysis\RunStaticAnalysisAgainstEscapedMutant; /** - * @covers \Roave\InfectionStaticAnalysis\Bootstrapper - * * @uses \Roave\InfectionStaticAnalysis\RunStaticAnalysisAgainstEscapedMutant + * + * @covers \Roave\InfectionStaticAnalysis\Bootstrapper */ final class BootstrapperTest extends TestCase { diff --git a/test/unit/Roave/InfectionStaticAnalysisTest/Psalm/RunStaticAnalysisAgainstMutantTest.php b/test/unit/Roave/InfectionStaticAnalysisTest/Psalm/RunStaticAnalysisAgainstMutantTest.php index 3c500df..09e8975 100644 --- a/test/unit/Roave/InfectionStaticAnalysisTest/Psalm/RunStaticAnalysisAgainstMutantTest.php +++ b/test/unit/Roave/InfectionStaticAnalysisTest/Psalm/RunStaticAnalysisAgainstMutantTest.php @@ -14,6 +14,7 @@ use Psalm\Internal\IncludeCollector; use Psalm\Report; use Roave\InfectionStaticAnalysis\Psalm\RunStaticAnalysisAgainstMutant; + use function array_combine; use function array_map; use function define; @@ -70,8 +71,8 @@ function add(array $input): int { } PHP; - $validCodePath = tempnam(sys_get_temp_dir(), 'valid-code-'); - $invalidCodePath = tempnam(sys_get_temp_dir(), 'invalid-code-'); + $validCodePath = tempnam(sys_get_temp_dir(), 'valid-code-'); + $invalidCodePath = tempnam(sys_get_temp_dir(), 'invalid-code-'); $validCodeReferencingProjectFilesPath = tempnam(sys_get_temp_dir(), 'valid-code-referencing-project-files-'); file_put_contents($validCodePath, $validCode); @@ -138,9 +139,11 @@ function add(array $input): int { define('PSALM_VERSION', Versions::getVersion('vimeo/psalm')); } - if (! defined('PHP_PARSER_VERSION')) { - define('PHP_PARSER_VERSION', Versions::getVersion('nikic/php-parser')); + if (defined('PHP_PARSER_VERSION')) { + return; } + + define('PHP_PARSER_VERSION', Versions::getVersion('nikic/php-parser')); } protected function tearDown(): void diff --git a/test/unit/Roave/InfectionStaticAnalysisTest/RunStaticAnalysisAgainstEscapedMutantTest.php b/test/unit/Roave/InfectionStaticAnalysisTest/RunStaticAnalysisAgainstEscapedMutantTest.php index 70f5a1e..1682735 100644 --- a/test/unit/Roave/InfectionStaticAnalysisTest/RunStaticAnalysisAgainstEscapedMutantTest.php +++ b/test/unit/Roave/InfectionStaticAnalysisTest/RunStaticAnalysisAgainstEscapedMutantTest.php @@ -17,6 +17,7 @@ use Roave\InfectionStaticAnalysis\Psalm\RunStaticAnalysisAgainstMutant; use Roave\InfectionStaticAnalysis\RunStaticAnalysisAgainstEscapedMutant; use Symfony\Component\Process\Process; + use function array_combine; use function array_map; @@ -55,7 +56,7 @@ protected function setUp(): void '' ); - $this->process = new MutantProcess(new Process(['echo', 'hi']), $this->mutant); + $this->process = new MutantProcess(new Process(['echo', 'hi']), $this->mutant); $this->staticAnalysis = $this->createMock(RunStaticAnalysisAgainstMutant::class); $this->nextFactory = $this->createMock(MutantExecutionResultFactory::class); $this->factory = new RunStaticAnalysisAgainstEscapedMutant($this->nextFactory, $this->staticAnalysis); From 79819d65cbb6c74acc4f40d7af517bdce4beabd2 Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Wed, 2 Sep 2020 21:58:02 +0200 Subject: [PATCH 11/14] Failing test case: `ReflectionClass#hasMethod()` cannot be found by Psalm's internal type map --- .../RunStaticAnalysisAgainstMutantTest.php | 54 +++++++++++++++++-- 1 file changed, 50 insertions(+), 4 deletions(-) diff --git a/test/unit/Roave/InfectionStaticAnalysisTest/Psalm/RunStaticAnalysisAgainstMutantTest.php b/test/unit/Roave/InfectionStaticAnalysisTest/Psalm/RunStaticAnalysisAgainstMutantTest.php index 09e8975..b18fb94 100644 --- a/test/unit/Roave/InfectionStaticAnalysisTest/Psalm/RunStaticAnalysisAgainstMutantTest.php +++ b/test/unit/Roave/InfectionStaticAnalysisTest/Psalm/RunStaticAnalysisAgainstMutantTest.php @@ -32,6 +32,7 @@ final class RunStaticAnalysisAgainstMutantTest extends TestCase private Mutant $mutantWithValidCode; private Mutant $mutantWithInvalidCode; private Mutant $mutantWithValidCodeReferencingProjectFiles; + private Mutant $mutantWithValidCodeReferencingReflectionApi; protected function setUp(): void { @@ -71,13 +72,24 @@ function add(array $input): int { } PHP; - $validCodePath = tempnam(sys_get_temp_dir(), 'valid-code-'); - $invalidCodePath = tempnam(sys_get_temp_dir(), 'invalid-code-'); - $validCodeReferencingProjectFilesPath = tempnam(sys_get_temp_dir(), 'valid-code-referencing-project-files-'); + $validCodeReferencingReflectionApi = <<<'PHP' +hasMethod($method); +} +PHP; + + $validCodePath = tempnam(sys_get_temp_dir(), 'valid-code-'); + $invalidCodePath = tempnam(sys_get_temp_dir(), 'invalid-code-'); + $validCodeReferencingProjectFilesPath = tempnam(sys_get_temp_dir(), 'valid-code-referencing-project-files-'); + $validCodeReferencingReflectionApiPath = tempnam(sys_get_temp_dir(), 'valid-code-referencing-reflection-api-'); file_put_contents($validCodePath, $validCode); file_put_contents($invalidCodePath, $invalidCode); file_put_contents($validCodeReferencingProjectFilesPath, $validCodeReferencingProjectFiles); + file_put_contents($validCodeReferencingReflectionApiPath, $validCodeReferencingReflectionApi); $mutationAttributes = array_combine( MutationAttributeKeys::ALL, @@ -135,6 +147,23 @@ function add(array $input): int { '' ); + $this->mutantWithValidCodeReferencingReflectionApi = new Mutant( + $validCodeReferencingReflectionApiPath, + new Mutation( + 'foo', + [], + 'Plus', + $mutationAttributes, + '', + MutatedNode::wrap([]), + 0, + [] + ), + $validCodeReferencingProjectFiles, + '', + '' + ); + if (! defined('PSALM_VERSION')) { define('PSALM_VERSION', Versions::getVersion('vimeo/psalm')); } @@ -151,6 +180,7 @@ protected function tearDown(): void unlink($this->mutantWithValidCode->getFilePath()); unlink($this->mutantWithInvalidCode->getFilePath()); unlink($this->mutantWithValidCodeReferencingProjectFiles->getFilePath()); + unlink($this->mutantWithValidCodeReferencingReflectionApi->getFilePath()); parent::tearDown(); } @@ -199,7 +229,23 @@ public function testWillConsiderMutantReferencingProjectFilesAsValid(): void self::assertTrue( (new RunStaticAnalysisAgainstMutant($psalmConfig)) - ->isMutantStillValidAccordingToStaticAnalysis($this->mutantWithValidCode) + ->isMutantStillValidAccordingToStaticAnalysis($this->mutantWithValidCodeReferencingProjectFiles) + ); + } + + public function testWillConsiderMutantReferencingReflectionApiAsValid(): void + { + $psalmConfig = Config::getConfigForPath( + self::PSALM_WORKING_DIRECTORY, + self::PSALM_WORKING_DIRECTORY, + Report::TYPE_CONSOLE + ); + + $psalmConfig->setIncludeCollector(new IncludeCollector()); + + self::assertTrue( + (new RunStaticAnalysisAgainstMutant($psalmConfig)) + ->isMutantStillValidAccordingToStaticAnalysis($this->mutantWithValidCodeReferencingReflectionApi) ); } } From 2bf4772f9b94c0d48f070443b5645e1ef1c62f7a Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Thu, 3 Sep 2020 00:49:34 +0200 Subject: [PATCH 12/14] As per @weirdan suggestion, clearing psalm **completely** between analysis runs Ref: https://github.com/vimeo/psalm/issues/4117#issuecomment-686053478 Ref: https://github.com/vimeo/psalm/issues/4117#issuecomment-686055998 Ref: https://github.com/vimeo/psalm/issues/4117 Ref: https://github.com/Roave/infection-static-analysis-plugin/pull/1#issuecomment-685984807 --- bin/roave-infection-static-analysis-plugin | 21 ++++++-- infection.json.dist | 2 +- psalm.xml | 1 + .../Psalm/RunStaticAnalysisAgainstMutant.php | 27 +++++----- .../RunStaticAnalysisAgainstMutantTest.php | 49 +++++++++++-------- 5 files changed, 63 insertions(+), 37 deletions(-) diff --git a/bin/roave-infection-static-analysis-plugin b/bin/roave-infection-static-analysis-plugin index e7dc494..6f16f89 100755 --- a/bin/roave-infection-static-analysis-plugin +++ b/bin/roave-infection-static-analysis-plugin @@ -9,8 +9,13 @@ use Infection\Console\Application; use Infection\Container; use PackageVersions\Versions; use Psalm\Config; +use Psalm\Internal\Analyzer\ProjectAnalyzer; use Psalm\Internal\IncludeCollector; +use Psalm\Internal\Provider\FileProvider; +use Psalm\Internal\Provider\Providers; +use Psalm\Internal\RuntimeCaches; use Psalm\Report; +use Psalm\Report\ReportOptions; use Roave\InfectionStaticAnalysis\Bootstrapper; use Roave\InfectionStaticAnalysis\Psalm\RunStaticAnalysisAgainstMutant; use function define; @@ -32,13 +37,23 @@ use function getcwd; define('PHP_PARSER_VERSION', Versions::getVersion('nikic/php-parser')); } - $psalmConfig = Config::getConfigForPath($cwd, $cwd, Report::TYPE_CONSOLE); + $makeAnalyzer = static function () use ($cwd): ProjectAnalyzer { + RuntimeCaches::clearAll(); - $psalmConfig->setIncludeCollector(new IncludeCollector()); + $config = Config::getConfigForPath($cwd, $cwd, Report::TYPE_CONSOLE); + + $config->setIncludeCollector(new IncludeCollector()); + + return new ProjectAnalyzer( + $config, + new Providers(new FileProvider()), + new ReportOptions() + ); + }; (new Application(Bootstrapper::bootstrap( Container::create(), - new RunStaticAnalysisAgainstMutant($psalmConfig) + new RunStaticAnalysisAgainstMutant($makeAnalyzer) ))) ->run(); })(); diff --git a/infection.json.dist b/infection.json.dist index 39a9c12..a1fa8ab 100644 --- a/infection.json.dist +++ b/infection.json.dist @@ -10,6 +10,6 @@ "branch": "master" } }, - "minMsi": 84, + "minMsi": 100, "minCoveredMsi": 100 } diff --git a/psalm.xml b/psalm.xml index a43e766..9e38806 100644 --- a/psalm.xml +++ b/psalm.xml @@ -8,6 +8,7 @@ allowPhpStormGenerics="true" > + diff --git a/src/Roave/InfectionStaticAnalysis/Psalm/RunStaticAnalysisAgainstMutant.php b/src/Roave/InfectionStaticAnalysis/Psalm/RunStaticAnalysisAgainstMutant.php index a62b091..7821ac9 100644 --- a/src/Roave/InfectionStaticAnalysis/Psalm/RunStaticAnalysisAgainstMutant.php +++ b/src/Roave/InfectionStaticAnalysis/Psalm/RunStaticAnalysisAgainstMutant.php @@ -5,11 +5,7 @@ namespace Roave\InfectionStaticAnalysis\Psalm; use Infection\Mutant\Mutant; -use Psalm\Config; use Psalm\Internal\Analyzer\ProjectAnalyzer; -use Psalm\Internal\Provider\FileProvider; -use Psalm\Internal\Provider\Providers; -use Psalm\Report\ReportOptions; use function array_key_exists; @@ -20,21 +16,26 @@ */ class RunStaticAnalysisAgainstMutant { - private Config $config; - - public function __construct(Config $config) + /** @var callable(): ProjectAnalyzer */ + private $makeFreshAnalyzer; + + /** + * Psalm has a lot of state in it, so we need a "fresh psalm" at each analysis - that's why + * a callable factory is injected + * + * @see https://github.com/vimeo/psalm/issues/4117 + * + * @param callable(): ProjectAnalyzer $makeFreshAnalyzer + */ + public function __construct(callable $makeFreshAnalyzer) { - $this->config = $config; + $this->makeFreshAnalyzer = $makeFreshAnalyzer; } public function isMutantStillValidAccordingToStaticAnalysis(Mutant $mutant): bool { $path = $mutant->getFilePath(); - $projectAnalyzer = new ProjectAnalyzer( - $this->config, - new Providers(new FileProvider()), - new ReportOptions() - ); + $projectAnalyzer = ($this->makeFreshAnalyzer)(); $projectAnalyzer->checkFile($path); diff --git a/test/unit/Roave/InfectionStaticAnalysisTest/Psalm/RunStaticAnalysisAgainstMutantTest.php b/test/unit/Roave/InfectionStaticAnalysisTest/Psalm/RunStaticAnalysisAgainstMutantTest.php index b18fb94..347e653 100644 --- a/test/unit/Roave/InfectionStaticAnalysisTest/Psalm/RunStaticAnalysisAgainstMutantTest.php +++ b/test/unit/Roave/InfectionStaticAnalysisTest/Psalm/RunStaticAnalysisAgainstMutantTest.php @@ -11,8 +11,13 @@ use PackageVersions\Versions; use PHPUnit\Framework\TestCase; use Psalm\Config; +use Psalm\Internal\Analyzer\ProjectAnalyzer; use Psalm\Internal\IncludeCollector; +use Psalm\Internal\Provider\FileProvider; +use Psalm\Internal\Provider\Providers; +use Psalm\Internal\RuntimeCaches; use Psalm\Report; +use Psalm\Report\ReportOptions; use Roave\InfectionStaticAnalysis\Psalm\RunStaticAnalysisAgainstMutant; use function array_combine; @@ -28,11 +33,11 @@ final class RunStaticAnalysisAgainstMutantTest extends TestCase { private const PSALM_WORKING_DIRECTORY = __DIR__ . '/../../../../..'; - private Mutant $mutantWithValidCode; private Mutant $mutantWithInvalidCode; private Mutant $mutantWithValidCodeReferencingProjectFiles; private Mutant $mutantWithValidCodeReferencingReflectionApi; + private RunStaticAnalysisAgainstMutant $runStaticAnalysis; protected function setUp(): void { @@ -168,11 +173,27 @@ function hasMethod(object $input, string $method): bool { define('PSALM_VERSION', Versions::getVersion('vimeo/psalm')); } - if (defined('PHP_PARSER_VERSION')) { - return; + if (! defined('PHP_PARSER_VERSION')) { + define('PHP_PARSER_VERSION', Versions::getVersion('nikic/php-parser')); } - define('PHP_PARSER_VERSION', Versions::getVersion('nikic/php-parser')); + $this->runStaticAnalysis = new RunStaticAnalysisAgainstMutant(static function (): ProjectAnalyzer { + RuntimeCaches::clearAll(); + + $config = Config::getConfigForPath( + self::PSALM_WORKING_DIRECTORY, + self::PSALM_WORKING_DIRECTORY, + Report::TYPE_CONSOLE + ); + + $config->setIncludeCollector(new IncludeCollector()); + + return new ProjectAnalyzer( + $config, + new Providers(new FileProvider()), + new ReportOptions() + ); + }); } protected function tearDown(): void @@ -195,10 +216,7 @@ public function testWillConsiderMutantValidIfNoErrorsAreDetectedByStaticAnalysis $psalmConfig->setIncludeCollector(new IncludeCollector()); - self::assertTrue( - (new RunStaticAnalysisAgainstMutant($psalmConfig)) - ->isMutantStillValidAccordingToStaticAnalysis($this->mutantWithValidCode) - ); + self::assertTrue($this->runStaticAnalysis->isMutantStillValidAccordingToStaticAnalysis($this->mutantWithValidCode)); } public function testWillConsiderMutantInvalidIfErrorsAreDetectedByStaticAnalysis(): void @@ -211,10 +229,7 @@ public function testWillConsiderMutantInvalidIfErrorsAreDetectedByStaticAnalysis $psalmConfig->setIncludeCollector(new IncludeCollector()); - self::assertFalse( - (new RunStaticAnalysisAgainstMutant($psalmConfig)) - ->isMutantStillValidAccordingToStaticAnalysis($this->mutantWithInvalidCode) - ); + self::assertFalse($this->runStaticAnalysis->isMutantStillValidAccordingToStaticAnalysis($this->mutantWithInvalidCode)); } public function testWillConsiderMutantReferencingProjectFilesAsValid(): void @@ -227,10 +242,7 @@ public function testWillConsiderMutantReferencingProjectFilesAsValid(): void $psalmConfig->setIncludeCollector(new IncludeCollector()); - self::assertTrue( - (new RunStaticAnalysisAgainstMutant($psalmConfig)) - ->isMutantStillValidAccordingToStaticAnalysis($this->mutantWithValidCodeReferencingProjectFiles) - ); + self::assertTrue($this->runStaticAnalysis->isMutantStillValidAccordingToStaticAnalysis($this->mutantWithValidCodeReferencingProjectFiles)); } public function testWillConsiderMutantReferencingReflectionApiAsValid(): void @@ -243,9 +255,6 @@ public function testWillConsiderMutantReferencingReflectionApiAsValid(): void $psalmConfig->setIncludeCollector(new IncludeCollector()); - self::assertTrue( - (new RunStaticAnalysisAgainstMutant($psalmConfig)) - ->isMutantStillValidAccordingToStaticAnalysis($this->mutantWithValidCodeReferencingReflectionApi) - ); + self::assertTrue($this->runStaticAnalysis->isMutantStillValidAccordingToStaticAnalysis($this->mutantWithValidCodeReferencingReflectionApi)); } } From 0121d0c112b785d1eeca01953b67ea2e03cb6de7 Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Thu, 3 Sep 2020 15:51:42 +0200 Subject: [PATCH 13/14] Ignore `.github` when creating a distribution package Ref: https://github.com/Roave/infection-static-analysis-plugin/pull/1#pullrequestreview-481702696 --- .gitattributes | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitattributes b/.gitattributes index cfc2966..2c71843 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,4 +1,5 @@ /test export-ignore +/.github export-ignore .gitattributes export-ignore .gitignore export-ignore composer.lock export-ignore From 7885e3a580bbed3ab7a61af137ba8eaa361277b5 Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Fri, 4 Sep 2020 11:24:31 +0200 Subject: [PATCH 14/14] Improved `README.md` as per @asgrim's suggestions Ref: https://github.com/Roave/infection-static-analysis-plugin/pull/1#pullrequestreview-482492318 --- README.md | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 38ad4dc..0a4240c 100644 --- a/README.md +++ b/README.md @@ -3,12 +3,23 @@ This plugin is designed to run static analysis on top of [`infection/infection`](https://github.com/infection/infection) test runs in order to discover if [escaped mutants](https://en.wikipedia.org/wiki/Mutation_testing) are valid mutations, or if they do not respect the type signature of your -program. - +program. If the mutation would result in a type error, it is "killed". + +TL;DR: + - This will improve your mutation score, since mutations which result in + type errors become killed. + - This is very hacky, and replaces `vendor/bin/infection` essentially. + Please read the `Stability` section below first for details. + - This is currently much slower than running infection by itself. + There are ideas/suggestions to improve this in the future. + ## Usage +The current design of this tool requires you to run `vendor/bin/roave-infection-static-analysis-plugin` +instead of running `vendor/bin/infection`: + ```sh -composer require roave/infection-static-analysis-plugin +composer require --dev roave/infection-static-analysis-plugin vendor/bin/roave-infection-static-analysis-plugin ```