diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 1250f0ba..36604993 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -11,6 +11,8 @@ on: env: GITHUB_TOKEN: ${{ secrets.ACCESS_TOKEN }} + # for phive + GITHUB_AUTH_TOKEN: ${{ secrets.ACCESS_TOKEN }} jobs: tests: @@ -18,14 +20,14 @@ jobs: name: Build and test strategy: matrix: - php: [8.0, 8.1, 8.2] + php: [8.2, 8.3, 8.4] deps: [high] include: - - php: 8.0 + - php: 8.2 deps: low steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Setup PHP uses: shivammathur/setup-php@v2 @@ -33,7 +35,7 @@ jobs: php-version: "${{ matrix.php }}" tools: composer ini-values: "phar.readonly=0" - coverage: none + coverage: pcov - if: matrix.deps == 'high' run: make update test package package-devkit @@ -41,14 +43,14 @@ jobs: - if: matrix.deps == 'low' run: make update-min test-min - - uses: actions/upload-artifact@v1 - if: matrix.php == '8.0' && matrix.deps == 'high' + - uses: actions/upload-artifact@v4 + if: matrix.php == '8.2' && matrix.deps == 'high' with: name: toolbox.phar path: build/toolbox.phar - - uses: actions/upload-artifact@v1 - if: matrix.php == '8.0' && matrix.deps == 'high' + - uses: actions/upload-artifact@v4 + if: matrix.php == '8.2' && matrix.deps == 'high' with: name: devkit.phar path: build/devkit.phar @@ -59,10 +61,10 @@ jobs: needs: tests strategy: matrix: - php: [8.0, 8.1, 8.2] + php: [8.2, 8.3, 8.4] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Setup PHP uses: shivammathur/setup-php@v2 @@ -73,14 +75,13 @@ jobs: coverage: none extensions: bz2, zip - - uses: actions/download-artifact@v1 + - uses: actions/download-artifact@v4 with: name: toolbox.phar path: build/ - - run: make test-integration env: - GITHUB_AUTH_TOKEN: ${{ secrets.ACCESS_TOKEN }} + GITHUB_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }} publish-phars: runs-on: ubuntu-latest @@ -88,29 +89,20 @@ jobs: needs: tests if: github.event_name == 'release' steps: - - uses: actions/download-artifact@v1 + - uses: actions/download-artifact@v4 with: name: toolbox.phar path: . - - uses: actions/download-artifact@v1 + - uses: actions/download-artifact@v4 with: name: devkit.phar path: . - name: Upload toolbox.phar - uses: actions/upload-release-asset@v1 + run: gh release upload ${{ github.event.release.tag_name }} toolbox.phar --clobber --repo github.com/jakzal/toolbox env: GITHUB_TOKEN: ${{ secrets.ACCESS_TOKEN }} - with: - upload_url: ${{ github.event.release.upload_url }} - asset_path: ./toolbox.phar - asset_name: toolbox.phar - asset_content_type: application/zip - name: Upload devkit.phar - uses: actions/upload-release-asset@v1 + run: gh release upload ${{ github.event.release.tag_name }} devkit.phar --clobber --repo github.com/jakzal/toolbox env: GITHUB_TOKEN: ${{ secrets.ACCESS_TOKEN }} - with: - upload_url: ${{ github.event.release.upload_url }} - asset_path: ./devkit.phar - asset_name: devkit.phar - asset_content_type: application/zip + diff --git a/.github/workflows/publish-website.yml b/.github/workflows/publish-website.yml index 1f87cc89..309ac156 100644 --- a/.github/workflows/publish-website.yml +++ b/.github/workflows/publish-website.yml @@ -11,14 +11,14 @@ jobs: runs-on: ubuntu-latest name: Build and publish steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: persist-credentials: false - name: Setup PHP uses: shivammathur/setup-php@v2 with: - php-version: "8.0" + php-version: "8.2" ini-values: "phar.readonly=0" - name: Build the website diff --git a/.github/workflows/update-phars.yml b/.github/workflows/update-phars.yml index 50d25efd..38db0c04 100644 --- a/.github/workflows/update-phars.yml +++ b/.github/workflows/update-phars.yml @@ -8,17 +8,20 @@ jobs: runs-on: ubuntu-latest name: Create a PR steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Setup PHP uses: shivammathur/setup-php@v2 with: - php-version: "8.0" + php-version: "8.2" ini-values: "phar.readonly=0" - name: Configure git run: git config user.email 'jakub@zalas.pl' && git config user.name 'Jakub Zalas' + - name: Install dependencies + run: sudo apt-get update && sudo apt-get install -y hub + - name: Update PHARs run: make package-devkit update-phars diff --git a/.scrutinizer.yml b/.scrutinizer.yml index 766c1964..832cd37f 100644 --- a/.scrutinizer.yml +++ b/.scrutinizer.yml @@ -3,7 +3,9 @@ inherit: true build: environment: php: - version: 8.0 + version: 8.2 + variables: + XDEBUG_MODE: coverage tests: override: - make phpunit @@ -12,7 +14,7 @@ build: coverage: tests: override: - - command: make phpunit-coverage + - command: make phpunit coverage: file: build/coverage.xml format: clover diff --git a/Makefile b/Makefile index 35386d75..06f222b5 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,6 @@ default: build PHP_VERSION:=$(shell php -r 'echo PHP_MAJOR_VERSION.".".PHP_MINOR_VERSION;') -IS_PHP81:=$(shell php -r 'echo (int)version_compare(PHP_VERSION, "8.1", ">=");') TOOLBOX_VERSION?=dev build: install test @@ -50,17 +49,13 @@ deptrac: tools/deptrac .PHONY: deptrac infection: - phpdbg -qrr ./vendor/bin/infection --no-interaction --formatter=progress --min-msi=100 --min-covered-msi=100 --only-covered --ansi + ./vendor/bin/infection --no-interaction --formatter=progress --min-msi=100 --min-covered-msi=100 --only-covered --ansi .PHONY: infection phpunit: tools/phpunit tools/phpunit .PHONY: phpunit -phpunit-coverage: tools/phpunit - phpdbg -qrr tools/phpunit -.PHONY: phpunit - package: tools/box @rm -rf build/phar && mkdir -p build/phar build/phar/bin @@ -68,7 +63,7 @@ package: tools/box sed -e 's/Application('"'"'dev/Application('"'"'$(TOOLBOX_VERSION)/g' bin/toolbox.php > build/phar/bin/toolbox.php cd build/phar && \ - composer config platform.php 8.0.0 && \ + composer config platform.php 8.2.0 && \ composer update --no-dev -o -a tools/box compile @@ -84,7 +79,7 @@ package-devkit: tools/box sed -e 's/\(Application(.*\)'"'"'dev/\1'"'"'$(TOOLBOX_VERSION)/g' bin/devkit.php > build/devkit-phar/bin/devkit.php cd build/devkit-phar && \ - composer config platform.php 8.0.0 && \ + composer config platform.php 8.2.0 && \ composer update --no-dev -o -a tools/box compile -c box-devkit.json.dist @@ -138,17 +133,7 @@ tools/php-cs-fixer: curl -Ls https://cs.symfony.com/download/php-cs-fixer-v3.phar -o tools/php-cs-fixer && chmod +x tools/php-cs-fixer tools/deptrac: -ifeq ($(IS_PHP81),1) - curl -Ls https://github.com/qossmic/deptrac/releases/download/1.0.2/deptrac.phar -o tools/deptrac && chmod +x tools/deptrac - curl -Ls https://github.com/qossmic/deptrac/releases/download/1.0.2/deptrac.phar.asc -o tools/deptrac.asc -else - curl -Ls https://github.com/qossmic/deptrac/releases/download/0.24.0/deptrac.phar -o tools/deptrac && chmod +x tools/deptrac - curl -Ls https://github.com/qossmic/deptrac/releases/download/0.24.0/deptrac.phar.asc -o tools/deptrac.asc -endif + ln -sf ../vendor/bin/deptrac tools/deptrac tools/box: -ifeq ($(IS_PHP81),1) curl -Ls https://github.com/humbug/box/releases/download/4.2.0/box.phar -o tools/box && chmod +x tools/box -else - curl -Ls https://github.com/humbug/box/releases/download/3.15.0/box.phar -o tools/box && chmod +x tools/box -endif diff --git a/README.md b/README.md index 1a83523c..a6b6bf19 100644 --- a/README.md +++ b/README.md @@ -14,40 +14,44 @@ It has been extracted as a separate project to make maintenance easier and enabl ## Available tools -| Name | Description | PHP 8.0 | PHP 8.1 | PHP 8.2 | +| Name | Description | PHP 8.2 | PHP 8.3 | PHP 8.4 | | :--- | :---------- | :------ | :------ | :------ | | behat | [Helps to test business expectations](http://behat.org/) | ✅ | ✅ | ✅ | -| box | [Fast, zero config application bundler with PHARs](https://github.com/humbug/box) | ❌ | ✅ | ✅ | -| box-3 | [Fast, zero config application bundler with PHARs](https://github.com/humbug/box) | ✅ | ✅ | ❌ | +| box | [Fast, zero config application bundler with PHARs](https://github.com/humbug/box) | ✅ | ✅ | ✅ | +| box-3 | [Fast, zero config application bundler with PHARs](https://github.com/humbug/box) | ❌ | ✅ | ✅ | | churn | [Discovers good candidates for refactoring](https://github.com/bmitch/churn-php) | ✅ | ✅ | ✅ | | codeception | [Codeception is a BDD-styled PHP testing framework](https://codeception.com/) | ✅ | ✅ | ✅ | | composer | [Dependency Manager for PHP](https://getcomposer.org/) | ✅ | ✅ | ✅ | | composer-bin-plugin | [Composer plugin to install bin vendors in isolated locations](https://github.com/bamarni/composer-bin-plugin) | ✅ | ✅ | ✅ | +| composer-lock-diff | [Composer plugin to check what has changed after a composer update](https://github.com/davidrjonas/composer-lock-diff) | ✅ | ✅ | ✅ | | composer-normalize | [Composer plugin to normalize composer.json files](https://github.com/ergebnis/composer-normalize) | ✅ | ✅ | ✅ | -| composer-require-checker | [Verify that no unknown symbols are used in the sources of a package.](https://github.com/maglnet/ComposerRequireChecker) | ❌ | ✅ | ✅ | +| composer-require-checker | [Verify that no unknown symbols are used in the sources of a package.](https://github.com/maglnet/ComposerRequireChecker) | ✅ | ✅ | ✅ | | composer-require-checker-3 | [Verify that no unknown symbols are used in the sources of a package.](https://github.com/maglnet/ComposerRequireChecker) | ✅ | ✅ | ✅ | | composer-unused | [Show unused packages by scanning your code](https://github.com/icanhazstring/composer-unused) | ✅ | ✅ | ✅ | +| cyclonedx-php-composer | [Composer plugin to create Software-Bill-of-Materials (SBOM) in CycloneDX format](https://github.com/CycloneDX/cyclonedx-php-composer) | ✅ | ✅ | ✅ | | dephpend | [Detect flaws in your architecture](https://dephpend.com/) | ✅ | ✅ | ✅ | | deprecation-detector | [Finds usages of deprecated code](https://github.com/sensiolabs-de/deprecation-detector) | ✅ | ✅ | ✅ | -| deptrac | [Enforces dependency rules between software layers](https://github.com/qossmic/deptrac) | ❌ | ✅ | ✅ | +| deptrac | [Enforces dependency rules between software layers](https://github.com/deptrac/deptrac) | ✅ | ✅ | ✅ | | diffFilter | [Applies QA tools to run on a single pull request](https://github.com/exussum12/coverageChecker) | ✅ | ✅ | ✅ | | ecs | [Sets up and runs coding standard checks](https://github.com/Symplify/EasyCodingStandard) | ✅ | ✅ | ✅ | -| infection | [AST based PHP Mutation Testing Framework](https://infection.github.io/) | ❌ | ✅ | ✅ | +| gherkin-lint-php | [Gherkin linter for PHP](https://github.com/dantleech/gherkin-lint-php) | ✅ | ✅ | ✅ | +| infection | [AST based PHP Mutation Testing Framework](https://infection.github.io/) | ✅ | ✅ | ✅ | +| kahlan | [Kahlan is a full-featured Unit & BDD test framework a la RSpec/JSpec](https://kahlan.github.io/docs/) | ✅ | ✅ | ✅ | | larastan | [PHPStan extension for Laravel](https://github.com/nunomaduro/larastan) | ✅ | ✅ | ✅ | +| lines | [CLI tool for quick metrics of PHP projects](https://github.com/tomasVotruba/lines) | ✅ | ✅ | ✅ | | local-php-security-checker | [Checks composer dependencies for known security vulnerabilities](https://github.com/fabpot/local-php-security-checker) | ✅ | ✅ | ✅ | | parallel-lint | [Checks PHP file syntax](https://github.com/php-parallel-lint/PHP-Parallel-Lint) | ✅ | ✅ | ✅ | | paratest | [Parallel testing for PHPUnit](https://github.com/paratestphp/paratest) | ✅ | ✅ | ✅ | | pdepend | [Static Analysis Tool](https://pdepend.org/) | ✅ | ✅ | ✅ | | phan | [Static Analysis Tool](https://github.com/phan/phan) | ✅ | ✅ | ✅ | | phive | [PHAR Installation and Verification Environment](https://phar.io/) | ✅ | ✅ | ✅ | -| php-coupling-detector | [Detects code coupling issues](https://akeneo.github.io/php-coupling-detector/) | ✅ | ✅ | ✅ | | php-cs-fixer | [PHP Coding Standards Fixer](http://cs.symfony.com/) | ✅ | ✅ | ✅ | | php-fuzzer | [A fuzzer for PHP, which can be used to find bugs in libraries by feeding them 'random' inputs](https://github.com/nikic/PHP-Fuzzer) | ✅ | ✅ | ✅ | | php-semver-checker | [Suggests a next version according to semantic versioning](https://github.com/tomzx/php-semver-checker) | ✅ | ✅ | ✅ | | phpa | [Checks for weak assumptions](https://github.com/rskuipers/php-assumptions) | ✅ | ✅ | ✅ | | phparkitect | [Helps to put architectural constraints in a PHP code base](https://github.com/phparkitect/arkitect) | ✅ | ✅ | ✅ | | phpat | [Easy to use architecture testing tool](https://github.com/carlosas/phpat) | ✅ | ✅ | ✅ | -| phpbench | [PHP Benchmarking framework](https://github.com/phpbench/phpbench) | ❌ | ✅ | ✅ | +| phpbench | [PHP Benchmarking framework](https://github.com/phpbench/phpbench) | ✅ | ✅ | ✅ | | phpca | [Finds usage of non-built-in extensions](https://github.com/wapmorgan/PhpCodeAnalyzer) | ✅ | ✅ | ✅ | | phpcb | [PHP Code Browser](https://github.com/mayflower/PHP_CodeBrowser) | ✅ | ✅ | ✅ | | phpcbf | [Automatically corrects coding standard violations](https://github.com/squizlabs/PHP_CodeSniffer) | ✅ | ✅ | ✅ | @@ -56,7 +60,6 @@ It has been extracted as a separate project to make maintenance easier and enabl | phpcpd | [Copy/Paste Detector](https://github.com/sebastianbergmann/phpcpd) | ✅ | ✅ | ✅ | | phpcs | [Detects coding standard violations](https://github.com/squizlabs/PHP_CodeSniffer) | ✅ | ✅ | ✅ | | phpcs-security-audit | [Finds vulnerabilities and weaknesses related to security in PHP code](https://github.com/FloeDesignTechnologies/phpcs-security-audit) | ✅ | ✅ | ✅ | -| phpda | [Generates dependency graphs](https://mamuz.github.io/PhpDependencyAnalysis/) | ✅ | ❌ | ❌ | | phpdd | [Finds usage of deprecated features](http://wapmorgan.github.io/PhpDeprecationDetector) | ✅ | ✅ | ✅ | | phpDocumentor | [Documentation generator](https://www.phpdoc.org/) | ✅ | ✅ | ✅ | | phpinsights | [Analyses code quality, style, architecture and complexity](https://phpinsights.com/) | ✅ | ✅ | ✅ | @@ -65,20 +68,21 @@ It has been extracted as a separate project to make maintenance easier and enabl | phpmd | [A tool for finding problems in PHP code](https://phpmd.org/) | ✅ | ✅ | ✅ | | phpmetrics | [Static Analysis Tool](http://www.phpmetrics.org/) | ✅ | ✅ | ✅ | | phpmnd | [Helps to detect magic numbers](https://github.com/povils/phpmnd) | ✅ | ✅ | ✅ | -| phpspec | [SpecBDD Framework](http://www.phpspec.net/) | ✅ | ✅ | ❌ | +| phpspec | [SpecBDD Framework](http://www.phpspec.net/) | ✅ | ✅ | ✅ | | phpstan | [Static Analysis Tool](https://github.com/phpstan/phpstan) | ✅ | ✅ | ✅ | | phpstan-banned-code | [PHPStan rules for detecting calls to specific functions you don't want in your project](https://github.com/ekino/phpstan-banned-code) | ✅ | ✅ | ✅ | | phpstan-beberlei-assert | [PHPStan extension for beberlei/assert](https://github.com/phpstan/phpstan-beberlei-assert) | ✅ | ✅ | ✅ | | phpstan-deprecation-rules | [PHPStan rules for detecting deprecated code](https://github.com/phpstan/phpstan-deprecation-rules) | ✅ | ✅ | ✅ | | phpstan-doctrine | [Doctrine extensions for PHPStan](https://github.com/phpstan/phpstan-doctrine) | ✅ | ✅ | ✅ | | phpstan-ergebnis-rules | [Additional rules for PHPstan](https://github.com/ergebnis/phpstan-rules) | ✅ | ✅ | ✅ | -| phpstan-exception-rules | [PHPStan rules for checked and unchecked exceptions](https://github.com/pepakriz/phpstan-exception-rules) | ✅ | ✅ | ✅ | | phpstan-larastan | [Separate installation of phpstan for larastan](https://github.com/phpstan/phpstan) | ✅ | ✅ | ✅ | | phpstan-phpunit | [PHPUnit extensions and rules for PHPStan](https://github.com/phpstan/phpstan-phpunit) | ✅ | ✅ | ✅ | | phpstan-strict-rules | [Extra strict and opinionated rules for PHPStan](https://github.com/phpstan/phpstan-strict-rules) | ✅ | ✅ | ✅ | | phpstan-symfony | [Symfony extension for PHPStan](https://github.com/phpstan/phpstan-symfony) | ✅ | ✅ | ✅ | | phpstan-webmozart-assert | [PHPStan extension for webmozart/assert](https://github.com/phpstan/phpstan-webmozart-assert) | ✅ | ✅ | ✅ | | phpunit | [The PHP testing framework](https://phpunit.de/) | ❌ | ✅ | ✅ | +| phpunit-10 | [The PHP testing framework (10.x version)](https://phpunit.de/) | ✅ | ✅ | ✅ | +| phpunit-11 | [The PHP testing framework (11.x version)](https://phpunit.de/) | ✅ | ✅ | ✅ | | phpunit-8 | [The PHP testing framework (8.x version)](https://phpunit.de/) | ✅ | ✅ | ✅ | | phpunit-9 | [The PHP testing framework (9.x version)](https://phpunit.de/) | ✅ | ✅ | ✅ | | pint | [Opinionated PHP code style fixer for Laravel](https://github.com/laravel/pint) | ✅ | ✅ | ✅ | @@ -88,12 +92,13 @@ It has been extracted as a separate project to make maintenance easier and enabl | psalm-plugin-symfony | [Psalm Plugin for Symfony](https://github.com/psalm/psalm-plugin-symfony) | ✅ | ✅ | ✅ | | psecio-parse | [Scans code for potential security-related issues](https://github.com/psecio/parse) | ✅ | ✅ | ✅ | | rector | [Tool for instant code upgrades and refactoring](https://github.com/rectorphp/rector) | ✅ | ✅ | ✅ | -| roave-backward-compatibility-check | [Tool to compare two revisions of a class API to check for BC breaks](https://github.com/Roave/BackwardCompatibilityCheck) | ✅ | ✅ | ✅ | +| roave-backward-compatibility-check | [Tool to compare two revisions of a class API to check for BC breaks](https://github.com/Roave/BackwardCompatibilityCheck) | ✅ | ✅ | ❌ | | simple-phpunit | [Provides utilities to report legacy tests and usage of deprecated code](https://symfony.com/doc/current/components/phpunit_bridge.html) | ✅ | ✅ | ✅ | +| twig-cs-fixer | [Automatically corrects twig files following the official coding standard rules](https://github.com/VincentLanglet/Twig-CS-Fixer) | ✅ | ✅ | ✅ | | twig-lint | [Standalone cli twig 1.X linter](https://github.com/asm89/twig-lint) | ✅ | ✅ | ✅ | | twig-linter | [Standalone cli twig 3.X linter](https://github.com/sserbin/twig-linter) | ✅ | ✅ | ✅ | | twigcs | [The missing checkstyle for twig!](https://github.com/friendsoftwig/twigcs) | ✅ | ✅ | ✅ | -| yaml-lint | [Compact command line utility for checking YAML file syntax](https://github.com/j13k/yaml-lint) | ❌ | ✅ | ✅ | +| yaml-lint | [Compact command line utility for checking YAML file syntax](https://github.com/j13k/yaml-lint) | ✅ | ✅ | ✅ | ### Removed tools @@ -101,12 +106,15 @@ It has been extracted as a separate project to make maintenance easier and enabl | :--- | :------ | | analyze | [Visualizes metrics and source code](https://github.com/Qafoo/QualityAnalyzer) | | box-legacy | [Legacy version of box](https://box-project.github.io/box2/) | -| composer-normalize | [Composer plugin to normalize composer.json files](https://github.com/localheinz/composer-normalize) | | design-pattern | [Detects design patterns](https://github.com/Halleck45/DesignPatternDetector) | | parallel-lint | [Checks PHP file syntax](https://github.com/JakubOnderka/PHP-Parallel-Lint) | +| pest | [The elegant PHP Testing Framework](https://github.com/pestphp/pest) | +| php-coupling-detector | [Detects code coupling issues](https://akeneo.github.io/php-coupling-detector/) | | php-formatter | [Custom coding standards fixer](https://github.com/mmoreram/php-formatter) | | phpcf | [Finds usage of deprecated features](http://wapmorgan.github.io/PhpCodeFixer/) | +| phpda | [Generates dependency graphs](https://mamuz.github.io/PhpDependencyAnalysis/) | | phpdoc-to-typehint | [Automatically adds type hints and return types based on PHPDocs](https://github.com/dunglas/phpdoc-to-typehint) | +| phpstan-exception-rules | [PHPStan rules for checked and unchecked exceptions](https://github.com/pepakriz/phpstan-exception-rules) | | phpstan-localheinz-rules | [Additional rules for PHPstan](https://github.com/localheinz/phpstan-rules) | | phpunit-5 | [The PHP testing framework (5.x version)](https://phpunit.de/) | | phpunit-7 | [The PHP testing framework (7.x version)](https://phpunit.de/) | @@ -239,7 +247,7 @@ Tools can be tagged in order to enable grouping and filtering them. The tags below have a special meaning: * `pre-installation` - these tools will be installed before any other tools. -* `exclude-php:8.1`, `exclude-php:8.2` etc - used to exclude installation on the specified php version. +* `exclude-php:8.2`, `exclude-php:8.3` etc - used to exclude installation on the specified php version. ## Contributing diff --git a/bin/devkit.php b/bin/devkit.php index ff870c03..8201017e 100755 --- a/bin/devkit.php +++ b/bin/devkit.php @@ -42,9 +42,6 @@ private function toolsJsonDefault(): array ]; } - /** - * @return Collection|Tool[] - */ private function loadTools($jsonPath, ?Filter $filter = null): Collection { return (new JsonTools(function () use ($jsonPath) { @@ -59,7 +56,7 @@ private function loadTools($jsonPath, ?Filter $filter = null): Collection { use Tools; - protected function configure() + protected function configure(): void { $this->setName('update:readme'); $this->setDescription('Updates README.md with latest list of available tools'); @@ -67,13 +64,13 @@ protected function configure() $this->addOption('readme', null, InputOption::VALUE_REQUIRED, 'Path to the readme file', __DIR__ . '/../README.md'); } - protected function execute(InputInterface $input, OutputInterface $output) + protected function execute(InputInterface $input, OutputInterface $output): int { $jsonPath = $input->getOption('tools'); $readmePath = $input->getOption('readme'); $tools = $this->loadTools($jsonPath); - $toolsList = '| Name | Description | PHP 8.0 | PHP 8.1 | PHP 8.2 |' . PHP_EOL; + $toolsList = '| Name | Description | PHP 8.2 | PHP 8.3 | PHP 8.4 |' . PHP_EOL; $toolsList .= '| :--- | :---------- | :------ | :------ | :------ |' . PHP_EOL; $toolsList .= $tools->sort(function (Tool $left, Tool $right) { return strcasecmp($left->name(), $right->name()); @@ -83,9 +80,9 @@ protected function execute(InputInterface $input, OutputInterface $output) $tool->name(), $tool->summary(), $tool->website(), - in_array('exclude-php:8.0', $tool->tags(), true) ? '❌' : '✅', - in_array('exclude-php:8.1', $tool->tags(), true) ? '❌' : '✅', - in_array('exclude-php:8.2', $tool->tags(), true) ? '❌' : '✅' + in_array('exclude-php:8.2', $tool->tags(), true) ? '❌' : '✅', + in_array('exclude-php:8.3', $tool->tags(), true) ? '❌' : '✅', + in_array('exclude-php:8.4', $tool->tags(), true) ? '❌' : '✅', ) . PHP_EOL; }); @@ -105,14 +102,14 @@ protected function execute(InputInterface $input, OutputInterface $output) { use Tools; - protected function configure() + protected function configure(): void { $this->setName('update:phars'); $this->setDescription('Attempts to update phar links to latest versions'); $this->addOption('tools', null, InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 'Path(s) to the list of tools. Can also be set with TOOLBOX_JSON environment variable.', $this->toolsJsonDefault()); } - protected function execute(InputInterface $input, OutputInterface $output) + protected function execute(InputInterface $input, OutputInterface $output): int { foreach ($input->getOption('tools') as $jsonPath) { $result = $this->updatePhars($jsonPath, $output); @@ -125,7 +122,7 @@ protected function execute(InputInterface $input, OutputInterface $output) return 0; } - private function updatePhars(string $jsonPath, OutputInterface $output) + private function updatePhars(string $jsonPath, OutputInterface $output): int { $phars = $this->findLatestPhars($jsonPath); @@ -192,14 +189,14 @@ function (string $phar) { { use Tools; - protected function configure() + protected function configure(): void { $this->setName('generate:html'); $this->setDescription('Generates an html list of available tools'); $this->addOption('tools', null, InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 'Path(s) to the list of tools. Can also be set with TOOLBOX_JSON environment variable.', $this->toolsJsonDefault()); } - protected function execute(InputInterface $input, OutputInterface $output) + protected function execute(InputInterface $input, OutputInterface $output): int { $tools = $this->loadTools($input->getOption('tools'), new Filter(['pre-installation'], [])); @@ -241,10 +238,6 @@ private function toolToHtml(): \Closure }; } - /** - * @param Collection|string[] $toolsHtml - * @return string - */ private function renderPage(Collection $toolsHtml): string { $template = <<<'TEMPLATE' diff --git a/composer.json b/composer.json index 5782f260..04fbb107 100644 --- a/composer.json +++ b/composer.json @@ -3,15 +3,15 @@ "description": "Helps to discover and install tools", "type": "project", "require": { - "php": "~8.0.0 || ~8.1.0 || ~8.2.0", - "symfony/console": "^4.4 || ^5.4 || ^6.1", - "psr/container": "^1.0" + "php": "~8.2.0 || ~8.3.0 || ~8.4.0", + "symfony/console": "^6.4.18 || ^7.2", + "psr/container": "^2.0" }, "require-dev": { - "phpunit/phpunit": "^9.5", - "zalas/phpunit-globals": "^2.1", - "phpspec/prophecy-phpunit": "^2.0", - "infection/infection": "^0.26" + "phpunit/phpunit": "^11.5.9 || ^12.0", + "zalas/phpunit-globals": "^4.0", + "infection/infection": "^0.29", + "deptrac/deptrac": "^3.0" }, "autoload": { "psr-4": { diff --git a/deptrac.yaml b/deptrac.yaml index 99dfe48c..d7543f8c 100644 --- a/deptrac.yaml +++ b/deptrac.yaml @@ -5,47 +5,47 @@ parameters: layers: - name: Cli collectors: - - type: className - regex: ^Zalas\\Toolbox\\Cli\\.* + - type: classLike + value: ^Zalas\\Toolbox\\Cli\\.* - name: Json collectors: - - type: className - regex: ^Zalas\\Toolbox\\Json\\.* + - type: classLike + value: ^Zalas\\Toolbox\\Json\\.* - name: Runner collectors: - - type: className - regex: ^Zalas\\Toolbox\\Runner\\.* + - type: classLike + value: ^Zalas\\Toolbox\\Runner\\.* - name: Tool collectors: - - type: className - regex: ^Zalas\\Toolbox\\Tool\\.* + - type: classLike + value: ^Zalas\\Toolbox\\Tool\\.* - name: UseCase collectors: - - type: className - regex: ^Zalas\\Toolbox\\UseCase\\.* + - type: classLike + value: ^Zalas\\Toolbox\\UseCase\\.* - name: Psr Container collectors: - - type: className - regex: ^Psr\\Container\\.* + - type: classLike + value: ^Psr\\Container\\.* - name: Symfony Console collectors: - - type: className - regex: ^Symfony\\Component\\Console\\.* + - type: classLike + value: ^Symfony\\Component\\Console\\.* - name: Other Vendors collectors: - type: bool must: # must be outside of global namespace - - type: className - regex: '[\\]+' + - type: classLike + value: '[\\]+' must_not: # must not be one of the known vendors - - type: className - regex: ^Zalas\\Toolbox\\(Cli|Json|Runner|Tool|UseCase)\\.* - - type: className - regex: ^Psr\\Container\\.* - - type: className - regex: ^Symfony\\Component\\Console\\.* + - type: classLike + value: ^Zalas\\Toolbox\\(Cli|Json|Runner|Tool|UseCase)\\.* + - type: classLike + value: ^Psr\\Container\\.* + - type: classLike + value: ^Symfony\\Component\\Console\\.* ruleset: Cli: - Tool diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 158f138e..f7d4e1c6 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -1,9 +1,6 @@ - - - - src - + + @@ -20,7 +17,12 @@ - + + + + src + + diff --git a/resources/architecture.json b/resources/architecture.json index cf11dfe0..a54288e7 100644 --- a/resources/architecture.json +++ b/resources/architecture.json @@ -17,16 +17,14 @@ { "name": "deptrac", "summary": "Enforces dependency rules between software layers", - "website": "https://github.com/qossmic/deptrac", + "website": "https://github.com/deptrac/deptrac", "command": { - "phive-install": { - "alias": "deptrac", - "bin": "%target-dir%/deptrac", - "sig": "B8F640134AB1782E" + "composer-global-install": { + "package": "deptrac/deptrac" } }, "test": "deptrac list", - "tags": ["featured", "architecture", "exclude-php:8.0"] + "tags": ["featured", "architecture"] }, { "name": "pdepend", @@ -42,20 +40,6 @@ "test": "pdepend --version", "tags": ["featured", "architecture"] }, - { - "name": "php-coupling-detector", - "summary": "Detects code coupling issues", - "website": "https://akeneo.github.io/php-coupling-detector/", - "command": { - "composer-bin-plugin": { - "package": "akeneo/php-coupling-detector", - "namespace": "tools", - "links": {"%target-dir%/php-coupling-detector": "php-coupling-detector"} - } - }, - "test": "php-coupling-detector list", - "tags": ["architecture"] - }, { "name": "phparkitect", "summary": "Helps to put architectural constraints in a PHP code base", @@ -68,20 +52,6 @@ }, "test": "phparkitect --version", "tags": ["architecture"] - }, - { - "name": "phpda", - "summary": "Generates dependency graphs", - "website": "https://mamuz.github.io/PhpDependencyAnalysis/", - "command": { - "composer-bin-plugin": { - "package": "mamuz/php-dependency-analysis", - "namespace": "phpda", - "links": {"%target-dir%/phpda": "phpda"} - } - }, - "test": "phpda list", - "tags": ["exclude-php:8.2", "exclude-php:8.1", "featured", "architecture"] } ] } diff --git a/resources/checkstyle.json b/resources/checkstyle.json index f98cb6d7..0c92d62b 100644 --- a/resources/checkstyle.json +++ b/resources/checkstyle.json @@ -50,7 +50,7 @@ "phive-install": { "alias": "phpcbf", "bin": "%target-dir%/phpcbf", - "sig": "31C7E470E2138192" + "sig": "97B02DD8E5071466" } }, "test": "phpcbf --help", @@ -69,6 +69,20 @@ }, "test": "twigcs --help", "tags": ["checkstyle"] + }, + { + "name": "twig-cs-fixer", + "summary": "Automatically corrects twig files following the official coding standard rules", + "website": "https://github.com/VincentLanglet/Twig-CS-Fixer", + "command": { + "composer-bin-plugin": { + "package": "vincentlanglet/twig-cs-fixer", + "namespace": "twig-cs-fixer", + "links": {"%target-dir%/twig-cs-fixer": "twig-cs-fixer"} + } + }, + "test": "twig-cs-fixer --help", + "tags": ["checkstyle"] } ] } diff --git a/resources/compatibility.json b/resources/compatibility.json index 4ad290a4..a6310d33 100644 --- a/resources/compatibility.json +++ b/resources/compatibility.json @@ -6,7 +6,7 @@ "website": "https://github.com/tomzx/php-semver-checker", "command": { "phar-download": { - "phar": "http://psvc.coreteks.org/php-semver-checker.phar", + "phar": "https://github.com/tomzx/php-semver-checker/releases/download/v0.17.0/php-semver-checker.phar", "bin": "%target-dir%/php-semver-checker" } }, @@ -28,7 +28,7 @@ } }, "test": "roave-backward-compatibility-check --version", - "tags": ["compatibility"] + "tags": ["compatibility", "exclude-php:8.4"] } ] } diff --git a/resources/composer.json b/resources/composer.json index 7b0d7c70..bee3b319 100644 --- a/resources/composer.json +++ b/resources/composer.json @@ -23,7 +23,7 @@ "phive-install": { "alias": "composer-unused", "bin": "%target-dir%/composer-unused", - "sig": "F4D32E2C9343B2AE" + "sig": "3135AA4CB4F1AB0B" } }, "test": "composer-unused -V", @@ -41,7 +41,7 @@ } }, "test": "composer-require-checker -V", - "tags": ["composer", "exclude-php:8.0"] + "tags": ["composer"] }, { "name": "composer-require-checker-3", @@ -56,6 +56,35 @@ }, "test": "composer-require-checker-3 -V", "tags": ["composer"] + }, + { + "name": "cyclonedx-php-composer", + "summary": "Composer plugin to create Software-Bill-of-Materials (SBOM) in CycloneDX format", + "website": "https://github.com/CycloneDX/cyclonedx-php-composer", + "command": { + "sh": { + "command": "composer global config --no-plugins allow-plugins.cyclonedx/cyclonedx-php-composer true" + }, + "composer-global-install": { + "package": "cyclonedx/cyclonedx-php-composer" + } + }, + "test": "composer global show cyclonedx/cyclonedx-php-composer", + "tags": ["composer"] + }, + { + "name": "composer-lock-diff", + "summary": "Composer plugin to check what has changed after a composer update", + "website": "https://github.com/davidrjonas/composer-lock-diff", + "command": { + "composer-bin-plugin": { + "package": "davidrjonas/composer-lock-diff", + "namespace": "composer-lock-diff", + "links": {"%target-dir%/composer-lock-diff": "composer-lock-diff"} + } + }, + "test": "composer-lock-diff --help", + "tags": ["composer"] } ] } diff --git a/resources/documentation.json b/resources/documentation.json index 06c372a8..5fc2b870 100644 --- a/resources/documentation.json +++ b/resources/documentation.json @@ -8,10 +8,10 @@ "phive-install": { "alias": "phpDocumentor", "bin": "%target-dir%/phpDocumentor", - "sig": "67F861C3D889C656" + "sig": "6DA3ACC4991FFAE5" } }, - "test": "phpDocumentor list", + "test": "phpDocumentor --help", "tags": ["featured", "documentation"] }, { diff --git a/resources/linting.json b/resources/linting.json index a73cea59..78578f94 100644 --- a/resources/linting.json +++ b/resources/linting.json @@ -48,11 +48,11 @@ "phive-install": { "alias": "j13k/yaml-lint", "bin": "%target-dir%/yaml-lint", - "sig": "985E1E22802973B2" + "sig": "38A182AB413064D7" } }, "test": "yaml-lint --version", - "tags": ["exclude-php:8.0", "linting"] + "tags": ["linting"] }, { "name": "twig-linter", @@ -67,6 +67,20 @@ }, "test": "twig-linter --help", "tags": ["linting"] + }, + { + "name": "gherkin-lint-php", + "summary": "Gherkin linter for PHP", + "website": "https://github.com/dantleech/gherkin-lint-php", + "command": { + "composer-bin-plugin": { + "package": "dantleech/gherkin-lint", + "namespace": "gherkin-lint-php", + "links": {"%target-dir%/gherkinlint": "gherkinlint"} + } + }, + "test": "gherkinlint --help", + "tags": ["linting"] } ] } diff --git a/resources/metrics.json b/resources/metrics.json index e19e5c17..491427c2 100644 --- a/resources/metrics.json +++ b/resources/metrics.json @@ -43,6 +43,20 @@ }, "test": "phpmetrics --version", "tags": ["featured", "metrics"] + }, + { + "name": "lines", + "summary": "CLI tool for quick metrics of PHP projects", + "website": "https://github.com/tomasVotruba/lines", + "command": { + "composer-bin-plugin": { + "package": "tomasvotruba/lines", + "namespace": "lines", + "links": {"%target-dir%/lines": "lines"} + } + }, + "test": "lines --version", + "tags": ["metrics"] } ] } diff --git a/resources/phpstan.json b/resources/phpstan.json index 5dcf3c54..a8c3172b 100644 --- a/resources/phpstan.json +++ b/resources/phpstan.json @@ -118,19 +118,6 @@ "test": "composer global bin phpstan show phpstan/phpstan-webmozart-assert", "tags": ["phpstan"] }, - { - "name": "phpstan-exception-rules", - "summary": "PHPStan rules for checked and unchecked exceptions", - "website": "https://github.com/pepakriz/phpstan-exception-rules", - "command": { - "composer-bin-plugin": { - "package": "pepakriz/phpstan-exception-rules", - "namespace": "phpstan" - } - }, - "test": "composer global bin phpstan show pepakriz/phpstan-exception-rules", - "tags": ["phpstan"] - }, { "name": "phpat", "summary": "Easy to use architecture testing tool", diff --git a/resources/pre-installation.json b/resources/pre-installation.json index 374123cb..8fedc89f 100644 --- a/resources/pre-installation.json +++ b/resources/pre-installation.json @@ -18,11 +18,11 @@ "website": "https://phar.io/", "command": { "file-download": { - "url": "https://github.com/phar-io/phive/releases/download/0.15.2/phive-0.15.2.phar.asc", + "url": "https://github.com/phar-io/phive/releases/download/0.16.0/phive-0.16.0.phar.asc", "file": "%target-dir%/phive.asc" }, "phar-download": { - "phar": "https://github.com/phar-io/phive/releases/download/0.15.2/phive-0.15.2.phar", + "phar": "https://github.com/phar-io/phive/releases/download/0.16.0/phive-0.16.0.phar", "bin": "%target-dir%/phive" }, "sh": { @@ -59,7 +59,7 @@ } }, "test": "box list", - "tags": ["pre-installation", "exclude-php:8.0"] + "tags": ["pre-installation"] }, { "name": "box-3", diff --git a/resources/test.json b/resources/test.json index e17d64f9..10268fce 100644 --- a/resources/test.json +++ b/resources/test.json @@ -5,9 +5,10 @@ "summary": "Helps to test business expectations", "website": "http://behat.org/", "command": { - "phar-download": { - "phar": "https://github.com/Behat/Behat/releases/download/v3.13.0/behat.phar", - "bin": "%target-dir%/behat" + "composer-bin-plugin": { + "package": "behat/behat", + "namespace": "behat", + "links": {"%target-dir%/behat": "behat"} } }, "test": "behat --version", @@ -38,7 +39,7 @@ } }, "test": "infection --version", - "tags": ["featured", "test", "exclude-php:8.0"] + "tags": ["featured", "test"] }, { "name": "paratest", @@ -66,7 +67,7 @@ } }, "test": "phpcov -v", - "tags": ["exclude-php:8.0", "test"] + "tags": ["test", "exclude-php:8.2"] }, { "name": "php-fuzzer", @@ -92,7 +93,7 @@ } }, "test": "phpspec --version", - "tags": ["exclude-php:8.2", "featured", "test"] + "tags": ["featured", "test"] }, { "name": "phpunit", @@ -106,7 +107,35 @@ } }, "test": "phpunit --version", - "tags": ["exclude-php:8.0", "featured", "test"] + "tags": ["featured", "test", "exclude-php:8.2"] + }, + { + "name": "phpunit-11", + "summary": "The PHP testing framework (11.x version)", + "website": "https://phpunit.de/", + "command": { + "phive-install": { + "alias": "phpunit@^11.0", + "bin": "%target-dir%/phpunit-11", + "sig": "4AA394086372C20A" + } + }, + "test": "phpunit-11 --version", + "tags": ["test"] + }, + { + "name": "phpunit-10", + "summary": "The PHP testing framework (10.x version)", + "website": "https://phpunit.de/", + "command": { + "phive-install": { + "alias": "phpunit@^10.0", + "bin": "%target-dir%/phpunit-10", + "sig": "4AA394086372C20A" + } + }, + "test": "phpunit-10 --version", + "tags": ["test"] }, { "name": "phpunit-9", @@ -152,6 +181,20 @@ }, "test": "simple-phpunit --version", "tags": ["test"] + }, + { + "name": "kahlan", + "summary": "Kahlan is a full-featured Unit & BDD test framework a la RSpec/JSpec", + "website": "https://kahlan.github.io/docs/", + "command": { + "composer-bin-plugin": { + "package": "kahlan/kahlan", + "namespace": "kahlan", + "links": {"%target-dir%/kahlan": "kahlan"} + } + }, + "test": "kahlan --version", + "tags": ["test"] } ] } diff --git a/resources/tools.json b/resources/tools.json index b3a7f785..6a53f7f7 100644 --- a/resources/tools.json +++ b/resources/tools.json @@ -19,10 +19,9 @@ "summary": "Static Analysis Tool", "website": "https://github.com/phan/phan", "command": { - "phive-install": { - "alias": "phan", - "bin": "%target-dir%/phan", - "sig": "8101FB57DD8130F0" + "phar-download": { + "phar": "https://github.com/phan/phan/releases/latest/download/phan.phar", + "bin": "%target-dir%/phan" } }, "test": "phan -v", @@ -40,7 +39,7 @@ } }, "test": "phpbench -V", - "tags": ["exclude-php:8.0"] + "tags": [] }, { "name": "phpa", @@ -91,7 +90,7 @@ "phive-install": { "alias": "phpmd", "bin": "%target-dir%/phpmd", - "sig": "A4E55EA12C7C085C" + "sig": "9093F8B32E4815AA" } }, "test": "phpmd --version" diff --git a/src/Cli/Application.php b/src/Cli/Application.php index 8fd96087..8078230e 100644 --- a/src/Cli/Application.php +++ b/src/Cli/Application.php @@ -16,7 +16,7 @@ final class Application extends CliApplication { - private $serviceContainer; + private ServiceContainer $serviceContainer; public function __construct(string $version, ServiceContainer $serviceContainer) { @@ -27,7 +27,10 @@ public function __construct(string $version, ServiceContainer $serviceContainer) $this->setCommandLoader($this->createCommandLoader($serviceContainer)); } - public function doRun(InputInterface $input, OutputInterface $output) + /** + * @throws \Throwable + */ + public function doRun(InputInterface $input, OutputInterface $output): int { $this->serviceContainer->set(InputInterface::class, $input); $this->serviceContainer->set(OutputInterface::class, $output); diff --git a/src/Cli/Command/InstallCommand.php b/src/Cli/Command/InstallCommand.php index 18630365..6c5ab9e7 100644 --- a/src/Cli/Command/InstallCommand.php +++ b/src/Cli/Command/InstallCommand.php @@ -17,8 +17,8 @@ final class InstallCommand extends Command public const NAME = 'install'; - private $useCase; - private $runner; + private InstallTools $useCase; + private Runner $runner; public function __construct(InstallTools $useCase, Runner $runner) { @@ -28,7 +28,7 @@ public function __construct(InstallTools $useCase, Runner $runner) $this->runner = $runner; } - protected function configure() + protected function configure(): void { $this->setDescription('Installs tools'); $this->addOption('dry-run', null, InputOption::VALUE_NONE, 'Output the command without executing it'); @@ -37,7 +37,7 @@ protected function configure() $this->addOption('tag', 't', InputOption::VALUE_REQUIRED|InputOption::VALUE_IS_ARRAY, 'Tool tags to filter by', $this->defaultTag()); } - protected function execute(InputInterface $input, OutputInterface $output) + protected function execute(InputInterface $input, OutputInterface $output): int { return $this->runner->run(\call_user_func($this->useCase, new Filter($input->getOption('exclude-tag'), $input->getOption('tag')))); } diff --git a/src/Cli/Command/ListCommand.php b/src/Cli/Command/ListCommand.php index 9ee4f9ab..d29a35aa 100644 --- a/src/Cli/Command/ListCommand.php +++ b/src/Cli/Command/ListCommand.php @@ -18,7 +18,7 @@ final class ListCommand extends Command public const NAME = 'list-tools'; - private $listTools; + private ListTools $listTools; public function __construct(ListTools $listTools) { @@ -27,14 +27,14 @@ public function __construct(ListTools $listTools) $this->listTools = $listTools; } - protected function configure() + protected function configure(): void { $this->setDescription('Lists available tools'); $this->addOption('exclude-tag', 'e', InputOption::VALUE_REQUIRED|InputOption::VALUE_IS_ARRAY, 'Tool tags to exclude', $this->defaultExcludeTag()); $this->addOption('tag', 't', InputOption::VALUE_REQUIRED|InputOption::VALUE_IS_ARRAY, 'Tool tags to filter by', $this->defaultTag()); } - protected function execute(InputInterface $input, OutputInterface $output) + protected function execute(InputInterface $input, OutputInterface $output): int { $tools = \call_user_func($this->listTools, new Filter($input->getOption('exclude-tag'), $input->getOption('tag'))); diff --git a/src/Cli/Command/TestCommand.php b/src/Cli/Command/TestCommand.php index 5192b834..71169915 100644 --- a/src/Cli/Command/TestCommand.php +++ b/src/Cli/Command/TestCommand.php @@ -17,8 +17,8 @@ final class TestCommand extends Command public const NAME = 'test'; - private $useCase; - private $runner; + private TestTools $useCase; + private Runner $runner; public function __construct(TestTools $useCase, Runner $runner) { @@ -28,7 +28,7 @@ public function __construct(TestTools $useCase, Runner $runner) $this->runner = $runner; } - protected function configure() + protected function configure(): void { $this->setDescription('Runs basic tests to verify tools are installed'); $this->addOption('dry-run', null, InputOption::VALUE_NONE, 'Output the command without executing it'); @@ -37,7 +37,7 @@ protected function configure() $this->addOption('tag', 't', InputOption::VALUE_REQUIRED|InputOption::VALUE_IS_ARRAY, 'Tool tags to filter by', $this->defaultTag()); } - protected function execute(InputInterface $input, OutputInterface $output) + protected function execute(InputInterface $input, OutputInterface $output): int { return $this->runner->run(\call_user_func($this->useCase, new Filter($input->getOption('exclude-tag'), $input->getOption('tag')))); } diff --git a/src/Cli/Runner/DryRunner.php b/src/Cli/Runner/DryRunner.php index 244ca609..109fb508 100644 --- a/src/Cli/Runner/DryRunner.php +++ b/src/Cli/Runner/DryRunner.php @@ -8,7 +8,7 @@ final class DryRunner implements Runner { - private $output; + private OutputInterface $output; public function __construct(OutputInterface $output) { diff --git a/src/Cli/ServiceContainer.php b/src/Cli/ServiceContainer.php index 1cd3d9f5..655005fd 100644 --- a/src/Cli/ServiceContainer.php +++ b/src/Cli/ServiceContainer.php @@ -22,7 +22,7 @@ class ServiceContainer implements ContainerInterface { - private $services = [ + private array $services = [ InstallCommand::class => 'createInstallCommand', ListCommand::class => 'createListCommand', TestCommand::class => 'createTestCommand', @@ -33,7 +33,7 @@ class ServiceContainer implements ContainerInterface Tools::class => 'createTools', ]; - private $runtimeServices = [ + private array $runtimeServices = [ InputInterface::class => null, OutputInterface::class => null, ]; @@ -51,7 +51,7 @@ public function set(string $id, /*object */$service): void /** * {@inheritdoc} */ - public function get($id) + public function get(string $id) { if (isset($this->runtimeServices[$id])) { return $this->runtimeServices[$id]; @@ -68,21 +68,33 @@ public function get($id) /** * {@inheritdoc} */ - public function has($id) + public function has(string $id): bool { return isset($this->services[$id]) || isset($this->runtimeServices[$id]); } + /** + * @throws ContainerExceptionInterface + * @throws NotFoundExceptionInterface + */ private function createInstallCommand(): InstallCommand { return new InstallCommand($this->get(InstallTools::class), $this->get(Runner::class)); } + /** + * @throws ContainerExceptionInterface + * @throws NotFoundExceptionInterface + */ private function createListCommand(): ListCommand { return new ListCommand($this->get(ListTools::class)); } + /** + * @throws ContainerExceptionInterface + * @throws NotFoundExceptionInterface + */ private function createTestCommand(): TestCommand { return new TestCommand($this->get(TestTools::class), $this->get(Runner::class)); @@ -93,16 +105,28 @@ private function createRunner(): Runner return new LazyRunner(new RunnerFactory($this)); } + /** + * @throws ContainerExceptionInterface + * @throws NotFoundExceptionInterface + */ private function createInstallToolsUseCase(): InstallTools { return new InstallTools($this->get(Tools::class)); } + /** + * @throws ContainerExceptionInterface + * @throws NotFoundExceptionInterface + */ private function createListToolsUseCase(): ListTools { return new ListTools($this->get(Tools::class)); } + /** + * @throws ContainerExceptionInterface + * @throws NotFoundExceptionInterface + */ private function createTestToolsUseCase(): TestTools { return new TestTools($this->get(Tools::class)); diff --git a/src/Cli/ServiceContainer/LazyRunner.php b/src/Cli/ServiceContainer/LazyRunner.php index b2ce407a..8f49a285 100644 --- a/src/Cli/ServiceContainer/LazyRunner.php +++ b/src/Cli/ServiceContainer/LazyRunner.php @@ -2,25 +2,35 @@ namespace Zalas\Toolbox\Cli\ServiceContainer; +use Psr\Container\ContainerExceptionInterface; +use Psr\Container\NotFoundExceptionInterface; use Zalas\Toolbox\Runner\Runner; use Zalas\Toolbox\Tool\Command; final class LazyRunner implements Runner { - private $runner; + private ?Runner $runner = null; - private $factory; + private RunnerFactory $factory; public function __construct(RunnerFactory $factory) { $this->factory = $factory; } + /** + * @throws ContainerExceptionInterface + * @throws NotFoundExceptionInterface + */ public function run(Command $command): int { return $this->runner()->run($command); } + /** + * @throws ContainerExceptionInterface + * @throws NotFoundExceptionInterface + */ private function runner(): Runner { if (null === $this->runner) { diff --git a/src/Cli/ServiceContainer/RunnerFactory.php b/src/Cli/ServiceContainer/RunnerFactory.php index 225c2151..8056c420 100644 --- a/src/Cli/ServiceContainer/RunnerFactory.php +++ b/src/Cli/ServiceContainer/RunnerFactory.php @@ -4,6 +4,7 @@ use Psr\Container\ContainerExceptionInterface; use Psr\Container\ContainerInterface; +use Psr\Container\NotFoundExceptionInterface; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; use Zalas\Toolbox\Cli\Runner\DryRunner; @@ -13,13 +14,17 @@ class RunnerFactory { - private $container; + private ContainerInterface $container; public function __construct(ContainerInterface $container) { $this->container = $container; } + /** + * @throws ContainerExceptionInterface + * @throws NotFoundExceptionInterface + */ public function createRunner(): Runner { $runner = $this->createRealRunner(); @@ -32,9 +37,10 @@ public function createRunner(): Runner } /** - * @return DryRunner|PassthruRunner + * @throws ContainerExceptionInterface + * @throws NotFoundExceptionInterface */ - private function createRealRunner() + private function createRealRunner(): DryRunner|PassthruRunner { if ($this->container->get(InputInterface::class)->getOption('dry-run')) { return new DryRunner($this->container->get(OutputInterface::class)); @@ -43,6 +49,10 @@ private function createRealRunner() return new PassthruRunner(); } + /** + * @throws ContainerExceptionInterface + * @throws NotFoundExceptionInterface + */ private function parameters(): array { if ($targetDir = $this->targetDir()) { @@ -52,6 +62,10 @@ private function parameters(): array return []; } + /** + * @throws ContainerExceptionInterface + * @throws NotFoundExceptionInterface + */ private function targetDir(): ?string { if (!$this->container->get(InputInterface::class)->hasOption('target-dir')) { diff --git a/src/Json/Factory/Assert.php b/src/Json/Factory/Assert.php index 1ff0a1e6..105becfe 100644 --- a/src/Json/Factory/Assert.php +++ b/src/Json/Factory/Assert.php @@ -4,7 +4,7 @@ final class Assert { - public static function requireFields(array $fields, array $data, string $type) + public static function requireFields(array $fields, array $data, string $type): void { $missingFields = \array_filter($fields, function (string $field) use ($data) { return !isset($data[$field]); diff --git a/src/Json/JsonTools.php b/src/Json/JsonTools.php index c33f51fa..ad5ff1a4 100644 --- a/src/Json/JsonTools.php +++ b/src/Json/JsonTools.php @@ -7,7 +7,6 @@ use Zalas\Toolbox\Json\Factory\ToolFactory; use Zalas\Toolbox\Tool\Collection; use Zalas\Toolbox\Tool\Filter; -use Zalas\Toolbox\Tool\Tool; use Zalas\Toolbox\Tool\Tools; final class JsonTools implements Tools @@ -23,7 +22,8 @@ public function __construct(callable $resourceLocator) } /** - * @return Collection|Tool[] + * @param Filter $filter + * @return Collection */ public function all(Filter $filter): Collection { diff --git a/src/Runner/ParametrisedRunner.php b/src/Runner/ParametrisedRunner.php index 1f6ec049..b73a8f43 100644 --- a/src/Runner/ParametrisedRunner.php +++ b/src/Runner/ParametrisedRunner.php @@ -6,8 +6,8 @@ final class ParametrisedRunner implements Runner { - private $decoratedRunner; - private $parameters; + private Runner $decoratedRunner; + private array $parameters; public function __construct(Runner $decoratedRunner, array $parameters) { @@ -18,8 +18,8 @@ public function __construct(Runner $decoratedRunner, array $parameters) public function run(Command $command): int { return $this->decoratedRunner->run(new class($command, $this->parameters) implements Command { - private $command; - private $parameters; + private Command $command; + private array $parameters; public function __construct(Command $command, array $parameters) { diff --git a/src/Tool/Collection.php b/src/Tool/Collection.php index 0405da25..54939457 100644 --- a/src/Tool/Collection.php +++ b/src/Tool/Collection.php @@ -8,10 +8,7 @@ class Collection implements IteratorAggregate, Countable { - /** - * @var array - */ - private $elements; + private array $elements; private function __construct(array $elements) { diff --git a/src/Tool/Command/BoxBuildCommand.php b/src/Tool/Command/BoxBuildCommand.php index d2e0e8ce..547a4179 100644 --- a/src/Tool/Command/BoxBuildCommand.php +++ b/src/Tool/Command/BoxBuildCommand.php @@ -6,11 +6,11 @@ final class BoxBuildCommand implements Command { - private $repository; - private $phar; - private $bin; - private $workDir; - private $version; + private string $repository; + private string $phar; + private string $bin; + private string $workDir; + private ?string $version; public function __construct(string $repository, string $phar, string $bin, string $workDir, ?string $version = null) { diff --git a/src/Tool/Command/ComposerBinPluginCommand.php b/src/Tool/Command/ComposerBinPluginCommand.php index de66ceaa..0a2986c4 100644 --- a/src/Tool/Command/ComposerBinPluginCommand.php +++ b/src/Tool/Command/ComposerBinPluginCommand.php @@ -7,11 +7,11 @@ final class ComposerBinPluginCommand implements Command { - private $package; + private string $package; - private $namespace; + private string $namespace; - private $links; + private Collection $links; public function __construct(string $package, string $namespace, Collection $links) { diff --git a/src/Tool/Command/ComposerBinPluginLinkCommand.php b/src/Tool/Command/ComposerBinPluginLinkCommand.php index cb2cd99e..4587f526 100644 --- a/src/Tool/Command/ComposerBinPluginLinkCommand.php +++ b/src/Tool/Command/ComposerBinPluginLinkCommand.php @@ -6,9 +6,9 @@ final class ComposerBinPluginLinkCommand implements Command { - private $source; - private $target; - private $namespace; + private string $source; + private string $target; + private string $namespace; public function __construct(string $source, string $target, string $namespace) { diff --git a/src/Tool/Command/ComposerGlobalInstallCommand.php b/src/Tool/Command/ComposerGlobalInstallCommand.php index 1fef35c4..70f3bd7d 100644 --- a/src/Tool/Command/ComposerGlobalInstallCommand.php +++ b/src/Tool/Command/ComposerGlobalInstallCommand.php @@ -6,7 +6,7 @@ final class ComposerGlobalInstallCommand implements Command { - private $package; + private string $package; public function __construct(string $package) { diff --git a/src/Tool/Command/ComposerGlobalMultiInstallCommand.php b/src/Tool/Command/ComposerGlobalMultiInstallCommand.php index 1a2b1e70..7ee962f2 100644 --- a/src/Tool/Command/ComposerGlobalMultiInstallCommand.php +++ b/src/Tool/Command/ComposerGlobalMultiInstallCommand.php @@ -8,7 +8,7 @@ final class ComposerGlobalMultiInstallCommand implements Command { - private $commands; + private Collection $commands; public function __construct(Collection $commands) { diff --git a/src/Tool/Command/ComposerInstallCommand.php b/src/Tool/Command/ComposerInstallCommand.php index 519c04c7..74f0840c 100644 --- a/src/Tool/Command/ComposerInstallCommand.php +++ b/src/Tool/Command/ComposerInstallCommand.php @@ -6,9 +6,9 @@ final class ComposerInstallCommand implements Command { - private $repository; - private $targetDir; - private $version; + private string $repository; + private string $targetDir; + private ?string $version; public function __construct(string $repository, string $targetDir, ?string $version = null) { diff --git a/src/Tool/Command/FileDownloadCommand.php b/src/Tool/Command/FileDownloadCommand.php index 9b910f43..610b380b 100644 --- a/src/Tool/Command/FileDownloadCommand.php +++ b/src/Tool/Command/FileDownloadCommand.php @@ -6,8 +6,8 @@ final class FileDownloadCommand implements Command { - private $url; - private $file; + private string $url; + private string $file; public function __construct(string $url, string $file) { diff --git a/src/Tool/Command/MultiStepCommand.php b/src/Tool/Command/MultiStepCommand.php index 57631716..1ef8ddca 100644 --- a/src/Tool/Command/MultiStepCommand.php +++ b/src/Tool/Command/MultiStepCommand.php @@ -8,8 +8,8 @@ final class MultiStepCommand implements Command { - private $commands; - private $glue; + private Collection $commands; + private mixed $glue; public function __construct(Collection $commands, $glue = ' && ') { diff --git a/src/Tool/Command/OptimisedComposerBinPluginCommand.php b/src/Tool/Command/OptimisedComposerBinPluginCommand.php index e7d0c62a..78d23dc5 100644 --- a/src/Tool/Command/OptimisedComposerBinPluginCommand.php +++ b/src/Tool/Command/OptimisedComposerBinPluginCommand.php @@ -8,7 +8,7 @@ final class OptimisedComposerBinPluginCommand implements Command { - private $commands; + private Collection $commands; public function __construct(Collection $commands) { diff --git a/src/Tool/Command/PharDownloadCommand.php b/src/Tool/Command/PharDownloadCommand.php index 80375416..92a35323 100644 --- a/src/Tool/Command/PharDownloadCommand.php +++ b/src/Tool/Command/PharDownloadCommand.php @@ -6,8 +6,8 @@ final class PharDownloadCommand implements Command { - private $phar; - private $bin; + private string $phar; + private string $bin; public function __construct(string $phar, string $bin) { diff --git a/src/Tool/Command/PhiveInstallCommand.php b/src/Tool/Command/PhiveInstallCommand.php index 790cad0f..e0dbf448 100644 --- a/src/Tool/Command/PhiveInstallCommand.php +++ b/src/Tool/Command/PhiveInstallCommand.php @@ -6,9 +6,9 @@ final class PhiveInstallCommand implements Command { - private $alias; - private $bin; - private $sig; + private string $alias; + private string $bin; + private ?string $sig; public function __construct(string $alias, string $bin, ?string $sig = null) { diff --git a/src/Tool/Command/ShCommand.php b/src/Tool/Command/ShCommand.php index f2b058e5..0e8acc5d 100644 --- a/src/Tool/Command/ShCommand.php +++ b/src/Tool/Command/ShCommand.php @@ -6,7 +6,7 @@ final class ShCommand implements Command { - private $command; + private string $command; public function __construct(string $command) { diff --git a/src/Tool/Command/TestCommand.php b/src/Tool/Command/TestCommand.php index 2c539b9d..bc2fb1a0 100644 --- a/src/Tool/Command/TestCommand.php +++ b/src/Tool/Command/TestCommand.php @@ -6,8 +6,8 @@ final class TestCommand implements Command { - private $command; - private $name; + private string $command; + private string $name; public function __construct(string $command, string $name) { @@ -17,6 +17,6 @@ public function __construct(string $command, string $name) public function __toString(): string { - return \sprintf('((%s > /dev/null && echo -e "\e[0;32m✔\e[0m︎%s") || (echo -e "\e[1;31m✘\e[0m%s" && false))', $this->command, $this->name, $this->name); + return \sprintf('(output=$(%s 2>&1) && echo -e "\e[0;32m✔\e[0m︎%s" || (echo -e "\e[1;31m✘\e[0m%s\n$output" && false))', $this->command, $this->name, $this->name); } } diff --git a/src/Tool/Filter.php b/src/Tool/Filter.php index afcbcb67..84341616 100644 --- a/src/Tool/Filter.php +++ b/src/Tool/Filter.php @@ -7,12 +7,12 @@ class Filter /** * @var string[] */ - private $excludedTags; + private array $excludedTags; /** * @var string[] */ - private $tags; + private array $tags; /** * @param string[] $excludedTags diff --git a/src/Tool/Tool.php b/src/Tool/Tool.php index d7033b3e..b1b019ae 100644 --- a/src/Tool/Tool.php +++ b/src/Tool/Tool.php @@ -4,12 +4,12 @@ class Tool { - private $name; - private $summary; - private $website; - private $command; - private $testCommand; - private $tags; + private string $name; + private string $summary; + private string $website; + private Command $command; + private Command $testCommand; + private array $tags; public function __construct(string $name, string $summary, string $website, array $tags, Command $command, Command $testCommand) { diff --git a/src/Tool/Tools.php b/src/Tool/Tools.php index 99b5d15f..eb38e49f 100644 --- a/src/Tool/Tools.php +++ b/src/Tool/Tools.php @@ -7,7 +7,8 @@ interface Tools { /** - * @return Collection|Tool[] + * @param Filter $filter + * @return Collection * @throws RuntimeException in case tools cannot be loaded */ public function all(Filter $filter): Collection; diff --git a/src/UseCase/InstallTools.php b/src/UseCase/InstallTools.php index 5b49fe64..4fdf7071 100644 --- a/src/UseCase/InstallTools.php +++ b/src/UseCase/InstallTools.php @@ -24,7 +24,7 @@ class InstallTools { public const PRE_INSTALLATION_TAG = 'pre-installation'; - private $tools; + private Tools $tools; public function __construct(Tools $tools) { @@ -60,7 +60,7 @@ private function commandFilter(Collection $commands): Closure }; } - private function installationCommands(Collection $tools) + private function installationCommands(Collection $tools): Collection { return $tools->filter(function (Tool $tool) { return \in_array(self::PRE_INSTALLATION_TAG, $tool->tags()); @@ -69,7 +69,7 @@ private function installationCommands(Collection $tools) }); } - private function toolCommands(Collection $tools) + private function toolCommands(Collection $tools): Collection { return $tools->filter(function (Tool $tool) { return !\in_array(self::PRE_INSTALLATION_TAG, $tool->tags()); diff --git a/src/UseCase/ListTools.php b/src/UseCase/ListTools.php index 04f1ab93..7f761c52 100644 --- a/src/UseCase/ListTools.php +++ b/src/UseCase/ListTools.php @@ -4,24 +4,17 @@ use Zalas\Toolbox\Tool\Collection; use Zalas\Toolbox\Tool\Filter; -use Zalas\Toolbox\Tool\Tool; use Zalas\Toolbox\Tool\Tools; class ListTools { - /** - * @var Tools - */ - private $tools; + private Tools $tools; public function __construct(Tools $tools) { $this->tools = $tools; } - /** - * @return Collection|Tool[] - */ public function __invoke(Filter $filter): Collection { return $this->tools->all($filter); diff --git a/src/UseCase/TestTools.php b/src/UseCase/TestTools.php index 4c255bbe..64681137 100644 --- a/src/UseCase/TestTools.php +++ b/src/UseCase/TestTools.php @@ -10,7 +10,7 @@ class TestTools { - private $tools; + private Tools $tools; public function __construct(Tools $tools) { diff --git a/tests/Cli/ApplicationTest.php b/tests/Cli/ApplicationTest.php index e5ed3960..a880c033 100644 --- a/tests/Cli/ApplicationTest.php +++ b/tests/Cli/ApplicationTest.php @@ -3,13 +3,11 @@ namespace Zalas\Toolbox\Tests\Cli; use PHPUnit\Framework\TestCase; -use Prophecy\Argument; -use Prophecy\PhpUnit\ProphecyTrait; -use Prophecy\Prophecy\ObjectProphecy; use Symfony\Component\Console\Application as CliApplication; use Symfony\Component\Console\Input\ArrayInput; use Symfony\Component\Console\Output\NullOutput; use Symfony\Component\Console\Output\OutputInterface; +use Zalas\PHPUnit\Globals\Attribute\Putenv; use Zalas\Toolbox\Cli\Application; use Zalas\Toolbox\Cli\Command\InstallCommand; use Zalas\Toolbox\Cli\Command\ListCommand; @@ -17,24 +15,14 @@ class ApplicationTest extends TestCase { - use ProphecyTrait; - private const VERSION = 'test'; - /** - * @var Application - */ - private $app; - - /** - * @var ServiceContainer|ObjectProphecy - */ - private $container; + private Application $app; protected function setUp(): void { - $this->container = $this->prophesize(ServiceContainer::class); - $this->app = new Application(self::VERSION, $this->container->reveal()); + $container = $this->createStub(ServiceContainer::class); + $this->app = new Application(self::VERSION, $container); } public function test_it_is_a_cli_application() @@ -74,17 +62,13 @@ public function test_it_defines_tools_option() ); } - /** - * @putenv TOOLBOX_JSON=resources/pre.json,resources/tools.json - */ + #[Putenv('TOOLBOX_JSON', 'resources/pre.json,resources/tools.json')] public function test_it_takes_the_tools_option_default_from_environment_if_present() { $this->assertSame(['resources/pre.json', 'resources/tools.json'], $this->app->getDefinition()->getOption('tools')->getDefault()); } - /** - * @putenv TOOLBOX_JSON=resources/pre.json , resources/tools.json - */ + #[Putenv('TOOLBOX_JSON', 'resources/pre.json , resources/tools.json')] public function test_it_trims_the_tools_option() { $this->assertSame(['resources/pre.json', 'resources/tools.json'], $this->app->getDefinition()->getOption('tools')->getDefault()); @@ -113,7 +97,7 @@ public function test_it_allows_to_override_tools_location() */ public function test_it_runs_the_command_in_dry_run_mode() { - $output = $this->prophesize(OutputInterface::class); + $output = $this->givenOutputThatExpectsMessageWritten('composer global bin phpstan require'); $app = new Application(self::VERSION, new ServiceContainer()); $app->doRun( @@ -123,12 +107,17 @@ public function test_it_runs_the_command_in_dry_run_mode() '--tools' => [__DIR__.'/../resources/tools.json'], '--no-interaction' => true, ]), - $output->reveal() + $output ); + } + + public function givenOutputThatExpectsMessageWritten(string $message): OutputInterface + { + $output = $this->createMock(OutputInterface::class); + $output->expects(self::once()) + ->method('writeln') + ->with(self::stringContains($message)); - $output->writeln(Argument::allOf( - Argument::type('string'), - Argument::containingString('composer global bin phpstan require') - ))->shouldHaveBeenCalled(); + return $output; } } diff --git a/tests/Cli/Command/InstallCommandTest.php b/tests/Cli/Command/InstallCommandTest.php index 20c8b20a..2081e852 100644 --- a/tests/Cli/Command/InstallCommandTest.php +++ b/tests/Cli/Command/InstallCommandTest.php @@ -2,35 +2,27 @@ namespace Zalas\Toolbox\Tests\Cli\Command; -use Prophecy\Argument; -use Prophecy\PhpUnit\ProphecyTrait; -use Prophecy\Prophecy\ObjectProphecy; +use PHPUnit\Framework\MockObject\Stub; +use Zalas\PHPUnit\Globals\Attribute\Putenv; use Zalas\Toolbox\Cli\Command\InstallCommand; use Zalas\Toolbox\Runner\Runner; use Zalas\Toolbox\Tool\Command; +use Zalas\Toolbox\Tool\Command\ShCommand; use Zalas\Toolbox\Tool\Filter; use Zalas\Toolbox\UseCase\InstallTools; class InstallCommandTest extends ToolboxCommandTestCase { - use ProphecyTrait; - protected const CLI_COMMAND_NAME = InstallCommand::NAME; - /** - * @var Runner|ObjectProphecy - */ - private $runner; + private Runner|Stub $runner; - /** - * @var InstallTools|ObjectProphecy - */ - private $useCase; + private InstallTools|Stub $useCase; protected function setUp(): void { - $this->runner = $this->prophesize(Runner::class); - $this->useCase = $this->prophesize(InstallTools::class); + $this->runner = $this->createStub(Runner::class); + $this->useCase = $this->createStub(InstallTools::class); parent::setUp(); } @@ -38,20 +30,18 @@ protected function setUp(): void public function test_it_runs_the_install_tools_use_case() { $command = $this->createCommand(); - $this->useCase->__invoke(Argument::type(Filter::class))->willReturn($command); - $this->runner->run($command)->willReturn(0); + $this->useCase->method('__invoke')->willReturn($command); + $this->runner->method('run')->with($command)->willReturn(0); $tester = $this->executeCliCommand(); - $this->runner->run($command)->shouldHaveBeenCalled(); - $this->assertSame(0, $tester->getStatusCode()); } public function test_it_returns_the_status_code_of_the_run() { - $this->useCase->__invoke(Argument::type(Filter::class))->willReturn($this->createCommand()); - $this->runner->run(Argument::any())->willReturn(1); + $this->useCase->method('__invoke')->willReturn($this->createCommand()); + $this->runner->method('run')->willReturn(1); $tester = $this->executeCliCommand(); @@ -60,12 +50,15 @@ public function test_it_returns_the_status_code_of_the_run() public function test_it_filters_by_tags() { - $this->useCase->__invoke(Argument::type(Filter::class))->willReturn($this->createCommand()); - $this->runner->run(Argument::any())->willReturn(0); + $this->useCase + ->method('__invoke') + ->with(new Filter(['foo'], ['bar'])) + ->willReturn($this->createCommand()); + $this->runner->method('run')->willReturn(0); - $this->executeCliCommand(['--exclude-tag' => ['foo'], '--tag' => ['bar']]); + $tester = $this->executeCliCommand(['--exclude-tag' => ['foo'], '--tag' => ['bar']]); - $this->useCase->__invoke(new Filter(['foo'], ['bar']))->shouldBeCalled(); + $this->assertSame(0, $tester->getStatusCode()); } public function test_it_defines_dry_run_option() @@ -79,9 +72,7 @@ public function test_it_defines_target_dir_option() $this->assertSame('/usr/local/bin', $this->cliCommand()->getDefinition()->getOption('target-dir')->getDefault()); } - /** - * @putenv TOOLBOX_TARGET_DIR=/tmp - */ + #[Putenv('TOOLBOX_TARGET_DIR', '/tmp')] public function test_it_takes_the_target_dir_option_default_from_environment_if_present() { $this->assertSame('/tmp', $this->cliCommand()->getDefinition()->getOption('target-dir')->getDefault()); @@ -93,9 +84,7 @@ public function test_it_defines_exclude_tag_option() $this->assertSame([], $this->cliCommand()->getDefinition()->getOption('exclude-tag')->getDefault()); } - /** - * @putenv TOOLBOX_EXCLUDED_TAGS=foo,bar,baz - */ + #[Putenv('TOOLBOX_EXCLUDED_TAGS', 'foo,bar,baz')] public function test_it_takes_the_excluded_tag_option_default_from_environment_if_present() { $this->assertSame(['foo', 'bar', 'baz'], $this->cliCommand()->getDefinition()->getOption('exclude-tag')->getDefault()); @@ -107,9 +96,7 @@ public function test_it_defines_tag_option() $this->assertSame([], $this->cliCommand()->getDefinition()->getOption('tag')->getDefault()); } - /** - * @putenv TOOLBOX_TAGS=foo,bar,baz - */ + #[Putenv('TOOLBOX_TAGS', 'foo,bar,baz')] public function test_it_takes_the_tag_option_default_from_environment_if_present() { $this->assertSame(['foo', 'bar', 'baz'], $this->cliCommand()->getDefinition()->getOption('tag')->getDefault()); @@ -118,16 +105,13 @@ public function test_it_takes_the_tag_option_default_from_environment_if_present protected function getContainerTestDoubles(): array { return [ - Runner::class => $this->runner->reveal(), - InstallTools::class => $this->useCase->reveal(), + Runner::class => $this->runner, + InstallTools::class => $this->useCase, ]; } private function createCommand(): Command { - $command = $this->prophesize(Command::class); - $command->__toString()->willReturn('echo "foo"'); - - return $command->reveal(); + return new ShCommand('echo "foo"'); } } diff --git a/tests/Cli/Command/ListCommandTest.php b/tests/Cli/Command/ListCommandTest.php index a45be286..8195b76c 100644 --- a/tests/Cli/Command/ListCommandTest.php +++ b/tests/Cli/Command/ListCommandTest.php @@ -2,36 +2,32 @@ namespace Zalas\Toolbox\Tests\Cli\Command; -use Prophecy\Argument; -use Prophecy\PhpUnit\ProphecyTrait; -use Prophecy\Prophecy\ObjectProphecy; +use PHPUnit\Framework\MockObject\Stub; +use Zalas\PHPUnit\Globals\Attribute\Putenv; use Zalas\Toolbox\Cli\Command\ListCommand; use Zalas\Toolbox\Tool\Collection; +use Zalas\Toolbox\Tool\Command\ShCommand; +use Zalas\Toolbox\Tool\Command\TestCommand; use Zalas\Toolbox\Tool\Filter; use Zalas\Toolbox\Tool\Tool; use Zalas\Toolbox\UseCase\ListTools; class ListCommandTest extends ToolboxCommandTestCase { - use ProphecyTrait; - protected const CLI_COMMAND_NAME = ListCommand::NAME; - /** - * @var ListTools|ObjectProphecy - */ - private $useCase; + private ListTools|Stub $useCase; protected function setUp(): void { - $this->useCase = $this->prophesize(ListTools::class); + $this->useCase = $this->createStub(ListTools::class); parent::setUp(); } public function test_it_runs_the_list_tools_use_case() { - $this->useCase->__invoke(Argument::type(Filter::class))->willReturn(Collection::create([ + $this->useCase->method('__invoke')->willReturn(Collection::create([ $this->createTool('Behat', 'Tests business expectations', 'http://behat.org'), ])); @@ -44,13 +40,15 @@ public function test_it_runs_the_list_tools_use_case() public function test_it_filters_by_tags() { - $this->useCase->__invoke(Argument::type(Filter::class))->willReturn(Collection::create([ - $this->createTool('Behat', 'Tests business expectations', 'http://behat.org'), - ])); + $this->useCase->method('__invoke') + ->with(new Filter(['foo'], ['bar'])) + ->willReturn(Collection::create([ + $this->createTool('Behat', 'Tests business expectations', 'http://behat.org'), + ])); - $this->executeCliCommand(['--exclude-tag' => ['foo'], '--tag' => ['bar']]); + $tester = $this->executeCliCommand(['--exclude-tag' => ['foo'], '--tag' => ['bar']]); - $this->useCase->__invoke(new Filter(['foo'], ['bar']))->shouldHaveBeenCalled(); + $this->assertSame(0, $tester->getStatusCode()); } public function test_it_defines_exclude_tag_option() @@ -59,9 +57,7 @@ public function test_it_defines_exclude_tag_option() $this->assertSame([], $this->cliCommand()->getDefinition()->getOption('exclude-tag')->getDefault()); } - /** - * @putenv TOOLBOX_EXCLUDED_TAGS=foo,bar,baz - */ + #[Putenv('TOOLBOX_EXCLUDED_TAGS', 'foo,bar,baz')] public function test_it_takes_the_excluded_tag_option_default_from_environment_if_present() { $this->assertSame(['foo', 'bar', 'baz'], $this->cliCommand()->getDefinition()->getOption('exclude-tag')->getDefault()); @@ -72,9 +68,7 @@ public function test_it_defines_tag_option() $this->assertTrue($this->cliCommand()->getDefinition()->hasOption('tag')); } - /** - * @putenv TOOLBOX_TAGS=foo,bar,baz - */ + #[Putenv('TOOLBOX_TAGS', 'foo,bar,baz')] public function test_it_takes_the_tag_option_default_from_environment_if_present() { $this->assertSame(['foo', 'bar', 'baz'], $this->cliCommand()->getDefinition()->getOption('tag')->getDefault()); @@ -83,17 +77,19 @@ public function test_it_takes_the_tag_option_default_from_environment_if_present protected function getContainerTestDoubles(): array { return [ - ListTools::class => $this->useCase->reveal(), + ListTools::class => $this->useCase, ]; } private function createTool(string $name, string $summary, string $website): Tool { - $tool = $this->prophesize(Tool::class); - $tool->name()->willReturn($name); - $tool->summary()->willReturn($summary); - $tool->website()->willReturn($website); - - return $tool->reveal(); + return new Tool( + $name, + $summary, + $website, + [], + new ShCommand('any command'), + new TestCommand('any test command', 'any') + ); } } diff --git a/tests/Cli/Command/TestCommandTest.php b/tests/Cli/Command/TestCommandTest.php index 43ee76fc..1f8b5a2b 100644 --- a/tests/Cli/Command/TestCommandTest.php +++ b/tests/Cli/Command/TestCommandTest.php @@ -2,35 +2,27 @@ namespace Zalas\Toolbox\Tests\Cli\Command; -use Prophecy\Argument; -use Prophecy\PhpUnit\ProphecyTrait; -use Prophecy\Prophecy\ObjectProphecy; +use PHPUnit\Framework\MockObject\Stub; +use Zalas\PHPUnit\Globals\Attribute\Putenv; use Zalas\Toolbox\Cli\Command\TestCommand; use Zalas\Toolbox\Runner\Runner; use Zalas\Toolbox\Tool\Command; +use Zalas\Toolbox\Tool\Command\ShCommand; use Zalas\Toolbox\Tool\Filter; use Zalas\Toolbox\UseCase\TestTools; class TestCommandTest extends ToolboxCommandTestCase { - use ProphecyTrait; - protected const CLI_COMMAND_NAME = TestCommand::NAME; - /** - * @var Runner|ObjectProphecy - */ - private $runner; + private Runner|Stub $runner; - /** - * @var TestTools|ObjectProphecy - */ - private $useCase; + private TestTools|Stub $useCase; protected function setUp(): void { - $this->runner = $this->prophesize(Runner::class); - $this->useCase = $this->prophesize(TestTools::class); + $this->runner = $this->createStub(Runner::class); + $this->useCase = $this->createStub(TestTools::class); parent::setUp(); } @@ -38,20 +30,18 @@ protected function setUp(): void public function test_it_runs_the_test_tools_use_case() { $command = $this->createCommand(); - $this->useCase->__invoke(Argument::type(Filter::class))->willReturn($command); - $this->runner->run($command)->willReturn(0); + $this->useCase->method('__invoke')->willReturn($command); + $this->runner->method('run')->with($command)->willReturn(0); $tester = $this->executeCliCommand(); - $this->runner->run($command)->shouldHaveBeenCalled(); - $this->assertSame(0, $tester->getStatusCode()); } public function test_it_returns_the_status_code_of_the_run() { - $this->useCase->__invoke(Argument::type(Filter::class))->willReturn($this->createCommand()); - $this->runner->run(Argument::any())->willReturn(1); + $this->useCase->method('__invoke')->willReturn($this->createCommand()); + $this->runner->method('run')->willReturn(1); $tester = $this->executeCliCommand(); @@ -60,12 +50,12 @@ public function test_it_returns_the_status_code_of_the_run() public function test_it_filters_by_tags() { - $this->useCase->__invoke(Argument::type(Filter::class))->willReturn($this->createCommand()); - $this->runner->run(Argument::any())->willReturn(0); + $this->useCase->method('__invoke')->with(new Filter(['foo'], ['bar']))->willReturn($this->createCommand()); + $this->runner->method('run')->willReturn(0); - $this->executeCliCommand(['--exclude-tag' => ['foo'], '--tag' => ['bar']]); + $tester = $this->executeCliCommand(['--exclude-tag' => ['foo'], '--tag' => ['bar']]); - $this->useCase->__invoke(new Filter(['foo'], ['bar']))->shouldBeCalled(); + $this->assertSame(0, $tester->getStatusCode()); } public function test_it_defines_dry_run_option() @@ -79,9 +69,7 @@ public function test_it_defines_target_dir_option() $this->assertTrue($this->cliCommand()->getDefinition()->hasOption('target-dir')); } - /** - * @putenv TOOLBOX_TARGET_DIR=/tmp - */ + #[Putenv('TOOLBOX_TARGET_DIR', '/tmp')] public function test_it_takes_the_target_dir_option_default_from_environment_if_present() { $this->assertSame('/tmp', $this->cliCommand()->getDefinition()->getOption('target-dir')->getDefault()); @@ -93,9 +81,7 @@ public function test_it_defines_exclude_tag_option() $this->assertSame([], $this->cliCommand()->getDefinition()->getOption('exclude-tag')->getDefault()); } - /** - * @putenv TOOLBOX_EXCLUDED_TAGS=foo,bar,baz - */ + #[Putenv('TOOLBOX_EXCLUDED_TAGS', 'foo,bar,baz')] public function test_it_takes_the_excluded_tag_option_default_from_environment_if_present() { $this->assertSame(['foo', 'bar', 'baz'], $this->cliCommand()->getDefinition()->getOption('exclude-tag')->getDefault()); @@ -106,9 +92,7 @@ public function test_it_defines_tag_option() $this->assertTrue($this->cliCommand()->getDefinition()->hasOption('tag')); } - /** - * @putenv TOOLBOX_TAGS=foo,bar,baz - */ + #[Putenv('TOOLBOX_TAGS', 'foo,bar,baz')] public function test_it_takes_the_tag_option_default_from_environment_if_present() { $this->assertSame(['foo', 'bar', 'baz'], $this->cliCommand()->getDefinition()->getOption('tag')->getDefault()); @@ -117,16 +101,13 @@ public function test_it_takes_the_tag_option_default_from_environment_if_present protected function getContainerTestDoubles(): array { return [ - Runner::class => $this->runner->reveal(), - TestTools::class => $this->useCase->reveal(), + Runner::class => $this->runner, + TestTools::class => $this->useCase, ]; } private function createCommand(): Command { - $command = $this->prophesize(Command::class); - $command->__toString()->willReturn('true'); - - return $command->reveal(); + return new ShCommand('true'); } } diff --git a/tests/Cli/Command/ToolboxCommandTestCase.php b/tests/Cli/Command/ToolboxCommandTestCase.php index b186549c..0b1b24cf 100644 --- a/tests/Cli/Command/ToolboxCommandTestCase.php +++ b/tests/Cli/Command/ToolboxCommandTestCase.php @@ -12,10 +12,7 @@ abstract class ToolboxCommandTestCase extends TestCase { protected const CLI_COMMAND_NAME = ''; - /** - * @var Application - */ - protected $app; + protected Application $app; protected function setUp(): void { @@ -48,7 +45,7 @@ protected function cliCommand(): Command private function createServiceContainer(): ServiceContainer { return new class($this->getContainerTestDoubles()) extends ServiceContainer { - private $services; + private array $services; public function __construct(array $services) { diff --git a/tests/Cli/Runner/DryRunnerTest.php b/tests/Cli/Runner/DryRunnerTest.php index a0f20a4f..719a8730 100644 --- a/tests/Cli/Runner/DryRunnerTest.php +++ b/tests/Cli/Runner/DryRunnerTest.php @@ -2,9 +2,8 @@ namespace Zalas\Toolbox\Tests\Cli\Runner; +use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; -use Prophecy\PhpUnit\ProphecyTrait; -use Prophecy\Prophecy\ObjectProphecy; use Symfony\Component\Console\Output\OutputInterface; use Zalas\Toolbox\Cli\Runner\DryRunner; use Zalas\Toolbox\Runner\Runner; @@ -12,22 +11,14 @@ class DryRunnerTest extends TestCase { - use ProphecyTrait; + private DryRunner $runner; - /** - * @var DryRunner - */ - private $runner; - - /** - * @var OutputInterface|ObjectProphecy - */ - private $out; + private OutputInterface|MockObject $out; protected function setUp(): void { - $this->out = $this->prophesize(OutputInterface::class); - $this->runner = new DryRunner($this->out->reveal()); + $this->out = $this->createMock(OutputInterface::class); + $this->runner = new DryRunner($this->out); } public function test_it_is_a_runner() @@ -37,6 +28,10 @@ public function test_it_is_a_runner() public function test_it_sends_the_command_to_the_output() { + $this->out->expects(self::once()) + ->method('writeln') + ->with('echo "Foo"'); + $result = $this->runner->run(new class implements Command { public function __toString(): string { @@ -44,8 +39,6 @@ public function __toString(): string } }); - $this->out->writeln('echo "Foo"')->shouldHaveBeenCalled(); - $this->assertSame(0, $result); } } diff --git a/tests/Cli/ServiceContainer/LazyRunnerTest.php b/tests/Cli/ServiceContainer/LazyRunnerTest.php index 6c533735..de7dd73a 100644 --- a/tests/Cli/ServiceContainer/LazyRunnerTest.php +++ b/tests/Cli/ServiceContainer/LazyRunnerTest.php @@ -2,9 +2,8 @@ namespace Zalas\Toolbox\Tests\Cli\ServiceContainer; +use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; -use Prophecy\PhpUnit\ProphecyTrait; -use Prophecy\Prophecy\ObjectProphecy; use Zalas\Toolbox\Cli\ServiceContainer\LazyRunner; use Zalas\Toolbox\Cli\ServiceContainer\RunnerFactory; use Zalas\Toolbox\Runner\Runner; @@ -12,59 +11,62 @@ class LazyRunnerTest extends TestCase { - use ProphecyTrait; + private LazyRunner $lazyRunner; - /** - * @var LazyRunner - */ - private $runner; - - /** - * @var RunnerFactory|ObjectProphecy - */ - private $factory; + private RunnerFactory|MockObject $factory; protected function setUp(): void { - $this->factory = $this->prophesize(RunnerFactory::class); + $this->factory = $this->createMock(RunnerFactory::class); - $this->runner = new LazyRunner($this->factory->reveal()); + $this->lazyRunner = new LazyRunner($this->factory); } public function test_it_is_a_runner() { - $this->assertInstanceOf(Runner::class, $this->runner); + $this->assertInstanceOf(Runner::class, $this->lazyRunner); } public function test_it_returns_status_code_of_returned_by_the_created_runner() { $command = $this->command(); - $runner = $this->prophesize(Runner::class); - $runner->run($command)->willReturn(1); - - $this->factory->createRunner()->willReturn($runner); + $runner = $this->givenRunner(command: $command, result: 1); + $this->givenFactoryCreates($runner); - $this->assertSame(1, $this->runner->run($command)); + $this->assertSame(1, $this->lazyRunner->run($command)); } public function test_it_only_initializes_the_runner_once() { $command = $this->command(); - $runner = $this->prophesize(Runner::class); - $runner->run($command)->willReturn(0); + $runner = $this->givenRunner($command, 0); - $this->factory->createRunner()->willReturn($runner); + $this->factory + ->expects(self::once()) + ->method('createRunner') + ->willReturn($runner); + + $this->lazyRunner->run($command); + $this->lazyRunner->run($command); + } - $this->runner->run($command); - $this->runner->run($command); + public function givenRunner(Command $command, int $result): Runner + { + $runner = $this->createStub(Runner::class); + $runner->method('run')->with($command)->willReturn($result); - $this->factory->createRunner()->shouldHaveBeenCalledTimes(1); + return $runner; } private function command(): Command { - return $this->prophesize(Command::class)->reveal(); + return new Command\ShCommand('any command'); + } + + private function givenFactoryCreates(Runner $runner): void + { + $this->factory->method('createRunner')->willReturn($runner); } } diff --git a/tests/Cli/ServiceContainer/RunnerFactoryTest.php b/tests/Cli/ServiceContainer/RunnerFactoryTest.php index 0d415504..27e75d6c 100644 --- a/tests/Cli/ServiceContainer/RunnerFactoryTest.php +++ b/tests/Cli/ServiceContainer/RunnerFactoryTest.php @@ -2,12 +2,14 @@ namespace Zalas\Toolbox\Tests\Cli\ServiceContainer; +use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; -use Prophecy\PhpUnit\ProphecyTrait; -use Prophecy\Prophecy\ObjectProphecy; use Psr\Container\ContainerExceptionInterface; use Psr\Container\ContainerInterface; +use Symfony\Component\Console\Input\ArrayInput; +use Symfony\Component\Console\Input\InputDefinition; use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; use Zalas\Toolbox\Cli\Runner\DryRunner; use Zalas\Toolbox\Cli\ServiceContainer\RunnerFactory; @@ -17,40 +19,35 @@ class RunnerFactoryTest extends TestCase { - use ProphecyTrait; + private RunnerFactory $runnerFactory; - /** - * @var ContainerInterface|ObjectProphecy - */ - private $container; + private InputInterface $input; - /** - * @var RunnerFactory - */ - private $runnerFactory; - - /** - * @var InputInterface|ObjectProphecy - */ - private $input; - - /** - * @var OutputInterface|ObjectProphecy - */ - private $output; + private OutputInterface|MockObject $output; protected function setUp(): void { - $this->container = $this->prophesize(ContainerInterface::class); - $this->input = $this->prophesize(InputInterface::class); - $this->output = $this->prophesize(OutputInterface::class); + $this->input = $this->givenInput([]); + $this->output = $this->createMock(OutputInterface::class); + + $container = new class([ InputInterface::class => &$this->input, OutputInterface::class => &$this->output, ]) implements ContainerInterface { - $this->container->get(InputInterface::class)->willReturn($this->input); - $this->container->get(OutputInterface::class)->willReturn($this->output); - $this->input->getOption('dry-run')->willReturn(false); - $this->input->hasOption('target-dir')->willReturn(false); + public function __construct(private readonly array $services) + { + } - $this->runnerFactory = new RunnerFactory($this->container->reveal()); + public function get(string $id) + { + return $this->services[$id]; + } + + public function has(string $id): bool + { + return isset($this->services[$id]); + } + }; + + $this->runnerFactory = new RunnerFactory($container); } public function test_it_creates_the_passthru_runner_by_default() @@ -62,7 +59,7 @@ public function test_it_creates_the_passthru_runner_by_default() public function test_it_creates_the_dry_runner_if_dry_run_option_is_passed() { - $this->input->getOption('dry-run')->willReturn(true); + $this->givenInput(['--dry-run' => true]); $runner = $this->runnerFactory->createRunner(); @@ -71,8 +68,7 @@ public function test_it_creates_the_dry_runner_if_dry_run_option_is_passed() public function test_it_creates_the_parametrised_runner_if_target_dir_option_is_present() { - $this->input->hasOption('target-dir')->willReturn(true); - $this->input->getOption('target-dir')->willReturn('/usr/local/bin'); + $this->givenInput(['--target-dir' => '/usr/local/bin']); $runner = $this->runnerFactory->createRunner(); @@ -81,9 +77,9 @@ public function test_it_creates_the_parametrised_runner_if_target_dir_option_is_ public function test_the_parametrised_runner_includes_the_target_dir_parameter() { - $this->input->hasOption('target-dir')->willReturn(true); - $this->input->getOption('target-dir')->willReturn('/usr/local/bin'); - $this->input->getOption('dry-run')->willReturn(true); + $this->givenInput(['--target-dir' => '/usr/local/bin', '--dry-run' => true]); + + $this->output->expects(self::once())->method('writeln')->with('ls /usr/local/bin'); $runner = $this->runnerFactory->createRunner(); @@ -93,25 +89,22 @@ public function __toString(): string return 'ls %target-dir%'; } }); - - $this->output->writeln('ls /usr/local/bin')->shouldHaveBeenCalled(); } public function test_it_throws_an_exception_if_target_dir_does_not_exist() { $this->expectException(ContainerExceptionInterface::class); - $this->input->hasOption('target-dir')->willReturn(true); - $this->input->getOption('target-dir')->willReturn('/foo/bar/baz'); + $this->givenInput(['--target-dir' => '/foo/bar/baz']); $this->runnerFactory->createRunner(); } public function test_it_uses_the_real_path_as_target_dir() { - $this->input->hasOption('target-dir')->willReturn(true); - $this->input->getOption('target-dir')->willReturn(__DIR__.'/../../../bin'); - $this->input->getOption('dry-run')->willReturn(true); + $this->givenInput(['--target-dir' => __DIR__.'/../../../bin', '--dry-run' => true]); + + $this->output->expects(self::once())->method('writeln')->with(\sprintf('ls %s', \realpath(__DIR__.'/../../../bin'))); $runner = $this->runnerFactory->createRunner(); $runner->run(new class implements Command { @@ -120,7 +113,15 @@ public function __toString(): string return 'ls %target-dir%'; } }); + } + + private function givenInput(array $parameters): InputInterface + { + $this->input = new ArrayInput($parameters, new InputDefinition(\array_filter([ + new InputOption('dry-run', null, InputOption::VALUE_NONE), + isset($parameters['--target-dir']) ? new InputOption('target-dir', null, InputOption::VALUE_REQUIRED) : null, + ]))); - $this->output->writeln(\sprintf('ls %s', \realpath(__DIR__.'/../../../bin')))->shouldHaveBeenCalled(); + return $this->input; } } diff --git a/tests/Cli/ServiceContainerTest.php b/tests/Cli/ServiceContainerTest.php index ff1f8030..0667fd23 100644 --- a/tests/Cli/ServiceContainerTest.php +++ b/tests/Cli/ServiceContainerTest.php @@ -2,8 +2,8 @@ namespace Zalas\Toolbox\Tests\Cli; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; -use Prophecy\PhpUnit\ProphecyTrait; use Psr\Container\ContainerExceptionInterface; use Psr\Container\ContainerInterface; use Psr\Container\NotFoundExceptionInterface; @@ -18,18 +18,13 @@ class ServiceContainerTest extends TestCase { - use ProphecyTrait; - - /** - * @var ServiceContainer - */ - private $container; + private ServiceContainer $container; protected function setUp(): void { $this->container = new ServiceContainer(); - $this->container->set(InputInterface::class, $this->prophesize(InputInterface::class)->reveal()); - $this->container->set(OutputInterface::class, $this->prophesize(OutputInterface::class)->reveal()); + $this->container->set(InputInterface::class, $this->createStub(InputInterface::class)); + $this->container->set(OutputInterface::class, $this->createStub(OutputInterface::class)); } public function test_it_is_a_psr_container() @@ -42,16 +37,14 @@ public function test_it_returns_false_if_service_is_not_registered() $this->assertFalse($this->container->has('foo')); } - /** - * @dataProvider provideApplicationServices - */ + #[DataProvider('provideApplicationServices')] public function test_it_creates_application_services(string $serviceId, string $expectedType) { $this->assertTrue($this->container->has($serviceId)); $this->assertInstanceOf($expectedType, $this->container->get($serviceId)); } - public function provideApplicationServices() + public static function provideApplicationServices(): \Generator { yield [InstallCommand::class, InstallCommand::class]; yield [ListCommand::class, ListCommand::class]; @@ -69,7 +62,7 @@ public function test_it_throws_an_exception_if_unregistered_service_is_accessed( public function test_it_registers_a_runtime_service() { - $service = $this->prophesize(InputInterface::class)->reveal(); + $service = $this->createStub(InputInterface::class); $this->container->set(InputInterface::class, $service); diff --git a/tests/Json/Factory/BoxBuildCommandFactoryTest.php b/tests/Json/Factory/BoxBuildCommandFactoryTest.php index d80f2bdc..5f1f9c96 100644 --- a/tests/Json/Factory/BoxBuildCommandFactoryTest.php +++ b/tests/Json/Factory/BoxBuildCommandFactoryTest.php @@ -2,6 +2,7 @@ namespace Zalas\Toolbox\Tests\Json\Factory; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; use Zalas\Toolbox\Json\Factory\BoxBuildCommandFactory; use Zalas\Toolbox\Tool\Command\BoxBuildCommand; @@ -40,9 +41,7 @@ public function test_the_version_is_not_required() $this->assertInstanceOf(BoxBuildCommand::class, $command); } - /** - * @dataProvider provideRequiredProperties - */ + #[DataProvider('provideRequiredProperties')] public function test_it_complains_if_any_of_required_properties_is_missing(string $property) { $this->expectException(\InvalidArgumentException::class); @@ -58,7 +57,7 @@ public function test_it_complains_if_any_of_required_properties_is_missing(strin BoxBuildCommandFactory::import($properties); } - public function provideRequiredProperties(): \Generator + public static function provideRequiredProperties(): \Generator { yield ['repository']; yield ['phar']; diff --git a/tests/Json/Factory/ComposerBinPluginCommandFactoryTest.php b/tests/Json/Factory/ComposerBinPluginCommandFactoryTest.php index 4d9d52b2..fdee673a 100644 --- a/tests/Json/Factory/ComposerBinPluginCommandFactoryTest.php +++ b/tests/Json/Factory/ComposerBinPluginCommandFactoryTest.php @@ -2,6 +2,7 @@ namespace Zalas\Toolbox\Tests\Json\Factory; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; use Zalas\Toolbox\Json\Factory\ComposerBinPluginCommandFactory; use Zalas\Toolbox\Tool\Collection; @@ -40,9 +41,7 @@ public function test_it_creates_a_command_with_links_in_tools() ); } - /** - * @dataProvider provideRequiredProperties - */ + #[DataProvider('provideRequiredProperties')] public function test_it_complains_if_any_of_required_properties_is_missing(string $property) { $this->expectException(\InvalidArgumentException::class); @@ -57,7 +56,7 @@ public function test_it_complains_if_any_of_required_properties_is_missing(strin ComposerBinPluginCommandFactory::import($properties); } - public function provideRequiredProperties(): \Generator + public static function provideRequiredProperties(): \Generator { yield ['package']; yield ['namespace']; diff --git a/tests/Json/Factory/ComposerInstallCommandFactoryTest.php b/tests/Json/Factory/ComposerInstallCommandFactoryTest.php index a9c93742..40470d62 100644 --- a/tests/Json/Factory/ComposerInstallCommandFactoryTest.php +++ b/tests/Json/Factory/ComposerInstallCommandFactoryTest.php @@ -2,6 +2,7 @@ namespace Zalas\Toolbox\Tests\Json\Factory; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; use Zalas\Toolbox\Json\Factory\ComposerInstallCommandFactory; use Zalas\Toolbox\Tool\Command\ComposerInstallCommand; @@ -24,9 +25,7 @@ public function test_it_creates_a_command() $this->assertMatchesRegularExpression('#git checkout '.self::VERSION.'#', (string) $command); } - /** - * @dataProvider provideRequiredProperties - */ + #[DataProvider('provideRequiredProperties')] public function test_it_complains_if_a_required_property_is_missing(string $property) { $this->expectException(\InvalidArgumentException::class); @@ -41,7 +40,7 @@ public function test_it_complains_if_a_required_property_is_missing(string $prop ComposerInstallCommandFactory::import($properties); } - public function provideRequiredProperties() + public static function provideRequiredProperties(): \Generator { yield ['repository']; yield ['target-dir']; diff --git a/tests/Json/Factory/FileDownloadCommandFactoryTest.php b/tests/Json/Factory/FileDownloadCommandFactoryTest.php index 6dd9ff28..6aa492c0 100644 --- a/tests/Json/Factory/FileDownloadCommandFactoryTest.php +++ b/tests/Json/Factory/FileDownloadCommandFactoryTest.php @@ -2,6 +2,7 @@ namespace Zalas\Toolbox\Tests\Json\Factory; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; use Zalas\Toolbox\Json\Factory\FileDownloadCommandFactory; use Zalas\Toolbox\Tool\Command\FileDownloadCommand; @@ -21,9 +22,7 @@ public function test_it_creates_a_command() $this->assertInstanceOf(FileDownloadCommand::class, $command); } - /** - * @dataProvider provideRequiredProperties - */ + #[DataProvider('provideRequiredProperties')] public function test_it_complains_if_any_of_required_properties_is_missing(string $property) { $this->expectException(\InvalidArgumentException::class); @@ -38,7 +37,7 @@ public function test_it_complains_if_any_of_required_properties_is_missing(strin FileDownloadCommandFactory::import($properties); } - public function provideRequiredProperties(): \Generator + public static function provideRequiredProperties(): \Generator { yield ['url']; yield ['file']; diff --git a/tests/Json/Factory/PharDownloadCommandFactoryTest.php b/tests/Json/Factory/PharDownloadCommandFactoryTest.php index 21ae9ae7..6b74a461 100644 --- a/tests/Json/Factory/PharDownloadCommandFactoryTest.php +++ b/tests/Json/Factory/PharDownloadCommandFactoryTest.php @@ -2,6 +2,7 @@ namespace Zalas\Toolbox\Tests\Json\Factory; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; use Zalas\Toolbox\Json\Factory\PharDownloadCommandFactory; use Zalas\Toolbox\Tool\Command\PharDownloadCommand; @@ -21,9 +22,7 @@ public function test_it_creates_a_command() $this->assertInstanceOf(PharDownloadCommand::class, $command); } - /** - * @dataProvider provideRequiredProperties - */ + #[DataProvider('provideRequiredProperties')] public function test_it_complains_if_any_of_required_properties_is_missing(string $property) { $this->expectException(\InvalidArgumentException::class); @@ -38,7 +37,7 @@ public function test_it_complains_if_any_of_required_properties_is_missing(strin PharDownloadCommandFactory::import($properties); } - public function provideRequiredProperties(): \Generator + public static function provideRequiredProperties(): \Generator { yield ['phar']; yield ['bin']; diff --git a/tests/Json/Factory/PhiveInstallCommandFactoryTest.php b/tests/Json/Factory/PhiveInstallCommandFactoryTest.php index 3ec413f6..5f48da00 100644 --- a/tests/Json/Factory/PhiveInstallCommandFactoryTest.php +++ b/tests/Json/Factory/PhiveInstallCommandFactoryTest.php @@ -2,6 +2,7 @@ namespace Zalas\Toolbox\Tests\Json\Factory; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; use Zalas\Toolbox\Json\Factory\PhiveInstallCommandFactory; use Zalas\Toolbox\Tool\Command\PhiveInstallCommand; @@ -24,9 +25,7 @@ public function test_it_creates_a_command() $this->assertStringNotContainsString('unsigned', (string)$command); } - /** - * @dataProvider provideRequiredProperties - */ + #[DataProvider('provideRequiredProperties')] public function test_it_complains_if_any_of_required_properties_is_missing(string $property) { $this->expectException(\InvalidArgumentException::class); @@ -53,7 +52,7 @@ public function test_it_accepts_unsigned_phars() $this->assertStringContainsString('unsigned', (string)$command); } - public function provideRequiredProperties(): \Generator + public static function provideRequiredProperties(): \Generator { yield ['alias']; yield ['bin']; diff --git a/tests/Json/Factory/ToolFactoryTest.php b/tests/Json/Factory/ToolFactoryTest.php index 42f0ce0b..b437579a 100644 --- a/tests/Json/Factory/ToolFactoryTest.php +++ b/tests/Json/Factory/ToolFactoryTest.php @@ -2,6 +2,7 @@ namespace Zalas\Toolbox\Tests\Json\Factory; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; use Zalas\Toolbox\Json\Factory\ToolFactory; use Zalas\Toolbox\Tool\Command; @@ -195,9 +196,7 @@ public function test_it_complains_if_the_command_is_empty() ToolFactory::import($this->definition(['command' => []])); } - /** - * @dataProvider provideRequiredProperties - */ + #[DataProvider('provideRequiredProperties')] public function test_it_complains_if_any_of_required_properties_is_missing(string $property) { $this->expectException(\InvalidArgumentException::class); @@ -209,7 +208,7 @@ public function test_it_complains_if_any_of_required_properties_is_missing(strin ToolFactory::import($properties); } - public function provideRequiredProperties(): \Generator + public static function provideRequiredProperties(): \Generator { yield ['name']; yield ['summary']; diff --git a/tests/Runner/ParametrisedRunnerTest.php b/tests/Runner/ParametrisedRunnerTest.php index 7d25f36f..17a11464 100644 --- a/tests/Runner/ParametrisedRunnerTest.php +++ b/tests/Runner/ParametrisedRunnerTest.php @@ -2,32 +2,23 @@ namespace Zalas\Toolbox\Tests\Runner; +use PHPUnit\Framework\MockObject\Stub; use PHPUnit\Framework\TestCase; -use Prophecy\Argument; -use Prophecy\PhpUnit\ProphecyTrait; -use Prophecy\Prophecy\ObjectProphecy; use Zalas\Toolbox\Runner\ParametrisedRunner; use Zalas\Toolbox\Runner\Runner; use Zalas\Toolbox\Tool\Command; +use Zalas\Toolbox\Tool\Command\ShCommand; class ParametrisedRunnerTest extends TestCase { - use ProphecyTrait; + private ParametrisedRunner $runner; - /** - * @var ParametrisedRunner - */ - private $runner; - - /** - * @var Runner|ObjectProphecy - */ - private $decoratedRunner; + private Runner|Stub $decoratedRunner; protected function setUp(): void { - $this->decoratedRunner = $this->prophesize(Runner::class); - $this->runner = new ParametrisedRunner($this->decoratedRunner->reveal(), ['%foo%' => 'ABC']); + $this->decoratedRunner = $this->createStub(Runner::class); + $this->runner = new ParametrisedRunner($this->decoratedRunner, ['%foo%' => 'ABC']); } public function test_it_is_a_runner() @@ -39,13 +30,15 @@ public function test_it_replaces_parameter_holders_in_the_command_before_running { $command = $this->command('echo "%foo%"'); - $this->decoratedRunner->run(Argument::that(function (Command $c) { - if ('echo "ABC"' !== $c->__toString()) { - throw new \RuntimeException(\sprintf('Expected `echo "ABC"`, but got `%s`.', $c->__toString())); - } + $this->decoratedRunner->method('run') + ->with(self::callback(function (Command $c) { + if ('echo "ABC"' !== $c->__toString()) { + throw new \RuntimeException(\sprintf('Expected `echo "ABC"`, but got `%s`.', $c->__toString())); + } - return true; - }))->willReturn(42); + return true; + })) + ->willReturn(42); $exitCode = $this->runner->run($command); @@ -54,9 +47,6 @@ public function test_it_replaces_parameter_holders_in_the_command_before_running private function command(string $commandString): Command { - $command = $this->prophesize(Command::class); - $command->__toString()->willReturn($commandString); - - return $command->reveal(); + return new ShCommand($commandString); } } diff --git a/tests/Tool/CollectionTest.php b/tests/Tool/CollectionTest.php index c524b4aa..48b24d3e 100644 --- a/tests/Tool/CollectionTest.php +++ b/tests/Tool/CollectionTest.php @@ -1,8 +1,9 @@ assertIterates(['ab', 'c', 'aa', 'aaa'], $c, 'The original collection is not modified'); } - private function assertIterates(array $elements, Collection $c) + private function assertIterates(array $elements, Collection $c, string $message = ''): void { - $this->assertSame($elements, \iterator_to_array($c)); + $this->assertSame($elements, \iterator_to_array($c), $message); } } diff --git a/tests/Tool/Command/ComposerBinPluginCommandTest.php b/tests/Tool/Command/ComposerBinPluginCommandTest.php index 4566939e..39d90946 100644 --- a/tests/Tool/Command/ComposerBinPluginCommandTest.php +++ b/tests/Tool/Command/ComposerBinPluginCommandTest.php @@ -13,10 +13,7 @@ class ComposerBinPluginCommandTest extends TestCase private const PACKAGE = 'phpstan/phpstan'; private const NAMESPACE = 'tools'; - /** - * @var ComposerBinPluginCommand - */ - private $command; + private ComposerBinPluginCommand $command; protected function setUp(): void { diff --git a/tests/Tool/Command/ComposerBinPluginLinkCommandTest.php b/tests/Tool/Command/ComposerBinPluginLinkCommandTest.php index d360d5c4..9ded7fc8 100644 --- a/tests/Tool/Command/ComposerBinPluginLinkCommandTest.php +++ b/tests/Tool/Command/ComposerBinPluginLinkCommandTest.php @@ -12,10 +12,7 @@ final class ComposerBinPluginLinkCommandTest extends TestCase private const TARGET = '/tools/churn'; private const NAMESPACE = 'tools'; - /** - * @var ComposerBinPluginLinkCommand - */ - private $command; + private ComposerBinPluginLinkCommand $command; protected function setUp(): void { diff --git a/tests/Tool/Command/ComposerGlobalInstallCommandTest.php b/tests/Tool/Command/ComposerGlobalInstallCommandTest.php index 748d17ee..33d5ace7 100644 --- a/tests/Tool/Command/ComposerGlobalInstallCommandTest.php +++ b/tests/Tool/Command/ComposerGlobalInstallCommandTest.php @@ -10,10 +10,7 @@ class ComposerGlobalInstallCommandTest extends TestCase { private const PACKAGE = 'phan/phan'; - /** - * @var ComposerGlobalInstallCommand - */ - private $command; + private ComposerGlobalInstallCommand $command; protected function setUp(): void { diff --git a/tests/Tool/Command/FileDownloadCommandTest.php b/tests/Tool/Command/FileDownloadCommandTest.php index a155f7d5..25a29421 100644 --- a/tests/Tool/Command/FileDownloadCommandTest.php +++ b/tests/Tool/Command/FileDownloadCommandTest.php @@ -11,10 +11,7 @@ class FileDownloadCommandTest extends TestCase private const URL = 'https://example.com/file'; private const FILE = '/usr/local/bin/file.txt'; - /** - * @var FileDownloadCommand - */ - private $command; + private FileDownloadCommand $command; protected function setUp(): void { diff --git a/tests/Tool/Command/MultiStepCommandTest.php b/tests/Tool/Command/MultiStepCommandTest.php index 14e06a11..ff9ef985 100644 --- a/tests/Tool/Command/MultiStepCommandTest.php +++ b/tests/Tool/Command/MultiStepCommandTest.php @@ -4,15 +4,13 @@ use InvalidArgumentException; use PHPUnit\Framework\TestCase; -use Prophecy\PhpUnit\ProphecyTrait; use Zalas\Toolbox\Tool\Collection; use Zalas\Toolbox\Tool\Command; use Zalas\Toolbox\Tool\Command\MultiStepCommand; +use Zalas\Toolbox\Tool\Command\ShCommand; class MultiStepCommandTest extends TestCase { - use ProphecyTrait; - public function test_it_is_a_command() { $command = new MultiStepCommand(Collection::create([$this->command('echo "A"')])); @@ -49,9 +47,6 @@ public function test_it_throws_an_exception_if_there_is_no_steps() private function command(string $commandString): Command { - $command = $this->prophesize(Command::class); - $command->__toString()->willReturn($commandString); - - return $command->reveal(); + return new ShCommand($commandString); } } diff --git a/tests/Tool/Command/PharDownloadCommandTest.php b/tests/Tool/Command/PharDownloadCommandTest.php index f7c0451c..ca4cd005 100644 --- a/tests/Tool/Command/PharDownloadCommandTest.php +++ b/tests/Tool/Command/PharDownloadCommandTest.php @@ -11,7 +11,7 @@ class PharDownloadCommandTest extends TestCase private const PHAR = 'https://example.com/foo.phar'; private const BIN = '/usr/local/bin/foo'; - private $command; + private PharDownloadCommand $command; protected function setUp(): void { diff --git a/tests/Tool/Command/PhiveInstallCommandTest.php b/tests/Tool/Command/PhiveInstallCommandTest.php index 79431528..7683f104 100644 --- a/tests/Tool/Command/PhiveInstallCommandTest.php +++ b/tests/Tool/Command/PhiveInstallCommandTest.php @@ -12,7 +12,7 @@ class PhiveInstallCommandTest extends TestCase private const BIN = '/usr/local/bin/foo'; private const SIG = '0000000000000000'; - private $command; + private PhiveInstallCommand $command; protected function setUp(): void { diff --git a/tests/Tool/FilterTest.php b/tests/Tool/FilterTest.php index 5688884c..7444e212 100644 --- a/tests/Tool/FilterTest.php +++ b/tests/Tool/FilterTest.php @@ -3,14 +3,13 @@ namespace Zalas\Toolbox\Tests\Tool; use PHPUnit\Framework\TestCase; -use Prophecy\PhpUnit\ProphecyTrait; +use Zalas\Toolbox\Tool\Command\ShCommand; +use Zalas\Toolbox\Tool\Command\TestCommand; use Zalas\Toolbox\Tool\Filter; use Zalas\Toolbox\Tool\Tool; class FilterTest extends TestCase { - use ProphecyTrait; - public function test_it_returns_true_if_no_excluded_tags_were_defined() { $filter = new Filter([], []); @@ -97,9 +96,13 @@ public function test_it_returns_false_if_a_tag_is_both_included_and_excluded() private function tool(array $tags): Tool { - $tool = $this->prophesize(Tool::class); - $tool->tags()->willReturn($tags); - - return $tool->reveal(); + return new Tool( + 'any name', + 'any summary', + 'https://example.com', + $tags, + new ShCommand('any command'), + new TestCommand('any test command', 'any') + ); } } diff --git a/tests/Tool/ToolTest.php b/tests/Tool/ToolTest.php index 2dd24433..e7b1449f 100644 --- a/tests/Tool/ToolTest.php +++ b/tests/Tool/ToolTest.php @@ -4,19 +4,16 @@ namespace Zalas\Toolbox\Tests\Tool; use PHPUnit\Framework\TestCase; -use Prophecy\PhpUnit\ProphecyTrait; use TypeError; -use Zalas\Toolbox\Tool\Command; +use Zalas\Toolbox\Tool\Command\ShCommand; use Zalas\Toolbox\Tool\Tool; class ToolTest extends TestCase { - use ProphecyTrait; - public function test_it_exposes_its_properties() { - $command = $this->prophesize(Command::class)->reveal(); - $testCommand = $this->prophesize(Command::class)->reveal(); + $command = $this->anyCommand(); + $testCommand = $this->anyCommand(); $tool = new Tool('phpstan', 'Static analysis tool', 'https://github.com/phpstan/phpstan', ['qa', 'static-analysis'], $command, $testCommand); @@ -31,9 +28,17 @@ public function test_it_exposes_its_properties() public function test_tags_can_only_be_strings() { $this->expectException(TypeError::class); - $command = $this->prophesize(Command::class)->reveal(); - $testCommand = $this->prophesize(Command::class)->reveal(); + $command = $this->anyCommand(); + $testCommand = $this->anyCommand(); new Tool('phpstan', 'Static analysis tool', 'https://github.com/phpstan/phpstan', [['qa'], ['static-analysis']], $command, $testCommand); } + + /** + * @return object + */ + public function anyCommand(): object + { + return new ShCommand('any command'); + } } diff --git a/tests/UseCase/InstallToolsTest.php b/tests/UseCase/InstallToolsTest.php index 3909e191..5fe8c580 100644 --- a/tests/UseCase/InstallToolsTest.php +++ b/tests/UseCase/InstallToolsTest.php @@ -2,10 +2,8 @@ namespace Zalas\Toolbox\Tests\UseCase; +use PHPUnit\Framework\MockObject\Stub; use PHPUnit\Framework\TestCase; -use Prophecy\Argument; -use Prophecy\PhpUnit\ProphecyTrait; -use Prophecy\Prophecy\ObjectProphecy; use Zalas\Toolbox\Tool\Collection; use Zalas\Toolbox\Tool\Command; use Zalas\Toolbox\Tool\Command\BoxBuildCommand; @@ -17,6 +15,7 @@ use Zalas\Toolbox\Tool\Command\PharDownloadCommand; use Zalas\Toolbox\Tool\Command\PhiveInstallCommand; use Zalas\Toolbox\Tool\Command\ShCommand; +use Zalas\Toolbox\Tool\Command\TestCommand; use Zalas\Toolbox\Tool\Filter; use Zalas\Toolbox\Tool\Tool; use Zalas\Toolbox\Tool\Tools; @@ -24,29 +23,21 @@ class InstallToolsTest extends TestCase { - use ProphecyTrait; + private InstallTools $useCase; - /** - * @var InstallTools - */ - private $useCase; - - /** - * @var Tools|ObjectProphecy - */ - private $tools; + private Tools|Stub $tools; protected function setUp(): void { - $this->tools = $this->prophesize(Tools::class); - $this->useCase = new InstallTools($this->tools->reveal()); + $this->tools = $this->createStub(Tools::class); + $this->useCase = new InstallTools($this->tools); } public function test_it_returns_a_multi_step_command() { $filter = $this->filter(); - $this->tools->all($filter)->willReturn(Collection::create([$this->tool(new ShCommand('echo "Foo"'))])); + $this->givenToolsFor($filter, Collection::create([$this->tool(new ShCommand('echo "Foo"'))])); $command = $this->useCase->__invoke($filter); @@ -55,7 +46,7 @@ public function test_it_returns_a_multi_step_command() public function test_it_groups_composer_global_install_commands() { - $this->tools->all(Argument::type(Filter::class))->willReturn(Collection::create([ + $this->givenTools(Collection::create([ $this->tool(new ComposerGlobalInstallCommand('phpstan/phpstan')), $this->tool(new ComposerGlobalInstallCommand('phan/phan')), ])); @@ -67,7 +58,7 @@ public function test_it_groups_composer_global_install_commands() public function test_it_does_not_include_empty_commands() { - $this->tools->all(Argument::type(Filter::class))->willReturn(Collection::create([ + $this->givenTools(Collection::create([ $this->tool(new ShCommand('echo "Foo"')), ])); @@ -79,7 +70,7 @@ public function test_it_does_not_include_empty_commands() public function test_it_groups_composer_bin_plugin_commands() { - $this->tools->all(Argument::type(Filter::class))->willReturn(Collection::create([ + $this->givenTools(Collection::create([ $this->tool(new ComposerBinPluginCommand('phpstan/phpstan', 'tools', Collection::create([]))), $this->tool(new ComposerBinPluginCommand('phan/phan', 'tools', Collection::create([]))), ])); @@ -91,7 +82,7 @@ public function test_it_groups_composer_bin_plugin_commands() public function test_it_includes_installation_tagged_commands_before_other_ones() { - $this->tools->all(Argument::type(Filter::class))->willReturn(Collection::create([ + $this->givenTools(Collection::create([ $this->tool(new ShCommand('echo "Foo"')), $this->tool(new ShCommand('echo "Installation"'), [InstallTools::PRE_INSTALLATION_TAG]), ])); @@ -104,7 +95,7 @@ public function test_it_includes_installation_tagged_commands_before_other_ones( public function test_it_includes_shell_commands() { - $this->tools->all(Argument::type(Filter::class))->willReturn(Collection::create([ + $this->givenTools(Collection::create([ $this->tool(new ShCommand('echo "Foo"')), ])); @@ -115,7 +106,7 @@ public function test_it_includes_shell_commands() public function test_it_includes_multi_step_commands() { - $this->tools->all(Argument::type(Filter::class))->willReturn(Collection::create([ + $this->givenTools(Collection::create([ $this->tool(new MultiStepCommand(Collection::create([ new ShCommand('echo "Foo"'), new ShCommand('echo "Bar"') @@ -129,7 +120,7 @@ public function test_it_includes_multi_step_commands() public function test_it_includes_composer_install_commands() { - $this->tools->all(Argument::type(Filter::class))->willReturn(Collection::create([ + $this->givenTools(Collection::create([ $this->tool(new ComposerInstallCommand('git@github.com:phpspec/phpspec.git', '/usr/local/bin')), ])); @@ -140,7 +131,7 @@ public function test_it_includes_composer_install_commands() public function test_it_includes_box_build_commands() { - $this->tools->all(Argument::type(Filter::class))->willReturn(Collection::create([ + $this->givenTools(Collection::create([ $this->tool(new BoxBuildCommand('https://github.com/behat/behat.git', 'behat.phar', '/tools/behat', '/tmp')), ])); @@ -151,7 +142,7 @@ public function test_it_includes_box_build_commands() public function test_it_includes_phar_download_commands() { - $this->tools->all(Argument::type(Filter::class))->willReturn(Collection::create([ + $this->givenTools(Collection::create([ $this->tool(new PharDownloadCommand('https://github.com/sensiolabs-de/deptrac/releases/download/0.2.0/deptrac-0.2.0.phar', '/tools/phar')), ])); @@ -162,7 +153,7 @@ public function test_it_includes_phar_download_commands() public function test_it_includes_phive_install_commands() { - $this->tools->all(Argument::type(Filter::class))->willReturn(Collection::create([ + $this->givenTools(Collection::create([ $this->tool(new PhiveInstallCommand('phpunit', '/tools/phpunit')), ])); @@ -172,7 +163,7 @@ public function test_it_includes_phive_install_commands() public function test_it_includes_file_download_commands() { - $this->tools->all(Argument::type(Filter::class))->willReturn(Collection::create([ + $this->givenTools(Collection::create([ $this->tool(new FileDownloadCommand('https://github.com/fabpot/local-php-security-checker/releases/download/v1.0.0/local-php-security-checker_1.0.0_linux_amd64', '/tools/security-checker')), ])); @@ -188,10 +179,26 @@ private function filter(): Filter private function tool(Command $command, array $tags = []): Tool { - $tool = $this->prophesize(Tool::class); - $tool->command()->willReturn($command); - $tool->tags()->willReturn($tags); + return new Tool( + "any name", + "any summary", + "https://example.com", + $tags, + $command, + new TestCommand("any test command", "any test name") + ); + } + + private function givenToolsFor(Filter $filter, Collection $tools): void + { + $this->tools->method('all') + ->with($filter) + ->willReturn($tools); + } - return $tool->reveal(); + private function givenTools(Collection $tools): void + { + $this->tools->method('all') + ->willReturn($tools); } } diff --git a/tests/UseCase/ListToolsTest.php b/tests/UseCase/ListToolsTest.php index e47bf469..fe1b1adb 100644 --- a/tests/UseCase/ListToolsTest.php +++ b/tests/UseCase/ListToolsTest.php @@ -3,8 +3,9 @@ namespace Zalas\Toolbox\Tests\UseCase; use PHPUnit\Framework\TestCase; -use Prophecy\PhpUnit\ProphecyTrait; use Zalas\Toolbox\Tool\Collection; +use Zalas\Toolbox\Tool\Command; +use Zalas\Toolbox\Tool\Command\TestCommand; use Zalas\Toolbox\Tool\Filter; use Zalas\Toolbox\Tool\Tool; use Zalas\Toolbox\Tool\Tools; @@ -12,20 +13,14 @@ class ListToolsTest extends TestCase { - use ProphecyTrait; - public function test_it_returns_loaded_tools() { - $tools = Collection::create([ - $this->prophesize(Tool::class)->reveal(), - $this->prophesize(Tool::class)->reveal(), - ]); + $tools = Collection::create([$this->anyTool(), $this->anyTool()]); $filter = $this->filter(); - $repository = $this->prophesize(Tools::class); - $repository->all($filter)->willReturn($tools); + $repository = $this->givenToolsFor($filter, $tools); - $useCase = new ListTools($repository->reveal()); + $useCase = new ListTools($repository); $this->assertSame($tools, $useCase($filter)); } @@ -34,4 +29,24 @@ private function filter(): Filter { return new Filter([], []); } + + private function anyTool(): Tool + { + return new Tool( + "any name", + "any summary", + "https://example.com", + [], + new Command\ShCommand("any command"), + new TestCommand("any test command", "any test name") + ); + } + + private function givenToolsFor(Filter $filter, Collection $tools): Tools + { + $repository = $this->createStub(Tools::class); + $repository->method('all')->with($filter)->willReturn($tools); + + return $repository; + } } diff --git a/tests/UseCase/TestToolsTest.php b/tests/UseCase/TestToolsTest.php index 74ba8f89..f0afd517 100644 --- a/tests/UseCase/TestToolsTest.php +++ b/tests/UseCase/TestToolsTest.php @@ -3,9 +3,9 @@ namespace Zalas\Toolbox\Tests\UseCase; use PHPUnit\Framework\TestCase; -use Prophecy\PhpUnit\ProphecyTrait; use Zalas\Toolbox\Tool\Collection; use Zalas\Toolbox\Tool\Command; +use Zalas\Toolbox\Tool\Command\ShCommand; use Zalas\Toolbox\Tool\Filter; use Zalas\Toolbox\Tool\Tool; use Zalas\Toolbox\Tool\Tools; @@ -13,8 +13,6 @@ class TestToolsTest extends TestCase { - use ProphecyTrait; - public function test_it_returns_test_aggregated_test_command() { $testCommands = [ @@ -31,30 +29,29 @@ public function test_it_returns_test_aggregated_test_command() private function tool(Command $testCommand): Tool { - $tool = $this->prophesize(Tool::class); - $tool->testCommand()->willReturn($testCommand); - $tool->tags()->willReturn([]); - - return $tool->reveal(); + return new Tool( + "any name", + "any summary", + "https://example.com", + [], + new Command\ShCommand("any command"), + $testCommand + ); } private function command(string $command): Command { - $c = $this->prophesize(Command::class); - $c->__toString()->willReturn($command); - - return $c->reveal(); + return new ShCommand($command); } private function tools(array $testCommands, Filter $filter): Tools { - $tools = $this->prophesize(Tools::class); - $tools->all($filter)->willReturn(Collection::create([ - $this->tool($testCommands[0]), - $this->tool($testCommands[1]), - ])); + $tools = $this->createStub(Tools::class); + $tools->method('all')->with($filter)->willReturn(Collection::create( + \array_map(fn ($command) => $this->tool($command), $testCommands) + )); - return $tools->reveal(); + return $tools; } private function filter(): Filter