diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php index 03ee96254..4cb978cd5 100644 --- a/.php-cs-fixer.dist.php +++ b/.php-cs-fixer.dist.php @@ -22,6 +22,7 @@ '@PHPUnit8x4Migration:risky' => true, '@PHPUnit9x1Migration:risky' => true, '@PHPUnit10x0Migration:risky' => true, + '@PHPUnit11x0Migration:risky' => true, 'header_comment' => ['header' => '',], // Make sure we remove any header comments 'phpdoc_add_missing_param_annotation' => ['only_untyped' => true], // @PhpCsFixer use default 'true', we don't want php doc that are already typed 'method_chaining_indentation' => false, // @PhpCsFixer use default 'true' impact readability on symfony configuration and sonata admin diff --git a/app/src/Entity/UserAddress.php b/app/src/Entity/UserAddress.php index 7affd39ba..44e7ea3d3 100644 --- a/app/src/Entity/UserAddress.php +++ b/app/src/Entity/UserAddress.php @@ -20,7 +20,7 @@ class UserAddress #[ORM\Embedded(class: Address::class)] #[Assert\Valid] - private ?Address $address; + private Address $address; #[ORM\Column(name: 'position', type: 'integer', nullable: false, options: ['default' => 0])] private ?int $position = null; diff --git a/composer.json b/composer.json index 03a777254..c76a19c6c 100644 --- a/composer.json +++ b/composer.json @@ -26,7 +26,7 @@ "ext-simplexml": "*", "ext-zip": "*", "fidry/cpu-core-counter": "^1.1", - "friendsofphp/php-cs-fixer": "^3.13", + "friendsofphp/php-cs-fixer": "^3.95", "guzzlehttp/psr7": "^1.8 || ^2.0", "jms/serializer": "^3.11", "jms/serializer-bundle": "^5.4.0", @@ -34,7 +34,7 @@ "nesbot/carbon": "^3.8", "php": ">=8.5", "phpdocumentor/reflection-docblock": "^5.2", - "phpunit/phpunit": "^11.3", + "phpunit/phpunit": "^13.2", "psr/http-message": "^1.0 || ^2.0", "psr/log": "^3", "ramsey/uuid": "^4.2", @@ -91,10 +91,10 @@ "monolog/monolog": "^3.5.0", "nelmio/cors-bundle": "^2.0", "pelago/emogrifier": "^8.0", - "phpstan/extension-installer": "^1.1", - "phpstan/phpstan": "^1.7", - "phpstan/phpstan-phpunit": "^1.1", - "phpstan/phpstan-symfony": "^1.2", + "phpstan/extension-installer": "^1.4", + "phpstan/phpstan": "^2.1", + "phpstan/phpstan-phpunit": "^2.0", + "phpstan/phpstan-symfony": "^2.0", "scheb/2fa-bundle": "^v7.6", "scheb/2fa-email": "^7.6", "scheb/2fa-totp": "^7.6", diff --git a/composer.lock b/composer.lock index 0c23a5185..04cf8c1f9 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "3c0b53803f5ad817e627e818fe7f6754", + "content-hash": "0b885f959c83fd0ca5da944ef96fcb6f", "packages": [ { "name": "aws/aws-crt-php", @@ -2011,6 +2011,75 @@ ], "time": "2025-03-06T22:45:56+00:00" }, + { + "name": "ergebnis/agent-detector", + "version": "1.2.0", + "source": { + "type": "git", + "url": "https://github.com/ergebnis/agent-detector.git", + "reference": "e211f17928c8b95a51e06040792d57f5462fb271" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ergebnis/agent-detector/zipball/e211f17928c8b95a51e06040792d57f5462fb271", + "reference": "e211f17928c8b95a51e06040792d57f5462fb271", + "shasum": "" + }, + "require": { + "php": "~7.4.0 || ~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0 || ~8.5.0 || ~8.6.0" + }, + "require-dev": { + "ergebnis/composer-normalize": "^2.51.0", + "ergebnis/license": "^2.7.0", + "ergebnis/php-cs-fixer-config": "^6.60.2", + "ergebnis/phpstan-rules": "^2.13.1", + "ergebnis/phpunit-slow-test-detector": "^2.24.0", + "ergebnis/rector-rules": "^1.18.1", + "fakerphp/faker": "^1.24.1", + "infection/infection": "^0.26.6", + "phpstan/extension-installer": "^1.4.3", + "phpstan/phpstan": "^2.1.54", + "phpstan/phpstan-deprecation-rules": "^2.0.4", + "phpstan/phpstan-phpunit": "^2.0.16", + "phpstan/phpstan-strict-rules": "^2.0.10", + "phpunit/phpunit": "^9.6.34", + "rector/rector": "^2.4.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.2-dev" + }, + "composer-normalize": { + "indent-size": 2, + "indent-style": "space" + } + }, + "autoload": { + "psr-4": { + "Ergebnis\\AgentDetector\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Andreas Möller", + "email": "am@localheinz.com", + "homepage": "https://localheinz.com" + } + ], + "description": "Provides a detector for detecting the presence of an agent.", + "homepage": "https://github.com/ergebnis/agent-detector", + "support": { + "issues": "https://github.com/ergebnis/agent-detector/issues", + "security": "https://github.com/ergebnis/agent-detector/blob/main/.github/SECURITY.md", + "source": "https://github.com/ergebnis/agent-detector" + }, + "time": "2026-05-07T08:19:07+00:00" + }, { "name": "evenement/evenement", "version": "v3.0.2", @@ -2121,22 +2190,23 @@ }, { "name": "friendsofphp/php-cs-fixer", - "version": "v3.94.2", + "version": "v3.95.5", "source": { "type": "git", "url": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer.git", - "reference": "7787ceff91365ba7d623ec410b8f429cdebb4f63" + "reference": "7f86d8763063f5d2e2e2d0e1e45bb2f15895361d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/7787ceff91365ba7d623ec410b8f429cdebb4f63", - "reference": "7787ceff91365ba7d623ec410b8f429cdebb4f63", + "url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/7f86d8763063f5d2e2e2d0e1e45bb2f15895361d", + "reference": "7f86d8763063f5d2e2e2d0e1e45bb2f15895361d", "shasum": "" }, "require": { "clue/ndjson-react": "^1.3", "composer/semver": "^3.4", "composer/xdebug-handler": "^3.0.5", + "ergebnis/agent-detector": "^1.2", "ext-filter": "*", "ext-hash": "*", "ext-json": "*", @@ -2147,32 +2217,32 @@ "react/event-loop": "^1.5", "react/socket": "^1.16", "react/stream": "^1.4", - "sebastian/diff": "^4.0.6 || ^5.1.1 || ^6.0.2 || ^7.0 || ^8.0", + "sebastian/diff": "^4.0.6 || ^5.1.1 || ^6.0.2 || ^7.0 || ^8.0 || ^9.0", "symfony/console": "^5.4.47 || ^6.4.24 || ^7.0 || ^8.0", "symfony/event-dispatcher": "^5.4.45 || ^6.4.24 || ^7.0 || ^8.0", "symfony/filesystem": "^5.4.45 || ^6.4.24 || ^7.0 || ^8.0", "symfony/finder": "^5.4.45 || ^6.4.24 || ^7.0 || ^8.0", "symfony/options-resolver": "^5.4.45 || ^6.4.24 || ^7.0 || ^8.0", - "symfony/polyfill-mbstring": "^1.33", - "symfony/polyfill-php80": "^1.33", - "symfony/polyfill-php81": "^1.33", - "symfony/polyfill-php84": "^1.33", + "symfony/polyfill-mbstring": "^1.37", + "symfony/polyfill-php80": "^1.37", + "symfony/polyfill-php81": "^1.37", + "symfony/polyfill-php84": "^1.37", "symfony/process": "^5.4.47 || ^6.4.24 || ^7.2 || ^8.0", "symfony/stopwatch": "^5.4.45 || ^6.4.24 || ^7.0 || ^8.0" }, "require-dev": { - "facile-it/paraunit": "^1.3.1 || ^2.7.1", - "infection/infection": "^0.32.3", - "justinrainbow/json-schema": "^6.6.4", + "facile-it/paraunit": "^1.3.1 || ^2.11.0", + "infection/infection": "^0.32.7", + "justinrainbow/json-schema": "^6.8.0", "keradus/cli-executor": "^2.3", "mikey179/vfsstream": "^1.6.12", "php-coveralls/php-coveralls": "^2.9.1", - "php-cs-fixer/phpunit-constraint-isidenticalstring": "^1.7", - "php-cs-fixer/phpunit-constraint-xmlmatchesxsd": "^1.7", - "phpunit/phpunit": "^9.6.34 || ^10.5.63 || ^11.5.51", - "symfony/polyfill-php85": "^1.33", - "symfony/var-dumper": "^5.4.48 || ^6.4.32 || ^7.4.4 || ^8.0.4", - "symfony/yaml": "^5.4.45 || ^6.4.30 || ^7.4.1 || ^8.0.1" + "php-cs-fixer/phpunit-constraint-isidenticalstring": "^1.8", + "php-cs-fixer/phpunit-constraint-xmlmatchesxsd": "^1.8", + "phpunit/phpunit": "^9.6.34 || ^10.5.63 || ^11.5.55", + "symfony/polyfill-php85": "^1.37", + "symfony/var-dumper": "^5.4.48 || ^6.4.32 || ^7.4.4 || ^8.0.8", + "symfony/yaml": "^5.4.45 || ^6.4.30 || ^7.4.1 || ^8.0.11" }, "suggest": { "ext-dom": "For handling output formats in XML", @@ -2213,7 +2283,7 @@ ], "support": { "issues": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/issues", - "source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.94.2" + "source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.95.5" }, "funding": [ { @@ -2221,7 +2291,7 @@ "type": "github" } ], - "time": "2026-02-20T16:13:53+00:00" + "time": "2026-06-09T14:55:16+00:00" }, { "name": "friendsofphp/proxy-manager-lts", @@ -4110,35 +4180,35 @@ }, { "name": "phpunit/php-code-coverage", - "version": "11.0.12", + "version": "14.2.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "2c1ed04922802c15e1de5d7447b4856de949cf56" + "reference": "10d7da3628a99289cdf4c662dd7f0d73f1baec83" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/2c1ed04922802c15e1de5d7447b4856de949cf56", - "reference": "2c1ed04922802c15e1de5d7447b4856de949cf56", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/10d7da3628a99289cdf4c662dd7f0d73f1baec83", + "reference": "10d7da3628a99289cdf4c662dd7f0d73f1baec83", "shasum": "" }, "require": { "ext-dom": "*", "ext-libxml": "*", + "ext-mbstring": "*", "ext-xmlwriter": "*", "nikic/php-parser": "^5.7.0", - "php": ">=8.2", - "phpunit/php-file-iterator": "^5.1.0", - "phpunit/php-text-template": "^4.0.1", - "sebastian/code-unit-reverse-lookup": "^4.0.1", - "sebastian/complexity": "^4.0.1", - "sebastian/environment": "^7.2.1", - "sebastian/lines-of-code": "^3.0.1", - "sebastian/version": "^5.0.2", - "theseer/tokenizer": "^1.3.1" + "php": ">=8.4", + "phpunit/php-text-template": "^6.0", + "sebastian/complexity": "^6.0", + "sebastian/environment": "^9.3.2", + "sebastian/git-state": "^1.0", + "sebastian/lines-of-code": "^5.0.1", + "sebastian/version": "^7.0", + "theseer/tokenizer": "^2.0.1" }, "require-dev": { - "phpunit/phpunit": "^11.5.46" + "phpunit/phpunit": "^13.2.0" }, "suggest": { "ext-pcov": "PHP extension that provides line coverage", @@ -4147,7 +4217,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "11.0.x-dev" + "dev-main": "14.2.x-dev" } }, "autoload": { @@ -4176,7 +4246,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy", - "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/11.0.12" + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/14.2.2" }, "funding": [ { @@ -4196,32 +4266,32 @@ "type": "tidelift" } ], - "time": "2025-12-24T07:01:01+00:00" + "time": "2026-06-08T11:50:38+00:00" }, { "name": "phpunit/php-file-iterator", - "version": "5.1.1", + "version": "7.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-file-iterator.git", - "reference": "2f3a64888c814fc235386b7387dd5b5ed92ad903" + "reference": "6e5aa1fb0a95b1703d83e721299ee18bb4e2de50" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/2f3a64888c814fc235386b7387dd5b5ed92ad903", - "reference": "2f3a64888c814fc235386b7387dd5b5ed92ad903", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/6e5aa1fb0a95b1703d83e721299ee18bb4e2de50", + "reference": "6e5aa1fb0a95b1703d83e721299ee18bb4e2de50", "shasum": "" }, "require": { - "php": ">=8.2" + "php": ">=8.4" }, "require-dev": { - "phpunit/phpunit": "^11.3" + "phpunit/phpunit": "^13.0" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "5.1-dev" + "dev-main": "7.0-dev" } }, "autoload": { @@ -4249,7 +4319,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/php-file-iterator/issues", "security": "https://github.com/sebastianbergmann/php-file-iterator/security/policy", - "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/5.1.1" + "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/7.0.0" }, "funding": [ { @@ -4269,28 +4339,28 @@ "type": "tidelift" } ], - "time": "2026-02-02T13:52:54+00:00" + "time": "2026-02-06T04:33:26+00:00" }, { "name": "phpunit/php-invoker", - "version": "5.0.1", + "version": "7.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-invoker.git", - "reference": "c1ca3814734c07492b3d4c5f794f4b0995333da2" + "reference": "42e5c5cae0c65df12d1b1a3ab52bf3f50f244d88" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/c1ca3814734c07492b3d4c5f794f4b0995333da2", - "reference": "c1ca3814734c07492b3d4c5f794f4b0995333da2", + "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/42e5c5cae0c65df12d1b1a3ab52bf3f50f244d88", + "reference": "42e5c5cae0c65df12d1b1a3ab52bf3f50f244d88", "shasum": "" }, "require": { - "php": ">=8.2" + "php": ">=8.4" }, "require-dev": { "ext-pcntl": "*", - "phpunit/phpunit": "^11.0" + "phpunit/phpunit": "^13.0" }, "suggest": { "ext-pcntl": "*" @@ -4298,7 +4368,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "5.0-dev" + "dev-main": "7.0-dev" } }, "autoload": { @@ -4325,40 +4395,52 @@ "support": { "issues": "https://github.com/sebastianbergmann/php-invoker/issues", "security": "https://github.com/sebastianbergmann/php-invoker/security/policy", - "source": "https://github.com/sebastianbergmann/php-invoker/tree/5.0.1" + "source": "https://github.com/sebastianbergmann/php-invoker/tree/7.0.0" }, "funding": [ { "url": "https://github.com/sebastianbergmann", "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpunit/php-invoker", + "type": "tidelift" } ], - "time": "2024-07-03T05:07:44+00:00" + "time": "2026-02-06T04:34:47+00:00" }, { "name": "phpunit/php-text-template", - "version": "4.0.1", + "version": "6.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-text-template.git", - "reference": "3e0404dc6b300e6bf56415467ebcb3fe4f33e964" + "reference": "a47af19f93f76aa3368303d752aa5272ca3299f4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/3e0404dc6b300e6bf56415467ebcb3fe4f33e964", - "reference": "3e0404dc6b300e6bf56415467ebcb3fe4f33e964", + "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/a47af19f93f76aa3368303d752aa5272ca3299f4", + "reference": "a47af19f93f76aa3368303d752aa5272ca3299f4", "shasum": "" }, "require": { - "php": ">=8.2" + "php": ">=8.4" }, "require-dev": { - "phpunit/phpunit": "^11.0" + "phpunit/phpunit": "^13.0" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "4.0-dev" + "dev-main": "6.0-dev" } }, "autoload": { @@ -4385,40 +4467,52 @@ "support": { "issues": "https://github.com/sebastianbergmann/php-text-template/issues", "security": "https://github.com/sebastianbergmann/php-text-template/security/policy", - "source": "https://github.com/sebastianbergmann/php-text-template/tree/4.0.1" + "source": "https://github.com/sebastianbergmann/php-text-template/tree/6.0.0" }, "funding": [ { "url": "https://github.com/sebastianbergmann", "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpunit/php-text-template", + "type": "tidelift" } ], - "time": "2024-07-03T05:08:43+00:00" + "time": "2026-02-06T04:36:37+00:00" }, { "name": "phpunit/php-timer", - "version": "7.0.1", + "version": "9.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-timer.git", - "reference": "3b415def83fbcb41f991d9ebf16ae4ad8b7837b3" + "reference": "a0e12065831f6ab0d83120dc61513eb8d9a966f6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/3b415def83fbcb41f991d9ebf16ae4ad8b7837b3", - "reference": "3b415def83fbcb41f991d9ebf16ae4ad8b7837b3", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/a0e12065831f6ab0d83120dc61513eb8d9a966f6", + "reference": "a0e12065831f6ab0d83120dc61513eb8d9a966f6", "shasum": "" }, "require": { - "php": ">=8.2" + "php": ">=8.4" }, "require-dev": { - "phpunit/phpunit": "^11.0" + "phpunit/phpunit": "^13.0" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "7.0-dev" + "dev-main": "9.0-dev" } }, "autoload": { @@ -4445,28 +4539,40 @@ "support": { "issues": "https://github.com/sebastianbergmann/php-timer/issues", "security": "https://github.com/sebastianbergmann/php-timer/security/policy", - "source": "https://github.com/sebastianbergmann/php-timer/tree/7.0.1" + "source": "https://github.com/sebastianbergmann/php-timer/tree/9.0.0" }, "funding": [ { "url": "https://github.com/sebastianbergmann", "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpunit/php-timer", + "type": "tidelift" } ], - "time": "2024-07-03T05:09:35+00:00" + "time": "2026-02-06T04:37:53+00:00" }, { "name": "phpunit/phpunit", - "version": "11.5.55", + "version": "13.2.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "adc7262fccc12de2b30f12a8aa0b33775d814f00" + "reference": "3796ea973f1e7698f0d432c1c66662af9764fd9a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/adc7262fccc12de2b30f12a8aa0b33775d814f00", - "reference": "adc7262fccc12de2b30f12a8aa0b33775d814f00", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/3796ea973f1e7698f0d432c1c66662af9764fd9a", + "reference": "3796ea973f1e7698f0d432c1c66662af9764fd9a", "shasum": "" }, "require": { @@ -4479,35 +4585,33 @@ "myclabs/deep-copy": "^1.13.4", "phar-io/manifest": "^2.0.4", "phar-io/version": "^3.2.1", - "php": ">=8.2", - "phpunit/php-code-coverage": "^11.0.12", - "phpunit/php-file-iterator": "^5.1.1", - "phpunit/php-invoker": "^5.0.1", - "phpunit/php-text-template": "^4.0.1", - "phpunit/php-timer": "^7.0.1", - "sebastian/cli-parser": "^3.0.2", - "sebastian/code-unit": "^3.0.3", - "sebastian/comparator": "^6.3.3", - "sebastian/diff": "^6.0.2", - "sebastian/environment": "^7.2.1", - "sebastian/exporter": "^6.3.2", - "sebastian/global-state": "^7.0.2", - "sebastian/object-enumerator": "^6.0.1", - "sebastian/recursion-context": "^6.0.3", - "sebastian/type": "^5.1.3", - "sebastian/version": "^5.0.2", + "php": ">=8.4.1", + "phpunit/php-code-coverage": "^14.2", + "phpunit/php-file-iterator": "^7.0.0", + "phpunit/php-invoker": "^7.0.0", + "phpunit/php-text-template": "^6.0.0", + "phpunit/php-timer": "^9.0.0", + "sebastian/cli-parser": "^5.0.0", + "sebastian/comparator": "^8.3.0", + "sebastian/diff": "^9.0", + "sebastian/environment": "^9.3.2", + "sebastian/exporter": "^8.1.0", + "sebastian/file-filter": "^1.0", + "sebastian/git-state": "^1.0", + "sebastian/global-state": "^9.0.1", + "sebastian/object-enumerator": "^8.0.0", + "sebastian/recursion-context": "^8.0.0", + "sebastian/type": "^7.0.1", + "sebastian/version": "^7.0.0", "staabm/side-effects-detector": "^1.0.5" }, - "suggest": { - "ext-soap": "To be able to generate mocks based on WSDL files" - }, "bin": [ "phpunit" ], "type": "library", "extra": { "branch-alias": { - "dev-main": "11.5-dev" + "dev-main": "13.2-dev" } }, "autoload": { @@ -4539,31 +4643,15 @@ "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", "security": "https://github.com/sebastianbergmann/phpunit/security/policy", - "source": "https://github.com/sebastianbergmann/phpunit/tree/11.5.55" + "source": "https://github.com/sebastianbergmann/phpunit/tree/13.2.0" }, "funding": [ { - "url": "https://phpunit.de/sponsors.html", - "type": "custom" - }, - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - }, - { - "url": "https://liberapay.com/sebastianbergmann", - "type": "liberapay" - }, - { - "url": "https://thanks.dev/u/gh/sebastianbergmann", - "type": "thanks_dev" - }, - { - "url": "https://tidelift.com/funding/github/packagist/phpunit/phpunit", - "type": "tidelift" + "url": "https://phpunit.de/sponsoring.html", + "type": "other" } ], - "time": "2026-02-18T12:37:06+00:00" + "time": "2026-06-05T03:13:07+00:00" }, { "name": "psr/cache", @@ -5701,28 +5789,28 @@ }, { "name": "sebastian/cli-parser", - "version": "3.0.2", + "version": "5.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/cli-parser.git", - "reference": "15c5dd40dc4f38794d383bb95465193f5e0ae180" + "reference": "48a4654fa5e48c1c81214e9930048a572d4b23ca" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/15c5dd40dc4f38794d383bb95465193f5e0ae180", - "reference": "15c5dd40dc4f38794d383bb95465193f5e0ae180", + "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/48a4654fa5e48c1c81214e9930048a572d4b23ca", + "reference": "48a4654fa5e48c1c81214e9930048a572d4b23ca", "shasum": "" }, "require": { - "php": ">=8.2" + "php": ">=8.4" }, "require-dev": { - "phpunit/phpunit": "^11.0" + "phpunit/phpunit": "^13.0" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "3.0-dev" + "dev-main": "5.0-dev" } }, "autoload": { @@ -5746,152 +5834,51 @@ "support": { "issues": "https://github.com/sebastianbergmann/cli-parser/issues", "security": "https://github.com/sebastianbergmann/cli-parser/security/policy", - "source": "https://github.com/sebastianbergmann/cli-parser/tree/3.0.2" + "source": "https://github.com/sebastianbergmann/cli-parser/tree/5.0.0" }, "funding": [ { "url": "https://github.com/sebastianbergmann", "type": "github" - } - ], - "time": "2024-07-03T04:41:36+00:00" - }, - { - "name": "sebastian/code-unit", - "version": "3.0.3", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/code-unit.git", - "reference": "54391c61e4af8078e5b276ab082b6d3c54c9ad64" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/code-unit/zipball/54391c61e4af8078e5b276ab082b6d3c54c9ad64", - "reference": "54391c61e4af8078e5b276ab082b6d3c54c9ad64", - "shasum": "" - }, - "require": { - "php": ">=8.2" - }, - "require-dev": { - "phpunit/phpunit": "^11.5" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "3.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "Collection of value objects that represent the PHP code units", - "homepage": "https://github.com/sebastianbergmann/code-unit", - "support": { - "issues": "https://github.com/sebastianbergmann/code-unit/issues", - "security": "https://github.com/sebastianbergmann/code-unit/security/policy", - "source": "https://github.com/sebastianbergmann/code-unit/tree/3.0.3" - }, - "funding": [ + }, { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2025-03-19T07:56:08+00:00" - }, - { - "name": "sebastian/code-unit-reverse-lookup", - "version": "4.0.1", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", - "reference": "183a9b2632194febd219bb9246eee421dad8d45e" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/183a9b2632194febd219bb9246eee421dad8d45e", - "reference": "183a9b2632194febd219bb9246eee421dad8d45e", - "shasum": "" - }, - "require": { - "php": ">=8.2" - }, - "require-dev": { - "phpunit/phpunit": "^11.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "4.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Looks up which function or method a line of code belongs to", - "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", - "support": { - "issues": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/issues", - "security": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/security/policy", - "source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/4.0.1" - }, - "funding": [ + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, { - "url": "https://github.com/sebastianbergmann", - "type": "github" + "url": "https://tidelift.com/funding/github/packagist/sebastian/cli-parser", + "type": "tidelift" } ], - "time": "2024-07-03T04:45:54+00:00" + "time": "2026-02-06T04:39:44+00:00" }, { "name": "sebastian/comparator", - "version": "6.3.3", + "version": "8.3.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/comparator.git", - "reference": "2c95e1e86cb8dd41beb8d502057d1081ccc8eca9" + "reference": "c025fc7604afab3f195fab7cdaf72327331af241" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/2c95e1e86cb8dd41beb8d502057d1081ccc8eca9", - "reference": "2c95e1e86cb8dd41beb8d502057d1081ccc8eca9", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/c025fc7604afab3f195fab7cdaf72327331af241", + "reference": "c025fc7604afab3f195fab7cdaf72327331af241", "shasum": "" }, "require": { "ext-dom": "*", "ext-mbstring": "*", - "php": ">=8.2", - "sebastian/diff": "^6.0", - "sebastian/exporter": "^6.0" + "php": ">=8.4", + "sebastian/diff": "^9.0", + "sebastian/exporter": "^8.1.0" }, "require-dev": { - "phpunit/phpunit": "^11.4" + "phpunit/phpunit": "^13.2" }, "suggest": { "ext-bcmath": "For comparing BcMath\\Number objects" @@ -5899,7 +5886,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "6.3-dev" + "dev-main": "8.3-dev" } }, "autoload": { @@ -5939,7 +5926,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/comparator/issues", "security": "https://github.com/sebastianbergmann/comparator/security/policy", - "source": "https://github.com/sebastianbergmann/comparator/tree/6.3.3" + "source": "https://github.com/sebastianbergmann/comparator/tree/8.3.0" }, "funding": [ { @@ -5959,33 +5946,33 @@ "type": "tidelift" } ], - "time": "2026-01-24T09:26:40+00:00" + "time": "2026-06-05T03:06:45+00:00" }, { "name": "sebastian/complexity", - "version": "4.0.1", + "version": "6.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/complexity.git", - "reference": "ee41d384ab1906c68852636b6de493846e13e5a0" + "reference": "c5651c795c98093480df79350cb050813fc7a2f3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/ee41d384ab1906c68852636b6de493846e13e5a0", - "reference": "ee41d384ab1906c68852636b6de493846e13e5a0", + "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/c5651c795c98093480df79350cb050813fc7a2f3", + "reference": "c5651c795c98093480df79350cb050813fc7a2f3", "shasum": "" }, "require": { "nikic/php-parser": "^5.0", - "php": ">=8.2" + "php": ">=8.4" }, "require-dev": { - "phpunit/phpunit": "^11.0" + "phpunit/phpunit": "^13.0" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "4.0-dev" + "dev-main": "6.0-dev" } }, "autoload": { @@ -6009,41 +5996,53 @@ "support": { "issues": "https://github.com/sebastianbergmann/complexity/issues", "security": "https://github.com/sebastianbergmann/complexity/security/policy", - "source": "https://github.com/sebastianbergmann/complexity/tree/4.0.1" + "source": "https://github.com/sebastianbergmann/complexity/tree/6.0.0" }, "funding": [ { "url": "https://github.com/sebastianbergmann", "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/complexity", + "type": "tidelift" } ], - "time": "2024-07-03T04:49:50+00:00" + "time": "2026-02-06T04:41:32+00:00" }, { "name": "sebastian/diff", - "version": "6.0.2", + "version": "9.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/diff.git", - "reference": "b4ccd857127db5d41a5b676f24b51371d76d8544" + "reference": "a3fb6a298a265ff487a91bbea46e03cd01dbb226" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/b4ccd857127db5d41a5b676f24b51371d76d8544", - "reference": "b4ccd857127db5d41a5b676f24b51371d76d8544", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/a3fb6a298a265ff487a91bbea46e03cd01dbb226", + "reference": "a3fb6a298a265ff487a91bbea46e03cd01dbb226", "shasum": "" }, "require": { - "php": ">=8.2" + "php": ">=8.4" }, "require-dev": { - "phpunit/phpunit": "^11.0", - "symfony/process": "^4.2 || ^5" + "phpunit/phpunit": "^13.2", + "symfony/process": "^7.4.13" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "6.0-dev" + "dev-main": "9.0-dev" } }, "autoload": { @@ -6076,35 +6075,47 @@ "support": { "issues": "https://github.com/sebastianbergmann/diff/issues", "security": "https://github.com/sebastianbergmann/diff/security/policy", - "source": "https://github.com/sebastianbergmann/diff/tree/6.0.2" + "source": "https://github.com/sebastianbergmann/diff/tree/9.0.0" }, "funding": [ { "url": "https://github.com/sebastianbergmann", "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/diff", + "type": "tidelift" } ], - "time": "2024-07-03T04:53:05+00:00" + "time": "2026-06-05T03:04:51+00:00" }, { "name": "sebastian/environment", - "version": "7.2.1", + "version": "9.3.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/environment.git", - "reference": "a5c75038693ad2e8d4b6c15ba2403532647830c4" + "reference": "6c9e487c9eb706a8d258102a1c0b0a3e53e86c2e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/a5c75038693ad2e8d4b6c15ba2403532647830c4", - "reference": "a5c75038693ad2e8d4b6c15ba2403532647830c4", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/6c9e487c9eb706a8d258102a1c0b0a3e53e86c2e", + "reference": "6c9e487c9eb706a8d258102a1c0b0a3e53e86c2e", "shasum": "" }, "require": { - "php": ">=8.2" + "php": ">=8.4" }, "require-dev": { - "phpunit/phpunit": "^11.3" + "phpunit/phpunit": "^13.1.11" }, "suggest": { "ext-posix": "*" @@ -6112,7 +6123,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "7.2-dev" + "dev-main": "9.3-dev" } }, "autoload": { @@ -6140,7 +6151,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/environment/issues", "security": "https://github.com/sebastianbergmann/environment/security/policy", - "source": "https://github.com/sebastianbergmann/environment/tree/7.2.1" + "source": "https://github.com/sebastianbergmann/environment/tree/9.3.2" }, "funding": [ { @@ -6160,34 +6171,34 @@ "type": "tidelift" } ], - "time": "2025-05-21T11:55:47+00:00" + "time": "2026-05-25T13:41:38+00:00" }, { "name": "sebastian/exporter", - "version": "6.3.2", + "version": "8.1.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/exporter.git", - "reference": "70a298763b40b213ec087c51c739efcaa90bcd74" + "reference": "c0d29a945f8cf82f300a05e69874508e307ca4c6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/70a298763b40b213ec087c51c739efcaa90bcd74", - "reference": "70a298763b40b213ec087c51c739efcaa90bcd74", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/c0d29a945f8cf82f300a05e69874508e307ca4c6", + "reference": "c0d29a945f8cf82f300a05e69874508e307ca4c6", "shasum": "" }, "require": { "ext-mbstring": "*", - "php": ">=8.2", - "sebastian/recursion-context": "^6.0" + "php": ">=8.4", + "sebastian/recursion-context": "^8.0" }, "require-dev": { - "phpunit/phpunit": "^11.3" + "phpunit/phpunit": "^13.1.10" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "6.3-dev" + "dev-main": "8.1-dev" } }, "autoload": { @@ -6230,7 +6241,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/exporter/issues", "security": "https://github.com/sebastianbergmann/exporter/security/policy", - "source": "https://github.com/sebastianbergmann/exporter/tree/6.3.2" + "source": "https://github.com/sebastianbergmann/exporter/tree/8.1.0" }, "funding": [ { @@ -6250,35 +6261,173 @@ "type": "tidelift" } ], - "time": "2025-09-24T06:12:51+00:00" + "time": "2026-05-21T11:50:56+00:00" + }, + { + "name": "sebastian/file-filter", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/file-filter.git", + "reference": "33a26f394330f6faa7684bb9cc73afb7727aae93" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/file-filter/zipball/33a26f394330f6faa7684bb9cc73afb7727aae93", + "reference": "33a26f394330f6faa7684bb9cc73afb7727aae93", + "shasum": "" + }, + "require": { + "php": ">=8.4" + }, + "require-dev": { + "phpunit/phpunit": "^13.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library for filtering files", + "homepage": "https://github.com/sebastianbergmann/file-filter", + "support": { + "issues": "https://github.com/sebastianbergmann/file-filter/issues", + "security": "https://github.com/sebastianbergmann/file-filter/security/policy", + "source": "https://github.com/sebastianbergmann/file-filter/tree/1.0.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/file-filter", + "type": "tidelift" + } + ], + "time": "2026-04-22T07:20:04+00:00" + }, + { + "name": "sebastian/git-state", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/git-state.git", + "reference": "792a952e0eba55b6960a48aeceb9f371aad1f76b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/git-state/zipball/792a952e0eba55b6960a48aeceb9f371aad1f76b", + "reference": "792a952e0eba55b6960a48aeceb9f371aad1f76b", + "shasum": "" + }, + "require": { + "php": ">=8.4" + }, + "require-dev": { + "phpunit/phpunit": "^13.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library for describing the state of a Git checkout", + "homepage": "https://github.com/sebastianbergmann/git-state", + "support": { + "issues": "https://github.com/sebastianbergmann/git-state/issues", + "security": "https://github.com/sebastianbergmann/git-state/security/policy", + "source": "https://github.com/sebastianbergmann/git-state/tree/1.0.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/git-state", + "type": "tidelift" + } + ], + "time": "2026-03-21T12:54:28+00:00" }, { "name": "sebastian/global-state", - "version": "7.0.2", + "version": "9.0.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/global-state.git", - "reference": "3be331570a721f9a4b5917f4209773de17f747d7" + "reference": "ba68ba79da690cf7eddefd3ce5b78b20b9ba9945" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/3be331570a721f9a4b5917f4209773de17f747d7", - "reference": "3be331570a721f9a4b5917f4209773de17f747d7", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/ba68ba79da690cf7eddefd3ce5b78b20b9ba9945", + "reference": "ba68ba79da690cf7eddefd3ce5b78b20b9ba9945", "shasum": "" }, "require": { - "php": ">=8.2", - "sebastian/object-reflector": "^4.0", - "sebastian/recursion-context": "^6.0" + "php": ">=8.4", + "sebastian/object-reflector": "^6.0", + "sebastian/recursion-context": "^8.0" }, "require-dev": { "ext-dom": "*", - "phpunit/phpunit": "^11.0" + "phpunit/phpunit": "^13.1.13" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "7.0-dev" + "dev-main": "9.0-dev" } }, "autoload": { @@ -6304,41 +6453,53 @@ "support": { "issues": "https://github.com/sebastianbergmann/global-state/issues", "security": "https://github.com/sebastianbergmann/global-state/security/policy", - "source": "https://github.com/sebastianbergmann/global-state/tree/7.0.2" + "source": "https://github.com/sebastianbergmann/global-state/tree/9.0.1" }, "funding": [ { "url": "https://github.com/sebastianbergmann", "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/global-state", + "type": "tidelift" } ], - "time": "2024-07-03T04:57:36+00:00" + "time": "2026-06-01T15:11:33+00:00" }, { "name": "sebastian/lines-of-code", - "version": "3.0.1", + "version": "5.0.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/lines-of-code.git", - "reference": "d36ad0d782e5756913e42ad87cb2890f4ffe467a" + "reference": "d2cff273a90c79b0eb590baa682d4b5c318bdbb7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/d36ad0d782e5756913e42ad87cb2890f4ffe467a", - "reference": "d36ad0d782e5756913e42ad87cb2890f4ffe467a", + "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/d2cff273a90c79b0eb590baa682d4b5c318bdbb7", + "reference": "d2cff273a90c79b0eb590baa682d4b5c318bdbb7", "shasum": "" }, "require": { - "nikic/php-parser": "^5.0", - "php": ">=8.2" + "nikic/php-parser": "^5.7.0", + "php": ">=8.4" }, "require-dev": { - "phpunit/phpunit": "^11.0" + "phpunit/phpunit": "^13.1.10" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "3.0-dev" + "dev-main": "5.0-dev" } }, "autoload": { @@ -6362,42 +6523,54 @@ "support": { "issues": "https://github.com/sebastianbergmann/lines-of-code/issues", "security": "https://github.com/sebastianbergmann/lines-of-code/security/policy", - "source": "https://github.com/sebastianbergmann/lines-of-code/tree/3.0.1" + "source": "https://github.com/sebastianbergmann/lines-of-code/tree/5.0.1" }, "funding": [ { "url": "https://github.com/sebastianbergmann", "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/lines-of-code", + "type": "tidelift" } ], - "time": "2024-07-03T04:58:38+00:00" + "time": "2026-05-19T16:23:37+00:00" }, { "name": "sebastian/object-enumerator", - "version": "6.0.1", + "version": "8.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/object-enumerator.git", - "reference": "f5b498e631a74204185071eb41f33f38d64608aa" + "reference": "b39ab125fd9a7434b0ecbc4202eebce11a98cfc5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/f5b498e631a74204185071eb41f33f38d64608aa", - "reference": "f5b498e631a74204185071eb41f33f38d64608aa", + "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/b39ab125fd9a7434b0ecbc4202eebce11a98cfc5", + "reference": "b39ab125fd9a7434b0ecbc4202eebce11a98cfc5", "shasum": "" }, "require": { - "php": ">=8.2", - "sebastian/object-reflector": "^4.0", - "sebastian/recursion-context": "^6.0" + "php": ">=8.4", + "sebastian/object-reflector": "^6.0", + "sebastian/recursion-context": "^8.0" }, "require-dev": { - "phpunit/phpunit": "^11.0" + "phpunit/phpunit": "^13.0" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "6.0-dev" + "dev-main": "8.0-dev" } }, "autoload": { @@ -6420,40 +6593,52 @@ "support": { "issues": "https://github.com/sebastianbergmann/object-enumerator/issues", "security": "https://github.com/sebastianbergmann/object-enumerator/security/policy", - "source": "https://github.com/sebastianbergmann/object-enumerator/tree/6.0.1" + "source": "https://github.com/sebastianbergmann/object-enumerator/tree/8.0.0" }, "funding": [ { "url": "https://github.com/sebastianbergmann", "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/object-enumerator", + "type": "tidelift" } ], - "time": "2024-07-03T05:00:13+00:00" + "time": "2026-02-06T04:46:36+00:00" }, { "name": "sebastian/object-reflector", - "version": "4.0.1", + "version": "6.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/object-reflector.git", - "reference": "6e1a43b411b2ad34146dee7524cb13a068bb35f9" + "reference": "3ca042c2c60b0eab094f8a1b6a7093f4d4c72200" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/6e1a43b411b2ad34146dee7524cb13a068bb35f9", - "reference": "6e1a43b411b2ad34146dee7524cb13a068bb35f9", + "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/3ca042c2c60b0eab094f8a1b6a7093f4d4c72200", + "reference": "3ca042c2c60b0eab094f8a1b6a7093f4d4c72200", "shasum": "" }, "require": { - "php": ">=8.2" + "php": ">=8.4" }, "require-dev": { - "phpunit/phpunit": "^11.0" + "phpunit/phpunit": "^13.0" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "4.0-dev" + "dev-main": "6.0-dev" } }, "autoload": { @@ -6476,40 +6661,52 @@ "support": { "issues": "https://github.com/sebastianbergmann/object-reflector/issues", "security": "https://github.com/sebastianbergmann/object-reflector/security/policy", - "source": "https://github.com/sebastianbergmann/object-reflector/tree/4.0.1" + "source": "https://github.com/sebastianbergmann/object-reflector/tree/6.0.0" }, "funding": [ { "url": "https://github.com/sebastianbergmann", "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/object-reflector", + "type": "tidelift" } ], - "time": "2024-07-03T05:01:32+00:00" + "time": "2026-02-06T04:47:13+00:00" }, { "name": "sebastian/recursion-context", - "version": "6.0.3", + "version": "8.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/recursion-context.git", - "reference": "f6458abbf32a6c8174f8f26261475dc133b3d9dc" + "reference": "74c5af21f6a5833e91767ca068c4d3dfec15317e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/f6458abbf32a6c8174f8f26261475dc133b3d9dc", - "reference": "f6458abbf32a6c8174f8f26261475dc133b3d9dc", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/74c5af21f6a5833e91767ca068c4d3dfec15317e", + "reference": "74c5af21f6a5833e91767ca068c4d3dfec15317e", "shasum": "" }, "require": { - "php": ">=8.2" + "php": ">=8.4" }, "require-dev": { - "phpunit/phpunit": "^11.3" + "phpunit/phpunit": "^13.0" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "6.0-dev" + "dev-main": "8.0-dev" } }, "autoload": { @@ -6540,7 +6737,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/recursion-context/issues", "security": "https://github.com/sebastianbergmann/recursion-context/security/policy", - "source": "https://github.com/sebastianbergmann/recursion-context/tree/6.0.3" + "source": "https://github.com/sebastianbergmann/recursion-context/tree/8.0.0" }, "funding": [ { @@ -6560,32 +6757,32 @@ "type": "tidelift" } ], - "time": "2025-08-13T04:42:22+00:00" + "time": "2026-02-06T04:51:28+00:00" }, { "name": "sebastian/type", - "version": "5.1.3", + "version": "7.0.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/type.git", - "reference": "f77d2d4e78738c98d9a68d2596fe5e8fa380f449" + "reference": "fee0309275847fefd7636167085e379c1dbf6990" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/f77d2d4e78738c98d9a68d2596fe5e8fa380f449", - "reference": "f77d2d4e78738c98d9a68d2596fe5e8fa380f449", + "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/fee0309275847fefd7636167085e379c1dbf6990", + "reference": "fee0309275847fefd7636167085e379c1dbf6990", "shasum": "" }, "require": { - "php": ">=8.2" + "php": ">=8.4" }, "require-dev": { - "phpunit/phpunit": "^11.3" + "phpunit/phpunit": "^13.1.10" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "5.1-dev" + "dev-main": "7.0-dev" } }, "autoload": { @@ -6609,7 +6806,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/type/issues", "security": "https://github.com/sebastianbergmann/type/security/policy", - "source": "https://github.com/sebastianbergmann/type/tree/5.1.3" + "source": "https://github.com/sebastianbergmann/type/tree/7.0.1" }, "funding": [ { @@ -6629,29 +6826,29 @@ "type": "tidelift" } ], - "time": "2025-08-09T06:55:48+00:00" + "time": "2026-05-20T06:49:11+00:00" }, { "name": "sebastian/version", - "version": "5.0.2", + "version": "7.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/version.git", - "reference": "c687e3387b99f5b03b6caa64c74b63e2936ff874" + "reference": "ad37a5552c8e2b88572249fdc19b6da7792e021b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/c687e3387b99f5b03b6caa64c74b63e2936ff874", - "reference": "c687e3387b99f5b03b6caa64c74b63e2936ff874", + "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/ad37a5552c8e2b88572249fdc19b6da7792e021b", + "reference": "ad37a5552c8e2b88572249fdc19b6da7792e021b", "shasum": "" }, "require": { - "php": ">=8.2" + "php": ">=8.4" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "5.0-dev" + "dev-main": "7.0-dev" } }, "autoload": { @@ -6675,15 +6872,27 @@ "support": { "issues": "https://github.com/sebastianbergmann/version/issues", "security": "https://github.com/sebastianbergmann/version/security/policy", - "source": "https://github.com/sebastianbergmann/version/tree/5.0.2" + "source": "https://github.com/sebastianbergmann/version/tree/7.0.0" }, "funding": [ { "url": "https://github.com/sebastianbergmann", "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/version", + "type": "tidelift" } ], - "time": "2024-10-09T05:16:32+00:00" + "time": "2026-02-06T04:52:52+00:00" }, { "name": "sensiolabs/ansi-to-html", @@ -8140,16 +8349,16 @@ }, { "name": "symfony/console", - "version": "v6.4.34", + "version": "v6.4.41", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "7b1f1c37eff5910ddda2831345467e593a5120ad" + "reference": "d21b17ed158e79180fac3895ff751707970eeb57" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/7b1f1c37eff5910ddda2831345467e593a5120ad", - "reference": "7b1f1c37eff5910ddda2831345467e593a5120ad", + "url": "https://api.github.com/repos/symfony/console/zipball/d21b17ed158e79180fac3895ff751707970eeb57", + "reference": "d21b17ed158e79180fac3895ff751707970eeb57", "shasum": "" }, "require": { @@ -8214,7 +8423,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v6.4.34" + "source": "https://github.com/symfony/console/tree/v6.4.41" }, "funding": [ { @@ -8234,7 +8443,7 @@ "type": "tidelift" } ], - "time": "2026-02-23T15:42:15+00:00" + "time": "2026-05-24T08:48:41+00:00" }, { "name": "symfony/css-selector", @@ -8392,16 +8601,16 @@ }, { "name": "symfony/deprecation-contracts", - "version": "v3.6.0", + "version": "v3.7.0", "source": { "type": "git", "url": "https://github.com/symfony/deprecation-contracts.git", - "reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62" + "reference": "50f59d1f3ca46d41ac911f97a78626b6756af35b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/63afe740e99a13ba87ec199bb07bbdee937a5b62", - "reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/50f59d1f3ca46d41ac911f97a78626b6756af35b", + "reference": "50f59d1f3ca46d41ac911f97a78626b6756af35b", "shasum": "" }, "require": { @@ -8414,7 +8623,7 @@ "name": "symfony/contracts" }, "branch-alias": { - "dev-main": "3.6-dev" + "dev-main": "3.7-dev" } }, "autoload": { @@ -8439,7 +8648,7 @@ "description": "A generic function and convention to trigger deprecation notices", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/deprecation-contracts/tree/v3.6.0" + "source": "https://github.com/symfony/deprecation-contracts/tree/v3.7.0" }, "funding": [ { @@ -8450,12 +8659,16 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2024-09-25T14:21:43+00:00" + "time": "2026-04-13T15:52:40+00:00" }, { "name": "symfony/doctrine-bridge", @@ -8797,16 +9010,16 @@ }, { "name": "symfony/event-dispatcher", - "version": "v6.4.32", + "version": "v6.4.37", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "99d7e101826e6610606b9433248f80c1997cd20b" + "reference": "2e3bf817ba9347341ab15926700fb6320367c0e1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/99d7e101826e6610606b9433248f80c1997cd20b", - "reference": "99d7e101826e6610606b9433248f80c1997cd20b", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/2e3bf817ba9347341ab15926700fb6320367c0e1", + "reference": "2e3bf817ba9347341ab15926700fb6320367c0e1", "shasum": "" }, "require": { @@ -8857,7 +9070,7 @@ "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/event-dispatcher/tree/v6.4.32" + "source": "https://github.com/symfony/event-dispatcher/tree/v6.4.37" }, "funding": [ { @@ -8877,20 +9090,20 @@ "type": "tidelift" } ], - "time": "2026-01-05T11:13:48+00:00" + "time": "2026-04-13T14:11:12+00:00" }, { "name": "symfony/event-dispatcher-contracts", - "version": "v3.6.0", + "version": "v3.7.0", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher-contracts.git", - "reference": "59eb412e93815df44f05f342958efa9f46b1e586" + "reference": "ccba7060602b7fed0b03c85bf025257f76d9ef32" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/59eb412e93815df44f05f342958efa9f46b1e586", - "reference": "59eb412e93815df44f05f342958efa9f46b1e586", + "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/ccba7060602b7fed0b03c85bf025257f76d9ef32", + "reference": "ccba7060602b7fed0b03c85bf025257f76d9ef32", "shasum": "" }, "require": { @@ -8904,7 +9117,7 @@ "name": "symfony/contracts" }, "branch-alias": { - "dev-main": "3.6-dev" + "dev-main": "3.7-dev" } }, "autoload": { @@ -8937,7 +9150,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v3.6.0" + "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v3.7.0" }, "funding": [ { @@ -8948,12 +9161,16 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2024-09-25T14:21:43+00:00" + "time": "2026-01-05T13:30:16+00:00" }, { "name": "symfony/expression-language", @@ -9025,16 +9242,16 @@ }, { "name": "symfony/filesystem", - "version": "v6.4.34", + "version": "v6.4.39", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "01ffe0411b842f93c571e5c391f289c3fdd498c3" + "reference": "c507b077756b4e3e09adbbe7975fac81cd3722ca" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/01ffe0411b842f93c571e5c391f289c3fdd498c3", - "reference": "01ffe0411b842f93c571e5c391f289c3fdd498c3", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/c507b077756b4e3e09adbbe7975fac81cd3722ca", + "reference": "c507b077756b4e3e09adbbe7975fac81cd3722ca", "shasum": "" }, "require": { @@ -9071,7 +9288,7 @@ "description": "Provides basic utilities for the filesystem", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/filesystem/tree/v6.4.34" + "source": "https://github.com/symfony/filesystem/tree/v6.4.39" }, "funding": [ { @@ -9091,7 +9308,7 @@ "type": "tidelift" } ], - "time": "2026-02-24T17:51:06+00:00" + "time": "2026-05-07T13:11:42+00:00" }, { "name": "symfony/finder", @@ -10194,16 +10411,16 @@ }, { "name": "symfony/polyfill-ctype", - "version": "v1.33.0", + "version": "v1.37.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638" + "reference": "141046a8f9477948ff284fa65be2095baafb94f2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/a3cc8b044a6ea513310cbd48ef7333b384945638", - "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/141046a8f9477948ff284fa65be2095baafb94f2", + "reference": "141046a8f9477948ff284fa65be2095baafb94f2", "shasum": "" }, "require": { @@ -10253,7 +10470,7 @@ "portable" ], "support": { - "source": "https://github.com/symfony/polyfill-ctype/tree/v1.33.0" + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.37.0" }, "funding": [ { @@ -10273,20 +10490,20 @@ "type": "tidelift" } ], - "time": "2024-09-09T11:45:10+00:00" + "time": "2026-04-10T16:19:22+00:00" }, { "name": "symfony/polyfill-intl-grapheme", - "version": "v1.33.0", + "version": "v1.38.1", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-grapheme.git", - "reference": "380872130d3a5dd3ace2f4010d95125fde5d5c70" + "reference": "e9247d281d694a5120554d9afaf54e070e88a603" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/380872130d3a5dd3ace2f4010d95125fde5d5c70", - "reference": "380872130d3a5dd3ace2f4010d95125fde5d5c70", + "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/e9247d281d694a5120554d9afaf54e070e88a603", + "reference": "e9247d281d694a5120554d9afaf54e070e88a603", "shasum": "" }, "require": { @@ -10335,7 +10552,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.33.0" + "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.38.1" }, "funding": [ { @@ -10355,7 +10572,7 @@ "type": "tidelift" } ], - "time": "2025-06-27T09:58:17+00:00" + "time": "2026-05-26T05:58:03+00:00" }, { "name": "symfony/polyfill-intl-icu", @@ -10534,16 +10751,16 @@ }, { "name": "symfony/polyfill-intl-normalizer", - "version": "v1.33.0", + "version": "v1.38.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-normalizer.git", - "reference": "3833d7255cc303546435cb650316bff708a1c75c" + "reference": "2d446c214bdbe5b71bde5011b060a05fece3ae6b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/3833d7255cc303546435cb650316bff708a1c75c", - "reference": "3833d7255cc303546435cb650316bff708a1c75c", + "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/2d446c214bdbe5b71bde5011b060a05fece3ae6b", + "reference": "2d446c214bdbe5b71bde5011b060a05fece3ae6b", "shasum": "" }, "require": { @@ -10595,7 +10812,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.33.0" + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.38.0" }, "funding": [ { @@ -10615,20 +10832,20 @@ "type": "tidelift" } ], - "time": "2024-09-09T11:45:10+00:00" + "time": "2026-05-25T13:48:31+00:00" }, { "name": "symfony/polyfill-mbstring", - "version": "v1.33.0", + "version": "v1.38.2", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493" + "reference": "d3d318bad5e7a1bfbd026009c8bfb8d8f99ae6b6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/6d857f4d76bd4b343eac26d6b539585d2bc56493", - "reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/d3d318bad5e7a1bfbd026009c8bfb8d8f99ae6b6", + "reference": "d3d318bad5e7a1bfbd026009c8bfb8d8f99ae6b6", "shasum": "" }, "require": { @@ -10680,7 +10897,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.33.0" + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.38.2" }, "funding": [ { @@ -10700,20 +10917,20 @@ "type": "tidelift" } ], - "time": "2024-12-23T08:48:59+00:00" + "time": "2026-05-27T06:59:30+00:00" }, { "name": "symfony/process", - "version": "v6.4.33", + "version": "v6.4.41", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "c46e854e79b52d07666e43924a20cb6dc546644e" + "reference": "c8fc09bdfe9fde9aaa89b415a4477feaccec16a7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/c46e854e79b52d07666e43924a20cb6dc546644e", - "reference": "c46e854e79b52d07666e43924a20cb6dc546644e", + "url": "https://api.github.com/repos/symfony/process/zipball/c8fc09bdfe9fde9aaa89b415a4477feaccec16a7", + "reference": "c8fc09bdfe9fde9aaa89b415a4477feaccec16a7", "shasum": "" }, "require": { @@ -10745,7 +10962,7 @@ "description": "Executes commands in sub-processes", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/process/tree/v6.4.33" + "source": "https://github.com/symfony/process/tree/v6.4.41" }, "funding": [ { @@ -10765,7 +10982,7 @@ "type": "tidelift" } ], - "time": "2026-01-23T16:02:12+00:00" + "time": "2026-05-23T13:47:21+00:00" }, { "name": "symfony/property-access", @@ -11668,16 +11885,16 @@ }, { "name": "symfony/service-contracts", - "version": "v3.6.1", + "version": "v3.7.0", "source": { "type": "git", "url": "https://github.com/symfony/service-contracts.git", - "reference": "45112560a3ba2d715666a509a0bc9521d10b6c43" + "reference": "d25d82433a80eba6aa0e6c24b61d7370d99e444a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/service-contracts/zipball/45112560a3ba2d715666a509a0bc9521d10b6c43", - "reference": "45112560a3ba2d715666a509a0bc9521d10b6c43", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/d25d82433a80eba6aa0e6c24b61d7370d99e444a", + "reference": "d25d82433a80eba6aa0e6c24b61d7370d99e444a", "shasum": "" }, "require": { @@ -11695,7 +11912,7 @@ "name": "symfony/contracts" }, "branch-alias": { - "dev-main": "3.6-dev" + "dev-main": "3.7-dev" } }, "autoload": { @@ -11731,7 +11948,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/service-contracts/tree/v3.6.1" + "source": "https://github.com/symfony/service-contracts/tree/v3.7.0" }, "funding": [ { @@ -11751,7 +11968,7 @@ "type": "tidelift" } ], - "time": "2025-07-15T11:30:57+00:00" + "time": "2026-03-28T09:44:51+00:00" }, { "name": "symfony/stimulus-bundle", @@ -11894,16 +12111,16 @@ }, { "name": "symfony/string", - "version": "v6.4.34", + "version": "v6.4.39", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "2adaf4106f2ef4c67271971bde6d3fe0a6936432" + "reference": "62e3c927de664edadb5bef260987eb047a17a113" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/2adaf4106f2ef4c67271971bde6d3fe0a6936432", - "reference": "2adaf4106f2ef4c67271971bde6d3fe0a6936432", + "url": "https://api.github.com/repos/symfony/string/zipball/62e3c927de664edadb5bef260987eb047a17a113", + "reference": "62e3c927de664edadb5bef260987eb047a17a113", "shasum": "" }, "require": { @@ -11959,7 +12176,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v6.4.34" + "source": "https://github.com/symfony/string/tree/v6.4.39" }, "funding": [ { @@ -11979,7 +12196,7 @@ "type": "tidelift" } ], - "time": "2026-02-08T20:44:54+00:00" + "time": "2026-05-12T11:44:19+00:00" }, { "name": "symfony/translation", @@ -12799,23 +13016,23 @@ }, { "name": "theseer/tokenizer", - "version": "1.3.1", + "version": "2.0.1", "source": { "type": "git", "url": "https://github.com/theseer/tokenizer.git", - "reference": "b7489ce515e168639d17feec34b8847c326b0b3c" + "reference": "7989e43bf381af0eac72e4f0ca5bcbfa81658be4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/theseer/tokenizer/zipball/b7489ce515e168639d17feec34b8847c326b0b3c", - "reference": "b7489ce515e168639d17feec34b8847c326b0b3c", + "url": "https://api.github.com/repos/theseer/tokenizer/zipball/7989e43bf381af0eac72e4f0ca5bcbfa81658be4", + "reference": "7989e43bf381af0eac72e4f0ca5bcbfa81658be4", "shasum": "" }, "require": { "ext-dom": "*", "ext-tokenizer": "*", "ext-xmlwriter": "*", - "php": "^7.2 || ^8.0" + "php": "^8.1" }, "type": "library", "autoload": { @@ -12837,7 +13054,7 @@ "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", "support": { "issues": "https://github.com/theseer/tokenizer/issues", - "source": "https://github.com/theseer/tokenizer/tree/1.3.1" + "source": "https://github.com/theseer/tokenizer/tree/2.0.1" }, "funding": [ { @@ -12845,7 +13062,7 @@ "type": "github" } ], - "time": "2025-11-17T20:03:58+00:00" + "time": "2025-12-08T11:19:18+00:00" }, { "name": "twig/string-extra", @@ -14257,15 +14474,15 @@ }, { "name": "phpstan/phpstan", - "version": "1.12.33", + "version": "2.2.2", "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/37982d6fc7cbb746dda7773530cda557cdf119e1", - "reference": "37982d6fc7cbb746dda7773530cda557cdf119e1", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/e5cc34d491a90e79c216d824f60fe21fd4d93bd6", + "reference": "e5cc34d491a90e79c216d824f60fe21fd4d93bd6", "shasum": "" }, "require": { - "php": "^7.2|^8.0" + "php": "^7.4|^8.0" }, "conflict": { "phpstan/phpstan-shim": "*" @@ -14284,6 +14501,17 @@ "license": [ "MIT" ], + "authors": [ + { + "name": "Ondřej Mirtes" + }, + { + "name": "Markus Staab" + }, + { + "name": "Vincent Langlet" + } + ], "description": "PHPStan - PHP Static Analysis Tool", "keywords": [ "dev", @@ -14306,34 +14534,35 @@ "type": "github" } ], - "time": "2026-02-28T20:30:03+00:00" + "time": "2026-06-05T09:00:01+00:00" }, { "name": "phpstan/phpstan-phpunit", - "version": "1.4.2", + "version": "2.0.16", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan-phpunit.git", - "reference": "72a6721c9b64b3e4c9db55abbc38f790b318267e" + "reference": "6ab598e1bc106e6827fd346ae4a12b4a5d634c32" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan-phpunit/zipball/72a6721c9b64b3e4c9db55abbc38f790b318267e", - "reference": "72a6721c9b64b3e4c9db55abbc38f790b318267e", + "url": "https://api.github.com/repos/phpstan/phpstan-phpunit/zipball/6ab598e1bc106e6827fd346ae4a12b4a5d634c32", + "reference": "6ab598e1bc106e6827fd346ae4a12b4a5d634c32", "shasum": "" }, "require": { - "php": "^7.2 || ^8.0", - "phpstan/phpstan": "^1.12" + "php": "^7.4 || ^8.0", + "phpstan/phpstan": "^2.1.32" }, "conflict": { "phpunit/phpunit": "<7.0" }, "require-dev": { - "nikic/php-parser": "^4.13.0", + "nikic/php-parser": "^5", "php-parallel-lint/php-parallel-lint": "^1.2", - "phpstan/phpstan-strict-rules": "^1.5.1", - "phpunit/phpunit": "^9.5" + "phpstan/phpstan-deprecation-rules": "^2.0", + "phpstan/phpstan-strict-rules": "^2.0", + "phpunit/phpunit": "^9.6" }, "type": "phpstan-extension", "extra": { @@ -14354,41 +14583,43 @@ "MIT" ], "description": "PHPUnit extensions and rules for PHPStan", + "keywords": [ + "static analysis" + ], "support": { "issues": "https://github.com/phpstan/phpstan-phpunit/issues", - "source": "https://github.com/phpstan/phpstan-phpunit/tree/1.4.2" + "source": "https://github.com/phpstan/phpstan-phpunit/tree/2.0.16" }, - "time": "2024-12-17T17:20:49+00:00" + "time": "2026-02-14T09:05:21+00:00" }, { "name": "phpstan/phpstan-symfony", - "version": "1.4.16", + "version": "2.0.19", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan-symfony.git", - "reference": "18df9086a84fc28e9a231ea8e91d5aff1a0a3d6f" + "reference": "546071ed7f80a89ec30909346eb7cc741800740a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan-symfony/zipball/18df9086a84fc28e9a231ea8e91d5aff1a0a3d6f", - "reference": "18df9086a84fc28e9a231ea8e91d5aff1a0a3d6f", + "url": "https://api.github.com/repos/phpstan/phpstan-symfony/zipball/546071ed7f80a89ec30909346eb7cc741800740a", + "reference": "546071ed7f80a89ec30909346eb7cc741800740a", "shasum": "" }, "require": { "ext-simplexml": "*", - "php": "^7.2 || ^8.0", - "phpstan/phpstan": "^1.12" + "php": "^7.4 || ^8.0", + "phpstan/phpstan": "^2.1.13" }, "conflict": { "symfony/framework-bundle": "<3.0" }, "require-dev": { - "nikic/php-parser": "^4.13.0", "php-parallel-lint/php-parallel-lint": "^1.2", - "phpstan/phpstan-phpunit": "^1.3.11", - "phpstan/phpstan-strict-rules": "^1.5.1", - "phpunit/phpunit": "^8.5.29 || ^9.5", - "psr/container": "1.0 || 1.1.1", + "phpstan/phpstan-phpunit": "^2.0.8", + "phpstan/phpstan-strict-rules": "^2.0", + "phpunit/phpunit": "^9.6", + "psr/container": "1.1.2", "symfony/config": "^5.4 || ^6.1", "symfony/console": "^5.4 || ^6.1", "symfony/dependency-injection": "^5.4 || ^6.1", @@ -14426,11 +14657,14 @@ } ], "description": "Symfony Framework extensions and rules for PHPStan", + "keywords": [ + "static analysis" + ], "support": { "issues": "https://github.com/phpstan/phpstan-symfony/issues", - "source": "https://github.com/phpstan/phpstan-symfony/tree/1.4.16" + "source": "https://github.com/phpstan/phpstan-symfony/tree/2.0.19" }, - "time": "2025-09-07T06:55:28+00:00" + "time": "2026-05-29T12:52:44+00:00" }, { "name": "sabberworm/php-css-parser", diff --git a/packages/application/Tests/Configuration/DoctrineConfigurationRegistryTest.php b/packages/application/Tests/Configuration/DoctrineConfigurationRegistryTest.php index 94f679025..c3b84aca3 100644 --- a/packages/application/Tests/Configuration/DoctrineConfigurationRegistryTest.php +++ b/packages/application/Tests/Configuration/DoctrineConfigurationRegistryTest.php @@ -8,7 +8,6 @@ use Draw\Component\Application\Configuration\Entity\Config; use Draw\Component\Core\Reflection\ReflectionAccessor; use Draw\Component\Tester\DoctrineOrmTrait; -use Draw\Contracts\Application\ConfigurationRegistryInterface; use Draw\Contracts\Application\Exception\ConfigurationIsNotAccessibleException; use PHPUnit\Framework\Attributes\CoversClass; use PHPUnit\Framework\Attributes\DataProvider; @@ -47,11 +46,6 @@ protected function setUp(): void $this->object = new DoctrineConfigurationRegistry(static::createRegistry(self::$entityManager)); } - public function testConstruct(): void - { - static::assertInstanceOf(ConfigurationRegistryInterface::class, $this->object); - } - public function testHasNotSet(): void { static::assertFalse($this->object->has('value')); diff --git a/packages/application/Tests/DependencyInjection/FeatureIntegrationTest.php b/packages/application/Tests/DependencyInjection/FeatureIntegrationTest.php index c04487254..c93172bbe 100644 --- a/packages/application/Tests/DependencyInjection/FeatureIntegrationTest.php +++ b/packages/application/Tests/DependencyInjection/FeatureIntegrationTest.php @@ -45,8 +45,7 @@ public static function provideLoadCases(): iterable ] ), ], - [ - ], + [], [], ]; } diff --git a/packages/application/Tests/DependencyInjection/SystemMonitoringIntegrationTest.php b/packages/application/Tests/DependencyInjection/SystemMonitoringIntegrationTest.php index f58187acf..017311933 100644 --- a/packages/application/Tests/DependencyInjection/SystemMonitoringIntegrationTest.php +++ b/packages/application/Tests/DependencyInjection/SystemMonitoringIntegrationTest.php @@ -38,8 +38,7 @@ public function getDefaultConfiguration(): array { return [ 'enabled' => true, - 'service_status_providers' => [ - ], + 'service_status_providers' => [], ]; } @@ -100,13 +99,11 @@ public static function provideLoadCases(): iterable [ new ServiceConfiguration( 'draw.system_monitoring.monitored_service.doctrine_connection', - [ - ] + [] ), new ServiceConfiguration( 'draw.system_monitoring.monitored_service.messenger', - [ - ], + [], ), new ServiceConfiguration( 'draw.system_monitoring.action.ping_action', diff --git a/packages/application/Tests/Versioning/Command/UpdateDeployedVersionCommandTest.php b/packages/application/Tests/Versioning/Command/UpdateDeployedVersionCommandTest.php index 102931541..be0e2c238 100644 --- a/packages/application/Tests/Versioning/Command/UpdateDeployedVersionCommandTest.php +++ b/packages/application/Tests/Versioning/Command/UpdateDeployedVersionCommandTest.php @@ -7,7 +7,6 @@ use Draw\Component\Tester\Application\CommandDataTester; use Draw\Component\Tester\Application\CommandTestTrait; use PHPUnit\Framework\Attributes\CoversClass; -use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; /** @@ -18,12 +17,10 @@ class UpdateDeployedVersionCommandTest extends TestCase { use CommandTestTrait; - private VersionManager&MockObject $versionManager; - protected function setUp(): void { $this->command = new UpdateDeployedVersionCommand( - $this->versionManager = $this->createMock(VersionManager::class) + static::createStub(VersionManager::class) ); } @@ -44,15 +41,20 @@ public static function provideTestOption(): iterable public function testExecute(): void { - $this->versionManager + $this->command = new UpdateDeployedVersionCommand( + $versionManager = $this->createMock(VersionManager::class) + ); + + $versionManager ->expects(static::once()) ->method('updateDeployedVersion') ; - $this->versionManager + $versionManager ->expects(static::once()) ->method('getRunningVersion') ->willReturn($deployedVersion = uniqid('version-')) + ->seal() ; $this->execute([]) diff --git a/packages/application/Tests/Versioning/Event/FetchRunningVersionEventTest.php b/packages/application/Tests/Versioning/Event/FetchRunningVersionEventTest.php index 15cde261d..6fb618797 100644 --- a/packages/application/Tests/Versioning/Event/FetchRunningVersionEventTest.php +++ b/packages/application/Tests/Versioning/Event/FetchRunningVersionEventTest.php @@ -5,7 +5,6 @@ use Draw\Component\Application\Versioning\Event\FetchRunningVersionEvent; use PHPUnit\Framework\Attributes\CoversClass; use PHPUnit\Framework\TestCase; -use Symfony\Contracts\EventDispatcher\Event; /** * @internal @@ -20,14 +19,6 @@ protected function setUp(): void $this->event = new FetchRunningVersionEvent(); } - public function testConstruct(): void - { - static::assertInstanceOf( - Event::class, - $this->event - ); - } - public function testRunningVersionMutator(): void { static::assertFalse($this->event->isPropagationStopped()); diff --git a/packages/application/Tests/Versioning/EventListener/FetchRunningVersionListenerTest.php b/packages/application/Tests/Versioning/EventListener/FetchRunningVersionListenerTest.php index 5c29aeb58..77a1f5ca0 100644 --- a/packages/application/Tests/Versioning/EventListener/FetchRunningVersionListenerTest.php +++ b/packages/application/Tests/Versioning/EventListener/FetchRunningVersionListenerTest.php @@ -7,7 +7,6 @@ use Draw\Component\Core\Reflection\ReflectionAccessor; use PHPUnit\Framework\Attributes\CoversClass; use PHPUnit\Framework\TestCase; -use Symfony\Component\EventDispatcher\EventSubscriberInterface; /** * @internal @@ -30,15 +29,9 @@ protected function setUp(): void protected function tearDown(): void { - @unlink($this->projectDirectory.'/public/version.txt'); - } - - public function testConstruct(): void - { - static::assertInstanceOf( - EventSubscriberInterface::class, - $this->service - ); + if (file_exists($file = $this->projectDirectory.'/public/version.txt')) { + @unlink($file); + } } public function testGetSubscribedEvents(): void diff --git a/packages/application/Tests/Versioning/VersionManagerTest.php b/packages/application/Tests/Versioning/VersionManagerTest.php index a23abffd4..3782d7c54 100644 --- a/packages/application/Tests/Versioning/VersionManagerTest.php +++ b/packages/application/Tests/Versioning/VersionManagerTest.php @@ -6,9 +6,7 @@ use Draw\Component\Application\Versioning\VersionManager; use Draw\Component\Core\Reflection\ReflectionAccessor; use Draw\Contracts\Application\ConfigurationRegistryInterface; -use Draw\Contracts\Application\VersionVerificationInterface; use PHPUnit\Framework\Attributes\CoversClass; -use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; @@ -18,56 +16,37 @@ #[CoversClass(VersionManager::class)] class VersionManagerTest extends TestCase { - private VersionManager $service; - - private ConfigurationRegistryInterface&MockObject $configurationRegistry; - - private MockObject&EventDispatcherInterface $eventDispatcher; - - protected function setUp(): void - { - $this->service = new VersionManager( - $this->configurationRegistry = $this->createMock(ConfigurationRegistryInterface::class), - $this->eventDispatcher = $this->createMock(EventDispatcherInterface::class) - ); - } - - public function testConstant(): void - { - static::assertSame( - 'draw-application-deployed-version', - $this->service::CONFIG - ); - } - - public function testConstruct(): void + public function testGetRunningVersionNotFound(): void { - static::assertInstanceOf( - VersionVerificationInterface::class, - $this->service + $service = new VersionManager( + static::createStub(ConfigurationRegistryInterface::class), + $eventDispatcher = $this->createMock(EventDispatcherInterface::class) ); - } - public function testGetRunningVersionNotFound(): void - { - $this->eventDispatcher + $eventDispatcher ->expects(static::once()) ->method('dispatch') ->with(static::isInstanceOf(FetchRunningVersionEvent::class)) ->willReturnArgument(0) + ->seal() ; - static::assertNull($this->service->getRunningVersion()); + static::assertNull($service->getRunningVersion()); // Multiple call will not trigger multiple event - static::assertNull($this->service->getRunningVersion()); + static::assertNull($service->getRunningVersion()); } public function testGetRunningVersion(): void { + $service = new VersionManager( + static::createStub(ConfigurationRegistryInterface::class), + $eventDispatcher = $this->createMock(EventDispatcherInterface::class) + ); + $version = uniqid('version-'); - $this->eventDispatcher + $eventDispatcher ->expects(static::once()) ->method('dispatch') ->with( @@ -78,81 +57,106 @@ public function testGetRunningVersion(): void }) ) ->willReturnArgument(0) + ->seal() ; static::assertSame( $version, - $this->service->getRunningVersion() + $service->getRunningVersion() ); } public function testUpdateDeployedVersion(): void { + $service = new VersionManager( + $configurationRegistry = $this->createMock(ConfigurationRegistryInterface::class), + static::createStub(EventDispatcherInterface::class) + ); + $version = uniqid('version-'); ReflectionAccessor::setPropertyValue( - $this->service, + $service, 'runningVersion', $version ); - $this->configurationRegistry + $configurationRegistry ->expects(static::once()) ->method('set') - ->with($this->service::CONFIG, $version) + ->with($service::CONFIG, $version) + ->seal() ; - $this->service->updateDeployedVersion(); + $service->updateDeployedVersion(); } public function testGetDeployedVersion(): void { - $this->configurationRegistry + $service = new VersionManager( + $configurationRegistry = $this->createMock(ConfigurationRegistryInterface::class), + static::createStub(EventDispatcherInterface::class) + ); + + $configurationRegistry ->expects(static::once()) ->method('get') - ->with($this->service::CONFIG) + ->with($service::CONFIG) ->willReturn($version = uniqid('version-')) + ->seal() ; static::assertSame( $version, - $this->service->getDeployedVersion() + $service->getDeployedVersion() ); } public function testIsUpToDate(): void { - $this->configurationRegistry + $service = new VersionManager( + $configurationRegistry = $this->createMock(ConfigurationRegistryInterface::class), + static::createStub(EventDispatcherInterface::class) + ); + + $configurationRegistry ->expects(static::once()) ->method('get') - ->with($this->service::CONFIG) + ->with($service::CONFIG) ->willReturn($version = uniqid('version-')) + ->seal() ; ReflectionAccessor::setPropertyValue( - $this->service, + $service, 'runningVersion', $version ); - static::assertTrue($this->service->isUpToDate()); + static::assertTrue($service->isUpToDate()); } public function testIsUpToDateFalse(): void { - $this->configurationRegistry + $service = new VersionManager( + $configurationRegistry = $this->createMock(ConfigurationRegistryInterface::class), + static::createStub(EventDispatcherInterface::class) + ); + + $configurationRegistry ->expects(static::once()) ->method('get') - ->with($this->service::CONFIG) + ->with($service::CONFIG) ->willReturn(uniqid('version-')) + ->seal() ; ReflectionAccessor::setPropertyValue( - $this->service, + $service, 'runningVersion', uniqid('version-') ); - static::assertFalse($this->service->isUpToDate()); + static::assertFalse($service->isUpToDate()); } } diff --git a/packages/application/composer.json b/packages/application/composer.json index 4b339ef56..f4a5dd8ef 100644 --- a/packages/application/composer.json +++ b/packages/application/composer.json @@ -22,7 +22,7 @@ "symfony/event-dispatcher": "^6.4.0" }, "require-dev": { - "phpunit/phpunit": "^11.3 || ^12.0", + "phpunit/phpunit": "^11.3 || ^12.0 || ^13.0", "draw/dependency-injection": "^0.39", "draw/tester": "^0.39", "symfony/cache": "^6.4.0", diff --git a/packages/aws-tool-kit/Tests/Command/CloudWatchLogsDownloadCommandTest.php b/packages/aws-tool-kit/Tests/Command/CloudWatchLogsDownloadCommandTest.php index 80ad353d2..a55e5f2ea 100644 --- a/packages/aws-tool-kit/Tests/Command/CloudWatchLogsDownloadCommandTest.php +++ b/packages/aws-tool-kit/Tests/Command/CloudWatchLogsDownloadCommandTest.php @@ -4,12 +4,10 @@ use Aws\CloudWatchLogs\CloudWatchLogsClient; use Draw\Component\AwsToolKit\Command\CloudWatchLogsDownloadCommand; -use Draw\Component\Core\Reflection\ReflectionAccessor; use Draw\Component\Tester\Application\CommandDataTester; use Draw\Component\Tester\Application\CommandTestTrait; -use Draw\Component\Tester\MockTrait; +use Draw\Component\Tester\DoubleTrait; use PHPUnit\Framework\Attributes\CoversClass; -use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputOption; @@ -21,21 +19,11 @@ class CloudWatchLogsDownloadCommandTest extends TestCase { use CommandTestTrait; - use MockTrait; - - private CloudWatchLogsClient&MockObject $cloudWatchLogsClient; + use DoubleTrait; protected function setUp(): void { - $this->cloudWatchLogsClient = $this - ->getMockBuilder(CloudWatchLogsClient::class) - ->disableOriginalConstructor() - ->disableOriginalClone() - ->onlyMethods(['__call']) - ->getMock() - ; - - $this->command = new CloudWatchLogsDownloadCommand($this->cloudWatchLogsClient); + $this->command = new CloudWatchLogsDownloadCommand(static::createStub(CloudWatchLogsClient::class)); } public function getCommandName(): string @@ -64,11 +52,7 @@ public static function provideTestOption(): iterable public function testExecuteNoCloudWatchLogsClientService(): void { - ReflectionAccessor::setPropertyValue( - $this->command, - 'cloudWatchClient', - null - ); + $this->command = new CloudWatchLogsDownloadCommand(null); $this->expectException(\RuntimeException::class); $this->expectExceptionMessage('Service [Aws\CloudWatchLogs\CloudWatchLogsClient] is required for command [Draw\Component\AwsToolKit\Command\CloudWatchLogsDownloadCommand] to run.'); @@ -82,6 +66,10 @@ public function testExecuteNoCloudWatchLogsClientService(): void public function testExecuteNewFile(): void { + $this->command = new CloudWatchLogsDownloadCommand( + $cloudWatchLogsClient = $this->createMock(CloudWatchLogsClient::class) + ); + $logGroupName = 'group-name'; $logStreamName = 'stream-name'; $startTime = new \DateTimeImmutable('2001-01-01 00:00:00'); @@ -90,7 +78,7 @@ public function testExecuteNewFile(): void file_put_contents($output, "Before\n"); register_shutdown_function('unlink', $output); - $this->cloudWatchLogsClient + $cloudWatchLogsClient ->expects(static::exactly(2)) ->method('__call') ->with( @@ -129,6 +117,7 @@ public function testExecuteNewFile(): void 'nextForwardToken' => 'next-token', ] ) + ->seal() ; $this->execute( @@ -149,6 +138,10 @@ public function testExecuteNewFile(): void public function testExecuteAppendFile(): void { + $this->command = new CloudWatchLogsDownloadCommand( + $cloudWatchLogsClient = $this->createMock(CloudWatchLogsClient::class) + ); + $logGroupName = 'group-name'; $logStreamName = 'stream-name'; $startTime = new \DateTimeImmutable('2001-01-01 00:00:00'); @@ -157,7 +150,7 @@ public function testExecuteAppendFile(): void file_put_contents($output, "Before\n"); register_shutdown_function('unlink', $output); - $this->cloudWatchLogsClient + $cloudWatchLogsClient ->expects(static::once()) ->method('__call') ->with( @@ -180,6 +173,7 @@ public function testExecuteAppendFile(): void 'nextForwardToken' => null, ] ) + ->seal() ; $this->execute( diff --git a/packages/aws-tool-kit/Tests/EventListener/NewestInstanceRoleListenerCheckTest.php b/packages/aws-tool-kit/Tests/EventListener/NewestInstanceRoleListenerCheckTest.php index 6c07977c4..90a0b49db 100644 --- a/packages/aws-tool-kit/Tests/EventListener/NewestInstanceRoleListenerCheckTest.php +++ b/packages/aws-tool-kit/Tests/EventListener/NewestInstanceRoleListenerCheckTest.php @@ -5,14 +5,11 @@ use Aws\Ec2\Ec2Client; use Draw\Component\AwsToolKit\EventListener\NewestInstanceRoleCheckListener; use Draw\Component\AwsToolKit\Imds\ImdsClientInterface; -use Draw\Component\Core\Reflection\ReflectionAccessor; use PHPUnit\Framework\Attributes\CoversClass; -use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Symfony\Component\Console\Event\ConsoleCommandEvent; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\NullOutput; -use Symfony\Component\EventDispatcher\EventSubscriberInterface; /** * @internal @@ -20,49 +17,40 @@ #[CoversClass(NewestInstanceRoleCheckListener::class)] class NewestInstanceRoleListenerCheckTest extends TestCase { - private NewestInstanceRoleCheckListener $service; - - private ImdsClientInterface&MockObject $imdsClient; - - protected function setUp(): void - { - $this->service = new NewestInstanceRoleCheckListener( - $this->createMock(Ec2Client::class), - $this->imdsClient = $this->createMock(ImdsClientInterface::class), - ); - } - - public function testConstruct(): void + public function testGetSubscribedEvents(): void { - static::assertInstanceOf( - EventSubscriberInterface::class, - $this->service + $service = new NewestInstanceRoleCheckListener( + static::createStub(Ec2Client::class), + static::createStub(ImdsClientInterface::class), ); - } - public function testGetSubscribedEvents(): void - { static::assertSame( [ ConsoleCommandEvent::class => [ ['checkNewestInstance', 50], ], ], - $this->service::getSubscribedEvents() + $service::getSubscribedEvents() ); } public function testCheckNewestInstanceNoOption(): void { - $this->imdsClient + $service = new NewestInstanceRoleCheckListener( + static::createStub(Ec2Client::class), + $imdsClient = $this->createMock(ImdsClientInterface::class), + ); + + $imdsClient ->expects(static::never()) ->method('getCurrentInstanceId') + ->seal() ; - $this->service->checkNewestInstance( + $service->checkNewestInstance( $event = new ConsoleCommandEvent( null, - $this->createInput(false), + $this->createInput($service, false), new NullOutput(), ) ); @@ -72,15 +60,21 @@ public function testCheckNewestInstanceNoOption(): void public function testCheckNewestInstanceOptionNull(): void { - $this->imdsClient + $service = new NewestInstanceRoleCheckListener( + static::createStub(Ec2Client::class), + $imdsClient = $this->createMock(ImdsClientInterface::class), + ); + + $imdsClient ->expects(static::never()) ->method('getCurrentInstanceId') + ->seal() ; - $this->service->checkNewestInstance( + $service->checkNewestInstance( $event = new ConsoleCommandEvent( null, - $this->createInput(true), + $this->createInput($service, true), new NullOutput(), ) ); @@ -90,17 +84,23 @@ public function testCheckNewestInstanceOptionNull(): void public function testCheckNewestInstanceCurrentInstanceIdError(): void { - $this->imdsClient + $service = new NewestInstanceRoleCheckListener( + static::createStub(Ec2Client::class), + $imdsClient = $this->createMock(ImdsClientInterface::class), + ); + + $imdsClient ->expects(static::once()) ->method('getCurrentInstanceId') ->with() ->willThrowException(new \Exception()) + ->seal() ; - $this->service->checkNewestInstance( + $service->checkNewestInstance( $event = new ConsoleCommandEvent( null, - $this->createInput(true, uniqid('role-')), + $this->createInput($service, true, uniqid('role-')), new NullOutput(), ) ); @@ -110,17 +110,23 @@ public function testCheckNewestInstanceCurrentInstanceIdError(): void public function testCheckNewestInstanceCurrentInstanceIdEmpty(): void { - $this->imdsClient + $service = new NewestInstanceRoleCheckListener( + static::createStub(Ec2Client::class), + $imdsClient = $this->createMock(ImdsClientInterface::class), + ); + + $imdsClient ->expects(static::once()) ->method('getCurrentInstanceId') ->with() ->willReturn(null) + ->seal() ; - $this->service->checkNewestInstance( + $service->checkNewestInstance( $event = new ConsoleCommandEvent( null, - $this->createInput(true, uniqid('role-')), + $this->createInput($service, true, uniqid('role-')), new NullOutput(), ) ); @@ -130,23 +136,41 @@ public function testCheckNewestInstanceCurrentInstanceIdEmpty(): void public function testCheckNewestInstanceNoInstance(): void { - $role = uniqid('role-'); - $this->imdsClient + $service = new NewestInstanceRoleCheckListener( + $ec2Client = $this->createMock(Ec2Client::class), + $imdsClient = $this->createMock(ImdsClientInterface::class), + ); + + $imdsClient ->expects(static::once()) ->method('getCurrentInstanceId') ->with() ->willReturn(uniqid('instance-id-')) + ->seal() ; - $this->mockEc2ClientDescribeInstances( - $role, - [] - ); + $ec2Client->expects(static::once()) + ->method('__call') + ->with( + 'describeInstances', + self::provideDescribeInstancesArgs( + $role = uniqid('role-') + ) + ) + ->willReturn([ + 'Reservations' => [ + [ + 'Instances' => [], + ], + ], + ]) + ->seal() + ; - $this->service->checkNewestInstance( + $service->checkNewestInstance( $event = new ConsoleCommandEvent( null, - $this->createInput(true, $role), + $this->createInput($service, true, $role), new NullOutput(), ) ); @@ -156,32 +180,50 @@ public function testCheckNewestInstanceNoInstance(): void public function testCheckNewestInstanceNotNewestInstance(): void { - $role = uniqid('role-'); - $this->imdsClient + $service = new NewestInstanceRoleCheckListener( + $ec2Client = $this->createMock(Ec2Client::class), + $imdsClient = $this->createMock(ImdsClientInterface::class), + ); + + $imdsClient ->expects(static::once()) ->method('getCurrentInstanceId') ->with() ->willReturn($instanceId = uniqid('instance-id-')) + ->seal() ; - $this->mockEc2ClientDescribeInstances( - $role, - [ - [ - 'LaunchTime' => new \DateTimeImmutable('- 1 day'), - 'InstanceId' => $instanceId, - ], - [ - 'LaunchTime' => new \DateTimeImmutable(), - 'InstanceId' => uniqid('isntance-id-'), + $ec2Client->expects(static::once()) + ->method('__call') + ->with( + 'describeInstances', + self::provideDescribeInstancesArgs( + $role = uniqid('role-') + ) + ) + ->willReturn([ + 'Reservations' => [ + [ + 'Instances' => [ + [ + 'LaunchTime' => new \DateTimeImmutable('- 1 day'), + 'InstanceId' => $instanceId, + ], + [ + 'LaunchTime' => new \DateTimeImmutable(), + 'InstanceId' => uniqid('isntance-id-'), + ], + ], + ], ], - ] - ); + ]) + ->seal() + ; - $this->service->checkNewestInstance( + $service->checkNewestInstance( $event = new ConsoleCommandEvent( null, - $this->createInput(true, $role), + $this->createInput($service, true, $role), new NullOutput(), ) ); @@ -191,24 +233,35 @@ public function testCheckNewestInstanceNotNewestInstance(): void public function testCheckNewestInstanceError(): void { - $role = uniqid('role-'); - $this->imdsClient + $service = new NewestInstanceRoleCheckListener( + $ec2Client = $this->createMock(Ec2Client::class), + $imdsClient = $this->createMock(ImdsClientInterface::class), + ); + + $imdsClient ->expects(static::once()) ->method('getCurrentInstanceId') ->with() ->willReturn(uniqid('instance-id-')) + ->seal() ; - $this->mockEc2ClientDescribeInstances( - $role, - [], - new \Exception() - ); + $ec2Client->expects(static::once()) + ->method('__call') + ->with( + 'describeInstances', + self::provideDescribeInstancesArgs( + $role = uniqid('role-') + ) + ) + ->willThrowException(new \Exception()) + ->seal() + ; - $this->service->checkNewestInstance( + $service->checkNewestInstance( $event = new ConsoleCommandEvent( null, - $this->createInput(true, $role), + $this->createInput($service, true, $role), new NullOutput(), ) ); @@ -218,119 +271,104 @@ public function testCheckNewestInstanceError(): void public function testCheckNewestInstanceNewestInstance(): void { - $role = uniqid('role-'); - $this->imdsClient + $service = new NewestInstanceRoleCheckListener( + $ec2Client = $this->createMock(Ec2Client::class), + $imdsClient = $this->createMock(ImdsClientInterface::class), + ); + + $imdsClient ->expects(static::once()) ->method('getCurrentInstanceId') ->with() ->willReturn($instanceId = uniqid('instance-id-')) + ->seal() ; - $this->mockEc2ClientDescribeInstances( - $role, - [ - [ - 'LaunchTime' => new \DateTimeImmutable(), - 'InstanceId' => $instanceId, - ], - [ - 'LaunchTime' => new \DateTimeImmutable('- 1 day'), - 'InstanceId' => uniqid('instance-id-'), - ], - ] - ); - - $this->service->checkNewestInstance( - $event = new ConsoleCommandEvent( - null, - $this->createInput(true, $role), - new NullOutput(), - ) - ); - - static::assertTrue($event->commandShouldRun()); - } - - private function mockEc2ClientDescribeInstances( - string $role, - array $instances, - ?\Exception $error = null, - ): void { - $ec2Client = $this->getMockBuilder(Ec2Client::class) - ->disableOriginalConstructor() - ->onlyMethods(['__call']) - ->getMock() - ; - - ReflectionAccessor::setPropertyValue( - $this->service, - 'ec2Client', - $ec2Client - ); - - $invocationMocker = $ec2Client - ->expects(static::once()) + $ec2Client->expects(static::once()) ->method('__call') ->with( 'describeInstances', - [ + self::provideDescribeInstancesArgs( + $role = uniqid('role-') + ) + ) + ->willReturn([ + 'Reservations' => [ [ - 'DryRun' => false, - 'Filters' => [ + 'Instances' => [ [ - 'Name' => 'tag:Name', - 'Values' => [$role], + 'LaunchTime' => new \DateTimeImmutable(), + 'InstanceId' => $instanceId, ], [ - 'Name' => 'instance-state-name', - 'Values' => ['running'], + 'LaunchTime' => new \DateTimeImmutable('- 1 day'), + 'InstanceId' => uniqid('instance-id-'), ], ], ], - ] - ) + ], + ]) + ->seal() ; - if ($error) { - $invocationMocker->willThrowException($error); - } else { - $invocationMocker - ->willReturn( - [ - 'Reservations' => [ - [ - 'Instances' => $instances, - ], - ], - ] - ) - ; - } + $service->checkNewestInstance( + $event = new ConsoleCommandEvent( + null, + $this->createInput($service, true, $role), + new NullOutput(), + ) + ); + + static::assertTrue($event->commandShouldRun()); } - private function createInput(bool $hasOption, ?string $optionValue = null): InputInterface - { + private function createInput( + NewestInstanceRoleCheckListener $service, + bool $hasOption, + ?string $optionValue = null, + ): InputInterface { $input = $this->createMock(InputInterface::class); $input->expects(static::once()) ->method('hasOption') - ->with($this->service::OPTION_AWS_NEWEST_INSTANCE_ROLE) + ->with($service::OPTION_AWS_NEWEST_INSTANCE_ROLE) ->willReturn($hasOption) ; if ($hasOption) { $input->expects(static::once()) ->method('getOption') - ->with($this->service::OPTION_AWS_NEWEST_INSTANCE_ROLE) + ->with($service::OPTION_AWS_NEWEST_INSTANCE_ROLE) ->willReturn($optionValue) + ->seal() ; } else { $input->expects(static::never()) ->method('getOption') - ->with($this->service::OPTION_AWS_NEWEST_INSTANCE_ROLE) + ->with($service::OPTION_AWS_NEWEST_INSTANCE_ROLE) + ->seal() ; } return $input; } + + private static function provideDescribeInstancesArgs(string $role): array + { + return [ + [ + 'DryRun' => false, + 'Filters' => [ + [ + 'Name' => 'tag:Name', + 'Values' => [$role], + ], + [ + 'Name' => 'instance-state-name', + 'Values' => ['running'], + ], + ], + ], + ]; + } } diff --git a/packages/aws-tool-kit/Tests/Imds/ImdsClientV1Test.php b/packages/aws-tool-kit/Tests/Imds/ImdsClientV1Test.php index e26ca3810..327f73a1e 100644 --- a/packages/aws-tool-kit/Tests/Imds/ImdsClientV1Test.php +++ b/packages/aws-tool-kit/Tests/Imds/ImdsClientV1Test.php @@ -36,6 +36,7 @@ public function testGetCurrentInstanceId(): void 'http://169.254.169.254/latest/meta-data/instance-id' ) ->willReturn($response = $this->createMock(ResponseInterface::class)) + ->seal() ; $response @@ -43,6 +44,7 @@ public function testGetCurrentInstanceId(): void ->method('getContent') ->with() ->willReturn($instanceId = uniqid('instance-id-')) + ->seal() ; static::assertSame( diff --git a/packages/aws-tool-kit/Tests/Imds/ImdsClientV2Test.php b/packages/aws-tool-kit/Tests/Imds/ImdsClientV2Test.php index d51a5bbf8..f3adc737b 100644 --- a/packages/aws-tool-kit/Tests/Imds/ImdsClientV2Test.php +++ b/packages/aws-tool-kit/Tests/Imds/ImdsClientV2Test.php @@ -3,7 +3,7 @@ namespace Draw\Component\AwsToolKit\Tests\Imds; use Draw\Component\AwsToolKit\Imds\ImdsClientV2; -use Draw\Component\Tester\MockTrait; +use Draw\Component\Tester\DoubleTrait; use PHPUnit\Framework\Attributes\CoversClass; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; @@ -16,7 +16,7 @@ #[CoversClass(ImdsClientV2::class)] class ImdsClientV2Test extends TestCase { - use MockTrait; + use DoubleTrait; private ImdsClientV2 $imdsClientV1; @@ -37,6 +37,7 @@ public function testGetCurrentInstanceId(): void ->method('getContent') ->with() ->willReturn($token = uniqid('token-')) + ->seal() ; $instanceIdResponse = $this->createMock(ResponseInterface::class); @@ -45,6 +46,7 @@ public function testGetCurrentInstanceId(): void ->method('getContent') ->with() ->willReturn($instanceId = uniqid('instance-id-')) + ->seal() ; $this->httpClient @@ -76,6 +78,7 @@ public function testGetCurrentInstanceId(): void $tokenResponse, $instanceIdResponse, ) + ->seal() ; static::assertSame( diff --git a/packages/aws-tool-kit/composer.json b/packages/aws-tool-kit/composer.json index ca321a8e7..528c9db87 100644 --- a/packages/aws-tool-kit/composer.json +++ b/packages/aws-tool-kit/composer.json @@ -16,7 +16,7 @@ "draw/core": "^0.39", "draw/dependency-injection": "^0.39", "draw/tester": "^0.39", - "phpunit/phpunit": "^11.3 || ^12.0", + "phpunit/phpunit": "^11.3 || ^12.0 || ^13.0", "symfony/cache": "^6.4.0", "symfony/http-client": "^6.4.0", "symfony/http-client-contracts": "^3.4" diff --git a/packages/console/Command/PurgeExecutionCommand.php b/packages/console/Command/PurgeExecutionCommand.php index c992133e2..a5ed9fcc6 100644 --- a/packages/console/Command/PurgeExecutionCommand.php +++ b/packages/console/Command/PurgeExecutionCommand.php @@ -18,12 +18,13 @@ class PurgeExecutionCommand extends Command final public const DEFAULT_WAIT_SECOND = 10; final public const DEFAULT_BATCH_SIZE = 1000; - private ?LoggerInterface $logger; + private LoggerInterface $logger; public function __construct(private Connection $executionConnection, ?LoggerInterface $logger = null) { parent::__construct(); - $this->logger = $logger ?: new NullLogger(); + + $this->logger = $logger ?? new NullLogger(); } protected function configure(): void diff --git a/packages/console/Tests/Command/PurgeExecutionCommandTest.php b/packages/console/Tests/Command/PurgeExecutionCommandTest.php index e9edd567f..e8b05768d 100644 --- a/packages/console/Tests/Command/PurgeExecutionCommandTest.php +++ b/packages/console/Tests/Command/PurgeExecutionCommandTest.php @@ -6,9 +6,8 @@ use Draw\Component\Console\Command\PurgeExecutionCommand; use Draw\Component\Tester\Application\CommandDataTester; use Draw\Component\Tester\Application\CommandTestTrait; -use Draw\Component\Tester\MockTrait; +use Draw\Component\Tester\DoubleTrait; use PHPUnit\Framework\Attributes\CoversClass; -use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Psr\Log\LoggerInterface; use Symfony\Component\Console\Input\InputOption; @@ -20,18 +19,14 @@ class PurgeExecutionCommandTest extends TestCase { use CommandTestTrait; - use MockTrait; - - private Connection&MockObject $connection; - - private LoggerInterface&MockObject $logger; + use DoubleTrait; protected function setUp(): void { - $this->connection = $this->createMock(Connection::class); - $this->logger = $this->createMock(LoggerInterface::class); - - $this->command = new PurgeExecutionCommand($this->connection, $this->logger); + $this->command = new PurgeExecutionCommand( + static::createStub(Connection::class), + static::createStub(LoggerInterface::class), + ); } public function getCommandName(): string @@ -86,11 +81,14 @@ public function testExecuteInvalidSleep(): void public function testExecute(): void { + $this->command = new PurgeExecutionCommand( + $connection = $this->createMock(Connection::class), + $logger = $this->createMock(LoggerInterface::class), + ); + $date = '2000-01-01 00:00:01'; - $this->logger->expects( - static::exactly(3) - ) + $logger->expects(static::exactly(3)) ->method('debug') ->with( ...static::withConsecutive( @@ -108,9 +106,10 @@ public function testExecute(): void ] ) ) + ->seal() ; - $this->connection->expects(static::exactly(2)) + $connection->expects(static::exactly(2)) ->method('executeStatement') ->with( ...static::withConsecutive( @@ -127,6 +126,7 @@ public function testExecute(): void ) ) ->willReturnOnConsecutiveCalls(1000, 2) + ->seal() ; $this->execute(['--delay' => $date, '--sleep' => 0]) diff --git a/packages/console/Tests/Entity/ExecutionTest.php b/packages/console/Tests/Entity/ExecutionTest.php index 9446ecccb..014fe10f3 100644 --- a/packages/console/Tests/Entity/ExecutionTest.php +++ b/packages/console/Tests/Entity/ExecutionTest.php @@ -21,61 +21,8 @@ protected function setUp(): void $this->entity = new Execution(); } - public function testConstants(): void - { - static::assertSame( - 'initialized', - $this->entity::STATE_INITIALIZED - ); - - static::assertSame( - 'started', - $this->entity::STATE_STARTED - ); - - static::assertSame( - 'error', - $this->entity::STATE_ERROR - ); - - static::assertSame( - 'terminated', - $this->entity::STATE_TERMINATED - ); - - static::assertSame( - 'disabled', - $this->entity::STATE_DISABLED - ); - - static::assertSame( - 'acknowledge', - $this->entity::STATE_ACKNOWLEDGE - ); - - static::assertSame( - 'auto_acknowledge', - $this->entity::STATE_AUTO_ACKNOWLEDGE - ); - - static::assertSame( - [ - $this->entity::STATE_INITIALIZED, - $this->entity::STATE_STARTED, - $this->entity::STATE_DISABLED, - $this->entity::STATE_ERROR, - $this->entity::STATE_TERMINATED, - $this->entity::STATE_ACKNOWLEDGE, - $this->entity::STATE_AUTO_ACKNOWLEDGE, - ], - $this->entity::STATES, - ); - } - public function testIdMutator(): void { - static::assertNotNull($this->entity->getId()); - static::assertSame( $this->entity, $this->entity->setId($value = uniqid('id-')) @@ -241,7 +188,7 @@ public function testGetCommandLine(): void public function testUpdateTimestampNotSet(): void { - $this->entity->updateTimestamp($this->createMock(PreUpdateEventArgs::class)); + $this->entity->updateTimestamp(static::createStub(PreUpdateEventArgs::class)); static::assertEqualsWithDelta( $this->entity->getCreatedAt(), @@ -254,7 +201,7 @@ public function testUpdateTimestampAlreadySet(): void { $this->entity->setUpdatedAt($value = new \DateTimeImmutable('- 1 days')); - $this->entity->updateTimestamp($this->createMock(PreUpdateEventArgs::class)); + $this->entity->updateTimestamp(static::createStub(PreUpdateEventArgs::class)); static::assertNotEqualsWithDelta( $value, @@ -273,6 +220,7 @@ public function testUpdateTimestampAlreadyChanged(): void ->method('hasChangedField') ->with('updatedAt') ->willReturn(true) + ->seal() ; $this->entity->updateTimestamp($event); diff --git a/packages/console/Tests/Event/CommandErrorEventTest.php b/packages/console/Tests/Event/CommandErrorEventTest.php index 20f3144be..75b7440fa 100644 --- a/packages/console/Tests/Event/CommandErrorEventTest.php +++ b/packages/console/Tests/Event/CommandErrorEventTest.php @@ -5,7 +5,6 @@ use Draw\Component\Console\Event\CommandErrorEvent; use PHPUnit\Framework\Attributes\CoversClass; use PHPUnit\Framework\TestCase; -use Symfony\Contracts\EventDispatcher\Event; /** * @internal @@ -27,14 +26,6 @@ protected function setUp(): void ); } - public function testConstruct(): void - { - static::assertInstanceOf( - Event::class, - $this->event - ); - } - public function testGetExecutionId(): void { static::assertSame( diff --git a/packages/console/Tests/EventListener/CommandFlowListenerTest.php b/packages/console/Tests/EventListener/CommandFlowListenerTest.php index 75e4ed9fd..58107b9b5 100644 --- a/packages/console/Tests/EventListener/CommandFlowListenerTest.php +++ b/packages/console/Tests/EventListener/CommandFlowListenerTest.php @@ -15,10 +15,8 @@ use Draw\Component\Console\Output\BufferedConsoleOutput; use Draw\Component\Core\Reflection\ReflectionAccessor; use Draw\Component\Tester\DoctrineOrmTrait; -use Draw\Component\Tester\MockTrait; use PHPUnit\Framework\Attributes\CoversClass; use PHPUnit\Framework\Attributes\Depends; -use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Psr\Log\LoggerInterface; use Psr\Log\NullLogger; @@ -31,7 +29,6 @@ use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\BufferedOutput; use Symfony\Component\Console\Output\OutputInterface; -use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; /** @@ -41,16 +38,9 @@ class CommandFlowListenerTest extends TestCase { use DoctrineOrmTrait; - use MockTrait; private static EntityManagerInterface $entityManager; - private CommandFlowListener $object; - - private EventDispatcherInterface&MockObject $eventDispatcher; - - private LoggerInterface&MockObject $logger; - private ?Execution $execution = null; public static function setUpBeforeClass(): void @@ -62,27 +52,19 @@ public static function setUpBeforeClass(): void protected function setUp(): void { - $this->object = new CommandFlowListener( - self::$entityManager->getConnection(), - $this->eventDispatcher = $this->createMock(EventDispatcherInterface::class), - $this->logger = $this->createMock(LoggerInterface::class) - ); - if ($this->execution) { self::$entityManager->refresh($this->execution); } } - public function testConstruct(): void + public function testGetSubscribedEvents(): void { - static::assertInstanceOf( - EventSubscriberInterface::class, - $this->object + $listener = new CommandFlowListener( + self::$entityManager->getConnection(), + static::createStub(EventDispatcherInterface::class), + static::createStub(LoggerInterface::class) ); - } - public function testGetSubscribedEvents(): void - { static::assertSame( [ LoadExecutionIdEvent::class => [ @@ -99,21 +81,27 @@ public function testGetSubscribedEvents(): void Event\ConsoleTerminateEvent::class => ['logCommandTerminate'], Event\ConsoleErrorEvent::class => ['logCommandError'], ], - $this->object::getSubscribedEvents() + $listener::getSubscribedEvents() ); } public function testConfigureOptions(): void { + $listener = new CommandFlowListener( + self::$entityManager->getConnection(), + static::createStub(EventDispatcherInterface::class), + static::createStub(LoggerInterface::class) + ); + $commandEvent = $this->createCommandEvent(); - $this->object->configureOptions($commandEvent); + $listener->configureOptions($commandEvent); $command = $commandEvent->getCommand(); - $option = $command->getDefinition()->getOption($this->object::OPTION_IGNORE); + $option = $command->getDefinition()->getOption($listener::OPTION_IGNORE); static::assertSame( - $this->object::OPTION_IGNORE, + $listener::OPTION_IGNORE, $option->getName() ); @@ -134,10 +122,10 @@ public function testConfigureOptions(): void $option->getDefault() ); - $option = $command->getDefinition()->getOption($this->object::OPTION_EXECUTION_ID); + $option = $command->getDefinition()->getOption($listener::OPTION_EXECUTION_ID); static::assertSame( - $this->object::OPTION_EXECUTION_ID, + $listener::OPTION_EXECUTION_ID, $option->getName() ); @@ -161,19 +149,26 @@ public function testConfigureOptions(): void public function testCheckIgnoredCommandsIgnored(): void { + $listener = new CommandFlowListener( + self::$entityManager->getConnection(), + static::createStub(EventDispatcherInterface::class), + static::createStub(LoggerInterface::class) + ); + $event = new LoadExecutionIdEvent( $command = $this->createMock(Command::class), - $this->createMock(InputInterface::class), - $this->createMock(OutputInterface::class) + static::createStub(InputInterface::class), + static::createStub(OutputInterface::class) ); $command ->expects(static::once()) ->method('getName') ->willReturn('help') + ->seal() ; - $this->object->checkIgnoredCommands($event); + $listener->checkIgnoredCommands($event); static::assertNull($event->getExecutionId()); static::assertTrue($event->getIgnoreTracking()); @@ -181,19 +176,26 @@ public function testCheckIgnoredCommandsIgnored(): void public function testCheckIgnoredCommandsNotIgnored(): void { + $listener = new CommandFlowListener( + self::$entityManager->getConnection(), + static::createStub(EventDispatcherInterface::class), + static::createStub(LoggerInterface::class) + ); + $event = new LoadExecutionIdEvent( $command = $this->createMock(Command::class), - $this->createMock(InputInterface::class), - $this->createMock(OutputInterface::class) + static::createStub(InputInterface::class), + static::createStub(OutputInterface::class) ); $command ->expects(static::once()) ->method('getName') ->willReturn(uniqid('command-')) + ->seal() ; - $this->object->checkIgnoredCommands($event); + $listener->checkIgnoredCommands($event); static::assertNull($event->getExecutionId()); static::assertFalse($event->getIgnoreTracking()); @@ -201,10 +203,16 @@ public function testCheckIgnoredCommandsNotIgnored(): void public function testCheckHelpIgnored(): void { + $listener = new CommandFlowListener( + self::$entityManager->getConnection(), + static::createStub(EventDispatcherInterface::class), + static::createStub(LoggerInterface::class) + ); + $event = new LoadExecutionIdEvent( - $this->createMock(Command::class), + static::createStub(Command::class), $input = $this->createMock(InputInterface::class), - $this->createMock(OutputInterface::class) + static::createStub(OutputInterface::class) ); $input @@ -219,9 +227,10 @@ public function testCheckHelpIgnored(): void ->method('getOption') ->with('help') ->willReturn(true) + ->seal() ; - $this->object->checkHelp($event); + $listener->checkHelp($event); static::assertNull($event->getExecutionId()); static::assertTrue($event->getIgnoreTracking()); @@ -229,10 +238,16 @@ public function testCheckHelpIgnored(): void public function testCheckHelpNotIgnored(): void { + $listener = new CommandFlowListener( + self::$entityManager->getConnection(), + static::createStub(EventDispatcherInterface::class), + static::createStub(LoggerInterface::class) + ); + $event = new LoadExecutionIdEvent( - $this->createMock(Command::class), + static::createStub(Command::class), $input = $this->createMock(InputInterface::class), - $this->createMock(OutputInterface::class) + static::createStub(OutputInterface::class) ); $input @@ -240,9 +255,10 @@ public function testCheckHelpNotIgnored(): void ->method('hasOption') ->with('help') ->willReturn(false) + ->seal() ; - $this->object->checkHelp($event); + $listener->checkHelp($event); static::assertNull($event->getExecutionId()); static::assertFalse($event->getIgnoreTracking()); @@ -250,22 +266,23 @@ public function testCheckHelpNotIgnored(): void public function testCheckTableExistIgnoredTableDoesNotExists(): void { - $event = new LoadExecutionIdEvent( - $this->createMock(Command::class), - $this->createMock(InputInterface::class), - $this->createMock(OutputInterface::class) + $listener = new CommandFlowListener( + $connection = $this->createMock(Connection::class), + static::createStub(EventDispatcherInterface::class), + static::createStub(LoggerInterface::class) ); - $connection = $this->mockProperty( - $this->object, - 'connection', - Connection::class + $event = new LoadExecutionIdEvent( + static::createStub(Command::class), + static::createStub(InputInterface::class), + static::createStub(OutputInterface::class) ); $connection ->expects(static::once()) ->method('createSchemaManager') ->willReturn($schemaManager = $this->createMock(MySQLSchemaManager::class)) + ->seal() ; $schemaManager @@ -273,9 +290,10 @@ public function testCheckTableExistIgnoredTableDoesNotExists(): void ->method('tablesExist') ->with(['command__execution']) ->willReturn(false) + ->seal() ; - $this->object->checkTableExist($event); + $listener->checkTableExist($event); static::assertNull($event->getExecutionId()); static::assertTrue($event->getIgnoreTracking()); @@ -283,25 +301,26 @@ public function testCheckTableExistIgnoredTableDoesNotExists(): void public function testCheckTableExistIgnoredException(): void { - $event = new LoadExecutionIdEvent( - $this->createMock(Command::class), - $this->createMock(InputInterface::class), - $this->createMock(OutputInterface::class) + $listener = new CommandFlowListener( + $connection = $this->createMock(Connection::class), + static::createStub(EventDispatcherInterface::class), + static::createStub(LoggerInterface::class) ); - $connection = $this->mockProperty( - $this->object, - 'connection', - Connection::class + $event = new LoadExecutionIdEvent( + static::createStub(Command::class), + static::createStub(InputInterface::class), + static::createStub(OutputInterface::class) ); $connection ->expects(static::once()) ->method('createSchemaManager') ->willThrowException(new ConnectionException()) + ->seal() ; - $this->object->checkTableExist($event); + $listener->checkTableExist($event); static::assertNull($event->getExecutionId()); static::assertTrue($event->getIgnoreTracking()); @@ -309,20 +328,27 @@ public function testCheckTableExistIgnoredException(): void public function testLoadIdFromInputNotFound(): void { + $listener = new CommandFlowListener( + self::$entityManager->getConnection(), + static::createStub(EventDispatcherInterface::class), + static::createStub(LoggerInterface::class) + ); + $event = new LoadExecutionIdEvent( - $this->createMock(Command::class), + static::createStub(Command::class), $input = $this->createMock(InputInterface::class), - $this->createMock(OutputInterface::class) + static::createStub(OutputInterface::class) ); $input ->expects(static::once()) ->method('hasOption') - ->with($this->object::OPTION_EXECUTION_ID) + ->with($listener::OPTION_EXECUTION_ID) ->willReturn(false) + ->seal() ; - $this->object->loadIdFromInput($event); + $listener->loadIdFromInput($event); static::assertNull($event->getExecutionId()); static::assertFalse($event->getIgnoreTracking()); @@ -330,13 +356,19 @@ public function testLoadIdFromInputNotFound(): void public function testLoadIdFromInputExists(): void { + $listener = new CommandFlowListener( + self::$entityManager->getConnection(), + static::createStub(EventDispatcherInterface::class), + static::createStub(LoggerInterface::class) + ); + $event = new LoadExecutionIdEvent( - $this->createMock(Command::class), - $this->createOptionExecutionIdInput($id = uniqid('id-')), - $this->createMock(OutputInterface::class) + static::createStub(Command::class), + $this->createOptionExecutionIdInput($listener, $id = uniqid('id-')), + static::createStub(OutputInterface::class) ); - $this->object->loadIdFromInput($event); + $listener->loadIdFromInput($event); static::assertSame($id, $event->getExecutionId()); static::assertFalse($event->getIgnoreTracking()); @@ -344,16 +376,23 @@ public function testLoadIdFromInputExists(): void public function testGenerateFromDatabaseIgnoredException(): void { + $listener = new CommandFlowListener( + $connection = $this->createMock(PrimaryReadReplicaConnection::class), + static::createStub(EventDispatcherInterface::class), + $logger = $this->createMock(LoggerInterface::class) + ); + $event = new LoadExecutionIdEvent( $command = $this->createMock(Command::class), $input = $this->createMock(InputInterface::class), - $this->createMock(OutputInterface::class) + static::createStub(OutputInterface::class) ); $command ->expects(static::once()) ->method('getName') ->willReturn(uniqid('command-')) + ->seal() ; $input @@ -366,14 +405,9 @@ public function testGenerateFromDatabaseIgnoredException(): void ->expects(static::once()) ->method('getOptions') ->willReturn([]) + ->seal() ; - $connection = $this->mockProperty( - $this->object, - 'connection', - PrimaryReadReplicaConnection::class - ); - $connection ->expects(static::once()) ->method('isConnectedToPrimary') @@ -389,18 +423,20 @@ public function testGenerateFromDatabaseIgnoredException(): void $connection ->expects(static::once()) ->method('ensureConnectedToReplica') + ->seal() ; - $this->logger + $logger ->expects(static::once()) ->method('error') ->with( 'Command flow listener error while generating execution id', ['error' => $error] ) + ->seal() ; - $this->object->generateFromDatabase($event); + $listener->generateFromDatabase($event); static::assertNull($event->getExecutionId()); static::assertTrue($event->getIgnoreTracking()); @@ -408,16 +444,23 @@ public function testGenerateFromDatabaseIgnoredException(): void public function testGenerateFromDatabase(): void { + $listener = new CommandFlowListener( + $connection = $this->createMock(PrimaryReadReplicaConnection::class), + static::createStub(EventDispatcherInterface::class), + static::createStub(LoggerInterface::class) + ); + $event = new LoadExecutionIdEvent( $command = $this->createMock(Command::class), $input = $this->createMock(InputInterface::class), - $this->createMock(OutputInterface::class) + static::createStub(OutputInterface::class) ); $command ->expects(static::once()) ->method('getName') ->willReturn($commandName = uniqid('command-')) + ->seal() ; $input @@ -430,14 +473,9 @@ public function testGenerateFromDatabase(): void ->expects(static::once()) ->method('getOptions') ->willReturn(['null' => null, 'zero' => 0, 'false' => false, 'other' => 'value']) + ->seal() ; - $connection = $this->mockProperty( - $this->object, - 'connection', - PrimaryReadReplicaConnection::class - ); - $connection ->expects(static::once()) ->method('isConnectedToPrimary') @@ -498,9 +536,10 @@ public function testGenerateFromDatabase(): void $connection ->expects(static::once()) ->method('ensureConnectedToReplica') + ->seal() ; - $this->object->generateFromDatabase($event); + $listener->generateFromDatabase($event); static::assertIsString($event->getExecutionId()); static::assertFalse($event->getIgnoreTracking()); @@ -508,16 +547,23 @@ public function testGenerateFromDatabase(): void public function testGenerateFromDatabaseReal(): Execution { + $listener = new CommandFlowListener( + self::$entityManager->getConnection(), + static::createStub(EventDispatcherInterface::class), + static::createStub(LoggerInterface::class) + ); + $event = new LoadExecutionIdEvent( $command = $this->createMock(Command::class), $input = $this->createMock(InputInterface::class), - $this->createMock(OutputInterface::class) + static::createStub(OutputInterface::class) ); $command ->expects(static::once()) ->method('getName') ->willReturn(uniqid('command-')) + ->seal() ; $input @@ -530,9 +576,10 @@ public function testGenerateFromDatabaseReal(): Execution ->expects(static::once()) ->method('getOptions') ->willReturn([]) + ->seal() ; - $this->object->generateFromDatabase($event); + $listener->generateFromDatabase($event); static::assertNotNull($id = $event->getExecutionId()); static::assertFalse($event->getIgnoreTracking()); @@ -544,30 +591,44 @@ public function testGenerateFromDatabaseReal(): Execution public function testLogCommandStartNoExecutionId(): void { - $this->eventDispatcher + $listener = new CommandFlowListener( + self::$entityManager->getConnection(), + $eventDispatcher = $this->createMock(EventDispatcherInterface::class), + static::createStub(LoggerInterface::class) + ); + + $eventDispatcher ->expects(static::once()) ->method('dispatch') ->willReturnArgument(0) + ->seal() ; $event = new ConsoleCommandEvent( $command = $this->createMock(Command::class), - $this->createMock(InputInterface::class), - $this->createMock(OutputInterface::class) + static::createStub(InputInterface::class), + static::createStub(OutputInterface::class) ); $command ->expects(static::never()) ->method('getDefinition') + ->seal() ; - $this->object->logCommandStart($event); + $listener->logCommandStart($event); } #[Depends('testGenerateFromDatabaseReal')] public function testLogCommandStart(Execution $execution): void { - $this->eventDispatcher + $listener = new CommandFlowListener( + self::$entityManager->getConnection(), + $eventDispatcher = $this->createMock(EventDispatcherInterface::class), + static::createStub(LoggerInterface::class) + ); + + $eventDispatcher ->expects(static::once()) ->method('dispatch') ->with( @@ -578,28 +639,30 @@ public function testLogCommandStart(Execution $execution): void }) ) ->willReturnArgument(0) + ->seal() ; $event = new ConsoleCommandEvent( $command = $this->createMock(Command::class), - $this->createMock(InputInterface::class), - $this->createMock(OutputInterface::class) + static::createStub(InputInterface::class), + static::createStub(OutputInterface::class) ); $command ->expects(static::once()) ->method('getDefinition') ->willReturn($definition = new InputDefinition()) + ->seal() ; $definition->addOption( - $option = new InputOption($this->object::OPTION_EXECUTION_ID, null, InputOption::VALUE_REQUIRED) + $option = new InputOption($listener::OPTION_EXECUTION_ID, null, InputOption::VALUE_REQUIRED) ); $execution->setState(uniqid('state-')); self::$entityManager->flush(); - $this->object->logCommandStart($event); + $listener->logCommandStart($event); static::assertSame($execution->getId(), $option->getDefault()); @@ -610,10 +673,10 @@ public function testLogCommandStart(Execution $execution): void public function testLogCommandTerminateReplication(): void { - $connection = $this->mockProperty( - $this->object, - 'connection', - PrimaryReadReplicaConnection::class + $listener = new CommandFlowListener( + $connection = $this->createMock(PrimaryReadReplicaConnection::class), + static::createStub(EventDispatcherInterface::class), + static::createStub(LoggerInterface::class) ); $connection @@ -627,21 +690,33 @@ public function testLogCommandTerminateReplication(): void ->method('ensureConnectedToReplica') ; + $connection + ->expects(static::once()) + ->method('executeStatement') + ->seal() + ; + $event = new Event\ConsoleTerminateEvent( - $this->createMock(Command::class), - $this->createOptionExecutionIdInput(uniqid('id-')), - $this->createMock(OutputInterface::class), + static::createStub(Command::class), + $this->createOptionExecutionIdInput($listener, uniqid('id-')), + static::createStub(OutputInterface::class), 0 ); - $this->object->logCommandTerminate($event); + $listener->logCommandTerminate($event); } public function testLogCommandTerminateNoExecutionId(): void { + $listener = new CommandFlowListener( + self::$entityManager->getConnection(), + static::createStub(EventDispatcherInterface::class), + static::createStub(LoggerInterface::class) + ); + $event = new Event\ConsoleTerminateEvent( - $this->createMock(Command::class), - $this->createMock(InputInterface::class), + static::createStub(Command::class), + static::createStub(InputInterface::class), $output = $this->createMock(BufferedConsoleOutput::class), 0 ); @@ -649,17 +724,24 @@ public function testLogCommandTerminateNoExecutionId(): void $output ->expects(static::never()) ->method('fetch') + ->seal() ; - $this->object->logCommandTerminate($event); + $listener->logCommandTerminate($event); } #[Depends('testGenerateFromDatabaseReal')] public function testLogCommandTerminate(Execution $execution): void { + $listener = new CommandFlowListener( + self::$entityManager->getConnection(), + static::createStub(EventDispatcherInterface::class), + static::createStub(LoggerInterface::class) + ); + $event = new Event\ConsoleTerminateEvent( - $this->createMock(Command::class), - $this->createOptionExecutionIdInput($execution->getId()), + static::createStub(Command::class), + $this->createOptionExecutionIdInput($listener, $execution->getId()), $output = $this->createMock(BufferedConsoleOutput::class), 0 ); @@ -668,9 +750,10 @@ public function testLogCommandTerminate(Execution $execution): void ->expects(static::once()) ->method('fetch') ->willReturn($output = uniqid('output-')) + ->seal() ; - $this->object->logCommandTerminate($event); + $listener->logCommandTerminate($event); self::$entityManager->refresh($execution); @@ -681,9 +764,15 @@ public function testLogCommandTerminate(Execution $execution): void #[Depends('testGenerateFromDatabaseReal')] public function testLogCommandTerminateLongOutput(Execution $execution): void { + $listener = new CommandFlowListener( + self::$entityManager->getConnection(), + static::createStub(EventDispatcherInterface::class), + static::createStub(LoggerInterface::class) + ); + $event = new Event\ConsoleTerminateEvent( - $this->createMock(Command::class), - $this->createOptionExecutionIdInput($execution->getId()), + static::createStub(Command::class), + $this->createOptionExecutionIdInput($listener, $execution->getId()), $output = $this->createMock(BufferedConsoleOutput::class), 0 ); @@ -692,12 +781,13 @@ public function testLogCommandTerminateLongOutput(Execution $execution): void ->expects(static::once()) ->method('fetch') ->willReturn(str_repeat('Z', 50001)) + ->seal() ; $execution->setOutput(''); self::$entityManager->flush(); - $this->object->logCommandTerminate($event); + $listener->logCommandTerminate($event); self::$entityManager->refresh($execution); @@ -710,26 +800,39 @@ public function testLogCommandTerminateLongOutput(Execution $execution): void public function testLogCommandErrorNoExecutionId(): void { + $listener = new CommandFlowListener( + self::$entityManager->getConnection(), + $eventDispatcher = $this->createMock(EventDispatcherInterface::class), + static::createStub(LoggerInterface::class) + ); + $event = new Event\ConsoleErrorEvent( - $this->createMock(InputInterface::class), - $this->createMock(BufferedConsoleOutput::class), + static::createStub(InputInterface::class), + static::createStub(BufferedConsoleOutput::class), new \Exception() ); - $this->eventDispatcher + $eventDispatcher ->expects(static::never()) ->method('dispatch') + ->seal() ; - $this->object->logCommandError($event); + $listener->logCommandError($event); } #[Depends('testGenerateFromDatabaseReal')] public function testLogCommandError(Execution $execution): void { + $listener = new CommandFlowListener( + self::$entityManager->getConnection(), + $eventDispatcher = $this->createMock(EventDispatcherInterface::class), + static::createStub(LoggerInterface::class) + ); + $event = new Event\ConsoleErrorEvent( - $this->createOptionExecutionIdInput($execution->getId()), - $this->createMock(BufferedConsoleOutput::class), + $this->createOptionExecutionIdInput($listener, $execution->getId()), + static::createStub(BufferedConsoleOutput::class), $error = new \Exception(), $command = $this->createMock(Command::class) ); @@ -738,6 +841,7 @@ public function testLogCommandError(Execution $execution): void ->expects(static::once()) ->method('getApplication') ->willReturn($application = $this->createMock(Application::class)) + ->seal() ; $outputString = uniqid('output-string-'); @@ -753,9 +857,10 @@ public function testLogCommandError(Execution $execution): void return true; }) ) + ->seal() ; - $this->eventDispatcher + $eventDispatcher ->expects(static::once()) ->method('dispatch') ->with( @@ -767,9 +872,10 @@ public function testLogCommandError(Execution $execution): void }) ) ->willReturnArgument(0) + ->seal() ; - $this->object->logCommandError($event); + $listener->logCommandError($event); self::$entityManager->refresh($execution); @@ -781,14 +887,20 @@ public function testLogCommandError(Execution $execution): void #[Depends('testGenerateFromDatabaseReal')] public function testLogCommandErrorAutoAcknowledge(Execution $execution): void { + $listener = new CommandFlowListener( + self::$entityManager->getConnection(), + $eventDispatcher = $this->createMock(EventDispatcherInterface::class), + static::createStub(LoggerInterface::class) + ); + $event = new Event\ConsoleErrorEvent( - $this->createOptionExecutionIdInput($execution->getId()), - $this->createMock(BufferedConsoleOutput::class), + $this->createOptionExecutionIdInput($listener, $execution->getId()), + static::createStub(BufferedConsoleOutput::class), new \Exception() ); $reason = uniqid('reason-'); - $this->eventDispatcher + $eventDispatcher ->expects(static::once()) ->method('dispatch') ->with( @@ -799,13 +911,14 @@ public function testLogCommandErrorAutoAcknowledge(Execution $execution): void }) ) ->willReturnArgument(0) + ->seal() ; // If current state is error, state will not be changed $execution->setState(Execution::STATE_TERMINATED); self::$entityManager->flush(); - $this->object->logCommandError($event); + $listener->logCommandError($event); self::$entityManager->refresh($execution); @@ -816,9 +929,15 @@ public function testLogCommandErrorAutoAcknowledge(Execution $execution): void #[Depends('testGenerateFromDatabaseReal')] public function testLogCommandTerminateDisabled(Execution $execution): void { + $listener = new CommandFlowListener( + self::$entityManager->getConnection(), + static::createStub(EventDispatcherInterface::class), + static::createStub(LoggerInterface::class) + ); + $event = new Event\ConsoleTerminateEvent( - $this->createMock(Command::class), - $this->createOptionExecutionIdInput($execution->getId()), + static::createStub(Command::class), + $this->createOptionExecutionIdInput($listener, $execution->getId()), $output = $this->createMock(BufferedConsoleOutput::class), ConsoleCommandEvent::RETURN_CODE_DISABLED ); @@ -827,9 +946,10 @@ public function testLogCommandTerminateDisabled(Execution $execution): void ->expects(static::once()) ->method('fetch') ->willReturn(uniqid('output-')) + ->seal() ; - $this->object->logCommandTerminate($event); + $listener->logCommandTerminate($event); self::$entityManager->refresh($execution); @@ -839,9 +959,15 @@ public function testLogCommandTerminateDisabled(Execution $execution): void #[Depends('testGenerateFromDatabaseReal')] public function testLogCommandTerminateDisabledIgnored(Execution $execution): void { + $listener = new CommandFlowListener( + self::$entityManager->getConnection(), + static::createStub(EventDispatcherInterface::class), + static::createStub(LoggerInterface::class) + ); + $event = new Event\ConsoleTerminateEvent( - $this->createMock(Command::class), - $this->createOptionExecutionIdInput($execution->getId()), + static::createStub(Command::class), + $this->createOptionExecutionIdInput($listener, $execution->getId()), $output = $this->createMock(BufferedConsoleOutput::class), ConsoleCommandEvent::RETURN_CODE_DISABLED ); @@ -850,11 +976,12 @@ public function testLogCommandTerminateDisabledIgnored(Execution $execution): vo ->expects(static::once()) ->method('fetch') ->willReturn(uniqid('output-')) + ->seal() ; - ReflectionAccessor::setPropertyValue($this->object, 'ignoreDisabledCommand', true); + ReflectionAccessor::setPropertyValue($listener, 'ignoreDisabledCommand', true); - $this->object->logCommandTerminate($event); + $listener->logCommandTerminate($event); $execution = self::$entityManager->getRepository(Execution::class) ->findOneBy(['id' => $execution->getId()]) @@ -863,22 +990,23 @@ public function testLogCommandTerminateDisabledIgnored(Execution $execution): vo static::assertNull($execution); } - private function createOptionExecutionIdInput(string $id): InputInterface + private function createOptionExecutionIdInput(CommandFlowListener $listener, string $id): InputInterface { $input = $this->createMock(InputInterface::class); $input ->expects(static::once()) ->method('hasOption') - ->with($this->object::OPTION_EXECUTION_ID) + ->with($listener::OPTION_EXECUTION_ID) ->willReturn(true) ; $input ->expects(static::once()) ->method('getOption') - ->with($this->object::OPTION_EXECUTION_ID) + ->with($listener::OPTION_EXECUTION_ID) ->willReturn($id) + ->seal() ; return $input; @@ -893,8 +1021,8 @@ private function createCommandEvent(): ConsoleCommandEvent return new ConsoleCommandEvent( $command, - $this->createMock(InputInterface::class), - $this->createMock(OutputInterface::class) + static::createStub(InputInterface::class), + static::createStub(OutputInterface::class) ); } } diff --git a/packages/console/Tests/Output/BufferedConsoleOutputTest.php b/packages/console/Tests/Output/BufferedConsoleOutputTest.php index 8ba25c35a..ac6b40fc8 100644 --- a/packages/console/Tests/Output/BufferedConsoleOutputTest.php +++ b/packages/console/Tests/Output/BufferedConsoleOutputTest.php @@ -4,11 +4,10 @@ use Draw\Component\Console\Output\BufferedConsoleOutput; use Draw\Component\Core\Reflection\ReflectionAccessor; -use Draw\Component\Tester\MockTrait; +use Draw\Component\Tester\DoubleTrait; use PHPUnit\Framework\Attributes\CoversClass; use PHPUnit\Framework\TestCase; use Symfony\Component\Console\Formatter\OutputFormatterInterface; -use Symfony\Component\Console\Output\ConsoleOutput; use Symfony\Component\Console\Output\OutputInterface; /** @@ -17,7 +16,8 @@ #[CoversClass(BufferedConsoleOutput::class)] class BufferedConsoleOutputTest extends TestCase { - use MockTrait; + use DoubleTrait; + private BufferedConsoleOutput $object; protected function setUp(): void @@ -25,14 +25,6 @@ protected function setUp(): void $this->object = new BufferedConsoleOutput(OutputInterface::VERBOSITY_NORMAL); } - public function testConstruct(): void - { - static::assertInstanceOf( - ConsoleOutput::class, - $this->object - ); - } - public function testSetDecorated(): void { $formatter = $this->mockProperty( @@ -51,6 +43,7 @@ public function testSetDecorated(): void ->expects(static::once()) ->method('setDecorated') ->with(true) + ->seal() ; $this->object->setDecorated(true); @@ -62,7 +55,7 @@ public function testSetDecorated(): void public function testSetFormatter(): void { // This is to test we are not in a infinite loop - $this->object->setFormatter($this->createMock(OutputFormatterInterface::class)); + $this->object->setFormatter(static::createStub(OutputFormatterInterface::class)); $this->addToAssertionCount(1); } diff --git a/packages/console/composer.json b/packages/console/composer.json index 35092a160..c9243b15c 100644 --- a/packages/console/composer.json +++ b/packages/console/composer.json @@ -20,7 +20,7 @@ "doctrine/orm": "^3.6", "draw/dependency-injection": "^0.39", "draw/tester": "^0.39", - "phpunit/phpunit": "^11.3 || ^12.0", + "phpunit/phpunit": "^11.3 || ^12.0 || ^13.0", "symfony/cache": "^6.4.0" }, "minimum-stability": "dev", diff --git a/packages/core/Reflection/ReflectionAccessor.php b/packages/core/Reflection/ReflectionAccessor.php index a84a4d639..1ce0dfac9 100644 --- a/packages/core/Reflection/ReflectionAccessor.php +++ b/packages/core/Reflection/ReflectionAccessor.php @@ -26,9 +26,10 @@ public static function setPropertyValue(object|string $objectOrClass, string $pr { $property = self::getPropertyReflection($objectOrClass, $propertyName); - $property->isStatic() - ? $property->setValue($value) - : $property->setValue($objectOrClass, $value); + $property->setValue( + $property->isStatic() ? null : $objectOrClass, + $value + ); } /** diff --git a/packages/core/Tests/FilterExpression/Expression/CompositeExpressionEvaluatorTest.php b/packages/core/Tests/FilterExpression/Expression/CompositeExpressionEvaluatorTest.php index 9fc669711..66f233416 100644 --- a/packages/core/Tests/FilterExpression/Expression/CompositeExpressionEvaluatorTest.php +++ b/packages/core/Tests/FilterExpression/Expression/CompositeExpressionEvaluatorTest.php @@ -6,9 +6,7 @@ use Draw\Component\Core\FilterExpression\Expression\CompositeExpression; use Draw\Component\Core\FilterExpression\Expression\CompositeExpressionEvaluator; use Draw\Component\Core\FilterExpression\Expression\ConstraintExpression; -use Draw\Component\Core\FilterExpression\Expression\ExpressionEvaluator; use PHPUnit\Framework\Attributes\CoversClass; -use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; /** @@ -17,59 +15,54 @@ #[CoversClass(CompositeExpressionEvaluator::class)] class CompositeExpressionEvaluatorTest extends TestCase { - private CompositeExpressionEvaluator $object; - - private Evaluator&MockObject $evaluator; - - protected function setUp(): void - { - $this->object = new CompositeExpressionEvaluator( - $this->evaluator = $this->createMock(Evaluator::class) - ); - } - - public function testConstruct(): void + public function testEvaluateInvalidExpression(): void { - static::assertInstanceOf( - ExpressionEvaluator::class, - $this->object + $object = new CompositeExpressionEvaluator( + static::createStub(Evaluator::class) ); - } - public function testEvaluateInvalidExpression(): void - { $this->expectException(\InvalidArgumentException::class); $this->expectExceptionMessage('Expression of class ['.ConstraintExpression::class.'] is not supported'); - $this->object->evaluate(null, new ConstraintExpression(null)); + $object->evaluate(null, new ConstraintExpression(null)); } public function testEvaluateNoExpression(): void { - $this->evaluator + $object = new CompositeExpressionEvaluator( + $evaluator = $this->createMock(Evaluator::class) + ); + + $evaluator ->expects(static::never()) ->method('evaluate') + ->seal() ; static::assertTrue( - $this->object->evaluate(null, new CompositeExpression(CompositeExpression::TYPE_AND, [])) + $object->evaluate(null, new CompositeExpression(CompositeExpression::TYPE_AND, [])) ); } public function testEvaluateInvalidType(): void { + $object = new CompositeExpressionEvaluator( + $evaluator = $this->createMock(Evaluator::class) + ); + $type = uniqid('type'); $this->expectException(\InvalidArgumentException::class); $this->expectExceptionMessage('Unsupported CompositeExpression type ['.$type.']'); - $this->evaluator + $evaluator ->expects(static::never()) ->method('evaluate') + ->seal() ; static::assertTrue( - $this->object->evaluate(null, new CompositeExpression($type, [])) + $object->evaluate(null, new CompositeExpression($type, [])) ); } } diff --git a/packages/core/Tests/FilterExpression/Expression/ConstraintExpressionEvaluatorTest.php b/packages/core/Tests/FilterExpression/Expression/ConstraintExpressionEvaluatorTest.php index 322e20493..57c04b6fd 100644 --- a/packages/core/Tests/FilterExpression/Expression/ConstraintExpressionEvaluatorTest.php +++ b/packages/core/Tests/FilterExpression/Expression/ConstraintExpressionEvaluatorTest.php @@ -4,7 +4,6 @@ use Draw\Component\Core\FilterExpression\Expression\CompositeExpression; use Draw\Component\Core\FilterExpression\Expression\ConstraintExpressionEvaluator; -use Draw\Component\Core\FilterExpression\Expression\ExpressionEvaluator; use PHPUnit\Framework\Attributes\CoversClass; use PHPUnit\Framework\TestCase; @@ -21,14 +20,6 @@ protected function setUp(): void $this->object = new ConstraintExpressionEvaluator(); } - public function testConstruct(): void - { - static::assertInstanceOf( - ExpressionEvaluator::class, - $this->object - ); - } - public function testEvaluateInvalidExpression(): void { $this->expectException(\InvalidArgumentException::class); diff --git a/packages/core/Tests/FilterExpression/ExpressionTest.php b/packages/core/Tests/FilterExpression/ExpressionTest.php index c8f960d1b..2f5eaa91b 100644 --- a/packages/core/Tests/FilterExpression/ExpressionTest.php +++ b/packages/core/Tests/FilterExpression/ExpressionTest.php @@ -21,7 +21,6 @@ public function testEqual(): void $groups = ['Default'] ); - static::assertInstanceOf(ConstraintExpression::class, $expression); static::assertSame($path, $expression->getPath()); static::assertSame($constraint, $expression->getConstraints()); static::assertSame($groups, $expression->getGroups()); @@ -34,7 +33,6 @@ public function testAndX(): void $expression2 = Expression::validate('[property]') ); - static::assertInstanceOf(CompositeExpression::class, $expression); static::assertSame(CompositeExpression::TYPE_AND, $expression->getType()); $expressions = $expression->getExpressions(); @@ -52,7 +50,6 @@ public function testAndWhereEqual(): void '[property2]' => 'value2', ]); - static::assertInstanceOf(CompositeExpression::class, $expression); static::assertSame(CompositeExpression::TYPE_AND, $expression->getType()); $expressions = $expression->getExpressions(); @@ -87,7 +84,6 @@ public function testOrX(): void $expression2 = Expression::validate('[property]') ); - static::assertInstanceOf(CompositeExpression::class, $expression); static::assertSame(CompositeExpression::TYPE_OR, $expression->getType()); $expressions = $expression->getExpressions(); diff --git a/packages/core/Tests/FilterExpression/QueryTest.php b/packages/core/Tests/FilterExpression/QueryTest.php index 17ad80989..bfc6f10fd 100644 --- a/packages/core/Tests/FilterExpression/QueryTest.php +++ b/packages/core/Tests/FilterExpression/QueryTest.php @@ -25,7 +25,7 @@ public function testWhere(): void { static::assertSame( $this->object, - $this->object->where($expression = $this->createMock(Expression::class)) + $this->object->where($expression = static::createStub(Expression::class)) ); static::assertSame( @@ -38,7 +38,7 @@ public function testAndWhereNoExpressionSet(): void { static::assertSame( $this->object, - $this->object->andWhere($expression = $this->createMock(Expression::class)) + $this->object->andWhere($expression = static::createStub(Expression::class)) ); static::assertSame( @@ -49,8 +49,8 @@ public function testAndWhereNoExpressionSet(): void public function testAndWhere(): void { - $this->object->andWhere($expression1 = $this->createMock(Expression::class)); - $this->object->andWhere($expression2 = $this->createMock(Expression::class)); + $this->object->andWhere($expression1 = static::createStub(Expression::class)); + $this->object->andWhere($expression2 = static::createStub(Expression::class)); /** @var CompositeExpression $expression */ $expression = $this->object->getExpression(); @@ -75,7 +75,7 @@ public function testOrWhereNoExpressionSet(): void { static::assertSame( $this->object, - $this->object->orWhere($expression = $this->createMock(Expression::class)) + $this->object->orWhere($expression = static::createStub(Expression::class)) ); static::assertSame( @@ -86,8 +86,8 @@ public function testOrWhereNoExpressionSet(): void public function testOrWhere(): void { - $this->object->orWhere($expression1 = $this->createMock(Expression::class)); - $this->object->orWhere($expression2 = $this->createMock(Expression::class)); + $this->object->orWhere($expression1 = static::createStub(Expression::class)); + $this->object->orWhere($expression2 = static::createStub(Expression::class)); $expression = $this->object->getExpression(); diff --git a/packages/core/composer.json b/packages/core/composer.json index 7fd22c2ec..b92ebf81d 100644 --- a/packages/core/composer.json +++ b/packages/core/composer.json @@ -10,7 +10,7 @@ "symfony/validator": "^6.4.0" }, "require-dev": { - "phpunit/phpunit": "^11.3 || ^12.0" + "phpunit/phpunit": "^11.3 || ^12.0 || ^13.0" }, "minimum-stability": "dev", "prefer-stable": true, diff --git a/packages/cron-job/Tests/Command/QueueCronJobByNameCommandTest.php b/packages/cron-job/Tests/Command/QueueCronJobByNameCommandTest.php index c205d6cf6..5bee1cb16 100644 --- a/packages/cron-job/Tests/Command/QueueCronJobByNameCommandTest.php +++ b/packages/cron-job/Tests/Command/QueueCronJobByNameCommandTest.php @@ -12,7 +12,6 @@ use Draw\Component\Tester\Application\CommandDataTester; use Draw\Component\Tester\Application\CommandTestTrait; use PHPUnit\Framework\Attributes\CoversClass; -use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputArgument; @@ -25,25 +24,11 @@ class QueueCronJobByNameCommandTest extends TestCase { use CommandTestTrait; - private ManagerRegistry&MockObject $managerRegistry; - - private CronJobProcessor&MockObject $cronJobProcessor; - - private EntityRepository&MockObject $repository; - protected function setUp(): void { - $this->managerRegistry = $this->createMock(ManagerRegistry::class); - $this->managerRegistry - ->expects(static::any()) - ->method('getRepository') - ->with(CronJob::class) - ->willReturn($this->repository = $this->createMock(EntityRepository::class)) - ; - $this->command = new QueueCronJobByNameCommand( - $this->managerRegistry, - $this->cronJobProcessor = $this->createMock(CronJobProcessor::class) + static::createStub(ManagerRegistry::class), + static::createStub(CronJobProcessor::class) ); } @@ -64,17 +49,32 @@ public static function provideTestOption(): iterable public function testExecuteWithExistingCronJob(): void { - $this->repository + $this->command = new QueueCronJobByNameCommand( + $managerRegistry = $this->createMock(ManagerRegistry::class), + $cronJobProcessor = $this->createMock(CronJobProcessor::class) + ); + + $managerRegistry + ->expects(static::once()) + ->method('getRepository') + ->with(CronJob::class) + ->willReturn($repository = $this->createMock(EntityRepository::class)) + ->seal() + ; + + $repository ->expects(static::once()) ->method('findOneBy') ->with(['name' => $cronJobName = 'Existing Cron Job']) ->willReturn($cronJob = new CronJob()) + ->seal() ; - $this->cronJobProcessor + $cronJobProcessor ->expects(static::once()) ->method('queue') ->with($cronJob, true) + ->seal() ; $this @@ -93,16 +93,31 @@ public function testExecuteWithExistingCronJob(): void public function testExecuteWithoutExistingCronJob(): void { - $this->repository + $this->command = new QueueCronJobByNameCommand( + $managerRegistry = $this->createMock(ManagerRegistry::class), + $cronJobProcessor = $this->createMock(CronJobProcessor::class) + ); + + $managerRegistry + ->expects(static::once()) + ->method('getRepository') + ->with(CronJob::class) + ->willReturn($repository = $this->createMock(EntityRepository::class)) + ->seal() + ; + + $repository ->expects(static::once()) ->method('findOneBy') ->with(['name' => $cronJobName = 'Invalid Cron Job']) ->willReturn(null) + ->seal() ; - $this->cronJobProcessor + $cronJobProcessor ->expects(static::never()) ->method('queue') + ->seal() ; $this diff --git a/packages/cron-job/Tests/Command/QueueDueCronJobsCommandTest.php b/packages/cron-job/Tests/Command/QueueDueCronJobsCommandTest.php index fd87edb51..7e279184c 100644 --- a/packages/cron-job/Tests/Command/QueueDueCronJobsCommandTest.php +++ b/packages/cron-job/Tests/Command/QueueDueCronJobsCommandTest.php @@ -11,10 +11,10 @@ use Draw\Component\CronJob\Entity\CronJob; use Draw\Component\Tester\Application\CommandDataTester; use Draw\Component\Tester\Application\CommandTestTrait; -use Draw\Component\Tester\MockTrait; +use Draw\Component\Tester\DoubleTrait; use PHPUnit\Framework\Attributes\CoversClass; use PHPUnit\Framework\Attributes\DataProvider; -use PHPUnit\Framework\MockObject\MockObject; +use PHPUnit\Framework\MockObject\Stub; use PHPUnit\Framework\TestCase; use Symfony\Component\Console\Command\Command; @@ -25,17 +25,13 @@ class QueueDueCronJobsCommandTest extends TestCase { use CommandTestTrait; - use MockTrait; - - private ManagerRegistry&MockObject $managerRegistry; - - private CronJobProcessor&MockObject $cronJobProcessor; + use DoubleTrait; protected function setUp(): void { $this->command = new QueueDueCronJobsCommand( - $this->managerRegistry = $this->createMock(ManagerRegistry::class), - $this->cronJobProcessor = $this->createMock(CronJobProcessor::class) + static::createStub(ManagerRegistry::class), + static::createStub(CronJobProcessor::class) ); } @@ -61,11 +57,17 @@ public static function provideTestOption(): iterable #[DataProvider('provideExecuteCases')] public function testExecute(array $rawCronJobs, array $expectedDisplay): void { - $this->managerRegistry - ->expects(static::any()) + $this->command = new QueueDueCronJobsCommand( + $managerRegistry = $this->createMock(ManagerRegistry::class), + $cronJobProcessor = $this->createMock(CronJobProcessor::class) + ); + + $managerRegistry + ->expects(static::once()) ->method('getRepository') ->with(CronJob::class) ->willReturn($repository = $this->createMock(EntityRepository::class)) + ->seal() ; $repository @@ -74,13 +76,14 @@ public function testExecute(array $rawCronJobs, array $expectedDisplay): void ->with(['active' => true]) ->willReturn( $cronJobs = array_map( - fn (array $rawCronJob): CronJob&MockObject => $this->createCronJob( + fn (array $rawCronJob): CronJob&Stub => $this->createCronJob( $rawCronJob['name'], $rawCronJob['due'] ), $rawCronJobs ) ) + ->seal() ; $dueCronJobs = array_filter( @@ -89,12 +92,13 @@ public function testExecute(array $rawCronJobs, array $expectedDisplay): void ); if (0 === $numDueCronJobs = \count($dueCronJobs)) { - $this->cronJobProcessor + $cronJobProcessor ->expects(static::never()) ->method('queue') + ->seal() ; } else { - $this->cronJobProcessor + $cronJobProcessor ->expects(static::exactly($numDueCronJobs)) ->method('queue') ->with( @@ -103,6 +107,7 @@ public function testExecute(array $rawCronJobs, array $expectedDisplay): void $dueCronJobs )) ) + ->seal() ; } @@ -172,16 +177,14 @@ public static function provideExecuteCases(): iterable ]; } - private function createCronJob(string $name, bool $due): CronJob&MockObject + private function createCronJob(string $name, bool $due): CronJob&Stub { - $cronJob = $this->createMock(CronJob::class); + $cronJob = static::createStub(CronJob::class); $cronJob - ->expects(static::any()) ->method('getName') ->willReturn($name) ; $cronJob - ->expects(static::any()) ->method('isDue') ->willReturn($due) ; diff --git a/packages/cron-job/Tests/CronJobProcessorTest.php b/packages/cron-job/Tests/CronJobProcessorTest.php index 9800be39b..8a3d0f581 100644 --- a/packages/cron-job/Tests/CronJobProcessorTest.php +++ b/packages/cron-job/Tests/CronJobProcessorTest.php @@ -13,11 +13,10 @@ use Draw\Component\CronJob\Event\PostCronJobExecutionEvent; use Draw\Component\CronJob\Event\PreCronJobExecutionEvent; use Draw\Component\CronJob\Message\ExecuteCronJobMessage; -use Draw\Component\Tester\MockTrait; +use Draw\Component\Tester\DoubleTrait; use Draw\Contracts\Process\ProcessFactoryInterface; use PHPUnit\Framework\Attributes\CoversClass; use PHPUnit\Framework\Attributes\DataProvider; -use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag; use Symfony\Component\Messenger\Envelope; @@ -31,69 +30,59 @@ #[CoversClass(CronJobProcessor::class)] class CronJobProcessorTest extends TestCase { - use MockTrait; + use DoubleTrait; - private CronJobProcessor $cronJobProcessor; - - private EventDispatcherInterface&MockObject $eventDispatcher; - - private ProcessFactoryInterface&MockObject $processFactory; - - private MessageBusInterface&MockObject $messageBus; - - private EntityManagerInterface&MockObject $entityManager; - - protected function setUp(): void + #[DataProvider('provideQueueCases')] + public function testQueue(bool $force): void { - $managerRegistry = $this->createMock(ManagerRegistry::class); - $managerRegistry - ->expects(static::any()) - ->method('getManagerForClass') - ->with(CronJobExecution::class) - ->willReturn($this->entityManager = $this->createMock(EntityManagerInterface::class)) - ; - - $this->cronJobProcessor = new CronJobProcessor( - $managerRegistry, + $cronJobProcessor = new CronJobProcessor( + $managerRegistry = $this->createMock(ManagerRegistry::class), new ParameterBag([ 'kernel.cache_dir' => '/var/cache', ]), - $this->eventDispatcher = $this->createMock(EventDispatcherInterface::class), - $this->processFactory = $this->createMock(ProcessFactoryInterface::class), - $this->messageBus = $this->createMock(MessageBusInterface::class) + static::createStub(EventDispatcherInterface::class), + static::createStub(ProcessFactoryInterface::class), + $messageBus = $this->createMock(MessageBusInterface::class) ); - } - #[DataProvider('provideQueueCases')] - public function testQueue(bool $force): void - { + $managerRegistry + ->expects(static::once()) + ->method('getManagerForClass') + ->with(CronJobExecution::class) + ->willReturn($entityManager = $this->createMock(EntityManagerInterface::class)) + ->seal() + ; + $cronJob = $this->createMock(CronJob::class); $cronJob - ->expects(static::any()) + ->expects(static::once()) ->method('newExecution') ->with($force) ->willReturn($execution = $this->createCronJobExecution()) + ->seal() ; - $this->entityManager + $entityManager ->expects(static::once()) ->method('persist') ->with($execution) ; - $this->entityManager + $entityManager ->expects(static::once()) ->method('flush') + ->seal() ; - $this->messageBus + $messageBus ->expects(static::once()) ->method('dispatch') ->with($message = new ExecuteCronJobMessage($execution)) ->willReturn(new Envelope($message, [])) + ->seal() ; - $this->cronJobProcessor->queue($cronJob, $force); + $cronJobProcessor->queue($cronJob, $force); } public static function provideQueueCases(): iterable @@ -109,6 +98,24 @@ public function testProcess( ?string $overwrittenCommand, string $expectedProcessCommand, ): void { + $cronJobProcessor = new CronJobProcessor( + $managerRegistry = $this->createMock(ManagerRegistry::class), + new ParameterBag([ + 'kernel.cache_dir' => '/var/cache', + ]), + $eventDispatcher = $this->createMock(EventDispatcherInterface::class), + $processFactory = $this->createMock(ProcessFactoryInterface::class), + static::createStub(MessageBusInterface::class) + ); + + $managerRegistry + ->expects(static::once()) + ->method('getManagerForClass') + ->with(CronJobExecution::class) + ->willReturn($entityManager = $this->createMock(EntityManagerInterface::class)) + ->seal() + ; + $returnedPreCronJobExecutionEvent = new PreCronJobExecutionEvent( $execution = $this->createCronJobExecution($command) ); @@ -119,7 +126,7 @@ public function testProcess( $execution->getCronJob()->setExecutionTimeout($executionTimeout = random_int(1, 100)); - $this->eventDispatcher + $eventDispatcher ->expects(static::exactly(2)) ->method('dispatch') ->with( @@ -136,27 +143,30 @@ public function testProcess( $returnedPreCronJobExecutionEvent, $postExecutionEvent ) + ->seal() ; - $this->entityManager + $entityManager ->expects(static::exactly(2)) ->method('flush') ; - $this->entityManager + $entityManager ->expects(static::once()) ->method('getConnection') ->willReturn( $connection = $this->createMock(Connection::class) ) + ->seal() ; $connection ->expects(static::once()) ->method('close') + ->seal() ; - $this->processFactory + $processFactory ->expects(static::once()) ->method('createFromShellCommandLine') ->with( @@ -167,14 +177,16 @@ public function testProcess( $executionTimeout, ) ->willReturn($process = $this->createMock(Process::class)) + ->seal() ; $process ->expects(static::once()) ->method('mustRun') + ->seal() ; - $this->cronJobProcessor->process($execution); + $cronJobProcessor->process($execution); static::assertSame(CronJobExecution::STATE_TERMINATED, $execution->getState()); static::assertNotNull($execution->getExecutionStartedAt()); @@ -204,7 +216,25 @@ public static function provideProcessCases(): iterable public function testProcessWithError(): void { - $this->eventDispatcher + $cronJobProcessor = new CronJobProcessor( + $managerRegistry = $this->createMock(ManagerRegistry::class), + new ParameterBag([ + 'kernel.cache_dir' => '/var/cache', + ]), + $eventDispatcher = $this->createMock(EventDispatcherInterface::class), + $processFactory = $this->createMock(ProcessFactoryInterface::class), + static::createStub(MessageBusInterface::class) + ); + + $managerRegistry + ->expects(static::once()) + ->method('getManagerForClass') + ->with(CronJobExecution::class) + ->willReturn($entityManager = $this->createMock(EntityManagerInterface::class)) + ->seal() + ; + + $eventDispatcher ->expects(static::exactly(2)) ->method('dispatch') ->with( @@ -220,34 +250,38 @@ public function testProcessWithError(): void ) ) ->willReturnOnConsecutiveCalls($preExecutionEvent, $postExecutionEvent) + ->seal() ; - $this->entityManager + $entityManager ->expects(static::exactly(2)) ->method('flush') ; - $this->entityManager + $entityManager ->expects(static::once()) ->method('getConnection') ->willReturn( $connection = $this->createMock(Connection::class) ) + ->seal() ; $connection ->expects(static::once()) ->method('close') + ->seal() ; $process = $this->createMock(Process::class); $process - ->expects(static::any()) + ->expects(static::once()) ->method('getExitCode') ->willReturn($exitCode = 127) ; + $process - ->expects(static::any()) + ->expects(static::once()) ->method('mustRun') ->willThrowException( new \Exception( @@ -257,7 +291,18 @@ public function testProcessWithError(): void ) ; - $this->processFactory + $process + ->expects(static::once()) + ->method('getOutput') + ; + + $process + ->expects(static::once()) + ->method('getErrorOutput') + ->seal() + ; + + $processFactory ->expects(static::once()) ->method('createFromShellCommandLine') ->with( @@ -268,9 +313,10 @@ public function testProcessWithError(): void $execution->getCronJob()->getExecutionTimeout() ) ->willReturn($process) + ->seal() ; - $this->cronJobProcessor->process($execution); + $cronJobProcessor->process($execution); static::assertSame(CronJobExecution::STATE_ERRORED, $execution->getState()); static::assertNotNull($execution->getExecutionStartedAt()); @@ -282,22 +328,43 @@ public function testProcessWithError(): void public function testProcessWithInactiveCronJob(): void { - $this->eventDispatcher + $cronJobProcessor = new CronJobProcessor( + $managerRegistry = $this->createMock(ManagerRegistry::class), + new ParameterBag([ + 'kernel.cache_dir' => '/var/cache', + ]), + $eventDispatcher = $this->createMock(EventDispatcherInterface::class), + $processFactory = $this->createMock(ProcessFactoryInterface::class), + static::createStub(MessageBusInterface::class) + ); + + $managerRegistry + ->expects(static::once()) + ->method('getManagerForClass') + ->with(CronJobExecution::class) + ->willReturn($entityManager = $this->createMock(EntityManagerInterface::class)) + ->seal() + ; + + $eventDispatcher ->expects(static::never()) ->method('dispatch') + ->seal() ; - $this->entityManager + $entityManager ->expects(static::once()) ->method('flush') + ->seal() ; - $this->processFactory + $processFactory ->expects(static::never()) ->method('createFromShellCommandLine') + ->seal() ; - $this->cronJobProcessor->process( + $cronJobProcessor->process( $execution = (new CronJob()) ->setActive(false) ->newExecution() @@ -308,7 +375,25 @@ public function testProcessWithInactiveCronJob(): void public function testProcessWithCancelledExecution(): void { - $this->eventDispatcher + $cronJobProcessor = new CronJobProcessor( + $managerRegistry = $this->createMock(ManagerRegistry::class), + new ParameterBag([ + 'kernel.cache_dir' => '/var/cache', + ]), + $eventDispatcher = $this->createMock(EventDispatcherInterface::class), + $processFactory = $this->createMock(ProcessFactoryInterface::class), + static::createStub(MessageBusInterface::class) + ); + + $managerRegistry + ->expects(static::once()) + ->method('getManagerForClass') + ->with(CronJobExecution::class) + ->willReturn($entityManager = $this->createMock(EntityManagerInterface::class)) + ->seal() + ; + + $eventDispatcher ->expects(static::once()) ->method('dispatch') ->with( @@ -317,19 +402,22 @@ public function testProcessWithCancelledExecution(): void ->willReturn( new PreCronJobExecutionEvent($execution, true) ) + ->seal() ; - $this->entityManager + $entityManager ->expects(static::once()) ->method('flush') + ->seal() ; - $this->processFactory + $processFactory ->expects(static::never()) ->method('createFromShellCommandLine') + ->seal() ; - $this->cronJobProcessor->process($execution); + $cronJobProcessor->process($execution); static::assertSame(CronJobExecution::STATE_SKIPPED, $execution->getState()); } diff --git a/packages/cron-job/Tests/MessageHandler/ExecuteCronJobMessageHandlerTest.php b/packages/cron-job/Tests/MessageHandler/ExecuteCronJobMessageHandlerTest.php index c695e9482..34d433adb 100644 --- a/packages/cron-job/Tests/MessageHandler/ExecuteCronJobMessageHandlerTest.php +++ b/packages/cron-job/Tests/MessageHandler/ExecuteCronJobMessageHandlerTest.php @@ -38,6 +38,7 @@ public function testHandleExecuteCronJobMessage(): void ->expects(static::once()) ->method('process') ->with($execution = (new CronJob())->newExecution()) + ->seal() ; $this->handler->handleExecuteCronJobMessage( diff --git a/packages/cron-job/composer.json b/packages/cron-job/composer.json index e2e94bd78..5d2362c80 100644 --- a/packages/cron-job/composer.json +++ b/packages/cron-job/composer.json @@ -29,7 +29,7 @@ "symfony/messenger": "^6.4.0" }, "require-dev": { - "phpunit/phpunit": "^11.3 || ^12.0", + "phpunit/phpunit": "^11.3 || ^12.0 || ^13.0", "draw/dependency-injection": "^0.39", "draw/tester": "^0.39", "nesbot/carbon": "^3.8" diff --git a/packages/dependency-injection/Integration/Test/IntegrationTestCase.php b/packages/dependency-injection/Integration/Test/IntegrationTestCase.php index b5f9603a4..c6d3f7f3c 100644 --- a/packages/dependency-injection/Integration/Test/IntegrationTestCase.php +++ b/packages/dependency-injection/Integration/Test/IntegrationTestCase.php @@ -26,15 +26,14 @@ abstract public function getDefaultConfiguration(): array; protected function mockExtension(string $name): ExtensionInterface { - $extension = $this->createMock(ExtensionInterface::class); + $extension = static::createStub(ExtensionInterface::class); - $extension->expects(static::any()) + $extension ->method('getAlias') ->willReturn($name) ; $extension - ->expects(static::any()) ->method('getNamespace') ->willReturn($name) ; diff --git a/packages/dependency-injection/composer.json b/packages/dependency-injection/composer.json index 9e4321162..e23e4de1b 100644 --- a/packages/dependency-injection/composer.json +++ b/packages/dependency-injection/composer.json @@ -20,7 +20,7 @@ "symfony/dependency-injection": "^6.4.0" }, "require-dev": { - "phpunit/phpunit": "^11.3 || ^12.0" + "phpunit/phpunit": "^11.3 || ^12.0 || ^13.0" }, "minimum-stability": "dev", "prefer-stable": true, diff --git a/packages/doctrine-extra/Tests/Common/DataFixtures/ObjectReferenceTraitTest.php b/packages/doctrine-extra/Tests/Common/DataFixtures/ObjectReferenceTraitTest.php index be68a1519..049b5efcf 100644 --- a/packages/doctrine-extra/Tests/Common/DataFixtures/ObjectReferenceTraitTest.php +++ b/packages/doctrine-extra/Tests/Common/DataFixtures/ObjectReferenceTraitTest.php @@ -51,6 +51,7 @@ public function testAddObjectReference(): void ), $object = new \stdClass() ) + ->seal() ; $this->trait->addObjectReference($class, $name, $object); @@ -70,6 +71,7 @@ public function testHasObjectReference(): void $class ) ->willReturn(false) + ->seal() ; static::assertFalse( @@ -91,6 +93,7 @@ public function testGetObjectReference(): void $class ) ->willReturn($object = new \stdClass()) + ->seal() ; static::assertSame( @@ -112,6 +115,7 @@ public function testSetObjectReference(): void ), $object = new \stdClass() ) + ->seal() ; $this->trait->setObjectReference($class, $name, $object); diff --git a/packages/doctrine-extra/composer.json b/packages/doctrine-extra/composer.json index 7e4455949..0823489c8 100644 --- a/packages/doctrine-extra/composer.json +++ b/packages/doctrine-extra/composer.json @@ -24,7 +24,7 @@ "doctrine/data-fixtures": "^2.0", "draw/dependency-injection": "^0.39", "draw/graphviz": "^0.39", - "phpunit/phpunit": "^11.3 || ^12.0" + "phpunit/phpunit": "^11.3 || ^12.0 || ^13.0" }, "suggest": { "draw/graphviz": "To generate graph of the database schema" diff --git a/packages/entity-migrator/Tests/Message/MigrateEntityCommandTest.php b/packages/entity-migrator/Tests/Message/MigrateEntityCommandTest.php index dd3a3d655..c30bc3831 100644 --- a/packages/entity-migrator/Tests/Message/MigrateEntityCommandTest.php +++ b/packages/entity-migrator/Tests/Message/MigrateEntityCommandTest.php @@ -8,6 +8,7 @@ use Draw\Component\Messenger\DoctrineEnvelopeEntityReference\Exception\ObjectNotFoundException; use Draw\Component\Messenger\DoctrineEnvelopeEntityReference\Stamp\PropertyReferenceStamp; use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\MockObject\Stub; use PHPUnit\Framework\TestCase; /** @@ -18,12 +19,12 @@ class MigrateEntityCommandTest extends TestCase { private MigrateEntityCommand $object; - private EntityMigrationInterface $entityMigration; + private EntityMigrationInterface&Stub $entityMigration; protected function setUp(): void { $this->object = new MigrateEntityCommand( - $this->entityMigration = $this->createMock(EntityMigrationInterface::class) + $this->entityMigration = static::createStub(EntityMigrationInterface::class) ); } diff --git a/packages/entity-migrator/composer.json b/packages/entity-migrator/composer.json index bf154820b..939689715 100644 --- a/packages/entity-migrator/composer.json +++ b/packages/entity-migrator/composer.json @@ -24,7 +24,7 @@ }, "require-dev": { "draw/tester": "^0.39", - "phpunit/phpunit": "^11.3 || ^12.0" + "phpunit/phpunit": "^11.3 || ^12.0 || ^13.0" }, "minimum-stability": "dev", "prefer-stable": true, diff --git a/packages/fixer/composer.json b/packages/fixer/composer.json index 3f6bba9c7..d2c756691 100644 --- a/packages/fixer/composer.json +++ b/packages/fixer/composer.json @@ -18,7 +18,7 @@ "friendsofphp/php-cs-fixer": "^3.13" }, "require-dev": { - "phpunit/phpunit": "^11.3 || ^12.0" + "phpunit/phpunit": "^11.3 || ^12.0 || ^13.0" }, "minimum-stability": "dev", "prefer-stable": true, diff --git a/packages/framework-extra-bundle/Tests/DrawFrameworkExtraBundleTest.php b/packages/framework-extra-bundle/Tests/DrawFrameworkExtraBundleTest.php index c83dadee9..2bd44b6d9 100644 --- a/packages/framework-extra-bundle/Tests/DrawFrameworkExtraBundleTest.php +++ b/packages/framework-extra-bundle/Tests/DrawFrameworkExtraBundleTest.php @@ -15,7 +15,7 @@ use Draw\Component\Security\DependencyInjection\Compiler\UserCheckerDecoratorPass; use Draw\Component\Security\DependencyInjection\Factory\JwtAuthenticatorFactory; use Draw\Component\Security\DependencyInjection\Factory\MessengerMessageAuthenticatorFactory; -use Draw\Component\Tester\MockTrait; +use Draw\Component\Tester\DoubleTrait; use PHPUnit\Framework\TestCase; use Symfony\Bundle\SecurityBundle\DependencyInjection\SecurityExtension; use Symfony\Component\DependencyInjection\Compiler\PassConfig; @@ -26,7 +26,7 @@ */ class DrawFrameworkExtraBundleTest extends TestCase { - use MockTrait; + use DoubleTrait; private DrawFrameworkExtraBundle $bundle; @@ -111,6 +111,7 @@ public function testBuild(): void ->method('getExtension') ->with('security') ->willReturn($extension = $this->createMock(SecurityExtension::class)) + ->seal() ; $extension @@ -122,6 +123,7 @@ public function testBuild(): void [static::isInstanceOf(MessengerMessageAuthenticatorFactory::class)], ) ) + ->seal() ; $this->bundle->build($containerBuilder); diff --git a/packages/framework-extra-bundle/composer.json b/packages/framework-extra-bundle/composer.json index b644e20bf..cc9c487ae 100644 --- a/packages/framework-extra-bundle/composer.json +++ b/packages/framework-extra-bundle/composer.json @@ -46,7 +46,7 @@ "draw/workflow": "^0.39", "monolog/monolog": "^3.5.0", "pelago/emogrifier": "^8.0", - "phpunit/phpunit": "^11.3 || ^12.0", + "phpunit/phpunit": "^11.3 || ^12.0 || ^13.0", "psr/log": "^3", "symfony/event-dispatcher": "^6.4.0", "symfony/http-foundation": "^6.4.0", diff --git a/packages/graphviz/composer.json b/packages/graphviz/composer.json index 45f274fdf..58ff7edc2 100644 --- a/packages/graphviz/composer.json +++ b/packages/graphviz/composer.json @@ -18,7 +18,7 @@ "php": ">=8.5" }, "require-dev": { - "phpunit/phpunit": "^11.3 || ^12.0" + "phpunit/phpunit": "^11.3 || ^12.0 || ^13.0" }, "minimum-stability": "dev", "prefer-stable": true, diff --git a/packages/log/Symfony/Processor/RequestHeadersProcessor.php b/packages/log/Symfony/Processor/RequestHeadersProcessor.php index 9ed19ab0a..ab21d301f 100644 --- a/packages/log/Symfony/Processor/RequestHeadersProcessor.php +++ b/packages/log/Symfony/Processor/RequestHeadersProcessor.php @@ -10,9 +10,9 @@ class RequestHeadersProcessor protected const UPPER = '_ABCDEFGHIJKLMNOPQRSTUVWXYZ'; protected const LOWER = '-abcdefghijklmnopqrstuvwxyz'; - private ?array $onlyHeaders; + private array $onlyHeaders; - private ?array $ignoreHeaders; + private array $ignoreHeaders; public function __construct( private ?RequestStack $requestStack = null, diff --git a/packages/log/Tests/DecoratedLoggerTest.php b/packages/log/Tests/DecoratedLoggerTest.php index 6e4043df3..5f37225d2 100644 --- a/packages/log/Tests/DecoratedLoggerTest.php +++ b/packages/log/Tests/DecoratedLoggerTest.php @@ -3,7 +3,6 @@ namespace Draw\Component\Log\Tests; use Draw\Component\Log\DecoratedLogger; -use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Psr\Log\LoggerInterface; @@ -12,79 +11,69 @@ */ class DecoratedLoggerTest extends TestCase { - private DecoratedLogger $object; - - private LoggerInterface&MockObject $logger; - - private array $defaultContext; - - private string $decorateMessage; - - protected function setUp(): void - { - $this->object = new DecoratedLogger( - $this->logger = $this->createMock(LoggerInterface::class), - $this->defaultContext = ['key' => uniqid()], - $this->decorateMessage = uniqid().' {message}' - ); - } - - public function testConstruct(): void + public function testLog(): void { - static::assertInstanceOf( - LoggerInterface::class, - $this->object + $object = new DecoratedLogger( + $logger = $this->createMock(LoggerInterface::class), + $defaultContext = ['key' => uniqid()], + $decorateMessage = uniqid().' {message}' ); - } - public function testLog(): void - { - $this->logger + $logger ->expects(static::once()) ->method('log') ->with( $level = uniqid(), - str_replace('{message}', $message = uniqid(), $this->decorateMessage), - $this->defaultContext, + str_replace('{message}', $message = uniqid(), $decorateMessage), + $defaultContext, ) + ->seal() ; - $this->object->log($level, $message); + $object->log($level, $message); } public function testLogWitContext(): void { - $this->logger + $object = new DecoratedLogger( + $logger = $this->createMock(LoggerInterface::class), + $defaultContext = ['key' => uniqid()], + $decorateMessage = uniqid().' {message}' + ); + + $logger ->expects(static::once()) ->method('log') ->with( $level = uniqid(), - str_replace('{message}', $message = uniqid(), $this->decorateMessage), - array_merge($this->defaultContext, $context = ['otherKey' => uniqid()]), + str_replace('{message}', $message = uniqid(), $decorateMessage), + array_merge($defaultContext, $context = ['otherKey' => uniqid()]), ) + ->seal() ; - $this->object->log($level, $message, $context); + $object->log($level, $message, $context); } public function testLogNoMessageToken(): void { - $this->object = new DecoratedLogger( - $this->logger = $this->createMock(LoggerInterface::class), - $this->defaultContext = ['key' => uniqid()], - $this->decorateMessage = uniqid() + $object = new DecoratedLogger( + $logger = $this->createMock(LoggerInterface::class), + $defaultContext = ['key' => uniqid()], + $decorateMessage = uniqid() ); - $this->logger + $logger ->expects(static::once()) ->method('log') ->with( $level = uniqid(), - $this->decorateMessage.' '.$message = uniqid(), - $this->defaultContext, + $decorateMessage.' '.$message = uniqid(), + $defaultContext, ) + ->seal() ; - $this->object->log($level, $message); + $object->log($level, $message); } } diff --git a/packages/log/Tests/Symfony/EventListener/SlowRequestLoggerTest.php b/packages/log/Tests/Symfony/EventListener/SlowRequestLoggerTest.php index 4cebf9d26..5671f3f34 100644 --- a/packages/log/Tests/Symfony/EventListener/SlowRequestLoggerTest.php +++ b/packages/log/Tests/Symfony/EventListener/SlowRequestLoggerTest.php @@ -3,11 +3,9 @@ namespace Draw\Component\Log\Tests\Symfony\EventListener; use Draw\Component\Log\Symfony\EventListener\SlowRequestLoggerListener; -use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Psr\Log\LoggerInterface; use Psr\Log\LogLevel; -use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\RequestMatcherInterface; use Symfony\Component\HttpFoundation\Response; @@ -19,73 +17,61 @@ */ class SlowRequestLoggerTest extends TestCase { - private SlowRequestLoggerListener $object; - - /** - * @var LoggerInterface&MockObject - */ - private LoggerInterface $logger; - - /** - * @var RequestMatcherInterface&MockObject - */ - private RequestMatcherInterface $requestMatcher; - - private array $durations = []; - - protected function setUp(): void + public function testGetSubscribedEvents(): void { - $this->requestMatcher = $this->createMock(RequestMatcherInterface::class); + $requestMatcher = static::createStub(RequestMatcherInterface::class); - $this->object = new SlowRequestLoggerListener( - $this->logger = $this->createMock(LoggerInterface::class), + $object = new SlowRequestLoggerListener( + static::createStub(LoggerInterface::class), [ - ($this->durations[] = 5000) => [$this->requestMatcher], - ($this->durations[] = 2000) => [$this->requestMatcher], + 5000 => [$requestMatcher], + 2000 => [$requestMatcher], ] ); - } - - public function testConstruct(): void - { - static::assertInstanceOf( - EventSubscriberInterface::class, - $this->object - ); - } - public function testGetSubscribedEvents(): void - { static::assertSame( [ TerminateEvent::class => ['onKernelTerminate', 2048], ], - $this->object::getSubscribedEvents() + $object::getSubscribedEvents() ); } public function testOnKernelTerminateMatch(): void { - $this->requestMatcher + $durations = []; + + $requestMatcher = $this->createMock(RequestMatcherInterface::class); + + $object = new SlowRequestLoggerListener( + $logger = $this->createMock(LoggerInterface::class), + [ + ($durations[] = 5000) => [$requestMatcher], + ($durations[] = 2000) => [$requestMatcher], + ] + ); + + $requestMatcher ->expects(static::exactly(2)) ->method('matches') ->with($request = new Request()) ->willReturn(true) + ->seal() ; $event = new TerminateEvent( - $this->createMock(HttpKernelInterface::class), + static::createStub(HttpKernelInterface::class), $request, new Response() ); - $this->logger + $logger ->expects(static::once()) ->method('log') ->with( LogLevel::WARNING, 'Response time too slow ({duration} milliseconds) for {url}', - static::callback(function (array $parameter) use ($request) { + static::callback(function (array $parameter) use ($request, $durations) { $this->assertSame( $parameter['url'], $request->getRequestUri() @@ -98,42 +84,57 @@ public function testOnKernelTerminateMatch(): void ); $this->assertSame( - min($this->durations), + min($durations), $parameter['durationThreshold'], ); return true; }) ) + ->seal() ; - $request->server->set('REQUEST_TIME_FLOAT', microtime(true) - (max($this->durations) / 1000) - 1); + $request->server->set('REQUEST_TIME_FLOAT', microtime(true) - (max($durations) / 1000) - 1); - $this->object->onKernelTerminate($event); + $object->onKernelTerminate($event); } public function testOnKernelTerminateNoMatch(): void { - $this->requestMatcher + $durations = []; + + $requestMatcher = $this->createMock(RequestMatcherInterface::class); + + $object = new SlowRequestLoggerListener( + $logger = $this->createMock(LoggerInterface::class), + [ + ($durations[] = 5000) => [$requestMatcher], + ($durations[] = 2000) => [$requestMatcher], + ] + ); + + $requestMatcher ->expects(static::exactly(2)) ->method('matches') ->with($request = new Request()) ->willReturn(false) + ->seal() ; $event = new TerminateEvent( - $this->createMock(HttpKernelInterface::class), + static::createStub(HttpKernelInterface::class), $request, new Response() ); - $this->logger + $logger ->expects(static::never()) ->method('log') + ->seal() ; - $request->server->set('REQUEST_TIME_FLOAT', microtime(true) - (max($this->durations) / 1000) - 1); + $request->server->set('REQUEST_TIME_FLOAT', microtime(true) - (max($durations) / 1000) - 1); - $this->object->onKernelTerminate($event); + $object->onKernelTerminate($event); } } diff --git a/packages/log/Tests/Symfony/Processor/RequestHeadersProcessorTest.php b/packages/log/Tests/Symfony/Processor/RequestHeadersProcessorTest.php index e25aa0705..fcbd54938 100644 --- a/packages/log/Tests/Symfony/Processor/RequestHeadersProcessorTest.php +++ b/packages/log/Tests/Symfony/Processor/RequestHeadersProcessorTest.php @@ -34,12 +34,14 @@ public function testInvoke( ->expects(static::once()) ->method('getMainRequest') ->willReturn(null) + ->seal() ; } else { $requestStack ->expects(static::once()) ->method('getMainRequest') ->willReturn($mainRequest = new Request()) + ->seal() ; $mainRequest->headers->replace($requestHeaders); diff --git a/packages/log/Tests/Symfony/Processor/TokenProcessorTest.php b/packages/log/Tests/Symfony/Processor/TokenProcessorTest.php index 9ee1d87ef..1093c4e5d 100644 --- a/packages/log/Tests/Symfony/Processor/TokenProcessorTest.php +++ b/packages/log/Tests/Symfony/Processor/TokenProcessorTest.php @@ -7,7 +7,6 @@ use Draw\Component\Log\Symfony\Processor\TokenProcessor; use Monolog\Level; use Monolog\LogRecord; -use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Symfony\Component\Security\Core\Authentication\Token\NullToken; use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; @@ -18,25 +17,16 @@ */ class TokenProcessorTest extends TestCase { - private TokenProcessor $service; - - private TokenStorageInterface&MockObject $tokenStorage; - - private string $key; - - protected function setUp(): void + public function testInvokeNoToken(): void { - $this->service = new TokenProcessor( - $this->tokenStorage = $this->createMock(TokenStorageInterface::class), - $this->key = uniqid() + $service = new TokenProcessor( + static::createStub(TokenStorageInterface::class), + $key = uniqid() ); - } - public function testInvokeNoToken(): void - { static::assertSame( - [$this->key => null], - $this->service->__invoke( + [$key => null], + $service->__invoke( new LogRecord( new \DateTimeImmutable(), 'test', @@ -49,22 +39,28 @@ public function testInvokeNoToken(): void public function testInvokeNotIdentifiedToken(): void { - $this->tokenStorage->expects(static::once()) + $service = new TokenProcessor( + $tokenStorage = $this->createMock(TokenStorageInterface::class), + $key = uniqid() + ); + + $tokenStorage->expects(static::once()) ->method('getToken') ->willReturn( new NullToken() ) + ->seal() ; static::assertSame( [ - $this->key => [ + $key => [ 'authenticated' => false, 'roles' => [], 'user_identifier' => '', ], ], - $this->service->__invoke( + $service->__invoke( new LogRecord( new \DateTimeImmutable(), 'test', @@ -108,7 +104,12 @@ public function setUserIdentifier(string $userIdentifier): self } }; - $this->tokenStorage->expects(static::once()) + $service = new TokenProcessor( + $tokenStorage = $this->createMock(TokenStorageInterface::class), + $key = uniqid() + ); + + $tokenStorage->expects(static::once()) ->method('getToken') ->willReturn( new UsernamePasswordToken( @@ -119,18 +120,19 @@ public function setUserIdentifier(string $userIdentifier): self $roles = [uniqid()] ) ) + ->seal() ; static::assertSame( [ - $this->key => [ + $key => [ 'authenticated' => true, 'roles' => $roles, 'user_identifier' => $user->getUserIdentifier(), 'user_id' => (string) $user->getId(), ], ], - $this->service->__invoke( + $service->__invoke( new LogRecord( new \DateTimeImmutable(), 'test', diff --git a/packages/log/composer.json b/packages/log/composer.json index 213e13fbb..4407126cb 100644 --- a/packages/log/composer.json +++ b/packages/log/composer.json @@ -22,7 +22,7 @@ "draw/dependency-injection": "^0.39", "draw/user-bundle": "^0.39", "monolog/monolog": "^3.5.0", - "phpunit/phpunit": "^11.3 || ^12.0", + "phpunit/phpunit": "^11.3 || ^12.0 || ^13.0", "symfony/event-dispatcher": "^6.4.0", "symfony/http-foundation": "^6.4.0", "symfony/http-kernel": "^6.4.0", diff --git a/packages/mailer/BodyRenderer/LocalizeBodyRenderer.php b/packages/mailer/BodyRenderer/LocalizeBodyRenderer.php index 9e5abf621..952176a85 100644 --- a/packages/mailer/BodyRenderer/LocalizeBodyRenderer.php +++ b/packages/mailer/BodyRenderer/LocalizeBodyRenderer.php @@ -32,8 +32,8 @@ public function render(Message $message): void try { $this->bodyRenderer->render($message); } finally { - if ($currentLocale) { - $this->translator?->setLocale($currentLocale); + if ($this->translator && $currentLocale) { + $this->translator->setLocale($currentLocale); } } } diff --git a/packages/mailer/EmailComposer.php b/packages/mailer/EmailComposer.php index b06fcde0f..4731dfcaf 100644 --- a/packages/mailer/EmailComposer.php +++ b/packages/mailer/EmailComposer.php @@ -48,8 +48,8 @@ public function compose(Message $message, Envelope $envelope): void } } } finally { - if ($currentLocale) { - $this->translator?->setLocale($currentLocale); + if ($this->translator && $currentLocale) { + $this->translator->setLocale($currentLocale); } } } diff --git a/packages/mailer/Tests/Command/SendTestEmailCommandTest.php b/packages/mailer/Tests/Command/SendTestEmailCommandTest.php index 19876e39e..151c31f24 100644 --- a/packages/mailer/Tests/Command/SendTestEmailCommandTest.php +++ b/packages/mailer/Tests/Command/SendTestEmailCommandTest.php @@ -6,7 +6,6 @@ use Draw\Component\Tester\Application\CommandDataTester; use Draw\Component\Tester\Application\CommandTestTrait; use PHPUnit\Framework\Attributes\CoversClass; -use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Mailer\MailerInterface; @@ -20,12 +19,10 @@ class SendTestEmailCommandTest extends TestCase { use CommandTestTrait; - private MailerInterface&MockObject $mailer; - protected function setUp(): void { $this->command = new SendTestEmailCommand( - $this->mailer = $this->createMock(MailerInterface::class) + static::createStub(MailerInterface::class) ); } @@ -49,8 +46,12 @@ public static function provideTestOption(): iterable public function testExecute(): void { + $this->command = new SendTestEmailCommand( + $mailer = $this->createMock(MailerInterface::class) + ); + $to = uniqid('email-').'@example.com'; - $this->mailer + $mailer ->expects(static::once()) ->method('send') ->with( @@ -64,6 +65,7 @@ function (Email $email) use ($to) { } ) ) + ->seal() ; $this->execute(['to' => $to]) diff --git a/packages/mailer/Tests/EmailComposerTest.php b/packages/mailer/Tests/EmailComposerTest.php index e19ec2bbf..6367c2a7d 100644 --- a/packages/mailer/Tests/EmailComposerTest.php +++ b/packages/mailer/Tests/EmailComposerTest.php @@ -6,9 +6,8 @@ use Draw\Component\Mailer\EmailComposer; use Draw\Component\Mailer\EmailWriter\EmailWriterInterface; use Draw\Component\Mailer\Tests\Stub\EmailWriter\EmailWriterStub; -use Draw\Component\Tester\MockTrait; +use Draw\Component\Tester\DoubleTrait; use PHPUnit\Framework\Attributes\CoversClass; -use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Psr\Container\ContainerInterface; use Symfony\Bridge\Twig\Mime\TemplatedEmail; @@ -24,62 +23,58 @@ #[CoversClass(EmailComposer::class)] class EmailComposerTest extends TestCase { - use MockTrait; + use DoubleTrait; - private EmailComposer $object; - - private ContainerInterface&MockObject $serviceLocator; - - private Translator&MockObject $translator; - - protected function setUp(): void + public function testWriterMutator(): void { - $this->object = new EmailComposer( - $this->serviceLocator = $this->createMock(ContainerInterface::class), - $this->translator = $this->createMock(Translator::class) + $object = new EmailComposer( + static::createStub(ContainerInterface::class), + static::createStub(Translator::class) ); - } - public function testWriterMutator(): void - { - static::assertSame([], $this->object->getWriters(\stdClass::class)); + static::assertSame([], $object->getWriters(\stdClass::class)); - $this->object->addWriter(\stdClass::class, $writer1 = uniqid('writer-'), $method1 = uniqid('method-')); + $object->addWriter(\stdClass::class, $writer1 = uniqid('writer-'), $method1 = uniqid('method-')); static::assertSame( [], - $this->object->getWriters(uniqid('other-class-')) + $object->getWriters(uniqid('other-class-')) ); static::assertSame( [ [$writer1, $method1], ], - $this->object->getWriters(\stdClass::class) + $object->getWriters(\stdClass::class) ); - $this->object->addWriter(\stdClass::class, $writer2 = uniqid('writer-'), $method2 = uniqid('method-'), 1); + $object->addWriter(\stdClass::class, $writer2 = uniqid('writer-'), $method2 = uniqid('method-'), 1); static::assertSame( [ [$writer2, $method2], [$writer1, $method1], ], - $this->object->getWriters(\stdClass::class) + $object->getWriters(\stdClass::class) ); } public function testComposeMessage(): void { + $object = new EmailComposer( + $serviceLocator = $this->createMock(ContainerInterface::class), + static::createStub(Translator::class) + ); + $message = new TemplatedEmail(); $envelope = new Envelope(new Address('test@example.com'), [new Address('test@example.com')]); - $this->object->addWriter(Message::class, $writer1 = uniqid('writer-1-'), 'method1'); - $this->object->addWriter(Email::class, $writer2 = uniqid('writer-2-'), 'method2'); - $this->object->addWriter(uniqid('other-class-'), uniqid('writer-'), uniqid('method-')); + $object->addWriter(Message::class, $writer1 = uniqid('writer-1-'), 'method1'); + $object->addWriter(Email::class, $writer2 = uniqid('writer-2-'), 'method2'); + $object->addWriter(uniqid('other-class-'), uniqid('writer-'), uniqid('method-')); - $this->serviceLocator + $serviceLocator ->expects(static::exactly(2)) ->method('get') ->with( @@ -91,6 +86,7 @@ public function testComposeMessage(): void ->willReturn( $emailWriter = $this->createMock(EmailWriterStub::class) ) + ->seal() ; $emailWriter @@ -109,14 +105,20 @@ public function testComposeMessage(): void $message, $envelope ) + ->seal() ; - $this->object->compose($message, $envelope); + $object->compose($message, $envelope); } public function testRegisterEmailWriter(): void { - $message = $this->createMock(Email::class); + $object = new EmailComposer( + $serviceLocator = $this->createMock(ContainerInterface::class), + static::createStub(Translator::class) + ); + + $message = static::createStub(Email::class); $envelope = new Envelope(new Address('test@example.com'), [new Address('test@example.com')]); @@ -144,28 +146,29 @@ public function compose2(Message $email): void } }; - $this->object->registerEmailWriter($emailWriter); + $object->registerEmailWriter($emailWriter); static::assertSame( [ [$emailWriter, 'compose1'], ], - $this->object->getWriters(Email::class) + $object->getWriters(Email::class) ); static::assertSame( [ [$emailWriter, 'compose2'], ], - $this->object->getWriters(Message::class) + $object->getWriters(Message::class) ); - $this->serviceLocator + $serviceLocator ->expects(static::never()) ->method('get') + ->seal() ; - $this->object->compose($message, $envelope); + $object->compose($message, $envelope); static::assertSame(1, $emailWriter->compose1CallCounter); static::assertSame(1, $emailWriter->compose2CallCounter); @@ -173,20 +176,25 @@ public function compose2(Message $email): void public function testComposeLocalizeEmail(): void { + $object = new EmailComposer( + static::createStub(ContainerInterface::class), + $translator = $this->createMock(Translator::class) + ); + $message = new class extends Email implements LocalizeEmailInterface { - public function getLocale(): ?string + public function getLocale(): string { return 'fr'; } }; - $this->translator + $translator ->expects(static::once()) ->method('getLocale') ->willReturn('en') ; - $this->translator + $translator ->expects(static::exactly(2)) ->method('setLocale') ->with( @@ -195,9 +203,10 @@ public function getLocale(): ?string ['en'] ) ) + ->seal() ; - $this->object->compose( + $object->compose( $message, new Envelope(new Address('test@example.com'), [new Address('test@example.com')]) ); diff --git a/packages/mailer/Tests/EmailWriter/AddTemplateHeaderEmailWriterTest.php b/packages/mailer/Tests/EmailWriter/AddTemplateHeaderEmailWriterTest.php index c3d097b2f..e6c13372d 100644 --- a/packages/mailer/Tests/EmailWriter/AddTemplateHeaderEmailWriterTest.php +++ b/packages/mailer/Tests/EmailWriter/AddTemplateHeaderEmailWriterTest.php @@ -3,7 +3,6 @@ namespace Draw\Component\Mailer\Tests\EmailWriter; use Draw\Component\Mailer\EmailWriter\AddTemplateHeaderEmailWriter; -use Draw\Component\Mailer\EmailWriter\EmailWriterInterface; use PHPUnit\Framework\Attributes\CoversClass; use PHPUnit\Framework\TestCase; use Symfony\Bridge\Twig\Mime\TemplatedEmail; @@ -21,14 +20,6 @@ protected function setUp(): void $this->object = new AddTemplateHeaderEmailWriter(); } - public function testConstruct(): void - { - static::assertInstanceOf( - EmailWriterInterface::class, - $this->object - ); - } - public function testGetForEmails(): void { static::assertSame( diff --git a/packages/mailer/Tests/EmailWriter/DefaultFromEmailWriterTest.php b/packages/mailer/Tests/EmailWriter/DefaultFromEmailWriterTest.php index 7d438ebab..33a350c2c 100644 --- a/packages/mailer/Tests/EmailWriter/DefaultFromEmailWriterTest.php +++ b/packages/mailer/Tests/EmailWriter/DefaultFromEmailWriterTest.php @@ -3,7 +3,6 @@ namespace Draw\Component\Mailer\Tests\EmailWriter; use Draw\Component\Mailer\EmailWriter\DefaultFromEmailWriter; -use Draw\Component\Mailer\EmailWriter\EmailWriterInterface; use PHPUnit\Framework\Attributes\CoversClass; use PHPUnit\Framework\TestCase; use Symfony\Component\Mime\Address; @@ -26,14 +25,6 @@ protected function setUp(): void ); } - public function testConstruct(): void - { - static::assertInstanceOf( - EmailWriterInterface::class, - $this->object - ); - } - public function testGetForEmails(): void { static::assertSame( diff --git a/packages/mailer/Tests/EventListener/EmailComposerListenerTest.php b/packages/mailer/Tests/EventListener/EmailComposerListenerTest.php index fab5a22d2..23ec5b150 100644 --- a/packages/mailer/Tests/EventListener/EmailComposerListenerTest.php +++ b/packages/mailer/Tests/EventListener/EmailComposerListenerTest.php @@ -4,7 +4,6 @@ use Draw\Component\Mailer\EmailComposer; use Draw\Component\Mailer\EventListener\EmailComposerListener; -use Draw\Component\Tester\MockTrait; use PHPUnit\Framework\Attributes\CoversClass; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; @@ -23,8 +22,6 @@ #[CoversClass(EmailComposerListener::class)] class EmailComposerListenerTest extends TestCase { - use MockTrait; - private EmailComposerListener $object; private EmailComposer&MockObject $emailComposer; @@ -41,11 +38,12 @@ public function testComposeMessageNotMessage(): void $this->emailComposer ->expects(static::never()) ->method('compose') + ->seal() ; $this->object->composeMessage( $this->createMessageEvent( - $this->createMock(RawMessage::class) + static::createStub(RawMessage::class) ) ); } @@ -55,6 +53,7 @@ public function testComposeMessageComposed(): void $this->emailComposer ->expects(static::never()) ->method('compose') + ->seal() ; $message = $this->createMock(Message::class); @@ -63,6 +62,7 @@ public function testComposeMessageComposed(): void ->expects(static::once()) ->method('getHeaders') ->willReturn($headers = new Headers()) + ->seal() ; $headers->add(new UnstructuredHeader('X-DrawEmail', '1')); @@ -79,6 +79,7 @@ public function testComposeMessage(): void $this->emailComposer ->expects(static::once()) ->method('compose') + ->seal() ; $this->object->composeMessage($event); @@ -93,9 +94,10 @@ public function testComposeMessageQueued(): void $this->emailComposer ->expects(static::never()) ->method('compose') + ->seal() ; - $message = $this->createMock(Message::class); + $message = static::createStub(Message::class); $this->object->composeMessage($this->createMessageEvent($message, true)); } diff --git a/packages/mailer/Tests/EventListener/EmailCssInlinerListenerTest.php b/packages/mailer/Tests/EventListener/EmailCssInlinerListenerTest.php index edd036249..74c4efb16 100644 --- a/packages/mailer/Tests/EventListener/EmailCssInlinerListenerTest.php +++ b/packages/mailer/Tests/EventListener/EmailCssInlinerListenerTest.php @@ -6,7 +6,6 @@ use PHPUnit\Framework\Attributes\CoversClass; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; -use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\Mailer\Envelope; use Symfony\Component\Mailer\Event\MessageEvent; use Symfony\Component\Mime\Address; @@ -26,14 +25,6 @@ protected function setUp(): void $this->object = new EmailCssInlinerListener(); } - public function testConstruct(): void - { - static::assertInstanceOf( - EventSubscriberInterface::class, - $this->object - ); - } - public function testGetSubscribedEvents(): void { static::assertSame( @@ -47,7 +38,7 @@ public function testGetSubscribedEvents(): void public function testInlineEmailCssNotEmail(): void { $event = new MessageEvent( - $this->createMock(RawMessage::class), + static::createStub(RawMessage::class), new Envelope(new Address('test@example.com'), [new Address('test@example.com')]), uniqid('transport-') ); @@ -74,6 +65,7 @@ public function testInlineEmailCssNoHtmlBody(): void $message ->expects(static::never()) ->method('html') + ->seal() ; $this->object->inlineEmailCss($event); @@ -102,6 +94,7 @@ public function testInlineEmailCss(): void ->with('
') + ->seal() ; $this->object->inlineEmailCss($event); diff --git a/packages/mailer/Tests/EventListener/EmailSubjectFromHtmlTitleListenerTest.php b/packages/mailer/Tests/EventListener/EmailSubjectFromHtmlTitleListenerTest.php index 7059a89e5..293aa6b0e 100644 --- a/packages/mailer/Tests/EventListener/EmailSubjectFromHtmlTitleListenerTest.php +++ b/packages/mailer/Tests/EventListener/EmailSubjectFromHtmlTitleListenerTest.php @@ -5,7 +5,6 @@ use Draw\Component\Mailer\EventListener\EmailSubjectFromHtmlTitleListener; use PHPUnit\Framework\Attributes\CoversClass; use PHPUnit\Framework\TestCase; -use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\Mailer\Envelope; use Symfony\Component\Mailer\Event\MessageEvent; use Symfony\Component\Mime\Address; @@ -25,14 +24,6 @@ protected function setUp(): void $this->object = new EmailSubjectFromHtmlTitleListener(); } - public function testConstruct(): void - { - static::assertInstanceOf( - EventSubscriberInterface::class, - $this->object - ); - } - public function testGetSubscribedEvents(): void { static::assertSame( @@ -47,7 +38,7 @@ public function testAssignSubjectFromHtmlTitleNotEmail(): void { $this->object->assignSubjectFromHtmlTitle( $this->createMessageEvent( - $this->createMock(RawMessage::class) + static::createStub(RawMessage::class) ) ); @@ -67,6 +58,7 @@ public function testAssignSubjectFromHtmlTitleAlreadyASubject(): void $message ->expects(static::never()) ->method('subject') + ->seal() ; $this->object->assignSubjectFromHtmlTitle($this->createMessageEvent($message)); @@ -87,6 +79,12 @@ public function testAssignSubjectFromHtmlTitleNoHtmlBody(): void ->method('subject') ; + $message + ->expects(static::once()) + ->method('getSubject') + ->seal() + ; + $this->object->assignSubjectFromHtmlTitle($this->createMessageEvent($message)); } @@ -105,6 +103,12 @@ public function testAssignSubjectFromHtmlTitleNoTitle(): void ->method('subject') ; + $message + ->expects(static::once()) + ->method('getSubject') + ->seal() + ; + $this->object->assignSubjectFromHtmlTitle($this->createMessageEvent($message)); } @@ -123,6 +127,12 @@ public function testAssignSubjectFromHtmlTitleTitleEmpty(): void ->method('subject') ; + $message + ->expects(static::once()) + ->method('getSubject') + ->seal() + ; + $this->object->assignSubjectFromHtmlTitle($this->createMessageEvent($message)); } @@ -142,6 +152,12 @@ public function testAssignSubjectFromHtmlTitle(): void ->with('Title') ; + $message + ->expects(static::once()) + ->method('getSubject') + ->seal() + ; + $this->object->assignSubjectFromHtmlTitle($this->createMessageEvent($message)); } diff --git a/packages/mailer/Tests/Twig/TranslationExtensionTest.php b/packages/mailer/Tests/Twig/TranslationExtensionTest.php index 03111b0de..7b24cea8c 100644 --- a/packages/mailer/Tests/Twig/TranslationExtensionTest.php +++ b/packages/mailer/Tests/Twig/TranslationExtensionTest.php @@ -3,12 +3,10 @@ namespace Draw\Component\Mailer\Tests\Twig; use Draw\Component\Mailer\Twig\TranslationExtension; -use Draw\Component\Tester\MockTrait; +use Draw\Component\Tester\DoubleTrait; use PHPUnit\Framework\Attributes\CoversClass; -use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Symfony\Contracts\Translation\TranslatorInterface; -use Twig\Extension\AbstractExtension; use Twig\TwigFilter; /** @@ -17,30 +15,15 @@ #[CoversClass(TranslationExtension::class)] class TranslationExtensionTest extends TestCase { - use MockTrait; + use DoubleTrait; - private TranslationExtension $object; - - private TranslatorInterface&MockObject $translator; - - protected function setUp(): void - { - $this->object = new TranslationExtension( - $this->translator = $this->createMock(TranslatorInterface::class) - ); - } - - public function testConstruct(): void + public function testGetFilters(): void { - static::assertInstanceOf( - AbstractExtension::class, - $this->object + $object = new TranslationExtension( + static::createStub(TranslatorInterface::class) ); - } - public function testGetFilters(): void - { - $filters = $this->object->getFilters(); + $filters = $object->getFilters(); static::assertCount(1, $filters); @@ -54,20 +37,24 @@ public function testGetFilters(): void ); static::assertSame( - [$this->object, 'trans'], + [$object, 'trans'], $filter->getCallable() ); } public function testTrans(): void { + $object = new TranslationExtension( + $translator = $this->createMock(TranslatorInterface::class) + ); + $message = uniqid('message-'); $arguments = ['key' => uniqid('value-')]; $domain = uniqid('domain-'); $locale = uniqid('locale-'); $count = random_int(0, \PHP_INT_MAX); - $this->translator + $translator ->expects(static::once()) ->method('trans') ->with( @@ -77,11 +64,12 @@ public function testTrans(): void $locale ) ->willReturnArgument(0) + ->seal() ; static::assertSame( $message, - $this->object->trans( + $object->trans( $message, $arguments, $domain, @@ -93,10 +81,14 @@ public function testTrans(): void public function testTransMultipleMessage(): void { + $object = new TranslationExtension( + $translator = $this->createMock(TranslatorInterface::class) + ); + $message1 = uniqid('message-'); $message2 = uniqid('message-'); - $this->translator + $translator ->expects(static::exactly(2)) ->method('trans') ->with( @@ -109,11 +101,12 @@ public function testTransMultipleMessage(): void $message1, $result = uniqid('result-') ) + ->seal() ; static::assertSame( $result, - $this->object->trans( + $object->trans( [$message1, $message2, uniqid('message-not-use-')], ) ); diff --git a/packages/mailer/composer.json b/packages/mailer/composer.json index 83856ab82..5eef39f4e 100644 --- a/packages/mailer/composer.json +++ b/packages/mailer/composer.json @@ -23,7 +23,7 @@ "draw/dependency-injection": "^0.39", "draw/tester": "^0.39", "pelago/emogrifier": "^8.0", - "phpunit/phpunit": "^11.3 || ^12.0" + "phpunit/phpunit": "^11.3 || ^12.0 || ^13.0" }, "minimum-stability": "dev", "prefer-stable": true, diff --git a/packages/messenger/Tests/AutoStamp/EventListener/AutoStampEnvelopeListenerTest.php b/packages/messenger/Tests/AutoStamp/EventListener/AutoStampEnvelopeListenerTest.php index 3cdd72d66..90036f492 100644 --- a/packages/messenger/Tests/AutoStamp/EventListener/AutoStampEnvelopeListenerTest.php +++ b/packages/messenger/Tests/AutoStamp/EventListener/AutoStampEnvelopeListenerTest.php @@ -6,7 +6,6 @@ use Draw\Component\Messenger\AutoStamp\Message\StampingAwareInterface; use PHPUnit\Framework\Attributes\CoversClass; use PHPUnit\Framework\TestCase; -use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\Messenger\Envelope; use Symfony\Component\Messenger\Event\SendMessageToTransportsEvent; @@ -25,14 +24,6 @@ protected function setUp(): void $this->object = new AutoStampEnvelopeListener(); } - public function testConstruct(): void - { - static::assertInstanceOf( - EventSubscriberInterface::class, - $this->object - ); - } - public function testGetSubscribedEvents(): void { static::assertSame( diff --git a/packages/messenger/Tests/Broker/BrokerTest.php b/packages/messenger/Tests/Broker/BrokerTest.php index 85540e953..f5c9aeafd 100644 --- a/packages/messenger/Tests/Broker/BrokerTest.php +++ b/packages/messenger/Tests/Broker/BrokerTest.php @@ -6,10 +6,9 @@ use Draw\Component\Messenger\Broker\Event\BrokerRunningEvent; use Draw\Component\Messenger\Broker\Event\BrokerStartedEvent; use Draw\Component\Messenger\Broker\Event\NewConsumerProcessEvent; -use Draw\Component\Tester\MockTrait; +use Draw\Component\Tester\DoubleTrait; use Draw\Contracts\Process\ProcessFactoryInterface; use PHPUnit\Framework\Attributes\CoversClass; -use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Symfony\Component\Process\Process; use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; @@ -20,51 +19,55 @@ #[CoversClass(Broker::class)] class BrokerTest extends TestCase { - use MockTrait; - - private Broker $service; + use DoubleTrait; private string $context; private string $consolePath; - private ProcessFactoryInterface&MockObject $processFactory; - - private EventDispatcherInterface&MockObject $eventDispatcher; - protected function setUp(): void { - $this->service = new Broker( - $this->context = uniqid('context-'), - $this->consolePath = uniqid('console/bin-'), - $this->processFactory = $this->createMock(ProcessFactoryInterface::class), - $this->eventDispatcher = $this->createMock(EventDispatcherInterface::class) - ); + $this->context = uniqid('context-'); + $this->consolePath = uniqid('console/bin-'); } public function testGetContext(): void { + $service = new Broker( + $this->context, + $this->consolePath, + static::createStub(ProcessFactoryInterface::class), + static::createStub(EventDispatcherInterface::class) + ); + static::assertSame( $this->context, - $this->service->getContext() + $service->getContext() ); } public function testStart(): void { + $service = new Broker( + $this->context, + $this->consolePath, + $processFactory = $this->createMock(ProcessFactoryInterface::class), + $eventDispatcher = $this->createMock(EventDispatcherInterface::class) + ); + $concurrent = 1; $timeout = random_int(1, 10); $receiver = uniqid('receiver-'); - $this->eventDispatcher + $eventDispatcher ->expects(static::exactly($concurrent * 4)) ->method('dispatch') ->with( ...static::withConsecutive( [ - static::callback(function (BrokerStartedEvent $event) use ($concurrent, $timeout) { + static::callback(function (BrokerStartedEvent $event) use ($service, $concurrent, $timeout) { $this->assertSame( - $this->service, + $service, $event->getBroker() ); @@ -82,9 +85,9 @@ public function testStart(): void }), ], [ - static::callback(function (BrokerRunningEvent $event) { + static::callback(function (BrokerRunningEvent $event) use ($service) { $this->assertSame( - $this->service, + $service, $event->getBroker() ); @@ -104,13 +107,13 @@ public function testStart(): void }), ], [ - static::callback(function (BrokerRunningEvent $event) { + static::callback(function (BrokerRunningEvent $event) use ($service) { $this->assertSame( - $this->service, + $service, $event->getBroker() ); - $this->service->stop(); + $service->stop(); return true; }), @@ -118,9 +121,10 @@ public function testStart(): void ) ) ->willReturnArgument(0) + ->seal() ; - $this->processFactory + $processFactory ->expects(static::exactly($concurrent)) ->method('create') ->with( @@ -135,6 +139,7 @@ public function testStart(): void null ) ->willReturn($process = $this->createMock(Process::class)) + ->seal() ; $process @@ -146,33 +151,42 @@ public function testStart(): void ->expects(static::exactly($concurrent)) ->method('isRunning') ->willReturn(false) + ->seal() ; - $this->service->start($concurrent, $timeout); + $service->start($concurrent, $timeout); } public function testStartWithForceStop(): void { + $service = new Broker( + $this->context, + $this->consolePath, + $processFactory = $this->createMock(ProcessFactoryInterface::class), + $eventDispatcher = $this->createMock(EventDispatcherInterface::class) + ); + $concurrent = 2; $receiver = uniqid('receiver-'); - $this->eventDispatcher - ->expects(static::any()) + $eventDispatcher + ->expects(static::atLeastOnce()) ->method('dispatch') ->with( - static::callback(function ($event) use ($receiver) { + static::callback(static function ($event) use ($service, $receiver) { if ($event instanceof NewConsumerProcessEvent) { $event->setReceivers([$receiver]); - $this->service->stop(false); + $service->stop(false); } return true; }) ) ->willReturnArgument(0) + ->seal() ; - $this->processFactory + $processFactory ->expects(static::exactly($concurrent)) ->method('create') ->with( @@ -187,6 +201,7 @@ public function testStartWithForceStop(): void null ) ->willReturn($process = $this->createMock(Process::class)) + ->seal() ; $process @@ -219,18 +234,27 @@ public function testStartWithForceStop(): void ->method('stop') ->with(0) ->willReturn(0) + ->seal() ; - $this->service->start($concurrent, 0); + $service->start($concurrent, 0); } public function testStartNoReceiver(): void { + $service = new Broker( + $this->context, + $this->consolePath, + $processFactory = $this->createMock(ProcessFactoryInterface::class), + static::createStub(EventDispatcherInterface::class) + ); + $concurrent = 1; - $this->processFactory + $processFactory ->expects(static::never()) ->method('create') + ->seal() ; $this->expectException(\RuntimeException::class); @@ -239,11 +263,18 @@ public function testStartNoReceiver(): void NewConsumerProcessEvent::class.'::preventStart' )); - $this->service->start($concurrent); + $service->start($concurrent); } public function testStartForBuildOptions(): void { + $service = new Broker( + $this->context, + $this->consolePath, + $processFactory = $this->createMock(ProcessFactoryInterface::class), + $eventDispatcher = $this->createMock(EventDispatcherInterface::class) + ); + $concurrent = 1; $timeout = random_int(1, 10); $receiver = uniqid('receiver-'); @@ -253,25 +284,26 @@ public function testStartForBuildOptions(): void 'value' => 'value', ]; - $this->eventDispatcher - ->expects(static::any()) + $eventDispatcher + ->expects(static::atLeastOnce()) ->method('dispatch') ->with( - static::callback(function ($event) use ($receiver, $options) { + static::callback(static function ($event) use ($service, $receiver, $options) { if ($event instanceof NewConsumerProcessEvent) { $event->setReceivers([$receiver]); $event->setOptions($options); // This is to make sure we reach NewConsumerProcessEvent only once. - $this->service->stop(); + $service->stop(); } return true; }) ) ->willReturnArgument(0) + ->seal() ; - $this->processFactory + $processFactory ->expects(static::exactly($concurrent)) ->method('create') ->with( @@ -293,6 +325,7 @@ public function testStartForBuildOptions(): void null ) ->willReturn($process = $this->createMock(Process::class)) + ->seal() ; $process @@ -304,8 +337,9 @@ public function testStartForBuildOptions(): void ->expects(static::exactly($concurrent)) ->method('isRunning') ->willReturn(false) + ->seal() ; - $this->service->start($concurrent, $timeout); + $service->start($concurrent, $timeout); } } diff --git a/packages/messenger/Tests/Broker/Command/StartMessengerBrokerCommandTest.php b/packages/messenger/Tests/Broker/Command/StartMessengerBrokerCommandTest.php index bafaa08be..b56db0381 100644 --- a/packages/messenger/Tests/Broker/Command/StartMessengerBrokerCommandTest.php +++ b/packages/messenger/Tests/Broker/Command/StartMessengerBrokerCommandTest.php @@ -11,7 +11,7 @@ use Draw\Contracts\Process\ProcessFactoryInterface; use PHPUnit\Framework\Attributes\CoversClass; use PHPUnit\Framework\Attributes\DataProvider; -use PHPUnit\Framework\MockObject\MockObject; +use PHPUnit\Framework\MockObject\Stub; use PHPUnit\Framework\TestCase; use Symfony\Component\Console\Exception\InvalidOptionException; use Symfony\Component\Console\Input\InputOption; @@ -29,7 +29,7 @@ class StartMessengerBrokerCommandTest extends TestCase private EventDispatcher $eventDispatcher; - private CpuCounter&MockObject $cpuCounter; + private CpuCounter&Stub $cpuCounter; private string $consolePath; @@ -37,9 +37,9 @@ protected function setUp(): void { $this->command = new StartMessengerBrokerCommand( $this->consolePath = uniqid('console-path-'), - $this->processFactory = $this->createMock(ProcessFactoryInterface::class), + $this->processFactory = static::createStub(ProcessFactoryInterface::class), $this->eventDispatcher = new EventDispatcher(), - $this->cpuCounter = $this->createMock(CpuCounter::class) + $this->cpuCounter = static::createStub(CpuCounter::class) ); } diff --git a/packages/messenger/Tests/Broker/Event/BrokerRunningEventTest.php b/packages/messenger/Tests/Broker/Event/BrokerRunningEventTest.php index d7b1e0efa..97712bea7 100644 --- a/packages/messenger/Tests/Broker/Event/BrokerRunningEventTest.php +++ b/packages/messenger/Tests/Broker/Event/BrokerRunningEventTest.php @@ -5,8 +5,8 @@ use Draw\Component\Messenger\Broker\Broker; use Draw\Component\Messenger\Broker\Event\BrokerRunningEvent; use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\MockObject\Stub; use PHPUnit\Framework\TestCase; -use Symfony\Contracts\EventDispatcher\Event; /** * @internal @@ -16,20 +16,12 @@ class BrokerRunningEventTest extends TestCase { private BrokerRunningEvent $event; - private Broker $broker; + private Broker&Stub $broker; protected function setUp(): void { $this->event = new BrokerRunningEvent( - $this->broker = $this->createMock(Broker::class) - ); - } - - public function testConstruct(): void - { - static::assertInstanceOf( - Event::class, - $this->event + $this->broker = static::createStub(Broker::class) ); } diff --git a/packages/messenger/Tests/Broker/Event/BrokerStartedEventTest.php b/packages/messenger/Tests/Broker/Event/BrokerStartedEventTest.php index b30054ff2..eae7b6215 100644 --- a/packages/messenger/Tests/Broker/Event/BrokerStartedEventTest.php +++ b/packages/messenger/Tests/Broker/Event/BrokerStartedEventTest.php @@ -5,8 +5,8 @@ use Draw\Component\Messenger\Broker\Broker; use Draw\Component\Messenger\Broker\Event\BrokerStartedEvent; use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\MockObject\Stub; use PHPUnit\Framework\TestCase; -use Symfony\Contracts\EventDispatcher\Event; /** * @internal @@ -16,7 +16,7 @@ class BrokerStartedEventTest extends TestCase { private BrokerStartedEvent $event; - private Broker $broker; + private Broker&Stub $broker; private int $concurrent; @@ -25,20 +25,12 @@ class BrokerStartedEventTest extends TestCase protected function setUp(): void { $this->event = new BrokerStartedEvent( - $this->broker = $this->createMock(Broker::class), + $this->broker = static::createStub(Broker::class), $this->concurrent = random_int(1, \PHP_INT_MAX), $this->timeout = random_int(1, \PHP_INT_MAX) ); } - public function testConstruct(): void - { - static::assertInstanceOf( - Event::class, - $this->event - ); - } - public function testGetBroker(): void { static::assertSame( diff --git a/packages/messenger/Tests/Broker/Event/NewConsumerProcessEventTest.php b/packages/messenger/Tests/Broker/Event/NewConsumerProcessEventTest.php index 1298de8b8..4dbf661c6 100644 --- a/packages/messenger/Tests/Broker/Event/NewConsumerProcessEventTest.php +++ b/packages/messenger/Tests/Broker/Event/NewConsumerProcessEventTest.php @@ -5,7 +5,6 @@ use Draw\Component\Messenger\Broker\Event\NewConsumerProcessEvent; use PHPUnit\Framework\Attributes\CoversClass; use PHPUnit\Framework\TestCase; -use Symfony\Contracts\EventDispatcher\Event; /** * @internal @@ -30,14 +29,6 @@ protected function setUp(): void ); } - public function testConstruct(): void - { - static::assertInstanceOf( - Event::class, - $this->event - ); - } - public function testGetContext(): void { static::assertSame( diff --git a/packages/messenger/Tests/Broker/EventListener/BrokerDefaultValuesListenerTest.php b/packages/messenger/Tests/Broker/EventListener/BrokerDefaultValuesListenerTest.php index 20a135398..370d3e0e5 100644 --- a/packages/messenger/Tests/Broker/EventListener/BrokerDefaultValuesListenerTest.php +++ b/packages/messenger/Tests/Broker/EventListener/BrokerDefaultValuesListenerTest.php @@ -6,7 +6,6 @@ use Draw\Component\Messenger\Broker\EventListener\BrokerDefaultValuesListener; use PHPUnit\Framework\Attributes\CoversClass; use PHPUnit\Framework\TestCase; -use Symfony\Component\EventDispatcher\EventSubscriberInterface; /** * @internal @@ -39,14 +38,6 @@ protected function setUp(): void ); } - public function testConstruct(): void - { - static::assertInstanceOf( - EventSubscriberInterface::class, - $this->service - ); - } - public function testGetSubscribedEvents(): void { static::assertSame( diff --git a/packages/messenger/Tests/Broker/EventListener/StopBrokerOnSigtermSignalListenerTest.php b/packages/messenger/Tests/Broker/EventListener/StopBrokerOnSigtermSignalListenerTest.php index 1b8ff03b0..4eff0abb5 100644 --- a/packages/messenger/Tests/Broker/EventListener/StopBrokerOnSigtermSignalListenerTest.php +++ b/packages/messenger/Tests/Broker/EventListener/StopBrokerOnSigtermSignalListenerTest.php @@ -37,7 +37,8 @@ public function testOnBrokerStarted(): void $event ->expects(static::once()) ->method('getBroker') - ->willReturn($this->createMock(Broker::class)) + ->willReturn(static::createStub(Broker::class)) + ->seal() ; $this->service->onBrokerStarted($event); diff --git a/packages/messenger/Tests/DoctrineMessageBusHook/EnvelopeFactory/BasicEnvelopeFactoryTest.php b/packages/messenger/Tests/DoctrineMessageBusHook/EnvelopeFactory/BasicEnvelopeFactoryTest.php index 847ef7432..9ac64f714 100644 --- a/packages/messenger/Tests/DoctrineMessageBusHook/EnvelopeFactory/BasicEnvelopeFactoryTest.php +++ b/packages/messenger/Tests/DoctrineMessageBusHook/EnvelopeFactory/BasicEnvelopeFactoryTest.php @@ -5,7 +5,7 @@ use Draw\Component\Messenger\DoctrineMessageBusHook\EnvelopeFactory\BasicEnvelopeFactory; use Draw\Component\Messenger\DoctrineMessageBusHook\Event\EnvelopeCreatedEvent; use Draw\Component\Messenger\DoctrineMessageBusHook\Model\MessageHolderInterface; -use Draw\Component\Tester\MockTrait; +use Draw\Component\Tester\DoubleTrait; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Symfony\Component\Messenger\Envelope; @@ -16,13 +16,11 @@ */ class BasicEnvelopeFactoryTest extends TestCase { - use MockTrait; + use DoubleTrait; + private BasicEnvelopeFactory $object; - /** - * @var EventDispatcherInterface&MockObject - */ - private EventDispatcherInterface $eventDispatcher; + private EventDispatcherInterface&MockObject $eventDispatcher; protected function setUp(): void { @@ -33,7 +31,7 @@ protected function setUp(): void public function testCreateEnvelopes(): void { - $messageHolder = $this->createMock(MessageHolderInterface::class); + $messageHolder = static::createStub(MessageHolderInterface::class); $messages = [ (object) [], (object) [], @@ -70,6 +68,7 @@ function (EnvelopeCreatedEvent $event) use ($messages, $messageHolder) { ) ) ->willReturnArgument(0) + ->seal() ; $envelopes = $this->object->createEnvelopes($messageHolder, $messages); diff --git a/packages/messenger/Tests/DoctrineMessageBusHook/Event/EnvelopeCreatedEventTest.php b/packages/messenger/Tests/DoctrineMessageBusHook/Event/EnvelopeCreatedEventTest.php index 78d25bfd1..8cf201a7b 100644 --- a/packages/messenger/Tests/DoctrineMessageBusHook/Event/EnvelopeCreatedEventTest.php +++ b/packages/messenger/Tests/DoctrineMessageBusHook/Event/EnvelopeCreatedEventTest.php @@ -5,10 +5,9 @@ use Draw\Component\Messenger\DoctrineMessageBusHook\Event\EnvelopeCreatedEvent; use Draw\Component\Messenger\DoctrineMessageBusHook\Model\MessageHolderInterface; use PHPUnit\Framework\Attributes\CoversClass; -use PHPUnit\Framework\MockObject\MockObject; +use PHPUnit\Framework\MockObject\Stub; use PHPUnit\Framework\TestCase; use Symfony\Component\Messenger\Envelope; -use Symfony\Contracts\EventDispatcher\Event; /** * @internal @@ -18,26 +17,18 @@ class EnvelopeCreatedEventTest extends TestCase { private EnvelopeCreatedEvent $object; - private MessageHolderInterface&MockObject $messageHolder; + private MessageHolderInterface&Stub $messageHolder; private Envelope $envelope; protected function setUp(): void { $this->object = new EnvelopeCreatedEvent( - $this->messageHolder = $this->createMock(MessageHolderInterface::class), + $this->messageHolder = static::createStub(MessageHolderInterface::class), $this->envelope = new Envelope((object) []) ); } - public function testConstruct(): void - { - static::assertInstanceOf( - Event::class, - $this->object - ); - } - public function testGetMessageHolder(): void { static::assertSame( diff --git a/packages/messenger/Tests/DoctrineMessageBusHook/EventListener/DoctrineBusMessageListenerTest.php b/packages/messenger/Tests/DoctrineMessageBusHook/EventListener/DoctrineBusMessageListenerTest.php index 9f32de55f..27efb2852 100644 --- a/packages/messenger/Tests/DoctrineMessageBusHook/EventListener/DoctrineBusMessageListenerTest.php +++ b/packages/messenger/Tests/DoctrineMessageBusHook/EventListener/DoctrineBusMessageListenerTest.php @@ -13,13 +13,10 @@ use Draw\Component\Messenger\DoctrineMessageBusHook\Message\LifeCycleAwareMessageInterface; use Draw\Component\Messenger\DoctrineMessageBusHook\Model\MessageHolderInterface; use Draw\Component\Messenger\Tests\Stub\Message\PreSendAwareMessageInterface; -use Draw\Component\Tester\MockTrait; use PHPUnit\Framework\Attributes\CoversClass; -use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Symfony\Component\Messenger\Envelope; use Symfony\Component\Messenger\MessageBusInterface; -use Symfony\Contracts\Service\ResetInterface; /** * @internal @@ -27,154 +24,179 @@ #[CoversClass(DoctrineBusMessageListener::class)] class DoctrineBusMessageListenerTest extends TestCase { - use MockTrait; - - private DoctrineBusMessageListener $object; - - private EnvelopeFactoryInterface&MockObject $envelopeFactory; - - private MessageBusInterface&MockObject $messageBus; - - private EntityManagerInterface&MockObject $entityManager; - - protected function setUp(): void + public function testPostPersist(): void { - $this->entityManager = $this->createMock(EntityManagerInterface::class); + $entityManager = $this->createMock(EntityManagerInterface::class); - $this->object = new DoctrineBusMessageListener( - $this->messageBus = $this->createMock(MessageBusInterface::class), - $this->envelopeFactory = $this->createMock(EnvelopeFactoryInterface::class) + $object = new DoctrineBusMessageListener( + static::createStub(MessageBusInterface::class), + static::createStub(EnvelopeFactoryInterface::class) ); - } - public function testConstruct(): void - { - static::assertInstanceOf( - ResetInterface::class, - $this->object - ); - } + $messageHolder = static::createStub(MessageHolderInterface::class); - public function testPostPersist(): void - { - $messageHolder = $this->createMock(MessageHolderInterface::class); - - $this->entityManager + $entityManager ->expects(static::once()) ->method('getClassMetadata') ->with($messageHolder::class) ->willReturn($classMetadata = new ClassMetadata(uniqid())) + ->seal() ; $classMetadata->rootEntityName = $messageHolder::class; - $this->object->postPersist( + $object->postPersist( new LifecycleEventArgs( $messageHolder, - $this->entityManager + $entityManager ) ); static::assertSame( [$messageHolder], - $this->object->getFlattenMessageHolders() + $object->getFlattenMessageHolders() ); } public function testPostPersistNotMessageHolderEntity(): void { + $entityManager = $this->createMock(EntityManagerInterface::class); + + $object = new DoctrineBusMessageListener( + static::createStub(MessageBusInterface::class), + static::createStub(EnvelopeFactoryInterface::class) + ); + $messageHolder = (object) []; - $this->entityManager + $entityManager ->expects(static::never()) ->method('getClassMetadata') + ->seal() ; - $this->object->postPersist( + $object->postPersist( new LifecycleEventArgs( $messageHolder, - $this->entityManager + $entityManager ) ); static::assertSame( [], - $this->object->getFlattenMessageHolders() + $object->getFlattenMessageHolders() ); } public function testPostLoad(): void { - $messageHolder = $this->createMock(MessageHolderInterface::class); + $entityManager = $this->createMock(EntityManagerInterface::class); + + $object = new DoctrineBusMessageListener( + static::createStub(MessageBusInterface::class), + static::createStub(EnvelopeFactoryInterface::class) + ); + + $messageHolder = static::createStub(MessageHolderInterface::class); - $this->entityManager + $entityManager ->expects(static::once()) ->method('getClassMetadata') ->with($messageHolder::class) ->willReturn($classMetadata = new ClassMetadata(uniqid())) + ->seal() ; $classMetadata->rootEntityName = $messageHolder::class; - $this->object->postLoad( + $object->postLoad( new LifecycleEventArgs( $messageHolder, - $this->entityManager + $entityManager ) ); static::assertSame( [$messageHolder], - $this->object->getFlattenMessageHolders() + $object->getFlattenMessageHolders() ); } public function testOnClearAll(): void { + $object = new DoctrineBusMessageListener( + static::createStub(MessageBusInterface::class), + static::createStub(EnvelopeFactoryInterface::class) + ); + $this->addMessageHolder( - $this->createMock(MessageHolderInterface::class) + $object, + static::createStub(MessageHolderInterface::class) ); - $this->object->onClear(new OnClearEventArgs($this->entityManager)); + $object->onClear( + new OnClearEventArgs(static::createStub(EntityManagerInterface::class)) + ); static::assertSame( [], - $this->object->getFlattenMessageHolders() + $object->getFlattenMessageHolders() ); } public function testOnClear(): void { + $object = new DoctrineBusMessageListener( + static::createStub(MessageBusInterface::class), + static::createStub(EnvelopeFactoryInterface::class) + ); + $this->addMessageHolder( - $this->createMock(MessageHolderInterface::class) + $object, + static::createStub(MessageHolderInterface::class) ); - $this->object->onClear(new OnClearEventArgs($this->entityManager)); + $object->onClear( + new OnClearEventArgs(static::createStub(EntityManagerInterface::class)) + ); static::assertCount( 0, - $this->object->getFlattenMessageHolders() + $object->getFlattenMessageHolders() ); } public function testPostFlushEmpty(): void { - $this->envelopeFactory + $object = new DoctrineBusMessageListener( + $messageBus = $this->createMock(MessageBusInterface::class), + $envelopeFactory = $this->createMock(EnvelopeFactoryInterface::class) + ); + + $envelopeFactory ->expects(static::never()) ->method('createEnvelopes') + ->seal() ; - $this->messageBus + $messageBus ->expects(static::never()) ->method('dispatch') + ->seal() ; - $this->object->postFlush(); + $object->postFlush(); } public function testPostFlushOnlyUninitializedProxy(): void { + $object = new DoctrineBusMessageListener( + $messageBus = $this->createMock(MessageBusInterface::class), + $envelopeFactory = $this->createMock(EnvelopeFactoryInterface::class) + ); + $this->addMessageHolder( + $object, new class implements Proxy, MessageHolderInterface { public function getOnHoldMessages(bool $clear): array { @@ -192,24 +214,31 @@ public function __isInitialized(): bool } ); - $this->envelopeFactory + $envelopeFactory ->expects(static::never()) ->method('createEnvelopes') + ->seal() ; - $this->messageBus + $messageBus ->expects(static::never()) ->method('dispatch') + ->seal() ; - $this->object->postFlush(); + $object->postFlush(); } public function testPostFlushWithOneMessage(): void { + $object = new DoctrineBusMessageListener( + $messageBus = $this->createMock(MessageBusInterface::class), + $envelopeFactory = $this->createMock(EnvelopeFactoryInterface::class) + ); + $messageHolder = $this->createMock(MessageHolderInterface::class); - $this->addMessageHolder($messageHolder); + $this->addMessageHolder($object, $messageHolder); $messageHolder->expects(static::once()) ->method('getOnHoldMessages') @@ -221,102 +250,121 @@ public function testPostFlushWithOneMessage(): void $message2 = $this->createMock(PreSendAwareMessageInterface::class), ] ) + ->seal() ; $message1 ->expects(static::once()) ->method('preSend') ->with($messageHolder) + ->seal() ; $message2 ->expects(static::never()) ->method('preSend') + ->seal() ; - $this->envelopeFactory + $envelopeFactory ->expects(static::once()) ->method('createEnvelopes') ->with($messageHolder, $messages) ->willReturn([$envelope = new Envelope((object) [])]) + ->seal() ; - $this->messageBus + $messageBus ->expects(static::once()) ->method('dispatch') ->with($envelope) ->willReturnArgument(0) + ->seal() ; - $this->object->postFlush(); + $object->postFlush(); } public function testPostFlushWithMultipleMessageHolder(): void { + $object = new DoctrineBusMessageListener( + $messageBus = $this->createMock(MessageBusInterface::class), + $envelopeFactory = $this->createMock(EnvelopeFactoryInterface::class) + ); + $messageHolder = $this->createMock(MessageHolderInterface::class); - $this->addMessageHolder($messageHolder); + $this->addMessageHolder($object, $messageHolder); $messageHolder ->expects(static::once()) ->method('getOnHoldMessages') ->with(true) ->willReturn([(object) []]) + ->seal() ; $messageHolder = $this->createMock(MessageHolderInterface::class); - $this->addMessageHolder($messageHolder); + $this->addMessageHolder($object, $messageHolder); $messageHolder ->expects(static::once()) ->method('getOnHoldMessages') ->with(true) ->willReturn([(object) []]) + ->seal() ; - $this->envelopeFactory + $envelopeFactory ->expects(static::exactly(2)) ->method('createEnvelopes') ->willReturn([$envelope = new Envelope((object) [])]) + ->seal() ; - $this->messageBus + $messageBus ->expects(static::exactly(2)) ->method('dispatch') ->with($envelope) ->willReturnArgument(0) + ->seal() ; - $this->object->postFlush(); + $object->postFlush(); } public function testReset(): void { - $messageHolder = $this->createMock(MessageHolderInterface::class); + $object = new DoctrineBusMessageListener( + static::createStub(MessageBusInterface::class), + static::createStub(EnvelopeFactoryInterface::class) + ); + + $messageHolder = static::createStub(MessageHolderInterface::class); - $this->addMessageHolder($messageHolder); + $this->addMessageHolder($object, $messageHolder); static::assertSame( [$messageHolder], - $this->object->getFlattenMessageHolders() + $object->getFlattenMessageHolders() ); - $this->object->reset(); + $object->reset(); static::assertSame( [], - $this->object->getFlattenMessageHolders() + $object->getFlattenMessageHolders() ); } - private function addMessageHolder(MessageHolderInterface $messageHolder): void + private function addMessageHolder(DoctrineBusMessageListener $object, MessageHolderInterface $messageHolder): void { - $messageHolders = ReflectionAccessor::getPropertyValue($this->object, 'messageHolders'); + $messageHolders = ReflectionAccessor::getPropertyValue($object, 'messageHolders'); $messageHolders[$messageHolder::class][spl_object_id($messageHolder)] = $messageHolder; ReflectionAccessor::setPropertyValue( - $this->object, + $object, 'messageHolders', $messageHolders ); diff --git a/packages/messenger/Tests/DoctrineMessageBusHook/EventListener/EnvelopeFactoryDelayStampListenerTest.php b/packages/messenger/Tests/DoctrineMessageBusHook/EventListener/EnvelopeFactoryDelayStampListenerTest.php index 8554095fd..301c47243 100644 --- a/packages/messenger/Tests/DoctrineMessageBusHook/EventListener/EnvelopeFactoryDelayStampListenerTest.php +++ b/packages/messenger/Tests/DoctrineMessageBusHook/EventListener/EnvelopeFactoryDelayStampListenerTest.php @@ -7,7 +7,6 @@ use Draw\Component\Messenger\DoctrineMessageBusHook\Model\MessageHolderInterface; use PHPUnit\Framework\Attributes\CoversClass; use PHPUnit\Framework\TestCase; -use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\Messenger\Envelope; use Symfony\Component\Messenger\Stamp\DelayStamp; @@ -28,14 +27,6 @@ protected function setUp(): void ); } - public function testConstruct(): void - { - static::assertInstanceOf( - EventSubscriberInterface::class, - $this->object - ); - } - public function testGetSubscribedEvents(): void { static::assertSame( @@ -50,7 +41,7 @@ public function testHandleEnvelopeCreatedEvent(): void { $this->object->handleEnvelopeCreatedEvent( $event = new EnvelopeCreatedEvent( - $this->createMock(MessageHolderInterface::class), + static::createStub(MessageHolderInterface::class), new Envelope((object) []) ) ); diff --git a/packages/messenger/Tests/DoctrineMessageBusHook/EventListener/EnvelopeFactoryDispatchAfterCurrentBusStampListenerTest.php b/packages/messenger/Tests/DoctrineMessageBusHook/EventListener/EnvelopeFactoryDispatchAfterCurrentBusStampListenerTest.php index 7e2e9da73..b96442d21 100644 --- a/packages/messenger/Tests/DoctrineMessageBusHook/EventListener/EnvelopeFactoryDispatchAfterCurrentBusStampListenerTest.php +++ b/packages/messenger/Tests/DoctrineMessageBusHook/EventListener/EnvelopeFactoryDispatchAfterCurrentBusStampListenerTest.php @@ -7,7 +7,6 @@ use Draw\Component\Messenger\DoctrineMessageBusHook\Model\MessageHolderInterface; use PHPUnit\Framework\Attributes\CoversClass; use PHPUnit\Framework\TestCase; -use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\Messenger\Envelope; use Symfony\Component\Messenger\Stamp\DispatchAfterCurrentBusStamp; @@ -24,14 +23,6 @@ protected function setUp(): void $this->object = new EnvelopeFactoryDispatchAfterCurrentBusStampListener(); } - public function testConstruct(): void - { - static::assertInstanceOf( - EventSubscriberInterface::class, - $this->object - ); - } - public function testGetSubscribedEvents(): void { static::assertSame( @@ -46,7 +37,7 @@ public function testHandleEnvelopeCreatedEvent(): void { $this->object->handleEnvelopeCreatedEvent( $event = new EnvelopeCreatedEvent( - $this->createMock(MessageHolderInterface::class), + static::createStub(MessageHolderInterface::class), new Envelope((object) []) ) ); diff --git a/packages/messenger/Tests/Entity/DrawMessageTagTraitTest.php b/packages/messenger/Tests/Entity/DrawMessageTagTraitTest.php index 01f6303a4..f6dac6b75 100644 --- a/packages/messenger/Tests/Entity/DrawMessageTagTraitTest.php +++ b/packages/messenger/Tests/Entity/DrawMessageTagTraitTest.php @@ -41,7 +41,7 @@ public function testMessageMutator(): void static::assertSame( $this->entity, - $this->entity->setMessage($value = $this->createMock(DrawMessageInterface::class)) + $this->entity->setMessage($value = static::createStub(DrawMessageInterface::class)) ); static::assertSame( diff --git a/packages/messenger/Tests/Entity/DrawMessageTraitTest.php b/packages/messenger/Tests/Entity/DrawMessageTraitTest.php index 110677389..c7e050571 100644 --- a/packages/messenger/Tests/Entity/DrawMessageTraitTest.php +++ b/packages/messenger/Tests/Entity/DrawMessageTraitTest.php @@ -22,8 +22,6 @@ protected function setUp(): void public function testIdMutator(): void { - static::assertNotNull($this->entity->getId()); - static::assertSame( $this->entity, $this->entity->setId($value = uniqid()) @@ -139,7 +137,7 @@ public function testTagMutator(): void static::assertSame( $this->entity, - $this->entity->addTag($value = $this->createMock(DrawMessageTagInterface::class)) + $this->entity->addTag($value = static::createStub(DrawMessageTagInterface::class)) ); static::assertCount(1, $this->entity->getTags()); diff --git a/packages/messenger/Tests/EventListener/StopOnNewVersionListenerTest.php b/packages/messenger/Tests/EventListener/StopOnNewVersionListenerTest.php index 168d34524..07609cdb0 100644 --- a/packages/messenger/Tests/EventListener/StopOnNewVersionListenerTest.php +++ b/packages/messenger/Tests/EventListener/StopOnNewVersionListenerTest.php @@ -10,7 +10,6 @@ use Draw\Contracts\Application\VersionVerificationInterface; use PHPUnit\Framework\Attributes\CoversClass; use PHPUnit\Framework\TestCase; -use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\Messenger\Event\WorkerRunningEvent; use Symfony\Component\Messenger\Event\WorkerStartedEvent; use Symfony\Component\Messenger\Worker; @@ -61,11 +60,6 @@ public function isUpToDate(): bool return $this->isUpToDate; } - public function testConstruct(): void - { - static::assertInstanceOf(EventSubscriberInterface::class, $this->service); - } - public function testGetSubscribedEvents(): void { static::assertSame( @@ -84,7 +78,11 @@ public function testOnWorkerStarted(): void $this->isUpToDate = false; $worker = $this->createMock(Worker::class); - $worker->expects(static::once())->method('stop'); + $worker + ->expects(static::once()) + ->method('stop') + ->seal() + ; $this->service->onWorkerStarted(new WorkerStartedEvent($worker)); } @@ -95,7 +93,11 @@ public function testOnWorkerStartedUpToDate(): void $this->isUpToDate = true; $worker = $this->createMock(Worker::class); - $worker->expects(static::never())->method('stop'); + $worker + ->expects(static::never()) + ->method('stop') + ->seal() + ; $this->service->onWorkerStarted(new WorkerStartedEvent($worker)); } @@ -106,7 +108,11 @@ public function testOnWorkerRunning(): void $this->isUpToDate = false; $worker = $this->createMock(Worker::class); - $worker->expects(static::once())->method('stop'); + $worker + ->expects(static::once()) + ->method('stop') + ->seal() + ; $this->service->onWorkerRunning(new WorkerRunningEvent($worker, false)); @@ -125,7 +131,11 @@ public function testOnWorkerRunningUpToDate(): void $this->isUpToDate = true; $worker = $this->createMock(Worker::class); - $worker->expects(static::never())->method('stop'); + $worker + ->expects(static::never()) + ->method('stop') + ->seal() + ; $this->service->onWorkerRunning(new WorkerRunningEvent($worker, false)); } @@ -135,7 +145,11 @@ public function testOnWorkerRunningUpToDateRunningVersionIsNull(): void $this->runningVersion = null; $worker = $this->createMock(Worker::class); - $worker->expects(static::never())->method('stop'); + $worker + ->expects(static::never()) + ->method('stop') + ->seal() + ; $this->service->onWorkerRunning(new WorkerRunningEvent($worker, false)); } @@ -146,7 +160,11 @@ public function testOnBrokerRunningEvent(): void $this->isUpToDate = false; $broker = $this->createMock(Broker::class); - $broker->expects(static::once())->method('stop'); + $broker + ->expects(static::once()) + ->method('stop') + ->seal() + ; $this->service->onBrokerRunningEvent(new BrokerRunningEvent($broker)); @@ -165,7 +183,11 @@ public function testOnBrokerRunningEventUpToDate(): void $this->isUpToDate = true; $broker = $this->createMock(Broker::class); - $broker->expects(static::never())->method('stop'); + $broker + ->expects(static::never()) + ->method('stop') + ->seal() + ; $this->service->onBrokerRunningEvent(new BrokerRunningEvent($broker)); } @@ -176,7 +198,11 @@ public function testOnBrokerRunningEventVersionInformationIsNotAccessibleExcepti $broker = $this->createMock(Broker::class); - $broker->expects(static::once())->method('stop'); + $broker + ->expects(static::once()) + ->method('stop') + ->seal() + ; $this->service->onBrokerRunningEvent(new BrokerRunningEvent($broker)); } @@ -187,6 +213,6 @@ public function testOnBrokerRunningEventException(): void $this->expectExceptionObject($this->throwable); - $this->service->onBrokerRunningEvent(new BrokerRunningEvent($this->createMock(Broker::class))); + $this->service->onBrokerRunningEvent(new BrokerRunningEvent(static::createStub(Broker::class))); } } diff --git a/packages/messenger/Tests/Exception/MessageNotFoundExceptionTest.php b/packages/messenger/Tests/Exception/MessageNotFoundExceptionTest.php index f6a0422bf..c36fd4900 100644 --- a/packages/messenger/Tests/Exception/MessageNotFoundExceptionTest.php +++ b/packages/messenger/Tests/Exception/MessageNotFoundExceptionTest.php @@ -23,14 +23,6 @@ protected function setUp(): void ); } - public function testConstruct(): void - { - static::assertInstanceOf( - \Exception::class, - $this->exception - ); - } - public function testGetMessage(): void { static::assertSame( diff --git a/packages/messenger/Tests/Expirable/Command/PurgeExpiredMessageCommandTest.php b/packages/messenger/Tests/Expirable/Command/PurgeExpiredMessageCommandTest.php index 6ee90215d..c0c474580 100644 --- a/packages/messenger/Tests/Expirable/Command/PurgeExpiredMessageCommandTest.php +++ b/packages/messenger/Tests/Expirable/Command/PurgeExpiredMessageCommandTest.php @@ -8,9 +8,8 @@ use Draw\Component\Messenger\Tests\Stub\Transport\PurgeAwareTransportInterface; use Draw\Component\Tester\Application\CommandDataTester; use Draw\Component\Tester\Application\CommandTestTrait; -use Draw\Component\Tester\MockTrait; +use Draw\Component\Tester\DoubleTrait; use PHPUnit\Framework\Attributes\CoversClass; -use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputOption; @@ -22,14 +21,12 @@ class PurgeExpiredMessageCommandTest extends TestCase { use CommandTestTrait; - use MockTrait; - - private TransportRepository&MockObject $transportRepository; + use DoubleTrait; protected function setUp(): void { $this->command = new PurgeExpiredMessageCommand( - $this->transportRepository = $this->createMock(TransportRepository::class), + static::createStub(TransportRepository::class), ); } @@ -58,11 +55,16 @@ public static function provideTestOption(): iterable public function testExecuteInvalidTransport(): void { - $this->transportRepository + $this->command = new PurgeExpiredMessageCommand( + $transportRepository = $this->createMock(TransportRepository::class), + ); + + $transportRepository ->expects(static::once()) ->method('has') ->with($transport = uniqid('transport-invalid-')) ->willReturn(false) + ->seal() ; $this->expectException(\RuntimeException::class); @@ -73,13 +75,17 @@ public function testExecuteInvalidTransport(): void public function testExecute(): void { - $this->transportRepository + $this->command = new PurgeExpiredMessageCommand( + $transportRepository = $this->createMock(TransportRepository::class), + ); + + $transportRepository ->expects(static::once()) ->method('getTransportNames') ->willReturn($transportNames = [uniqid('transport1-'), uniqid('transport2-')]) ; - $this->transportRepository + $transportRepository ->expects(static::exactly(2)) ->method('get') ->with( @@ -92,6 +98,7 @@ public function testExecute(): void $transport1 = $this->createMock(PurgeableTransportInterface::class), $transport2 = $this->createMock(PurgeAwareTransportInterface::class) ) + ->seal() ; $transport1 @@ -101,11 +108,13 @@ public function testExecute(): void static::equalToWithDelta(new \DateTime('- 1 month'), 1) ) ->willReturn($count = random_int(1, 10)) + ->seal() ; $transport2 ->expects(static::never()) ->method('purgeObsoleteMessages') + ->seal() ; $this->execute([], []) @@ -130,20 +139,25 @@ public function testExecute(): void public function testExecuteWithInputs(): void { - $this->transportRepository + $this->command = new PurgeExpiredMessageCommand( + $transportRepository = $this->createMock(TransportRepository::class), + ); + + $transportRepository ->expects(static::once()) ->method('has') ->with($transportName = uniqid('transport-')) ->willReturn(true) ; - $this->transportRepository + $transportRepository ->expects(static::once()) ->method('get') ->with($transportName) ->willReturn( $transport = $this->createMock(PurgeableTransportInterface::class), ) + ->seal() ; $delay = '- 4 months'; @@ -155,6 +169,7 @@ public function testExecuteWithInputs(): void static::equalToWithDelta(new \DateTime($delay), 1) ) ->willReturn($count = random_int(1, 10)) + ->seal() ; $this->execute(['transport' => $transportName, '--delay' => $delay], []) diff --git a/packages/messenger/Tests/Expirable/Stamp/ExpirationStampTest.php b/packages/messenger/Tests/Expirable/Stamp/ExpirationStampTest.php index 279843a76..387bba2d6 100644 --- a/packages/messenger/Tests/Expirable/Stamp/ExpirationStampTest.php +++ b/packages/messenger/Tests/Expirable/Stamp/ExpirationStampTest.php @@ -5,7 +5,6 @@ use Draw\Component\Messenger\Expirable\Stamp\ExpirationStamp; use PHPUnit\Framework\Attributes\CoversClass; use PHPUnit\Framework\TestCase; -use Symfony\Component\Messenger\Stamp\StampInterface; /** * @internal @@ -24,14 +23,6 @@ protected function setUp(): void ); } - public function testConstruct(): void - { - static::assertInstanceOf( - StampInterface::class, - $this->entity - ); - } - public function testGetDateTime(): void { static::assertSame( diff --git a/packages/messenger/Tests/ManualTrigger/Action/ClickMessageActionTest.php b/packages/messenger/Tests/ManualTrigger/Action/ClickMessageActionTest.php index 25c5f95a8..aba48aa51 100644 --- a/packages/messenger/Tests/ManualTrigger/Action/ClickMessageActionTest.php +++ b/packages/messenger/Tests/ManualTrigger/Action/ClickMessageActionTest.php @@ -2,7 +2,6 @@ namespace Draw\Component\Messenger\Tests\ManualTrigger\Action; -use Draw\Component\Messenger\Expirable\Stamp\ExpirationStamp; use Draw\Component\Messenger\ManualTrigger\Action\ClickMessageAction; use Draw\Component\Messenger\ManualTrigger\Event\MessageLinkErrorEvent; use Draw\Component\Messenger\Searchable\EnvelopeFinder; @@ -11,7 +10,6 @@ use Draw\Contracts\Messenger\Exception\MessageNotFoundException; use PHPUnit\Framework\Attributes\CoversClass; use PHPUnit\Framework\Attributes\DataProvider; -use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\HttpFoundation\Request; @@ -23,7 +21,6 @@ use Symfony\Component\Messenger\MessageBusInterface; use Symfony\Component\Messenger\Stamp\HandledStamp; use Symfony\Component\Messenger\Stamp\ReceivedStamp; -use Symfony\Component\Messenger\Stamp\SentToFailureTransportStamp; use Symfony\Component\Messenger\Stamp\TransportMessageIdStamp; use Symfony\Component\Messenger\Transport\TransportInterface; use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; @@ -35,18 +32,6 @@ #[CoversClass(ClickMessageAction::class)] class ClickMessageActionTest extends TestCase { - private ClickMessageAction $object; - - private MessageBusInterface&MockObject $messageBus; - - private EnvelopeFinder&MockObject $envelopeFinder; - - private EventDispatcherInterface&MockObject $eventDispatcher; - - private TranslatorInterface&MockObject $translator; - - private TransportRepository&MockObject $transportRepository; - private Request $request; protected function setUp(): void @@ -57,43 +42,36 @@ protected function setUp(): void new MockArraySessionStorage(), ) ); - - $this->object = new ClickMessageAction( - $this->messageBus = $this->createMock(MessageBusInterface::class), - $this->envelopeFinder = $this->createMock(EnvelopeFinder::class), - $this->eventDispatcher = $this->createMock(EventDispatcherInterface::class), - $this->translator = $this->createMock(TranslatorInterface::class), - $this->transportRepository = $this->createMock(TransportRepository::class) - ); - } - - public function testConstants(): void - { - static::assertSame( - 'dMUuid', - $this->object::MESSAGE_ID_PARAMETER_NAME - ); } #[DataProvider('provideClickEnvelopeErrorCases')] public function testClickEnvelopeError( - ?Envelope $returnedEnveloped, string $exceptionClass, ?string $translatedMessage, ): void { - $this->messageBus + $object = new ClickMessageAction( + $messageBus = $this->createMock(MessageBusInterface::class), + $envelopeFinder = $this->createMock(EnvelopeFinder::class), + $eventDispatcher = $this->createMock(EventDispatcherInterface::class), + $translator = $this->createMock(TranslatorInterface::class), + static::createStub(TransportRepository::class) + ); + + $messageBus ->expects(static::never()) ->method('dispatch') + ->seal() ; - $this->envelopeFinder + $envelopeFinder ->expects(static::once()) ->method('findById') ->with($messageId = uniqid('message-Id')) ->willThrowException(new MessageNotFoundException($messageId)) + ->seal() ; - $this->eventDispatcher + $eventDispatcher ->expects(static::once()) ->method('dispatch') ->with( @@ -121,24 +99,27 @@ function (MessageLinkErrorEvent $event) use ($messageId, $exceptionClass) { ) ) ->willReturnArgument(0) + ->seal() ; if ($translatedMessage) { - $this->translator + $translator ->expects(static::once()) ->method('trans') ->with($translatedMessage, [], 'DrawMessenger') ->willReturn($message = uniqid('translation-')) + ->seal() ; } else { $this->request->setSession($this->createMock(SessionInterface::class)); - $this->translator + $translator ->expects(static::never()) ->method('trans') + ->seal() ; } - $response = \call_user_func($this->object, $messageId, $this->request); + $response = \call_user_func($object, $messageId, $this->request); if ($translatedMessage) { static::assertSame( @@ -163,19 +144,16 @@ function (MessageLinkErrorEvent $event) use ($messageId, $exceptionClass) { public static function provideClickEnvelopeErrorCases(): iterable { yield 'not-found' => [ - null, MessageNotFoundException::class, 'link.invalid', ]; yield 'error-queue' => [ - new Envelope((object) [], [new SentToFailureTransportStamp(uniqid())]), MessageNotFoundException::class, 'link.invalid', ]; yield 'expired' => [ - new Envelope((object) [], [new ExpirationStamp(new \DateTimeImmutable('- 1 second'))]), MessageNotFoundException::class, 'link.invalid', ]; @@ -183,16 +161,25 @@ public static function provideClickEnvelopeErrorCases(): iterable public function testClick(): void { + $object = new ClickMessageAction( + $messageBus = $this->createMock(MessageBusInterface::class), + $envelopeFinder = $this->createMock(EnvelopeFinder::class), + static::createStub(EventDispatcherInterface::class), + $translator = $this->createMock(TranslatorInterface::class), + $transportRepository = $this->createMock(TransportRepository::class) + ); + $transportName = uniqid('transport-'); - $this->envelopeFinder + $envelopeFinder ->expects(static::once()) ->method('findById') ->with($messageId = uniqid('message-Id')) ->willReturn(new Envelope((object) [], [new FoundFromTransportStamp($transportName)])) + ->seal() ; - $this->messageBus + $messageBus ->expects(static::once()) ->method('dispatch') ->with( @@ -204,35 +191,40 @@ public function testClick(): void return true; }) - )->willReturn( + ) + ->willReturn( $envelope = new Envelope( (object) [], [new TransportMessageIdStamp($messageId), new HandledStamp(null, uniqid('handler-'))] ) ) + ->seal() ; - $this->translator + $translator ->expects(static::once()) ->method('trans') ->with('link.processed', [], 'DrawMessenger') ->willReturn($message = uniqid('translation-')) + ->seal() ; - $this->transportRepository + $transportRepository ->expects(static::once()) ->method('get') ->with($transportName) ->willReturn($transport = $this->createMock(TransportInterface::class)) + ->seal() ; $transport ->expects(static::once()) ->method('ack') ->with($envelope) + ->seal() ; - $response = \call_user_func($this->object, $messageId, $this->request); + $response = \call_user_func($object, $messageId, $this->request); static::assertSame( [ @@ -254,16 +246,25 @@ public function testClick(): void public function testClickWithResponse(): void { + $object = new ClickMessageAction( + $messageBus = $this->createMock(MessageBusInterface::class), + $envelopeFinder = $this->createMock(EnvelopeFinder::class), + static::createStub(EventDispatcherInterface::class), + $translator = $this->createMock(TranslatorInterface::class), + $transportRepository = $this->createMock(TransportRepository::class) + ); + $transportName = uniqid('transport-'); - $this->envelopeFinder + $envelopeFinder ->expects(static::once()) ->method('findById') ->with($messageId = uniqid('message-Id')) ->willReturn(new Envelope((object) [], [new FoundFromTransportStamp($transportName)])) + ->seal() ; - $this->messageBus + $messageBus ->expects(static::once()) ->method('dispatch') ->willReturn( @@ -275,37 +276,49 @@ public function testClickWithResponse(): void ] ) ) + ->seal() ; - $this->translator + $translator ->expects(static::never()) ->method('trans') + ->seal() ; - $this->transportRepository + $transportRepository ->expects(static::once()) ->method('get') ->with($transportName) ->willReturn($transport = $this->createMock(TransportInterface::class)) + ->seal() ; $transport ->expects(static::once()) ->method('ack') ->with($envelope) + ->seal() ; static::assertSame( $response, - \call_user_func($this->object, $messageId, $this->request) + \call_user_func($object, $messageId, $this->request) ); } public function testClickInvalidHandler(): void { + $object = new ClickMessageAction( + $messageBus = $this->createMock(MessageBusInterface::class), + $envelopeFinder = $this->createMock(EnvelopeFinder::class), + $eventDispatcher = $this->createMock(EventDispatcherInterface::class), + $translator = $this->createMock(TranslatorInterface::class), + static::createStub(TransportRepository::class) + ); + $transportName = uniqid('transport-'); - $this->envelopeFinder + $envelopeFinder ->expects(static::once()) ->method('findById') ->with($messageId = uniqid('message-Id')) @@ -315,9 +328,10 @@ public function testClickInvalidHandler(): void [new FoundFromTransportStamp($transportName)] ) ) + ->seal() ; - $this->messageBus + $messageBus ->expects(static::once()) ->method('dispatch') ->willReturn( @@ -330,16 +344,18 @@ public function testClickInvalidHandler(): void ] ) ) + ->seal() ; - $this->translator + $translator ->expects(static::never()) ->method('trans') + ->seal() ; $response = new Response(); - $this->eventDispatcher + $eventDispatcher ->expects(static::once()) ->method('dispatch') ->with( @@ -362,11 +378,12 @@ function (MessageLinkErrorEvent $event) use ($response, $handler1, $handler2) { ) ) ->willReturnArgument(0) + ->seal() ; static::assertSame( $response, - \call_user_func($this->object, $messageId, $this->request) + \call_user_func($object, $messageId, $this->request) ); } } diff --git a/packages/messenger/Tests/ManualTrigger/Event/MessageLinkErrorEventTest.php b/packages/messenger/Tests/ManualTrigger/Event/MessageLinkErrorEventTest.php index da1e81d1f..b5f98b404 100644 --- a/packages/messenger/Tests/ManualTrigger/Event/MessageLinkErrorEventTest.php +++ b/packages/messenger/Tests/ManualTrigger/Event/MessageLinkErrorEventTest.php @@ -7,7 +7,6 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; -use Symfony\Contracts\EventDispatcher\Event; /** * @internal @@ -32,14 +31,6 @@ protected function setUp(): void ); } - public function testConstruct(): void - { - static::assertInstanceOf( - Event::class, - $this->event - ); - } - public function testGetRequest(): void { static::assertSame( diff --git a/packages/messenger/Tests/ManualTrigger/EventListener/StampManuallyTriggeredEnvelopeListenerTest.php b/packages/messenger/Tests/ManualTrigger/EventListener/StampManuallyTriggeredEnvelopeListenerTest.php index c3e40e2b9..5922aa1ca 100644 --- a/packages/messenger/Tests/ManualTrigger/EventListener/StampManuallyTriggeredEnvelopeListenerTest.php +++ b/packages/messenger/Tests/ManualTrigger/EventListener/StampManuallyTriggeredEnvelopeListenerTest.php @@ -8,7 +8,6 @@ use PHPUnit\Framework\Attributes\CoversClass; use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; -use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\Messenger\Envelope; use Symfony\Component\Messenger\Event\SendMessageToTransportsEvent; @@ -25,14 +24,6 @@ protected function setUp(): void $this->service = new StampManuallyTriggeredEnvelopeListener(); } - public function testConstruct(): void - { - static::assertInstanceOf( - EventSubscriberInterface::class, - $this->service - ); - } - public function testGetSubscribedEvents(): void { static::assertSame( diff --git a/packages/messenger/Tests/ManualTrigger/Message/RedirectToRouteMessageTraitTest.php b/packages/messenger/Tests/ManualTrigger/Message/RedirectToRouteMessageTraitTest.php index 638f507da..1fc31fd60 100644 --- a/packages/messenger/Tests/ManualTrigger/Message/RedirectToRouteMessageTraitTest.php +++ b/packages/messenger/Tests/ManualTrigger/Message/RedirectToRouteMessageTraitTest.php @@ -5,7 +5,6 @@ use Draw\Component\Messenger\ManualTrigger\Message\RedirectToRouteMessageTrait; use PHPUnit\Framework\Attributes\CoversClass; use PHPUnit\Framework\TestCase; -use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\Routing\Generator\UrlGeneratorInterface; /** @@ -32,15 +31,11 @@ public function testGetRedirectResponse(): void UrlGeneratorInterface::ABSOLUTE_URL ) ->willReturn($url = uniqid('url-')) + ->seal() ; $response = $this->getRedirectResponse($urlGenerator); - static::assertInstanceOf( - RedirectResponse::class, - $response - ); - static::assertSame( $url, $response->getTargetUrl() diff --git a/packages/messenger/Tests/ManualTrigger/MessageHandler/RedirectToRouteMessageHandlerTest.php b/packages/messenger/Tests/ManualTrigger/MessageHandler/RedirectToRouteMessageHandlerTest.php index d1632123a..e63f11365 100644 --- a/packages/messenger/Tests/ManualTrigger/MessageHandler/RedirectToRouteMessageHandlerTest.php +++ b/packages/messenger/Tests/ManualTrigger/MessageHandler/RedirectToRouteMessageHandlerTest.php @@ -5,6 +5,7 @@ use Draw\Component\Messenger\ManualTrigger\Message\RedirectToRouteMessageInterface; use Draw\Component\Messenger\ManualTrigger\MessageHandler\RedirectToRouteMessageHandler; use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\MockObject\Stub; use PHPUnit\Framework\TestCase; use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\Routing\Generator\UrlGeneratorInterface; @@ -17,12 +18,12 @@ class RedirectToRouteMessageHandlerTest extends TestCase { private RedirectToRouteMessageHandler $service; - private UrlGeneratorInterface $urlGenerator; + private UrlGeneratorInterface&Stub $urlGenerator; protected function setUp(): void { $this->service = new RedirectToRouteMessageHandler( - $this->urlGenerator = $this->createMock(UrlGeneratorInterface::class) + $this->urlGenerator = static::createStub(UrlGeneratorInterface::class) ); } @@ -35,6 +36,7 @@ public function testInvoke(): void ->method('getRedirectResponse') ->with($this->urlGenerator) ->willReturn($response = new RedirectResponse('/')) + ->seal() ; static::assertSame( diff --git a/packages/messenger/Tests/ManualTrigger/Stamp/ManualTriggerStampTest.php b/packages/messenger/Tests/ManualTrigger/Stamp/ManualTriggerStampTest.php deleted file mode 100644 index e66e5ab30..000000000 --- a/packages/messenger/Tests/ManualTrigger/Stamp/ManualTriggerStampTest.php +++ /dev/null @@ -1,30 +0,0 @@ -entity = new ManualTriggerStamp(); - } - - public function testConstruct(): void - { - static::assertInstanceOf( - StampInterface::class, - $this->entity - ); - } -} diff --git a/packages/messenger/Tests/MessageHandler/RetryFailedMessageMessageHandlerTest.php b/packages/messenger/Tests/MessageHandler/RetryFailedMessageMessageHandlerTest.php index 48e454972..41aa0f72a 100644 --- a/packages/messenger/Tests/MessageHandler/RetryFailedMessageMessageHandlerTest.php +++ b/packages/messenger/Tests/MessageHandler/RetryFailedMessageMessageHandlerTest.php @@ -52,11 +52,13 @@ public function testHandleRetryFailedMessageMessage(): void ] ) ->willReturn($process = $this->createMock(Process::class)) + ->seal() ; $process ->expects(static::once()) ->method('mustRun') + ->seal() ; $this->handler->handleRetryFailedMessageMessage( diff --git a/packages/messenger/Tests/Retry/EventDrivenRetryStrategyTest.php b/packages/messenger/Tests/Retry/EventDrivenRetryStrategyTest.php index 9b61dc53a..a3b612ea1 100644 --- a/packages/messenger/Tests/Retry/EventDrivenRetryStrategyTest.php +++ b/packages/messenger/Tests/Retry/EventDrivenRetryStrategyTest.php @@ -5,7 +5,7 @@ use Draw\Component\Messenger\Retry\Event\GetWaitingTimeEvent; use Draw\Component\Messenger\Retry\Event\IsRetryableEvent; use Draw\Component\Messenger\Retry\EventDrivenRetryStrategy; -use Draw\Component\Tester\MockTrait; +use Draw\Component\Tester\DoubleTrait; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Symfony\Component\Messenger\Envelope; @@ -17,7 +17,7 @@ */ class EventDrivenRetryStrategyTest extends TestCase { - use MockTrait; + use DoubleTrait; private EventDrivenRetryStrategy $object; @@ -30,14 +30,6 @@ protected function setUp(): void ); } - public function testConstruct(): void - { - static::assertInstanceOf( - RetryStrategyInterface::class, - $this->object - ); - } - public function testIsRetryableDefault(): void { $envelope = new Envelope(new \stdClass()); @@ -52,6 +44,7 @@ static function (IsRetryableEvent $event) use ($envelope) { return $event; } ) + ->seal() ; static::assertFalse($this->object->isRetryable($envelope)); @@ -73,6 +66,7 @@ static function (IsRetryableEvent $event) use ($envelope) { return $event; } ) + ->seal() ; static::assertTrue($this->object->isRetryable($envelope)); @@ -94,6 +88,7 @@ static function (IsRetryableEvent $event) use ($envelope) { return $event; } ) + ->seal() ; static::assertFalse($this->object->isRetryable($envelope)); @@ -113,6 +108,7 @@ static function (IsRetryableEvent $event) use ($envelope) { return $event; } ) + ->seal() ; $this->mockProperty( @@ -124,6 +120,7 @@ static function (IsRetryableEvent $event) use ($envelope) { ->method('isRetryable') ->with($envelope) ->willReturn(true) + ->seal() ; static::assertTrue($this->object->isRetryable($envelope)); @@ -143,6 +140,7 @@ static function (GetWaitingTimeEvent $event) use ($envelope) { return $event; } ) + ->seal() ; static::assertSame( @@ -167,6 +165,7 @@ static function (GetWaitingTimeEvent $event) use ($envelope) { return $event; } ) + ->seal() ; static::assertSame( @@ -189,6 +188,7 @@ static function (GetWaitingTimeEvent $event) use ($envelope) { return $event; } ) + ->seal() ; $this->mockProperty( @@ -200,6 +200,7 @@ static function (GetWaitingTimeEvent $event) use ($envelope) { ->method('getWaitingTime') ->with($envelope) ->willReturn(5000) + ->seal() ; static::assertSame( diff --git a/packages/messenger/Tests/Retry/EventListener/SelfAwareMessageRetryableListenerTest.php b/packages/messenger/Tests/Retry/EventListener/SelfAwareMessageRetryableListenerTest.php index 6f6d1b0f7..7648cb1b3 100644 --- a/packages/messenger/Tests/Retry/EventListener/SelfAwareMessageRetryableListenerTest.php +++ b/packages/messenger/Tests/Retry/EventListener/SelfAwareMessageRetryableListenerTest.php @@ -8,7 +8,6 @@ use Draw\Component\Messenger\Retry\Message\SelfAwareRetryableMessageInterface; use PHPUnit\Framework\TestCase; use Symfony\Component\Messenger\Envelope; -use Symfony\Contracts\Service\ResetInterface; /** * @internal @@ -22,14 +21,6 @@ protected function setUp(): void $this->object = new SelfAwareMessageRetryableListener(); } - public function testConstruct(): void - { - static::assertInstanceOf( - ResetInterface::class, - $this->object - ); - } - public function testOnIsRetryableEventNoSelfAwareMessage(): void { $this->object->onIsRetryableEvent( @@ -49,6 +40,7 @@ public function testOnIsRetryableEventNotRetryable(): void $message->expects(static::once()) ->method('getRetryWaitingTime') ->willReturn(null) + ->seal() ; $envelope = new Envelope($message); @@ -73,6 +65,7 @@ public function testOnIsRetryableEventRetryable(): void 0 // Assuming this is the first retry ) ->willReturn(1000) + ->seal() ; $envelope = new Envelope($message); @@ -103,6 +96,7 @@ public function testOnGetWaitingTimeEventWithWaitingTime(): void $message->expects(static::once()) ->method('getRetryWaitingTime') ->willReturn(1000) + ->seal() ; $envelope = new Envelope($message); @@ -124,6 +118,7 @@ public function testReset(): void $message->expects(static::once()) ->method('getRetryWaitingTime') ->willReturn(1000) + ->seal() ; $envelope = new Envelope($message); diff --git a/packages/messenger/Tests/Searchable/EnvelopeFinderTest.php b/packages/messenger/Tests/Searchable/EnvelopeFinderTest.php index 4db5c70d2..cb0bea160 100644 --- a/packages/messenger/Tests/Searchable/EnvelopeFinderTest.php +++ b/packages/messenger/Tests/Searchable/EnvelopeFinderTest.php @@ -6,7 +6,6 @@ use Draw\Component\Messenger\Searchable\Stamp\FoundFromTransportStamp; use Draw\Component\Messenger\Searchable\TransportRepository; use Draw\Component\Messenger\Tests\Stub\Transport\FindAwareTransportInterface; -use Draw\Component\Tester\MockTrait; use Draw\Contracts\Messenger\Exception\MessageNotFoundException; use PHPUnit\Framework\Attributes\CoversClass; use PHPUnit\Framework\MockObject\MockObject; @@ -20,8 +19,6 @@ #[CoversClass(EnvelopeFinder::class)] class EnvelopeFinderTest extends TestCase { - use MockTrait; - private EnvelopeFinder $service; private TransportRepository&MockObject $transportRepository; @@ -44,6 +41,7 @@ public function testFindByIdNotFound(): void $transport, ] ) + ->seal() ; $transport @@ -51,6 +49,7 @@ public function testFindByIdNotFound(): void ->method('find') ->with($messageId = uniqid('message-id')) ->willReturn(null) + ->seal() ; static::expectException(MessageNotFoundException::class); @@ -69,11 +68,13 @@ public function testFindByIdNotListableReceiver(): void $transport, ] ) + ->seal() ; $transport ->expects(static::never()) ->method('find') + ->seal() ; static::expectException(MessageNotFoundException::class); @@ -91,6 +92,7 @@ public function testFindById(): void ($transportName = uniqid('transport-')) => $transport = $this->createMock(ListableReceiverInterface::class), ] ) + ->seal() ; $transport @@ -98,9 +100,10 @@ public function testFindById(): void ->method('find') ->with($messageId = uniqid('message-id-')) ->willReturn(new Envelope((object) [])) + ->seal() ; - static::assertNotNull($envelope = $this->service->findById($messageId)); + $envelope = $this->service->findById($messageId); static::assertNotNull( $stamp = $envelope->last(FoundFromTransportStamp::class) diff --git a/packages/messenger/Tests/Searchable/Stamp/FindFromTransportStampTest.php b/packages/messenger/Tests/Searchable/Stamp/FindFromTransportStampTest.php index 85818d61b..2012c398e 100644 --- a/packages/messenger/Tests/Searchable/Stamp/FindFromTransportStampTest.php +++ b/packages/messenger/Tests/Searchable/Stamp/FindFromTransportStampTest.php @@ -5,7 +5,6 @@ use Draw\Component\Messenger\Searchable\Stamp\FoundFromTransportStamp; use PHPUnit\Framework\Attributes\CoversClass; use PHPUnit\Framework\TestCase; -use Symfony\Component\Messenger\Stamp\StampInterface; /** * @internal @@ -24,14 +23,6 @@ protected function setUp(): void ); } - public function testConstruct(): void - { - static::assertInstanceOf( - StampInterface::class, - $this->entity - ); - } - public function testGetTransportName(): void { static::assertSame( diff --git a/packages/messenger/Tests/Searchable/Stamp/SearchableTagStampTest.php b/packages/messenger/Tests/Searchable/Stamp/SearchableTagStampTest.php index 268b9ae20..aa154d8d2 100644 --- a/packages/messenger/Tests/Searchable/Stamp/SearchableTagStampTest.php +++ b/packages/messenger/Tests/Searchable/Stamp/SearchableTagStampTest.php @@ -5,7 +5,6 @@ use Draw\Component\Messenger\Searchable\Stamp\SearchableTagStamp; use PHPUnit\Framework\Attributes\CoversClass; use PHPUnit\Framework\TestCase; -use Symfony\Component\Messenger\Stamp\StampInterface; /** * @internal @@ -27,14 +26,6 @@ protected function setUp(): void ); } - public function testConstruct(): void - { - static::assertInstanceOf( - StampInterface::class, - $this->entity - ); - } - public function testGetTags(): void { static::assertSame( diff --git a/packages/messenger/Tests/SerializerEventDispatcher/EventDispatcherSerializerDecoratorTest.php b/packages/messenger/Tests/SerializerEventDispatcher/EventDispatcherSerializerDecoratorTest.php index e2b38a393..99b276428 100644 --- a/packages/messenger/Tests/SerializerEventDispatcher/EventDispatcherSerializerDecoratorTest.php +++ b/packages/messenger/Tests/SerializerEventDispatcher/EventDispatcherSerializerDecoratorTest.php @@ -6,7 +6,7 @@ use Draw\Component\Messenger\SerializerEventDispatcher\Event\PostEncodeEvent; use Draw\Component\Messenger\SerializerEventDispatcher\Event\PreEncodeEvent; use Draw\Component\Messenger\SerializerEventDispatcher\EventDispatcherSerializerDecorator; -use Draw\Component\Tester\MockTrait; +use Draw\Component\Tester\DoubleTrait; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Symfony\Component\Messenger\Envelope; @@ -18,7 +18,7 @@ */ class EventDispatcherSerializerDecoratorTest extends TestCase { - use MockTrait; + use DoubleTrait; private EventDispatcherSerializerDecorator $object; @@ -34,14 +34,6 @@ protected function setUp(): void ); } - public function testConstruct(): void - { - static::assertInstanceOf( - SerializerInterface::class, - $this->object - ); - } - public function testDecode(): void { $data = ['body' => '', 'headers' => '']; @@ -51,6 +43,7 @@ public function testDecode(): void ->method('decode') ->with($data) ->willReturn($envelope = new Envelope((object) [])) + ->seal() ; $this->eventDispatcher @@ -60,6 +53,7 @@ public function testDecode(): void new PostDecodeEvent($envelope) ) ->willReturnArgument(0) + ->seal() ; static::assertSame( @@ -82,6 +76,7 @@ public function testEncode(): void ) ) ->willReturnArgument(0) + ->seal() ; $this->serializer @@ -89,6 +84,7 @@ public function testEncode(): void ->method('encode') ->with($envelope) ->willReturn($data = ['body' => '', 'headers' => '']) + ->seal() ; static::assertSame( diff --git a/packages/messenger/Tests/Transport/DrawTransportTest.php b/packages/messenger/Tests/Transport/DrawTransportTest.php index ce938d09e..216eca166 100644 --- a/packages/messenger/Tests/Transport/DrawTransportTest.php +++ b/packages/messenger/Tests/Transport/DrawTransportTest.php @@ -4,14 +4,12 @@ use Doctrine\DBAL\Connection; use Draw\Bundle\TesterBundle\PHPUnit\Extension\DoctrineTransaction\NoTransaction; -use Draw\Component\Messenger\Expirable\PurgeableTransportInterface; use Draw\Component\Messenger\Expirable\Stamp\ExpirationStamp; -use Draw\Component\Messenger\Searchable\SearchableTransportInterface; use Draw\Component\Messenger\Searchable\Stamp\SearchableTagStamp; use Draw\Component\Messenger\Tests\TestCase; use Draw\Component\Messenger\Transport\DrawTransport; use Draw\Component\Messenger\Transport\DrawTransportFactory; -use Draw\Component\Tester\MockTrait; +use Draw\Component\Tester\DoubleTrait; use PHPUnit\Framework\Attributes\AfterClass; use PHPUnit\Framework\Attributes\BeforeClass; use PHPUnit\Framework\Attributes\CoversClass; @@ -22,11 +20,7 @@ use Symfony\Component\Messenger\Stamp\DelayStamp; use Symfony\Component\Messenger\Stamp\RedeliveryStamp; use Symfony\Component\Messenger\Stamp\TransportMessageIdStamp; -use Symfony\Component\Messenger\Transport\Receiver\ListableReceiverInterface; -use Symfony\Component\Messenger\Transport\Receiver\MessageCountAwareInterface; use Symfony\Component\Messenger\Transport\Serialization\PhpSerializer; -use Symfony\Component\Messenger\Transport\SetupableTransportInterface; -use Symfony\Component\Messenger\Transport\TransportInterface; /** * @internal @@ -35,7 +29,7 @@ #[NoTransaction] class DrawTransportTest extends TestCase { - use MockTrait; + use DoubleTrait; private DrawTransport $service; @@ -63,39 +57,6 @@ protected function setUp(): void ); } - public function testConstruct(): void - { - static::assertInstanceOf( - TransportInterface::class, - $this->service - ); - - static::assertInstanceOf( - PurgeableTransportInterface::class, - $this->service - ); - - static::assertInstanceOf( - SearchableTransportInterface::class, - $this->service - ); - - static::assertInstanceOf( - SetupableTransportInterface::class, - $this->service - ); - - static::assertInstanceOf( - MessageCountAwareInterface::class, - $this->service - ); - - static::assertInstanceOf( - ListableReceiverInterface::class, - $this->service - ); - } - public function testSetup(): void { static::loadDefaultConnection() @@ -118,6 +79,7 @@ public function testSendException(): void $driverConnection->expects(static::once()) ->method('createQueryBuilder') ->willThrowException(new \Exception($exceptionMessage = uniqid('exception-message-'))) + ->seal() ; $this->expectException(TransportException::class); @@ -206,6 +168,7 @@ public function testFindByTagsNoTags(): void $driverConnection->expects(static::never()) ->method('createQueryBuilder') + ->seal() ; static::assertEmpty($this->service->findByTags([])); diff --git a/packages/messenger/composer.json b/packages/messenger/composer.json index d8265c245..3a9d3b71c 100644 --- a/packages/messenger/composer.json +++ b/packages/messenger/composer.json @@ -39,7 +39,7 @@ "doctrine/orm": "^3.6", "draw/dependency-injection": "^0.39", "draw/tester": "^0.39", - "phpunit/phpunit": "^11.3 || ^12.0", + "phpunit/phpunit": "^11.3 || ^12.0 || ^13.0", "psr/log": "^3" }, "suggest": { diff --git a/packages/open-api/EventListener/RequestQueryParameterFetcherListener.php b/packages/open-api/EventListener/RequestQueryParameterFetcherListener.php index f8ea9d7b8..bdc11e4b9 100644 --- a/packages/open-api/EventListener/RequestQueryParameterFetcherListener.php +++ b/packages/open-api/EventListener/RequestQueryParameterFetcherListener.php @@ -58,7 +58,6 @@ public function onKernelController(ControllerEvent $event): void $value = $request->query->getBoolean($name); break; case 'number': - /** @var @phpstan-ignore-next-line $value */ $value = $request->query->get($name) + 0; break; case 'array': diff --git a/packages/open-api/EventListener/ResponseApiExceptionListener.php b/packages/open-api/EventListener/ResponseApiExceptionListener.php index 08971aaf6..aeb357121 100644 --- a/packages/open-api/EventListener/ResponseApiExceptionListener.php +++ b/packages/open-api/EventListener/ResponseApiExceptionListener.php @@ -27,7 +27,9 @@ public function __construct( private bool $debug = false, private string $violationKey = 'errors', ) { - $this->errorToHttpCodeConverters ??= new ConfigurableErrorToHttpCodeConverter(); + if (empty($this->errorToHttpCodeConverters)) { + $this->errorToHttpCodeConverters[] = new ConfigurableErrorToHttpCodeConverter(); + } } #[AsEventListener] diff --git a/packages/open-api/Extraction/Extractor/PhpDoc/OperationExtractor.php b/packages/open-api/Extraction/Extractor/PhpDoc/OperationExtractor.php index ed3eb313e..16c9b8bac 100644 --- a/packages/open-api/Extraction/Extractor/PhpDoc/OperationExtractor.php +++ b/packages/open-api/Extraction/Extractor/PhpDoc/OperationExtractor.php @@ -23,7 +23,12 @@ class OperationExtractor implements ExtractorInterface { private ContextFactory $contextFactory; + private DocBlockFactoryInterface $docBlockFactory; + + /** + * @var array + */ private array $exceptionResponseCodes = []; public static function getDefaultPriority(): int diff --git a/packages/open-api/Tests/Command/InstallSandboxCommandTest.php b/packages/open-api/Tests/Command/InstallSandboxCommandTest.php index 4855c71a3..4bbf2f0dc 100644 --- a/packages/open-api/Tests/Command/InstallSandboxCommandTest.php +++ b/packages/open-api/Tests/Command/InstallSandboxCommandTest.php @@ -5,7 +5,7 @@ use Draw\Component\OpenApi\Command\InstallSandboxCommand; use Draw\Component\Tester\Application\CommandDataTester; use Draw\Component\Tester\Application\CommandTestTrait; -use Draw\Component\Tester\MockTrait; +use Draw\Component\Tester\DoubleTrait; use PHPUnit\Framework\Attributes\CoversClass; use PHPUnit\Framework\TestCase; use Symfony\Component\Console\Input\InputArgument; @@ -19,7 +19,7 @@ class InstallSandboxCommandTest extends TestCase { use CommandTestTrait; - use MockTrait; + use DoubleTrait; protected function setUp(): void { @@ -97,6 +97,7 @@ public function testExecuteZipError(): void $filesystem ->expects(static::once()) ->method('dumpFile') + ->seal() ; $this->expectException(\RuntimeException::class); diff --git a/packages/open-api/Tests/Controller/OpenApiControllerTest.php b/packages/open-api/Tests/Controller/OpenApiControllerTest.php index 95e746e3b..f6e0658c8 100644 --- a/packages/open-api/Tests/Controller/OpenApiControllerTest.php +++ b/packages/open-api/Tests/Controller/OpenApiControllerTest.php @@ -7,7 +7,6 @@ use Draw\Component\OpenApi\OpenApi; use Draw\Component\OpenApi\Schema\Root; use Draw\Component\OpenApi\SchemaBuilder\SchemaBuilderInterface; -use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\RedirectResponse; @@ -19,45 +18,31 @@ */ class OpenApiControllerTest extends TestCase { - private OpenApiController $object; - - /** - * @var OpenApi&MockObject - */ - private OpenApi $openApi; - - /** - * @var SchemaBuilderInterface&MockObject - */ - private SchemaBuilderInterface $schemaBuilder; - - /** - * @var UrlGeneratorInterface&MockObject - */ - private UrlGeneratorInterface $urlGenerator; - private string $sandboxUrl; protected function setUp(): void { - $this->object = new OpenApiController( - $this->openApi = $this->createMock(OpenApi::class), - $this->schemaBuilder = $this->createMock(SchemaBuilderInterface::class), - $this->urlGenerator = $this->createMock(UrlGeneratorInterface::class), - $this->sandboxUrl = uniqid('/path/').'/sandbox' - ); + $this->sandboxUrl = uniqid('/path/').'/sandbox'; } public function testApiDocAction(): void { - $this->openApi + $object = new OpenApiController( + $openApi = $this->createMock(OpenApi::class), + static::createStub(SchemaBuilderInterface::class), + $urlGenerator = $this->createMock(UrlGeneratorInterface::class), + $this->sandboxUrl + ); + + $openApi ->expects(static::never()) ->method('dump') + ->seal() ; $route = uniqid('route-'); - $this->urlGenerator + $urlGenerator ->expects(static::once()) ->method('generate') ->with( @@ -68,12 +53,13 @@ public function testApiDocAction(): void UrlGeneratorInterface::ABSOLUTE_URL ) ->willReturn($url = uniqid('url-')) + ->seal() ; $request = new Request(); $request->attributes->set('_route', $route); - $response = $this->object->apiDocAction($request); + $response = $object->apiDocAction($request); static::assertInstanceOf(RedirectResponse::class, $response); @@ -85,10 +71,17 @@ public function testApiDocAction(): void public function testApiDocActionVersioned(): void { + $object = new OpenApiController( + static::createStub(OpenApi::class), + static::createStub(SchemaBuilderInterface::class), + $urlGenerator = $this->createMock(UrlGeneratorInterface::class), + $this->sandboxUrl + ); + $route = uniqid('route-'); $version = uniqid('version-'); - $this->urlGenerator + $urlGenerator ->expects(static::once()) ->method('generate') ->with( @@ -100,43 +93,54 @@ public function testApiDocActionVersioned(): void UrlGeneratorInterface::ABSOLUTE_URL ) ->willReturn(uniqid('url-')) + ->seal() ; $request = new Request(); $request->attributes->set('_route', $route); - $this->object->apiDocAction($request, $version); + $object->apiDocAction($request, $version); } public function testApiDocActionJson(): void { + $object = new OpenApiController( + $openApi = $this->createMock(OpenApi::class), + $schemaBuilder = $this->createMock(SchemaBuilderInterface::class), + $urlGenerator = $this->createMock(UrlGeneratorInterface::class), + $this->sandboxUrl + ); + $version = uniqid('version-'); - $this->schemaBuilder + $schemaBuilder ->expects(static::once()) ->method('build') ->with( static::isInstanceOf(ExtractionContextInterface::class) ) ->willReturn($rootSchema = new Root()) + ->seal() ; - $this->openApi + $openApi ->expects(static::once()) ->method('dump') ->with($rootSchema) ->willReturn($rootSchemaJson = json_encode(['version' => $version], \JSON_THROW_ON_ERROR)) + ->seal() ; - $this->urlGenerator + $urlGenerator ->expects(static::never()) ->method('generate') + ->seal() ; $request = new Request(); $request->setRequestFormat('json'); - $response = $this->object->apiDocAction($request, $version); + $response = $object->apiDocAction($request, $version); static::assertInstanceOf(JsonResponse::class, $response); static::assertSame(200, $response->getStatusCode()); diff --git a/packages/open-api/Tests/DependencyInjection/OpenApiIntegrationTest.php b/packages/open-api/Tests/DependencyInjection/OpenApiIntegrationTest.php index 11d2605b7..94ef59597 100644 --- a/packages/open-api/Tests/DependencyInjection/OpenApiIntegrationTest.php +++ b/packages/open-api/Tests/DependencyInjection/OpenApiIntegrationTest.php @@ -106,11 +106,9 @@ public function getDefaultConfiguration(): array ], 'versioning' => [ 'enabled' => false, - 'versions' => [ - ], - ], - 'definitionAliases' => [ + 'versions' => [], ], + 'definitionAliases' => [], 'classNamingFilters' => [ 0 => AliasesClassNamingFilter::class, ], diff --git a/packages/open-api/Tests/Event/PreDumpRootSchemaEventTest.php b/packages/open-api/Tests/Event/PreDumpRootSchemaEventTest.php index 70e50debf..32c29500f 100644 --- a/packages/open-api/Tests/Event/PreDumpRootSchemaEventTest.php +++ b/packages/open-api/Tests/Event/PreDumpRootSchemaEventTest.php @@ -6,7 +6,6 @@ use Draw\Component\OpenApi\Schema\Root; use PHPUnit\Framework\Attributes\CoversClass; use PHPUnit\Framework\TestCase; -use Symfony\Contracts\EventDispatcher\Event; /** * @internal @@ -25,14 +24,6 @@ protected function setUp(): void ); } - public function testConstruct(): void - { - static::assertInstanceOf( - Event::class, - $this->object - ); - } - public function testGetSchema(): void { static::assertSame( diff --git a/packages/open-api/Tests/EventListener/RequestQueryParameterFetcherListenerTest.php b/packages/open-api/Tests/EventListener/RequestQueryParameterFetcherListenerTest.php index ab0549406..67182844a 100644 --- a/packages/open-api/Tests/EventListener/RequestQueryParameterFetcherListenerTest.php +++ b/packages/open-api/Tests/EventListener/RequestQueryParameterFetcherListenerTest.php @@ -7,7 +7,6 @@ use PHPUnit\Framework\Attributes\CoversClass; use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; -use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\Event\ControllerEvent; use Symfony\Component\HttpKernel\HttpKernelInterface; @@ -27,14 +26,6 @@ protected function setUp(): void $this->object = new RequestQueryParameterFetcherListener(); } - public function testConstruct(): void - { - static::assertInstanceOf( - EventSubscriberInterface::class, - $this->object - ); - } - public function testSubscribedEvents(): void { static::assertSame( @@ -48,7 +39,7 @@ public function testSubscribedEvents(): void public function testOnKernelControllerUnParsableController(): void { $event = new ControllerEvent( - $this->createMock(HttpKernelInterface::class), + static::createStub(HttpKernelInterface::class), 'gettype', $request = new Request(), null @@ -64,7 +55,7 @@ public function testOnKernelControllerUnParsableController(): void public function testOnKernelControllerInvoke(): void { $event = new ControllerEvent( - $this->createMock(HttpKernelInterface::class), + static::createStub(HttpKernelInterface::class), $this, $request = new Request(), null @@ -80,7 +71,7 @@ public function testOnKernelControllerInvoke(): void public function testOnKernelControllerAttributeConflict(): void { $event = new ControllerEvent( - $this->createMock(HttpKernelInterface::class), + static::createStub(HttpKernelInterface::class), $this, $request = new Request(), null @@ -193,7 +184,7 @@ public function actionTestBooleanFalseFalse( public function testOnKernelController(string $methodName, mixed $value, mixed $expectedValue): void { $controllerEvent = new ControllerEvent( - $this->createMock(KernelInterface::class), + static::createStub(KernelInterface::class), [$this, $methodName], $request = new Request(), HttpKernelInterface::MAIN_REQUEST @@ -227,7 +218,7 @@ public static function provideOnKernelControllerCases(): iterable public function testOnKernelControllerInvalidArrayCollectionFormat(): void { $controllerEvent = new ControllerEvent( - $this->createMock(KernelInterface::class), + static::createStub(KernelInterface::class), [$this, 'multiAction'], $request = new Request(), HttpKernelInterface::MAIN_REQUEST diff --git a/packages/open-api/Tests/EventListener/RequestValidationListenerTest.php b/packages/open-api/Tests/EventListener/RequestValidationListenerTest.php index 3820050cf..813ac5934 100644 --- a/packages/open-api/Tests/EventListener/RequestValidationListenerTest.php +++ b/packages/open-api/Tests/EventListener/RequestValidationListenerTest.php @@ -6,11 +6,9 @@ use Draw\Component\OpenApi\Exception\ConstraintViolationListException; use Draw\Component\OpenApi\Request\ValueResolver\RequestBody; use Draw\Component\OpenApi\Schema\QueryParameter; -use Draw\Component\Tester\MockTrait; +use Draw\Component\Tester\DoubleTrait; use PHPUnit\Framework\Attributes\CoversClass; -use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; -use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\Event\ControllerArgumentsEvent; use Symfony\Component\HttpKernel\HttpKernelInterface; @@ -28,59 +26,53 @@ #[CoversClass(RequestValidationListener::class)] class RequestValidationListenerTest extends TestCase { - use MockTrait; + use DoubleTrait; - private RequestValidationListener $object; - - private ValidatorInterface&MockObject $validator; - - protected function setUp(): void - { - $this->object = new RequestValidationListener( - $this->validator = $this->createMock(ValidatorInterface::class) - ); - } - - public function testConstruct(): void + public function testSubscribedEvents(): void { - static::assertInstanceOf( - EventSubscriberInterface::class, - $this->object + $object = new RequestValidationListener( + static::createStub(ValidatorInterface::class) ); - } - public function testSubscribedEvents(): void - { static::assertSame( [ KernelEvents::CONTROLLER_ARGUMENTS => ['onKernelController', -5], ], - $this->object::getSubscribedEvents() + $object::getSubscribedEvents() ); } public function testOnKernelControllerNoValidation(): void { + $object = new RequestValidationListener( + $validator = $this->createMock(ValidatorInterface::class) + ); + $event = new ControllerArgumentsEvent( - $this->createMock(HttpKernelInterface::class), + static::createStub(HttpKernelInterface::class), 'gettype', [], new Request(), null ); - $this->validator + $validator ->expects(static::never()) ->method('validate') + ->seal() ; - $this->object->onKernelController($event); + $object->onKernelController($event); } public function testOnKernelControllerBodyValidationNoError(): void { + $object = new RequestValidationListener( + $validator = $this->createMock(ValidatorInterface::class) + ); + $event = new ControllerArgumentsEvent( - $this->createMock(HttpKernelInterface::class), + static::createStub(HttpKernelInterface::class), 'gettype', [], $request = new Request(), @@ -91,20 +83,25 @@ public function testOnKernelControllerBodyValidationNoError(): void $requestBody->argumentName = $name = uniqid('name-'); $request->attributes->set($name, $bodyObject = (object) []); - $this->validator + $validator ->expects(static::once()) ->method('validate') ->with($bodyObject, null, ['Default']) - ->willReturn($this->createMock(ConstraintViolationListInterface::class)) + ->willReturn(static::createStub(ConstraintViolationListInterface::class)) + ->seal() ; - $this->object->onKernelController($event); + $object->onKernelController($event); } public function testOnKernelControllerQueryParametersValidationNoError(): void { + $object = new RequestValidationListener( + $validator = $this->createMock(ValidatorInterface::class) + ); + $event = new ControllerArgumentsEvent( - $this->createMock(HttpKernelInterface::class), + static::createStub(HttpKernelInterface::class), 'gettype', [], $request = new Request(), @@ -116,20 +113,25 @@ public function testOnKernelControllerQueryParametersValidationNoError(): void $queryParameter->name = $name = uniqid('name-'); $request->attributes->set($name, $parameterObject = (object) []); - $this->validator + $validator ->expects(static::once()) ->method('validate') ->with($parameterObject, [], null) - ->willReturn($this->createMock(ConstraintViolationListInterface::class)) + ->willReturn(static::createStub(ConstraintViolationListInterface::class)) + ->seal() ; - $this->object->onKernelController($event); + $object->onKernelController($event); } public function testOnKernelControllerDoNotValidate(): void { + $object = new RequestValidationListener( + $validator = $this->createMock(ValidatorInterface::class) + ); + $event = new ControllerArgumentsEvent( - $this->createMock(HttpKernelInterface::class), + static::createStub(HttpKernelInterface::class), 'gettype', [], $request = new Request(), @@ -141,18 +143,23 @@ public function testOnKernelControllerDoNotValidate(): void $request->attributes->set($name, (object) []); - $this->validator + $validator ->expects(static::never()) ->method('validate') + ->seal() ; - $this->object->onKernelController($event); + $object->onKernelController($event); } public function testOnKernelControllerWithError(): void { + $object = new RequestValidationListener( + $validator = $this->createMock(ValidatorInterface::class) + ); + $event = new ControllerArgumentsEvent( - $this->createMock(HttpKernelInterface::class), + static::createStub(HttpKernelInterface::class), 'gettype', [], $request = new Request(), @@ -172,7 +179,7 @@ public function testOnKernelControllerWithError(): void $request->attributes->set($name, $parameterObject = (object) []); $queryParameter->constraints = [new NotNull()]; - $this->validator + $validator ->expects(static::exactly(2)) ->method('validate') ->with( @@ -185,6 +192,7 @@ public function testOnKernelControllerWithError(): void $bodyViolationList = new ConstraintViolationList(), $parameterViolationList = new ConstraintViolationList(), ) + ->seal() ; $bodyViolationList->add( @@ -210,7 +218,7 @@ public function testOnKernelControllerWithError(): void ); try { - $this->object->onKernelController($event); + $object->onKernelController($event); static::fail('Expect exception of type: '.ConstraintViolationListException::class); } catch (ConstraintViolationListException $error) { $violationList = $error->getViolationList(); diff --git a/packages/open-api/Tests/EventListener/ResponseApiExceptionListenerTest.php b/packages/open-api/Tests/EventListener/ResponseApiExceptionListenerTest.php index 5c4d5b9eb..dcd1df5dd 100644 --- a/packages/open-api/Tests/EventListener/ResponseApiExceptionListenerTest.php +++ b/packages/open-api/Tests/EventListener/ResponseApiExceptionListenerTest.php @@ -10,6 +10,7 @@ use Draw\Component\OpenApi\Schema\Response as OpenResponse; use Draw\Component\OpenApi\Schema\Root; use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\MockObject\Stub; use PHPUnit\Framework\TestCase; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; @@ -28,18 +29,21 @@ class ResponseApiExceptionListenerTest extends TestCase { private ResponseApiExceptionListener $object; - private HttpKernelInterface $httpKernel; + private HttpKernelInterface&Stub $httpKernel; + private \Exception $exception; + private ExceptionEvent $exceptionEvent; - private Request $request; + + private Request&Stub $request; protected function setUp(): void { $this->object = new ResponseApiExceptionListener(); $this->exceptionEvent = new ExceptionEvent( - $this->httpKernel = $this->createMock(HttpKernelInterface::class), - $this->request = $this->createMock(Request::class), + $this->httpKernel = static::createStub(HttpKernelInterface::class), + $this->request = static::createStub(Request::class), HttpKernelInterface::MAIN_REQUEST, $this->exception = new \Exception( previous: new \Exception() @@ -47,7 +51,6 @@ protected function setUp(): void ); $this->request - ->expects(static::any()) ->method('getRequestFormat') ->willReturn('json') ; @@ -91,13 +94,12 @@ public function testOnKernelExceptionNoneJsonRequest(): void { $this->exceptionEvent = new ExceptionEvent( $this->httpKernel, - $this->request = $this->createMock(Request::class), + $request = static::createStub(Request::class), HttpKernelInterface::MAIN_REQUEST, $this->exception ); - $this->request - ->expects(static::any()) + $request ->method('getRequestFormat') ->willReturn('html') ; diff --git a/packages/open-api/Tests/EventListener/ResponseSerializerListenerTest.php b/packages/open-api/Tests/EventListener/ResponseSerializerListenerTest.php index 7d853a4ca..492d3f587 100644 --- a/packages/open-api/Tests/EventListener/ResponseSerializerListenerTest.php +++ b/packages/open-api/Tests/EventListener/ResponseSerializerListenerTest.php @@ -9,9 +9,7 @@ use JMS\Serializer\SerializationContext; use JMS\Serializer\SerializerInterface; use PHPUnit\Framework\Attributes\CoversClass; -use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; -use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; @@ -28,64 +26,60 @@ #[CoversClass(ResponseSerializerListener::class)] class ResponseSerializerListenerTest extends TestCase { - private ResponseSerializerListener $object; - - private SerializerInterface&MockObject $serializer; - - private SerializationContextFactoryInterface&MockObject $serializationContextFactory; - - private EventDispatcherInterface&MockObject $eventDispatcher; - - protected function setUp(): void + public function testSubscribedEvents(): void { - $this->object = new ResponseSerializerListener( - $this->serializer = $this->createMock(SerializerInterface::class), - $this->serializationContextFactory = $this->createMock(SerializationContextFactoryInterface::class), - $this->eventDispatcher = $this->createMock(EventDispatcherInterface::class), + $object = new ResponseSerializerListener( + static::createStub(SerializerInterface::class), + static::createStub(SerializationContextFactoryInterface::class), + static::createStub(EventDispatcherInterface::class), false ); - } - public function testConstruct(): void - { - static::assertInstanceOf( - EventSubscriberInterface::class, - $this->object - ); - } - - public function testSubscribedEvents(): void - { static::assertSame( [ KernelEvents::VIEW => ['onKernelView', 30], KernelEvents::RESPONSE => ['onKernelResponse', 30], ], - $this->object::getSubscribedEvents() + $object::getSubscribedEvents() ); } public function testOnKernelViewAlreadyResponse(): void { + $object = new ResponseSerializerListener( + static::createStub(SerializerInterface::class), + $serializationContextFactory = $this->createMock(SerializationContextFactoryInterface::class), + static::createStub(EventDispatcherInterface::class), + false + ); + $event = new ViewEvent( - $this->createMock(HttpKernelInterface::class), + static::createStub(HttpKernelInterface::class), new Request(), HttpKernelInterface::MAIN_REQUEST, new Response() ); - $this->serializationContextFactory + $serializationContextFactory ->expects(static::never()) ->method('createSerializationContext') + ->seal() ; - $this->object->onKernelView($event); + $object->onKernelView($event); } public function testOnKernelViewRequestNotJson(): void { + $object = new ResponseSerializerListener( + static::createStub(SerializerInterface::class), + $serializationContextFactory = $this->createMock(SerializationContextFactoryInterface::class), + static::createStub(EventDispatcherInterface::class), + false + ); + $event = new ViewEvent( - $this->createMock(HttpKernelInterface::class), + static::createStub(HttpKernelInterface::class), $request = new Request(), HttpKernelInterface::MAIN_REQUEST, null @@ -93,18 +87,26 @@ public function testOnKernelViewRequestNotJson(): void $request->setRequestFormat('html'); - $this->serializationContextFactory + $serializationContextFactory ->expects(static::never()) ->method('createSerializationContext') + ->seal() ; - $this->object->onKernelView($event); + $object->onKernelView($event); } public function testOnKernelViewResponseNull(): void { + $object = new ResponseSerializerListener( + static::createStub(SerializerInterface::class), + $serializationContextFactory = $this->createMock(SerializationContextFactoryInterface::class), + static::createStub(EventDispatcherInterface::class), + false + ); + $event = new ViewEvent( - $this->createMock(HttpKernelInterface::class), + static::createStub(HttpKernelInterface::class), $request = new Request(), HttpKernelInterface::MAIN_REQUEST, null @@ -112,12 +114,13 @@ public function testOnKernelViewResponseNull(): void $request->setRequestFormat('json'); - $this->serializationContextFactory + $serializationContextFactory ->expects(static::never()) ->method('createSerializationContext') + ->seal() ; - $this->object->onKernelView($event); + $object->onKernelView($event); $response = $event->getResponse(); @@ -126,9 +129,16 @@ public function testOnKernelViewResponseNull(): void public function testOnKernelView(): void { + $object = new ResponseSerializerListener( + $serializer = $this->createMock(SerializerInterface::class), + $serializationContextFactory = $this->createMock(SerializationContextFactoryInterface::class), + $eventDispatcher = $this->createMock(EventDispatcherInterface::class), + false + ); + $result = (object) []; $event = new ViewEvent( - $this->createMock(HttpKernelInterface::class), + static::createStub(HttpKernelInterface::class), $request = new Request(), HttpKernelInterface::MAIN_REQUEST, $result @@ -136,10 +146,11 @@ public function testOnKernelView(): void $request->setRequestFormat('json'); - $this->serializationContextFactory + $serializationContextFactory ->expects(static::once()) ->method('createSerializationContext') ->willReturn($context = new SerializationContext()) + ->seal() ; $request->attributes->set( @@ -152,7 +163,7 @@ public function testOnKernelView(): void ) ); - $this->eventDispatcher + $eventDispatcher ->expects(static::once()) ->method('dispatch') ->with( @@ -192,16 +203,18 @@ function (PreSerializerResponseEvent $event) use ( } ) ) + ->seal() ; - $this->serializer + $serializer ->expects(static::once()) ->method('serialize') ->with($result, 'json', $context) ->willReturn($jsonResult = json_encode(['key' => uniqid('value-')], \JSON_THROW_ON_ERROR)) + ->seal() ; - $this->object->onKernelView($event); + $object->onKernelView($event); $response = $event->getResponse(); @@ -218,8 +231,15 @@ function (PreSerializerResponseEvent $event) use ( public function testOnKernelResponse(): void { + $object = new ResponseSerializerListener( + static::createStub(SerializerInterface::class), + static::createStub(SerializationContextFactoryInterface::class), + static::createStub(EventDispatcherInterface::class), + false + ); + $responseEvent = new ResponseEvent( - $this->createMock(HttpKernelInterface::class), + static::createStub(HttpKernelInterface::class), $request = new Request(), HttpKernelInterface::MAIN_REQUEST, $response = new Response() @@ -238,19 +258,28 @@ public function testOnKernelResponse(): void ->expects(static::once()) ->method('add') ->with($headers) + ->seal() ; $headerBag ->expects(static::once()) ->method('allPreserveCase') ->willReturn($headers) + ->seal() ; - $this->object->onKernelResponse($responseEvent); + $object->onKernelResponse($responseEvent); } public function testSetResponseHeaderInvalidResponseHeaderBag(): void { + $object = new ResponseSerializerListener( + static::createStub(SerializerInterface::class), + static::createStub(SerializationContextFactoryInterface::class), + static::createStub(EventDispatcherInterface::class), + false + ); + $request = new Request(); $request->attributes->set('_responseHeaderBag', (object) []); @@ -258,11 +287,18 @@ public function testSetResponseHeaderInvalidResponseHeaderBag(): void $this->expectException(\RuntimeException::class); $this->expectExceptionMessage('The current attribute value of [_responseHeaderBag] is invalid'); - $this->object::setResponseHeader($request, uniqid('key-'), ['values']); + $object::setResponseHeader($request, uniqid('key-'), ['values']); } public function testSetResponseHeader(): void { + $object = new ResponseSerializerListener( + static::createStub(SerializerInterface::class), + static::createStub(SerializationContextFactoryInterface::class), + static::createStub(EventDispatcherInterface::class), + false + ); + $request = new Request(); $request->attributes->set( @@ -278,8 +314,9 @@ public function testSetResponseHeader(): void $values = ['values'], false ) + ->seal() ; - $this->object::setResponseHeader($request, $key, $values, false); + $object::setResponseHeader($request, $key, $values, false); } } diff --git a/packages/open-api/Tests/EventListener/SchemaAddDefaultHeadersListenerTest.php b/packages/open-api/Tests/EventListener/SchemaAddDefaultHeadersListenerTest.php index 9cf219701..8525cd4c5 100644 --- a/packages/open-api/Tests/EventListener/SchemaAddDefaultHeadersListenerTest.php +++ b/packages/open-api/Tests/EventListener/SchemaAddDefaultHeadersListenerTest.php @@ -7,7 +7,6 @@ use JMS\Serializer\ArrayTransformerInterface; use PHPUnit\Framework\Attributes\CoversClass; use PHPUnit\Framework\TestCase; -use Symfony\Component\EventDispatcher\EventSubscriberInterface; /** * @internal @@ -21,15 +20,7 @@ protected function setUp(): void { $this->object = new SchemaAddDefaultHeadersListener( [], - $this->createMock(ArrayTransformerInterface::class) - ); - } - - public function testConstruct(): void - { - static::assertInstanceOf( - EventSubscriberInterface::class, - $this->object + static::createStub(ArrayTransformerInterface::class) ); } diff --git a/packages/open-api/Tests/Exception/ConstraintViolationListExceptionTest.php b/packages/open-api/Tests/Exception/ConstraintViolationListExceptionTest.php index 266cbb1c1..93fc88d0b 100644 --- a/packages/open-api/Tests/Exception/ConstraintViolationListExceptionTest.php +++ b/packages/open-api/Tests/Exception/ConstraintViolationListExceptionTest.php @@ -6,7 +6,6 @@ use PHPUnit\Framework\Attributes\CoversClass; use PHPUnit\Framework\TestCase; use Symfony\Component\Validator\ConstraintViolationList; -use Symfony\Component\Validator\Exception\ValidatorException; /** * @internal @@ -25,14 +24,6 @@ protected function setUp(): void ); } - public function testConstruct(): void - { - static::assertInstanceOf( - ValidatorException::class, - $this->object - ); - } - public function testGetViolationList(): void { static::assertSame( diff --git a/packages/open-api/Tests/Exception/ExtractionImpossibleExceptionTest.php b/packages/open-api/Tests/Exception/ExtractionImpossibleExceptionTest.php deleted file mode 100644 index 49daa4eeb..000000000 --- a/packages/open-api/Tests/Exception/ExtractionImpossibleExceptionTest.php +++ /dev/null @@ -1,29 +0,0 @@ -object = new ExtractionImpossibleException(); - } - - public function testConstruct(): void - { - static::assertInstanceOf( - \Exception::class, - $this->object - ); - } -} diff --git a/packages/open-api/Tests/Extraction/Extractor/JmsSerializer/PropertiesExtractorTest.php b/packages/open-api/Tests/Extraction/Extractor/JmsSerializer/PropertiesExtractorTest.php index 13d8fd353..aaad8b4b4 100644 --- a/packages/open-api/Tests/Extraction/Extractor/JmsSerializer/PropertiesExtractorTest.php +++ b/packages/open-api/Tests/Extraction/Extractor/JmsSerializer/PropertiesExtractorTest.php @@ -9,7 +9,6 @@ use Draw\Component\OpenApi\Extraction\Extractor\TypeSchemaExtractor; use Draw\Component\OpenApi\OpenApi; use Draw\Component\OpenApi\Schema\Schema; -use Draw\Component\Tester\MockTrait; use JMS\Serializer\Annotation as Serializer; use JMS\Serializer\Naming\CamelCaseNamingStrategy; use JMS\Serializer\Naming\SerializedNameAnnotationStrategy; @@ -26,8 +25,6 @@ #[CoversClass(PropertiesExtractor::class)] class PropertiesExtractorTest extends TestCase { - use MockTrait; - private PropertiesExtractor $jmsExtractor; protected function setUp(): void @@ -55,7 +52,7 @@ public function testCanExtract(mixed $source, mixed $type, bool $canBeExtract): $this->jmsExtractor->canExtract( $source, $type, - $context = $this->createMock(ExtractionContextInterface::class) + $context = static::createStub(ExtractionContextInterface::class) ) ); diff --git a/packages/open-api/Tests/Extraction/Extractor/OpenApi/RootSchemaExtractorTest.php b/packages/open-api/Tests/Extraction/Extractor/OpenApi/RootSchemaExtractorTest.php index 66aa215e1..191345e57 100644 --- a/packages/open-api/Tests/Extraction/Extractor/OpenApi/RootSchemaExtractorTest.php +++ b/packages/open-api/Tests/Extraction/Extractor/OpenApi/RootSchemaExtractorTest.php @@ -6,7 +6,6 @@ use Draw\Component\OpenApi\Extraction\ExtractionContextInterface; use Draw\Component\OpenApi\Extraction\Extractor\OpenApi\JsonRootSchemaExtractor; use Draw\Component\OpenApi\Schema\Root; -use Draw\Component\Tester\MockTrait; use JMS\Serializer\SerializerBuilder; use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; @@ -16,8 +15,6 @@ */ class RootSchemaExtractorTest extends TestCase { - use MockTrait; - #[DataProvider('provideCanExtractCases')] public function testCanExtract(mixed $source, mixed $type, bool $expected): void { @@ -28,7 +25,7 @@ public function testCanExtract(mixed $source, mixed $type, bool $expected): void $extractor->canExtract( $source, $type, - $context = $this->createMock(ExtractionContextInterface::class) + $context = static::createStub(ExtractionContextInterface::class) ) ); diff --git a/packages/open-api/Tests/Extraction/Extractor/PhpDoc/OperationExtractorTest.php b/packages/open-api/Tests/Extraction/Extractor/PhpDoc/OperationExtractorTest.php index a7b905884..cdc6a371a 100644 --- a/packages/open-api/Tests/Extraction/Extractor/PhpDoc/OperationExtractorTest.php +++ b/packages/open-api/Tests/Extraction/Extractor/PhpDoc/OperationExtractorTest.php @@ -11,7 +11,6 @@ use Draw\Component\OpenApi\Schema\Operation; use Draw\Component\OpenApi\Schema\PathItem; use Draw\Component\OpenApi\Schema\QueryParameter; -use Draw\Component\Tester\MockTrait; use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; @@ -20,8 +19,6 @@ */ class OperationExtractorTest extends TestCase { - use MockTrait; - private OperationExtractor $phpDocOperationExtractor; protected function setUp(): void @@ -37,7 +34,7 @@ public function testCanExtract(mixed $source, mixed $type, bool $canBeExtract): $this->phpDocOperationExtractor->canExtract( $source, $type, - $context = $this->createMock(ExtractionContextInterface::class) + $context = static::createStub(ExtractionContextInterface::class) ) ); diff --git a/packages/open-api/Tests/Extraction/Extractor/TypeSchemaExtractorTest.php b/packages/open-api/Tests/Extraction/Extractor/TypeSchemaExtractorTest.php index d26869600..d00232f16 100644 --- a/packages/open-api/Tests/Extraction/Extractor/TypeSchemaExtractorTest.php +++ b/packages/open-api/Tests/Extraction/Extractor/TypeSchemaExtractorTest.php @@ -27,7 +27,7 @@ protected function setUp(): void #[DataProvider('provideCanExtractCases')] public function testCanExtract(mixed $source, mixed $type, bool $canBeExtract): void { - $context = $this->createMock(ExtractionContextInterface::class); + $context = static::createStub(ExtractionContextInterface::class); static::assertSame( $canBeExtract, diff --git a/packages/open-api/Tests/HttpFoundation/ErrorToHttpCodeConverter/ConfigurableErrorToHttpCodeConverterTest.php b/packages/open-api/Tests/HttpFoundation/ErrorToHttpCodeConverter/ConfigurableErrorToHttpCodeConverterTest.php index d58b8c1c7..c31566f63 100644 --- a/packages/open-api/Tests/HttpFoundation/ErrorToHttpCodeConverter/ConfigurableErrorToHttpCodeConverterTest.php +++ b/packages/open-api/Tests/HttpFoundation/ErrorToHttpCodeConverter/ConfigurableErrorToHttpCodeConverterTest.php @@ -3,7 +3,6 @@ namespace Draw\Component\OpenApi\Tests\HttpFoundation\ErrorToHttpCodeConverter; use Draw\Component\OpenApi\HttpFoundation\ErrorToHttpCodeConverter\ConfigurableErrorToHttpCodeConverter; -use Draw\Component\OpenApi\HttpFoundation\ErrorToHttpCodeConverter\ErrorToHttpCodeConverterInterface; use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; @@ -19,14 +18,6 @@ protected function setUp(): void $this->errorToHttpCodeConverter = new ConfigurableErrorToHttpCodeConverter(); } - public function testConstruct(): void - { - static::assertInstanceOf( - ErrorToHttpCodeConverterInterface::class, - $this->errorToHttpCodeConverter - ); - } - /** * @param array $errorCodes */ @@ -74,8 +65,12 @@ public static function provideConvertToHttpCodeCases(): iterable ]; $exception = new class extends \Exception implements \JsonSerializable { - public function jsonSerialize(): void + public function jsonSerialize(): mixed { + return [ + 'message' => $this->getMessage(), + 'code' => $this->getCode(), + ]; } }; diff --git a/packages/open-api/Tests/HttpFoundation/ErrorToHttpCodeConverter/HttpExceptionToHttpCodeConverterTest.php b/packages/open-api/Tests/HttpFoundation/ErrorToHttpCodeConverter/HttpExceptionToHttpCodeConverterTest.php index 68cbe81c8..59c4290e2 100644 --- a/packages/open-api/Tests/HttpFoundation/ErrorToHttpCodeConverter/HttpExceptionToHttpCodeConverterTest.php +++ b/packages/open-api/Tests/HttpFoundation/ErrorToHttpCodeConverter/HttpExceptionToHttpCodeConverterTest.php @@ -2,7 +2,6 @@ namespace Draw\Component\OpenApi\Tests\HttpFoundation\ErrorToHttpCodeConverter; -use Draw\Component\OpenApi\HttpFoundation\ErrorToHttpCodeConverter\ErrorToHttpCodeConverterInterface; use Draw\Component\OpenApi\HttpFoundation\ErrorToHttpCodeConverter\HttpExceptionToHttpCodeConverter; use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; @@ -21,14 +20,6 @@ protected function setUp(): void $this->httpExceptionToHttpCodeConverter = new HttpExceptionToHttpCodeConverter(); } - public function testConstruct(): void - { - static::assertInstanceOf( - ErrorToHttpCodeConverterInterface::class, - $this->httpExceptionToHttpCodeConverter - ); - } - #[DataProvider('provideConvertToHttpCodeCases')] public function testConvertToHttpCode(\Throwable $throwable, ?int $expectedErrorCode): void { diff --git a/packages/open-api/Tests/Naming/AliasesClassNamingFilterTest.php b/packages/open-api/Tests/Naming/AliasesClassNamingFilterTest.php index c36cd326a..54490812a 100644 --- a/packages/open-api/Tests/Naming/AliasesClassNamingFilterTest.php +++ b/packages/open-api/Tests/Naming/AliasesClassNamingFilterTest.php @@ -3,7 +3,6 @@ namespace Draw\Component\OpenApi\Tests\Naming; use Draw\Component\OpenApi\Naming\AliasesClassNamingFilter; -use Draw\Component\OpenApi\Naming\ClassNamingFilterInterface; use PHPUnit\Framework\Attributes\CoversClass; use PHPUnit\Framework\TestCase; @@ -37,14 +36,6 @@ protected function setUp(): void ); } - public function testConstruct(): void - { - static::assertInstanceOf( - ClassNamingFilterInterface::class, - $this->object - ); - } - public function testFilterClassNameNoChange(): void { static::assertSame( diff --git a/packages/open-api/Tests/OpenApiTest.php b/packages/open-api/Tests/OpenApiTest.php index 4eaa5620a..939bb90b4 100644 --- a/packages/open-api/Tests/OpenApiTest.php +++ b/packages/open-api/Tests/OpenApiTest.php @@ -57,9 +57,24 @@ public function testExtractExtractionCompletedException(): void $extractor2 = $this->createMock(ExtractorInterface::class), ]); - $extractor1->expects(static::once())->method('canExtract')->willReturn(true); - $extractor1->expects(static::once())->method('extract')->willThrowException(new ExtractionCompletedException()); - $extractor2->expects(static::never())->method('canExtract'); + $extractor1 + ->expects(static::once()) + ->method('canExtract') + ->willReturn(true) + ; + + $extractor1 + ->expects(static::once()) + ->method('extract') + ->willThrowException(new ExtractionCompletedException()) + ->seal() + ; + + $extractor2 + ->expects(static::never()) + ->method('canExtract') + ->seal() + ; $this->object->extract(''); } diff --git a/packages/open-api/composer.json b/packages/open-api/composer.json index 9fdf03307..a41d84cf5 100644 --- a/packages/open-api/composer.json +++ b/packages/open-api/composer.json @@ -20,7 +20,7 @@ "doctrine/common": "^3.1", "doctrine/doctrine-bundle": "^2.5", "doctrine/orm": "^3.6", - "phpunit/phpunit": "^11.3 || ^12.0" + "phpunit/phpunit": "^11.3 || ^12.0 || ^13.0" }, "conflict": { "draw/swagger": "*" diff --git a/packages/process/Tests/ProcessFactoryTest.php b/packages/process/Tests/ProcessFactoryTest.php index 56c916264..5828776e0 100644 --- a/packages/process/Tests/ProcessFactoryTest.php +++ b/packages/process/Tests/ProcessFactoryTest.php @@ -6,7 +6,6 @@ use Draw\Contracts\Process\ProcessFactoryInterface; use PHPUnit\Framework\Attributes\CoversClass; use PHPUnit\Framework\TestCase; -use Symfony\Component\Process\Process; /** * @internal @@ -24,20 +23,10 @@ protected function setUp(): void $this->service = new ProcessFactory(); } - public function testConstruct(): void - { - static::assertInstanceOf( - ProcessFactoryInterface::class, - $this->service - ); - } - public function testCreateDefault(): void { $process = $this->service->create(['cd']); - static::assertInstanceOf(Process::class, $process); - static::assertSame( "'cd'", $process->getCommandLine() @@ -72,8 +61,6 @@ public function testCreateWithArguments(): void $timeout = 5.0 ); - static::assertInstanceOf(Process::class, $process); - static::assertSame( "'cd'", $process->getCommandLine() @@ -104,7 +91,6 @@ public function testCreateFromShellCommandLineDefault(): void { $process = $this->service->createFromShellCommandLine('ls -lah | grep test'); - static::assertInstanceOf(Process::class, $process); static::assertSame('ls -lah | grep test', $process->getCommandLine()); static::assertSame(getcwd(), $process->getWorkingDirectory()); static::assertEmpty($process->getEnv()); @@ -122,7 +108,6 @@ public function testCreateFromShellCommandLineWithArguments(): void $timeout = 5.0 ); - static::assertInstanceOf(Process::class, $process); static::assertSame('ls -lah | grep test', $process->getCommandLine()); static::assertSame($workingDirectory, $process->getWorkingDirectory()); static::assertSame($env, $process->getEnv()); diff --git a/packages/process/composer.json b/packages/process/composer.json index 97a5ee0d0..0f8e2b688 100644 --- a/packages/process/composer.json +++ b/packages/process/composer.json @@ -20,7 +20,7 @@ }, "require-dev": { "draw/dependency-injection": "^0.39", - "phpunit/phpunit": "^11.3 || ^12.0" + "phpunit/phpunit": "^11.3 || ^12.0 || ^13.0" }, "minimum-stability": "dev", "prefer-stable": true, diff --git a/packages/profiling/Tests/ProfilerCoordinatorTest.php b/packages/profiling/Tests/ProfilerCoordinatorTest.php index caa9a46cb..a308add30 100644 --- a/packages/profiling/Tests/ProfilerCoordinatorTest.php +++ b/packages/profiling/Tests/ProfilerCoordinatorTest.php @@ -16,15 +16,9 @@ class ProfilerCoordinatorTest extends TestCase private ProfilerCoordinator $object; - /** - * @var ProfilerInterface&MockObject - */ - private ProfilerInterface $profiler; - protected function setUp(): void { $this->object = new ProfilerCoordinator(); - $this->profiler = $this->createMock(ProfilerInterface::class); } public function testIsStartedDefault(): void @@ -47,24 +41,64 @@ public function testIsStartedAfterStop(): void public function testRegisterProfile(): void { - $this->profiler->expects(static::once())->method('getType')->willReturn(self::PROFILER_TYPE); - $this->object->registerProfiler($this->profiler); + $this->doTestRegisterProfile(); } public function testStarAll(): void { - $this->testRegisterProfile(); - $this->profiler->expects(static::once())->method('start'); - $this->object->startAll(); + $this->doTestStartAll(); } public function testStopAll(): void { - $this->testStarAll(); - $this->profiler->expects(static::once())->method('stop')->willReturn($result = 'result'); + $profiler = $this->doTestStartAll(false); + $profiler + ->expects(static::once()) + ->method('stop') + ->willReturn($result = 'result') + ->seal() + ; + $metrics = $this->object->stopAll(); static::assertTrue(isset($metrics->{self::PROFILER_TYPE})); static::assertSame($result, $metrics->{self::PROFILER_TYPE}); } + + private function doTestRegisterProfile(bool $seal = true): ProfilerInterface&MockObject + { + $profiler = $this->createMock(ProfilerInterface::class); + + $invokation = $profiler + ->expects(static::once()) + ->method('getType') + ->willReturn(self::PROFILER_TYPE) + ; + + if ($seal) { + $invokation->seal(); + } + + $this->object->registerProfiler($profiler); + + return $profiler; + } + + private function doTestStartAll(bool $seal = true): ProfilerInterface&MockObject + { + $profiler = $this->doTestRegisterProfile(false); + + $invokation = $profiler + ->expects(static::once()) + ->method('start') + ; + + if ($seal) { + $invokation->seal(); + } + + $this->object->startAll(); + + return $profiler; + } } diff --git a/packages/profiling/Tests/Sql/SqlMetricBuilderTest.php b/packages/profiling/Tests/Sql/SqlMetricBuilderTest.php index f73d192f4..4ee19e3a0 100644 --- a/packages/profiling/Tests/Sql/SqlMetricBuilderTest.php +++ b/packages/profiling/Tests/Sql/SqlMetricBuilderTest.php @@ -2,9 +2,7 @@ namespace Draw\Component\Profiling\Tests\Sql; -use Draw\Component\Profiling\MetricBuilderInterface; use Draw\Component\Profiling\Sql\SqlLog; -use Draw\Component\Profiling\Sql\SqlMetric; use Draw\Component\Profiling\Sql\SqlMetricBuilder; use PHPUnit\Framework\TestCase; @@ -20,17 +18,11 @@ protected function setUp(): void $this->metricBuilder = new SqlMetricBuilder(); } - public function testConstruct(): void - { - static::assertInstanceOf(MetricBuilderInterface::class, $this->metricBuilder); - } - public function testBuild(): void { $this->metricBuilder->addLog(new SqlLog('query')); $metric = $this->metricBuilder->build(); - static::assertInstanceOf(SqlMetric::class, $metric); static::assertSame(1, $metric->count); static::assertSame( ['query'], diff --git a/packages/profiling/Tests/Sql/SqlProfilerTest.php b/packages/profiling/Tests/Sql/SqlProfilerTest.php index 1f451b2de..665ff3230 100644 --- a/packages/profiling/Tests/Sql/SqlProfilerTest.php +++ b/packages/profiling/Tests/Sql/SqlProfilerTest.php @@ -2,11 +2,8 @@ namespace Draw\Component\Profiling\Tests\Sql; -use Draw\Component\Profiling\Sql\SqlMetric; -use Draw\Component\Profiling\Sql\SqlMetricBuilder; use Draw\Component\Profiling\Sql\SqlProfiler; -use Draw\Component\Tester\MockTrait; -use PHPUnit\Framework\MockObject\MockObject; +use PHPUnit\Framework\MockObject\Stub; use PHPUnit\Framework\TestCase; /** @@ -14,13 +11,11 @@ */ class SqlProfilerTest extends TestCase { - use MockTrait; - - private SqlProfiler&MockObject $profiler; + private SqlProfiler&Stub $profiler; protected function setUp(): void { - $this->profiler = $this->createMock(SqlProfiler::class); + $this->profiler = static::createStub(SqlProfiler::class); $this->profiler ->method('getType') ->willReturn(SqlProfiler::PROFILER_TYPE) @@ -32,16 +27,10 @@ public function testGetType(): void static::assertSame(SqlProfiler::PROFILER_TYPE, $this->profiler->getType()); } - public function testGetMetricBuilder(): void - { - static::assertInstanceOf(SqlMetricBuilder::class, $this->profiler->getMetricBuilder()); - } - public function testStop(): void { $metric = $this->profiler->stop(); - static::assertInstanceOf(SqlMetric::class, $metric); static::assertSame(0, $metric->count); } } diff --git a/packages/profiling/composer.json b/packages/profiling/composer.json index 9b0fe6db6..2ed052709 100644 --- a/packages/profiling/composer.json +++ b/packages/profiling/composer.json @@ -17,7 +17,7 @@ ], "require-dev": { "draw/tester": "^0.39", - "phpunit/phpunit": "^11.3 || ^12.0" + "phpunit/phpunit": "^11.3 || ^12.0 || ^13.0" }, "minimum-stability": "dev", "prefer-stable": true, diff --git a/packages/security/Core/Authentication/Token/SystemToken.php b/packages/security/Core/Authentication/Token/SystemToken.php index 9b71b4591..c44e0b5b9 100644 --- a/packages/security/Core/Authentication/Token/SystemToken.php +++ b/packages/security/Core/Authentication/Token/SystemToken.php @@ -25,12 +25,12 @@ public function getUserIdentifier(): string return 'system'; } - public function getPassword(): ?string + public function getPassword(): null { return null; } - public function getSalt(): ?string + public function getSalt(): null { return null; } @@ -39,7 +39,7 @@ public function eraseCredentials(): void { } - public function getUsername(): ?string + public function getUsername(): null { return null; } diff --git a/packages/security/Tests/Core/Event/CheckPostAuthEventTest.php b/packages/security/Tests/Core/Event/CheckPostAuthEventTest.php index 1ba8b0e41..a880f00c3 100644 --- a/packages/security/Tests/Core/Event/CheckPostAuthEventTest.php +++ b/packages/security/Tests/Core/Event/CheckPostAuthEventTest.php @@ -20,7 +20,7 @@ class CheckPostAuthEventTest extends TestCase protected function setUp(): void { $this->event = new CheckPostAuthEvent( - $this->user = $this->createMock(UserInterface::class) + $this->user = static::createStub(UserInterface::class) ); } diff --git a/packages/security/Tests/Core/Event/CheckPreAuthEventTest.php b/packages/security/Tests/Core/Event/CheckPreAuthEventTest.php index a7c3bea26..a654835cf 100644 --- a/packages/security/Tests/Core/Event/CheckPreAuthEventTest.php +++ b/packages/security/Tests/Core/Event/CheckPreAuthEventTest.php @@ -20,7 +20,7 @@ class CheckPreAuthEventTest extends TestCase protected function setUp(): void { $this->event = new CheckPreAuthEvent( - $this->user = $this->createMock(UserInterface::class) + $this->user = static::createStub(UserInterface::class) ); } diff --git a/packages/security/Tests/Core/EventListener/SystemConsoleAuthenticatorListenerTest.php b/packages/security/Tests/Core/EventListener/SystemConsoleAuthenticatorListenerTest.php index 6727847c2..4a56859c9 100644 --- a/packages/security/Tests/Core/EventListener/SystemConsoleAuthenticatorListenerTest.php +++ b/packages/security/Tests/Core/EventListener/SystemConsoleAuthenticatorListenerTest.php @@ -1,17 +1,14 @@ object = new SystemConsoleAuthenticatorListener( - $this->tokenStorage = $this->createMock(TokenStorageInterface::class), - $this->systemAuthenticator = $this->createMock(SystemAuthenticatorInterface::class), + $object = new SystemConsoleAuthenticatorListener( + static::createStub(TokenStorageInterface::class), + static::createStub(SystemAuthenticatorInterface::class), true ); - } - public function testConstruct(): void - { - static::assertInstanceOf( - EventSubscriberInterface::class, - $this->object - ); - } - - public function testGetSubscribedEvents(): void - { static::assertSame( [ ConsoleCommandEvent::class => [ @@ -52,15 +32,21 @@ public function testGetSubscribedEvents(): void ['connectSystem', 0], ], ], - $this->object::getSubscribedEvents() + $object::getSubscribedEvents() ); } public function testAddOptions(): void { + $object = new SystemConsoleAuthenticatorListener( + static::createStub(TokenStorageInterface::class), + static::createStub(SystemAuthenticatorInterface::class), + true + ); + $consoleCommandEvent = $this->createConsoleCommandEvent(); - $this->object->addOptions($consoleCommandEvent); + $object->addOptions($consoleCommandEvent); $definition = $consoleCommandEvent->getCommand()->getDefinition(); @@ -74,137 +60,167 @@ public function testAddOptions(): void public function testConnectSystemAutoConnect(): void { - ReflectionAccessor::setPropertiesValue($this->object, ['systemAutoLogin' => true]); + $object = new SystemConsoleAuthenticatorListener( + $tokenStorage = $this->createMock(TokenStorageInterface::class), + $systemAuthenticator = $this->createMock(SystemAuthenticatorInterface::class), + true + ); $consoleCommandEvent = $this->createConsoleCommandEvent(); - $this->tokenStorage + $tokenStorage ->expects(static::once()) ->method('getToken') ->willReturn(null) ; - $this->systemAuthenticator + $systemAuthenticator ->expects(static::once()) ->method('getTokenForSystem') - ->willReturn($token = $this->createMock(TokenInterface::class)) + ->willReturn($token = static::createStub(TokenInterface::class)) + ->seal() ; - $this->tokenStorage + $tokenStorage ->expects(static::once()) ->method('setToken') ->with($token) + ->seal() ; - $this->object->connectSystem($consoleCommandEvent); + $object->connectSystem($consoleCommandEvent); } public function testConnectSystemAutoConnectDisabled(): void { - ReflectionAccessor::setPropertiesValue($this->object, ['systemAutoLogin' => false]); + $object = new SystemConsoleAuthenticatorListener( + $tokenStorage = $this->createMock(TokenStorageInterface::class), + $systemAuthenticator = $this->createMock(SystemAuthenticatorInterface::class), + false + ); $consoleCommandEvent = $this->createConsoleCommandEvent(); - $this->tokenStorage + $tokenStorage ->expects(static::never()) ->method('getToken') ->willReturn(null) ; - $this->systemAuthenticator + $systemAuthenticator ->expects(static::never()) ->method('getTokenForSystem') + ->seal() ; - $this->tokenStorage + $tokenStorage ->expects(static::never()) ->method('setToken') + ->seal() ; - $this->object->connectSystem($consoleCommandEvent); + $object->connectSystem($consoleCommandEvent); } public function testConnectSystemAutoConnectAlreadyConnected(): void { - ReflectionAccessor::setPropertiesValue($this->object, ['systemAutoLogin' => true]); + $object = new SystemConsoleAuthenticatorListener( + $tokenStorage = $this->createMock(TokenStorageInterface::class), + $systemAuthenticator = $this->createMock(SystemAuthenticatorInterface::class), + true + ); $consoleCommandEvent = $this->createConsoleCommandEvent(); - $this->tokenStorage + $tokenStorage ->expects(static::once()) ->method('getToken') - ->willReturn($this->createMock(TokenInterface::class)) + ->willReturn(static::createStub(TokenInterface::class)) ; - $this->systemAuthenticator + $systemAuthenticator ->expects(static::never()) ->method('getTokenForSystem') + ->seal() ; - $this->tokenStorage + $tokenStorage ->expects(static::never()) ->method('setToken') + ->seal() ; - $this->object->connectSystem($consoleCommandEvent); + $object->connectSystem($consoleCommandEvent); } public function testConnectSystemAutoConnectWithOption(): void { - ReflectionAccessor::setPropertiesValue($this->object, ['systemAutoLogin' => false]); + $object = new SystemConsoleAuthenticatorListener( + $tokenStorage = $this->createMock(TokenStorageInterface::class), + $systemAuthenticator = $this->createMock(SystemAuthenticatorInterface::class), + false + ); $consoleCommandEvent = $this->createConsoleCommandEvent(['--as-system' => true]); - $this->object->addOptions($consoleCommandEvent); + $object->addOptions($consoleCommandEvent); - $this->tokenStorage + $tokenStorage ->expects(static::once()) ->method('getToken') ->willReturn(null) ; - $this->systemAuthenticator + $systemAuthenticator ->expects(static::once()) ->method('getTokenForSystem') - ->willReturn($token = $this->createMock(TokenInterface::class)) + ->willReturn($token = static::createStub(TokenInterface::class)) + ->seal() ; - $this->tokenStorage + $tokenStorage ->expects(static::once()) ->method('setToken') ->with($token) + ->seal() ; - $this->object->connectSystem($consoleCommandEvent); + $object->connectSystem($consoleCommandEvent); } public function testConnectSystemAutoConnectWithOptionAndSystemAutoLogin(): void { - ReflectionAccessor::setPropertiesValue($this->object, ['systemAutoLogin' => true]); + $object = new SystemConsoleAuthenticatorListener( + $tokenStorage = $this->createMock(TokenStorageInterface::class), + $systemAuthenticator = $this->createMock(SystemAuthenticatorInterface::class), + false + ); $consoleCommandEvent = $this->createConsoleCommandEvent(['--as-system' => true]); - $this->object->addOptions($consoleCommandEvent); + $object->addOptions($consoleCommandEvent); - $this->tokenStorage + $tokenStorage ->expects(static::once()) ->method('getToken') ->willReturn(null) ; - $this->systemAuthenticator + $systemAuthenticator ->expects(static::once()) ->method('getTokenForSystem') - ->willReturn($token = $this->createMock(TokenInterface::class)) + ->willReturn($token = static::createStub(TokenInterface::class)) + ->seal() ; - $this->tokenStorage + $tokenStorage ->expects(static::once()) ->method('setToken') ->with($token) + ->seal() ; - $this->object->connectSystem($consoleCommandEvent); + $object->connectSystem($consoleCommandEvent); } protected function createConsoleCommandEvent(array $input = []): ConsoleCommandEvent diff --git a/packages/security/Tests/Core/EventListener/SystemMessengerAuthenticatorListenerTest.php b/packages/security/Tests/Core/EventListener/SystemMessengerAuthenticatorListenerTest.php index b796a0327..a3aa7d3e4 100644 --- a/packages/security/Tests/Core/EventListener/SystemMessengerAuthenticatorListenerTest.php +++ b/packages/security/Tests/Core/EventListener/SystemMessengerAuthenticatorListenerTest.php @@ -4,9 +4,7 @@ use Draw\Component\Security\Core\Authentication\SystemAuthenticatorInterface; use Draw\Component\Security\Core\EventListener\SystemMessengerAuthenticatorListener; -use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; -use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\Messenger\Event\WorkerMessageReceivedEvent; use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; @@ -16,74 +14,70 @@ */ class SystemMessengerAuthenticatorListenerTest extends TestCase { - private SystemMessengerAuthenticatorListener $object; - - private MockObject&TokenStorageInterface $tokenStorage; - - private MockObject&SystemAuthenticatorInterface $systemAuthenticator; - - protected function setUp(): void + public function testGetSubscribedEvents(): void { - $this->object = new SystemMessengerAuthenticatorListener( - $this->tokenStorage = $this->createMock(TokenStorageInterface::class), - $this->systemAuthenticator = $this->createMock(SystemAuthenticatorInterface::class) + $object = new SystemMessengerAuthenticatorListener( + static::createStub(TokenStorageInterface::class), + static::createStub(SystemAuthenticatorInterface::class) ); - } - public function testConstruct(): void - { - static::assertInstanceOf( - EventSubscriberInterface::class, - $this->object - ); - } - - public function testGetSubscribedEvents(): void - { static::assertSame( [ WorkerMessageReceivedEvent::class => 'connectSystem', ], - $this->object::getSubscribedEvents() + $object::getSubscribedEvents() ); } public function testConnectSystemAlreadyConnected(): void { - $this->tokenStorage + $object = new SystemMessengerAuthenticatorListener( + $tokenStorage = $this->createMock(TokenStorageInterface::class), + static::createStub(SystemAuthenticatorInterface::class) + ); + + $tokenStorage ->expects(static::once()) ->method('getToken') - ->willReturn($this->createMock(TokenInterface::class)) + ->willReturn(static::createStub(TokenInterface::class)) ; - $this->tokenStorage + $tokenStorage ->expects(static::never()) ->method('setToken') + ->seal() ; - $this->object->connectSystem(); + $object->connectSystem(); } public function testConnectSystemNotConnected(): void { - $this->tokenStorage + $object = new SystemMessengerAuthenticatorListener( + $tokenStorage = $this->createMock(TokenStorageInterface::class), + $systemAuthenticator = $this->createMock(SystemAuthenticatorInterface::class) + ); + + $tokenStorage ->expects(static::once()) ->method('getToken') ->willReturn(null) ; - $this->tokenStorage + $tokenStorage ->expects(static::once()) ->method('setToken') - ->with($token = $this->createMock(TokenInterface::class)) + ->with($token = static::createStub(TokenInterface::class)) + ->seal() ; - $this->systemAuthenticator + $systemAuthenticator ->expects(static::once()) ->method('getTokenForSystem') ->willReturn($token) + ->seal() ; - $this->object->connectSystem(); + $object->connectSystem(); } } diff --git a/packages/security/Tests/Core/User/EventDrivenUserCheckerTest.php b/packages/security/Tests/Core/User/EventDrivenUserCheckerTest.php index 779def210..6242e3586 100644 --- a/packages/security/Tests/Core/User/EventDrivenUserCheckerTest.php +++ b/packages/security/Tests/Core/User/EventDrivenUserCheckerTest.php @@ -32,22 +32,15 @@ protected function setUp(): void ); } - public function testConstruct(): void - { - static::assertInstanceOf( - UserCheckerInterface::class, - $this->object - ); - } - public function testCheckPreAuth(): void { - $user = $this->createMock(UserInterface::class); + $user = static::createStub(UserInterface::class); $this->decoratedUserChecker ->expects(static::once()) ->method('checkPreAuth') ->with($user) + ->seal() ; $this->eventDispatcher @@ -64,6 +57,7 @@ public function testCheckPreAuth(): void }) ) ->willReturnArgument(0) + ->seal() ; $this->object->checkPreAuth($user); @@ -71,12 +65,13 @@ public function testCheckPreAuth(): void public function testCheckPostAuth(): void { - $user = $this->createMock(UserInterface::class); + $user = static::createStub(UserInterface::class); $this->decoratedUserChecker ->expects(static::once()) ->method('checkPostAuth') ->with($user) + ->seal() ; $this->eventDispatcher @@ -93,6 +88,7 @@ public function testCheckPostAuth(): void }) ) ->willReturnArgument(0) + ->seal() ; $this->object->checkPostAuth($user); diff --git a/packages/security/Tests/Http/Authenticator/JwtAuthenticatorTest.php b/packages/security/Tests/Http/Authenticator/JwtAuthenticatorTest.php index 056ed4765..87b9b51d5 100644 --- a/packages/security/Tests/Http/Authenticator/JwtAuthenticatorTest.php +++ b/packages/security/Tests/Http/Authenticator/JwtAuthenticatorTest.php @@ -7,9 +7,7 @@ use Draw\Component\Security\Http\Authenticator\Passport\Badge\JwtPayloadBadge; use Draw\Component\Security\Jwt\JwtEncoder; use Draw\Component\Security\Tests\Stub\JwtAuthenticatableUserInterface; -use Draw\Component\Tester\MockTrait; use PHPUnit\Framework\Attributes\CoversClass; -use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; @@ -20,7 +18,6 @@ use Symfony\Component\Security\Core\User\UserInterface; use Symfony\Component\Security\Core\User\UserProviderInterface; use Symfony\Component\Security\Http\Authenticator\AbstractAuthenticator; -use Symfony\Component\Security\Http\Authenticator\AuthenticatorInterface; use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge; use Symfony\Component\Security\Http\Authenticator\Passport\Passport; use Symfony\Component\Security\Http\Authenticator\Passport\SelfValidatingPassport; @@ -33,88 +30,97 @@ #[CoversClass(JwtAuthenticator::class)] class JwtAuthenticatorTest extends TestCase { - use MockTrait; - - private JwtAuthenticator $object; - - private JwtEncoder&MockObject $jwtEncoder; - - private UserProviderInterface&MockObject $userProvider; - private string $userIdentifierPayloadKey; - private TranslatorInterface&MockObject $translator; - private static string $userIdentifierGetter = 'getJwtIdentifier'; protected function setUp(): void { - $this->userProvider = $this->createMock(UserProviderInterface::class); - - $this->object = new JwtAuthenticator( - $this->jwtEncoder = $this->createMock(JwtEncoder::class), - $this->userProvider, - $this->userIdentifierPayloadKey = uniqid('key'), - self::$userIdentifierGetter, - $this->translator = $this->createMock(TranslatorInterface::class) - ); + $this->userIdentifierPayloadKey = uniqid('key'); } - public function testConstruct(): void + public function testSupports(): void { - static::assertInstanceOf( - AuthenticatorInterface::class, - $this->object + $object = new JwtAuthenticator( + static::createStub(JwtEncoder::class), + static::createStub(UserProviderInterface::class), + $this->userIdentifierPayloadKey, + self::$userIdentifierGetter, + static::createStub(TranslatorInterface::class) ); - } - public function testSupports(): void - { $request = new Request(); $request->headers->set('Authorization', 'Bearer '.uniqid('jwt-')); - static::assertTrue($this->object->supports($request)); + static::assertTrue($object->supports($request)); } public function testSupportsInvalidToken(): void { + $object = new JwtAuthenticator( + $jwtEncoder = $this->createMock(JwtEncoder::class), + static::createStub(UserProviderInterface::class), + $this->userIdentifierPayloadKey, + self::$userIdentifierGetter, + static::createStub(TranslatorInterface::class) + ); + $request = new Request(); $request->headers->set('Authorization', 'Bearer '.uniqid('jwt-')); - $this->jwtEncoder + $jwtEncoder ->expects(static::once()) ->method('decode') ->willThrowException(new \UnexpectedValueException()) + ->seal() ; - static::assertFalse($this->object->supports($request)); + static::assertFalse($object->supports($request)); } public function testSupportsNoToken(): void { - static::assertFalse($this->object->supports(new Request())); + $object = new JwtAuthenticator( + static::createStub(JwtEncoder::class), + static::createStub(UserProviderInterface::class), + $this->userIdentifierPayloadKey, + self::$userIdentifierGetter, + static::createStub(TranslatorInterface::class) + ); + + static::assertFalse($object->supports(new Request())); } public function testGenerateToken(): void { + $object = new JwtAuthenticator( + $jwtEncoder = $this->createMock(JwtEncoder::class), + static::createStub(UserProviderInterface::class), + $this->userIdentifierPayloadKey, + self::$userIdentifierGetter, + static::createStub(TranslatorInterface::class) + ); + $user = $this->createMock(JwtAuthenticatableUserInterface::class); $user ->expects(static::once()) ->method(self::$userIdentifierGetter) ->willReturn($userId = uniqid('id')) + ->seal() ; - $this->jwtEncoder + $jwtEncoder ->expects(static::once()) ->method('encode') ->with([$this->userIdentifierPayloadKey => $userId], null) ->willReturn($token = uniqid('token-')) + ->seal() ; static::assertSame( $token, - $this->object->generaToken( + $object->generaToken( $user, 0 ) @@ -123,9 +129,12 @@ public function testGenerateToken(): void public function testGenerateTokenDefaultNull(): void { - ReflectionAccessor::setPropertyValue( - $this->object, - 'expiration', + $object = new JwtAuthenticator( + $jwtEncoder = $this->createMock(JwtEncoder::class), + static::createStub(UserProviderInterface::class), + $this->userIdentifierPayloadKey, + self::$userIdentifierGetter, + static::createStub(TranslatorInterface::class), null ); @@ -135,18 +144,20 @@ public function testGenerateTokenDefaultNull(): void ->expects(static::once()) ->method(self::$userIdentifierGetter) ->willReturn($userId = uniqid('id')) + ->seal() ; - $this->jwtEncoder + $jwtEncoder ->expects(static::once()) ->method('encode') ->with([$this->userIdentifierPayloadKey => $userId], null) ->willReturn($token = uniqid('token-')) + ->seal() ; static::assertSame( $token, - $this->object->generaToken( + $object->generaToken( $user ) ); @@ -154,27 +165,37 @@ public function testGenerateTokenDefaultNull(): void public function testGenerateTokenWithExpiration(): void { + $object = new JwtAuthenticator( + $jwtEncoder = $this->createMock(JwtEncoder::class), + static::createStub(UserProviderInterface::class), + $this->userIdentifierPayloadKey, + self::$userIdentifierGetter, + static::createStub(TranslatorInterface::class) + ); + $user = $this->createMock(JwtAuthenticatableUserInterface::class); $user ->expects(static::once()) ->method(self::$userIdentifierGetter) ->willReturn($userId = uniqid('id')) + ->seal() ; - $this->jwtEncoder - ->expects(static::once()) + $jwtEncoder + ->expects(static::atLeastOnce()) ->method('encode') ->with( [$this->userIdentifierPayloadKey => $userId], static::equalToWithDelta(new \DateTimeImmutable('+ 7 days'), 1) ) ->willReturn($token = uniqid('token-')) + ->seal() ; static::assertSame( $token, - $this->object->generaToken( + $object->generaToken( $user ) ); @@ -182,30 +203,41 @@ public function testGenerateTokenWithExpiration(): void public function testGenerateTokenWithExtraPayload(): void { + $object = new JwtAuthenticator( + $jwtEncoder = $this->createMock(JwtEncoder::class), + static::createStub(UserProviderInterface::class), + $this->userIdentifierPayloadKey, + self::$userIdentifierGetter, + static::createStub(TranslatorInterface::class), + null + ); + $user = $this->createMock(JwtAuthenticatableUserInterface::class); $user ->expects(static::once()) ->method(self::$userIdentifierGetter) ->willReturn($userId = uniqid('id')) + ->seal() ; $extraPayload = [ 'extra-data' => uniqid('value-'), ]; - $this->jwtEncoder + $jwtEncoder ->expects(static::once()) ->method('encode') ->with( [$this->userIdentifierPayloadKey => $userId] + $extraPayload, ) ->willReturn($token = uniqid('token-')) + ->seal() ; static::assertSame( $token, - $this->object->generaToken( + $object->generaToken( $user, null, $extraPayload @@ -215,14 +247,24 @@ public function testGenerateTokenWithExtraPayload(): void public function testAuthenticate(): void { + $object = new JwtAuthenticator( + $jwtEncoder = $this->createMock(JwtEncoder::class), + $userProvider = static::createMock(UserProviderInterface::class), + $this->userIdentifierPayloadKey, + self::$userIdentifierGetter, + static::createStub(TranslatorInterface::class), + null + ); + $request = new Request(); $request->headers->set('Authorization', 'Bearer '.$token = uniqid('jwt-')); - $this->jwtEncoder - ->expects(static::any()) + $jwtEncoder + ->expects(static::atLeastOnce()) ->method('decode') ->with($token) ->willReturn((object) [$this->userIdentifierPayloadKey => $userId = uniqid('id-')]) + ->seal() ; $user = $this->createMock(UserInterface::class); @@ -231,16 +273,18 @@ public function testAuthenticate(): void ->expects(static::once()) ->method('getUserIdentifier') ->willReturn($userId) + ->seal() ; - $this->userProvider + $userProvider ->expects(static::once()) ->method('loadUserByIdentifier') ->with($userId) ->willReturn($user) + ->seal() ; - $passport = $this->object->authenticate($request); + $passport = $object->authenticate($request); static::assertInstanceOf( SelfValidatingPassport::class, @@ -262,11 +306,20 @@ public function testAuthenticate(): void public function testAuthenticateWithExtraPayload(): void { + $object = new JwtAuthenticator( + $jwtEncoder = $this->createMock(JwtEncoder::class), + $userProvider = static::createMock(UserProviderInterface::class), + $this->userIdentifierPayloadKey, + self::$userIdentifierGetter, + static::createStub(TranslatorInterface::class), + null + ); + $request = new Request(); $request->headers->set('Authorization', 'Bearer '.$token = uniqid('jwt-')); - $this->jwtEncoder - ->expects(static::any()) + $jwtEncoder + ->expects(static::atLeastOnce()) ->method('decode') ->with($token) ->willReturn( @@ -275,6 +328,7 @@ public function testAuthenticateWithExtraPayload(): void $extraKey = uniqid('extra-key-') => $extraValue = uniqid('extra-value-'), ] ) + ->seal() ; $user = $this->createMock(UserInterface::class); @@ -283,16 +337,18 @@ public function testAuthenticateWithExtraPayload(): void ->expects(static::once()) ->method('getUserIdentifier') ->willReturn($userId) + ->seal() ; - $this->userProvider + $userProvider ->expects(static::once()) ->method('loadUserByIdentifier') ->with($userId) ->willReturn($user) + ->seal() ; - $passport = $this->object->authenticate($request); + $passport = $object->authenticate($request); $jwtPayloadBadge = $passport->getBadge(JwtPayloadBadge::class); @@ -308,45 +364,74 @@ public function testAuthenticateWithExtraPayload(): void public function testAuthenticateUserNotFound(): void { + $object = new JwtAuthenticator( + $jwtEncoder = $this->createMock(JwtEncoder::class), + static::createStub(UserProviderInterface::class), + $this->userIdentifierPayloadKey, + self::$userIdentifierGetter, + static::createStub(TranslatorInterface::class), + null + ); + $request = new Request(); $request->headers->set('Authorization', 'Bearer '.$token = uniqid('jwt-')); - $this->jwtEncoder - ->expects(static::any()) + $jwtEncoder + ->expects(static::atLeastOnce()) ->method('decode') ->with($token) ->willReturn((object) []) + ->seal() ; $this->expectException(UserNotFoundException::class); $this->expectExceptionMessage('Token attribute ['.$this->userIdentifierPayloadKey.'] not found'); - $this->object->authenticate($request); + $object->authenticate($request); } public function testAuthenticateInvalidPayload(): void { + $object = new JwtAuthenticator( + $jwtEncoder = $this->createMock(JwtEncoder::class), + static::createStub(UserProviderInterface::class), + $this->userIdentifierPayloadKey, + self::$userIdentifierGetter, + static::createStub(TranslatorInterface::class), + null + ); + $request = new Request(); $request->headers->set('Authorization', 'Bearer '.$token = uniqid('jwt-')); - $this->jwtEncoder - ->expects(static::any()) + $jwtEncoder + ->expects(static::atLeastOnce()) ->method('decode') ->with($token) ->willThrowException(new \UnexpectedValueException()) + ->seal() ; $this->expectException(\UnexpectedValueException::class); - $this->object->authenticate($request); + $object->authenticate($request); } public function testOnAuthenticationSuccess(): void { + $object = new JwtAuthenticator( + static::createStub(JwtEncoder::class), + static::createStub(UserProviderInterface::class), + $this->userIdentifierPayloadKey, + self::$userIdentifierGetter, + static::createStub(TranslatorInterface::class), + null + ); + static::assertNull( - $this->object->onAuthenticationSuccess( + $object->onAuthenticationSuccess( new Request(), - $this->createMock(TokenInterface::class), + static::createStub(TokenInterface::class), uniqid('firewall-') ) ); @@ -354,7 +439,16 @@ public function testOnAuthenticationSuccess(): void public function testOnAuthenticationFailure(): void { - $this->translator + $object = new JwtAuthenticator( + static::createStub(JwtEncoder::class), + static::createStub(UserProviderInterface::class), + $this->userIdentifierPayloadKey, + self::$userIdentifierGetter, + $translator = static::createMock(TranslatorInterface::class), + null + ); + + $translator ->expects(static::once()) ->method('trans') ->with( @@ -363,6 +457,7 @@ public function testOnAuthenticationFailure(): void 'security' ) ->willReturn($translatedMessage = uniqid('translated-')) + ->seal() ; $this->expectException(HttpException::class); @@ -374,7 +469,7 @@ public function testOnAuthenticationFailure(): void ); try { - $this->object->onAuthenticationFailure( + $object->onAuthenticationFailure( new Request(), $previous ); @@ -395,13 +490,23 @@ public function testOnAuthenticationFailure(): void public function testOnAuthenticationFailureNoTranslator(): void { - $this->translator + $object = new JwtAuthenticator( + static::createStub(JwtEncoder::class), + static::createStub(UserProviderInterface::class), + $this->userIdentifierPayloadKey, + self::$userIdentifierGetter, + $translator = static::createMock(TranslatorInterface::class), + null + ); + + $translator ->expects(static::never()) ->method('trans') + ->seal() ; ReflectionAccessor::setPropertyValue( - $this->object, + $object, 'translator', null ); @@ -415,7 +520,7 @@ public function testOnAuthenticationFailureNoTranslator(): void $this->expectExceptionMessage($translatedMessage); try { - $this->object->onAuthenticationFailure( + $object->onAuthenticationFailure( new Request(), new CustomUserMessageAuthenticationException( $message, @@ -439,20 +544,29 @@ public function testOnAuthenticationFailureNoTranslator(): void */ public function testCreateToken(): void { - $passport = $this->createMock(Passport::class); + $object = new JwtAuthenticator( + static::createStub(JwtEncoder::class), + static::createStub(UserProviderInterface::class), + $this->userIdentifierPayloadKey, + self::$userIdentifierGetter, + static::createStub(TranslatorInterface::class), + null + ); + + $passport = static::createStub(Passport::class); $passport - ->expects(static::any()) ->method('getUser') - ->willReturn($user = $this->createMock(UserInterface::class)) + ->willReturn($user = static::createStub(UserInterface::class)) + ->seal() ; $user - ->expects(static::any()) ->method('getRoles') ->willReturn($roles = [uniqid('ROLE_')]) + ->seal() ; - $token = $this->object->createToken( + $token = $object->createToken( $passport, $firewallName = uniqid('firewall-') ); diff --git a/packages/security/Tests/Http/Authenticator/MessageAuthenticatorTest.php b/packages/security/Tests/Http/Authenticator/MessageAuthenticatorTest.php index 6f8cfffc0..b699ded07 100644 --- a/packages/security/Tests/Http/Authenticator/MessageAuthenticatorTest.php +++ b/packages/security/Tests/Http/Authenticator/MessageAuthenticatorTest.php @@ -6,10 +6,8 @@ use Draw\Component\Security\Core\Security; use Draw\Component\Security\Http\Authenticator\MessageAuthenticator; use Draw\Component\Security\Http\Message\AutoConnectInterface; -use Draw\Component\Tester\MockTrait; use Draw\Contracts\Messenger\Exception\MessageNotFoundException; use PHPUnit\Framework\Attributes\CoversClass; -use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\Messenger\Envelope; @@ -18,7 +16,6 @@ use Symfony\Component\Security\Core\User\UserInterface; use Symfony\Component\Security\Core\User\UserProviderInterface; use Symfony\Component\Security\Http\Authenticator\AbstractAuthenticator; -use Symfony\Component\Security\Http\Authenticator\AuthenticatorInterface; use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge; use Symfony\Component\Security\Http\Authenticator\Passport\Passport; use Symfony\Component\Security\Http\Authenticator\Passport\SelfValidatingPassport; @@ -30,167 +27,192 @@ #[CoversClass(MessageAuthenticator::class)] class MessageAuthenticatorTest extends TestCase { - use MockTrait; - - private MessageAuthenticator $service; - - private EnvelopeFinder&MockObject $envelopeFinder; - - private UserProviderInterface&MockObject $userProvider; - - private Security&MockObject $security; - - protected function setUp(): void - { - $this->userProvider = $this->createMock(UserProviderInterface::class); - - $this->service = new MessageAuthenticator( - $this->envelopeFinder = $this->createMock(EnvelopeFinder::class), - $this->userProvider, - $this->security = $this->createMock(Security::class), - ); - } - - public function testConstruct(): void + public function testSupportsNoConnectedUser(): void { - static::assertInstanceOf( - AuthenticatorInterface::class, - $this->service + $service = new MessageAuthenticator( + $envelopeFinder = $this->createMock(EnvelopeFinder::class), + $userProvider = $this->createMock(UserProviderInterface::class), + $security = $this->createMock(Security::class), ); - } - public function testSupportsNoConnectedUser(): void - { $request = new Request(); $request->query->set('dMUuid', $messageId = uniqid('message-id')); - $this->security + $security ->expects(static::once()) ->method('getUser') ->willReturn(null) + ->seal() ; - $this->envelopeFinder + $envelopeFinder ->expects(static::once()) ->method('findById') ->with($messageId) ->willReturn(new Envelope($this->createAutoConnectMessage($userIdentifier = uniqid('user-id-')))) + ->seal() ; - $this->userProvider + $userProvider ->expects(static::once()) ->method('loadUserByIdentifier') ->with($userIdentifier) - ->willReturn($this->createMock(UserInterface::class)) + ->willReturn(static::createStub(UserInterface::class)) + ->seal() ; - static::assertTrue($this->service->supports($request)); + static::assertTrue($service->supports($request)); } public function testSupportsDifferentUser(): void { + $service = new MessageAuthenticator( + $envelopeFinder = $this->createMock(EnvelopeFinder::class), + $userProvider = $this->createMock(UserProviderInterface::class), + $security = $this->createMock(Security::class), + ); + $request = new Request(); $request->query->set('dMUuid', $messageId = uniqid('message-id')); - $this->security + $security ->expects(static::once()) ->method('getUser') - ->willReturn($this->createMock(UserInterface::class)) + ->willReturn(static::createStub(UserInterface::class)) + ->seal() ; - $this->envelopeFinder + $envelopeFinder ->expects(static::once()) ->method('findById') ->with($messageId) ->willReturn(new Envelope($this->createAutoConnectMessage($userIdentifier = uniqid('user-id-')))) + ->seal() ; - $this->userProvider + $userProvider ->expects(static::once()) ->method('loadUserByIdentifier') ->with($userIdentifier) - ->willReturn($this->createMock(UserInterface::class)) + ->willReturn(static::createStub(UserInterface::class)) + ->seal() ; - static::assertTrue($this->service->supports($request)); + static::assertTrue($service->supports($request)); } public function testSupportsNoMessageParameter(): void { - static::assertFalse($this->service->supports(new Request())); + $service = new MessageAuthenticator( + static::createStub(EnvelopeFinder::class), + static::createStub(UserProviderInterface::class), + static::createStub(Security::class), + ); + + static::assertFalse($service->supports(new Request())); } public function testSupportsSameUser(): void { + $service = new MessageAuthenticator( + $envelopeFinder = $this->createMock(EnvelopeFinder::class), + $userProvider = $this->createMock(UserProviderInterface::class), + $security = $this->createMock(Security::class), + ); + $request = new Request(); $request->query->set('dMUuid', $messageId = uniqid('message-id')); - $this->security + $security ->expects(static::once()) ->method('getUser') - ->willReturn($user = $this->createMock(UserInterface::class)) + ->willReturn($user = static::createStub(UserInterface::class)) + ->seal() ; - $this->envelopeFinder + $envelopeFinder ->expects(static::once()) ->method('findById') ->with($messageId) ->willReturn(new Envelope($this->createAutoConnectMessage($userIdentifier = uniqid('user-id-')))) + ->seal() ; - $this->userProvider + $userProvider ->expects(static::once()) ->method('loadUserByIdentifier') ->with($userIdentifier) ->willReturn($user) + ->seal() ; - static::assertFalse($this->service->supports($request)); + static::assertFalse($service->supports($request)); } public function testSupportsNoMessage(): void { + $service = new MessageAuthenticator( + $envelopeFinder = $this->createMock(EnvelopeFinder::class), + static::createStub(UserProviderInterface::class), + static::createStub(Security::class), + ); + $request = new Request(); $request->query->set('dMUuid', $messageId = uniqid('message-id')); - $this->envelopeFinder + $envelopeFinder ->expects(static::once()) ->method('findById') ->with($messageId) ->willThrowException(new MessageNotFoundException($messageId)) + ->seal() ; - static::assertFalse($this->service->supports($request)); + static::assertFalse($service->supports($request)); } public function testAuthenticateNoMessage(): void { + $service = new MessageAuthenticator( + $envelopeFinder = $this->createMock(EnvelopeFinder::class), + static::createStub(UserProviderInterface::class), + static::createStub(Security::class), + ); + $request = new Request(); $request->query->set('dMUuid', $messageId = uniqid('message-id')); - $this->envelopeFinder + $envelopeFinder ->expects(static::once()) ->method('findById') ->with($messageId) ->willThrowException(new MessageNotFoundException($messageId)) + ->seal() ; $this->expectException(CustomUserMessageAuthenticationException::class); $this->expectExceptionMessage('Invalid message id.'); - $this->service->authenticate($request); + $service->authenticate($request); } public function testAuthenticate(): void { + $service = new MessageAuthenticator( + $envelopeFinder = $this->createMock(EnvelopeFinder::class), + $userProvider = $this->createMock(UserProviderInterface::class), + static::createStub(Security::class), + ); + $request = new Request(); $request->query->set('dMUuid', $messageId = uniqid('message-id')); - $this->envelopeFinder + $envelopeFinder ->expects(static::once()) ->method('findById') ->with($messageId) ->willReturn(new Envelope($this->createAutoConnectMessage($userIdentifier = uniqid('user-id-')))) + ->seal() ; $user = $this->createMock(UserInterface::class); @@ -199,16 +221,18 @@ public function testAuthenticate(): void ->expects(static::once()) ->method('getUserIdentifier') ->willReturn($userIdentifier) + ->seal() ; - $this->userProvider + $userProvider ->expects(static::once()) ->method('loadUserByIdentifier') ->with($userIdentifier) ->willReturn($user) + ->seal() ; - $passport = $this->service->authenticate($request); + $passport = $service->authenticate($request); static::assertInstanceOf( SelfValidatingPassport::class, @@ -230,10 +254,16 @@ public function testAuthenticate(): void public function testOnAuthenticationSuccess(): void { + $service = new MessageAuthenticator( + static::createStub(EnvelopeFinder::class), + static::createStub(UserProviderInterface::class), + static::createStub(Security::class), + ); + static::assertNull( - $this->service->onAuthenticationSuccess( + $service->onAuthenticationSuccess( new Request(), - $this->createMock(TokenInterface::class), + static::createStub(TokenInterface::class), uniqid('firewall-') ) ); @@ -241,8 +271,14 @@ public function testOnAuthenticationSuccess(): void public function testOnAuthenticationFailure(): void { + $service = new MessageAuthenticator( + static::createStub(EnvelopeFinder::class), + static::createStub(UserProviderInterface::class), + static::createStub(Security::class), + ); + static::assertNull( - $this->service->onAuthenticationFailure( + $service->onAuthenticationFailure( new Request(), new CustomUserMessageAuthenticationException() ) @@ -256,20 +292,26 @@ public function testOnAuthenticationFailure(): void */ public function testCreateToken(): void { - $passport = $this->createMock(Passport::class); + $service = new MessageAuthenticator( + static::createStub(EnvelopeFinder::class), + static::createStub(UserProviderInterface::class), + static::createStub(Security::class), + ); + + $passport = static::createStub(Passport::class); $passport - ->expects(static::any()) ->method('getUser') - ->willReturn($user = $this->createMock(UserInterface::class)) + ->willReturn($user = static::createStub(UserInterface::class)) + ->seal() ; $user - ->expects(static::any()) ->method('getRoles') ->willReturn($roles = [uniqid('ROLE_')]) + ->seal() ; - $token = $this->service->createToken( + $token = $service->createToken( $passport, $firewallName = uniqid('firewall-') ); @@ -297,11 +339,12 @@ public function testCreateToken(): void private function createAutoConnectMessage(string $userIdentifier): AutoConnectInterface { - $message = $this->createMock(AutoConnectInterface::class); + $message = static::createStub(AutoConnectInterface::class); - $message->expects(static::any()) + $message ->method('getUserIdentifier') ->willReturn($userIdentifier) + ->seal() ; return $message; diff --git a/packages/security/Tests/Http/EventListener/RoleRestrictedAuthenticatorListenerTest.php b/packages/security/Tests/Http/EventListener/RoleRestrictedAuthenticatorListenerTest.php index 090ec290f..399738c8e 100644 --- a/packages/security/Tests/Http/EventListener/RoleRestrictedAuthenticatorListenerTest.php +++ b/packages/security/Tests/Http/EventListener/RoleRestrictedAuthenticatorListenerTest.php @@ -5,9 +5,7 @@ use Draw\Component\Security\Http\Authenticator\Passport\Badge\RoleRestrictedBadge; use Draw\Component\Security\Http\EventListener\RoleRestrictedAuthenticatorListener; use PHPUnit\Framework\Attributes\CoversClass; -use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; -use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\Security\Core\Exception\CustomUserMessageAuthenticationException; use Symfony\Component\Security\Core\Role\RoleHierarchyInterface; use Symfony\Component\Security\Core\User\UserInterface; @@ -22,109 +20,114 @@ #[CoversClass(RoleRestrictedAuthenticatorListener::class)] class RoleRestrictedAuthenticatorListenerTest extends TestCase { - private RoleRestrictedAuthenticatorListener $service; - - private RoleHierarchyInterface&MockObject $roleHierarchy; - - private UserInterface&MockObject $user; - - protected function setUp(): void - { - $this->user = $this->createMock(UserInterface::class); - - $this->service = new RoleRestrictedAuthenticatorListener( - $this->roleHierarchy = $this->createMock(RoleHierarchyInterface::class), - ); - } - - public function testConstruct(): void + public function testGetSubscribedEvents(): void { - static::assertInstanceOf( - EventSubscriberInterface::class, - $this->service + $service = new RoleRestrictedAuthenticatorListener( + static::createStub(RoleHierarchyInterface::class), ); - } - public function testGetSubscribedEvents(): void - { static::assertSame( [CheckPassportEvent::class => ['checkPassport', -1]], - $this->service::getSubscribedEvents() + $service::getSubscribedEvents() ); } public function testCheckPassportNoRoleRestrictedBadge(): void { - $this->roleHierarchy + $user = $this->createMock(UserInterface::class); + + $service = new RoleRestrictedAuthenticatorListener( + $roleHierarchy = $this->createMock(RoleHierarchyInterface::class), + ); + + $roleHierarchy ->expects(static::never()) ->method('getReachableRoleNames') + ->seal() ; - $this->user + $user ->expects(static::never()) ->method('getRoles') + ->seal() ; - $this->service - ->checkPassport($this->createCheckPassportEvent()) + $service + ->checkPassport($this->createCheckPassportEvent($user)) ; } public function testCheckPassportRoleDoNotMatch(): void { - $this->user + $user = $this->createMock(UserInterface::class); + + $service = new RoleRestrictedAuthenticatorListener( + $roleHierarchy = $this->createMock(RoleHierarchyInterface::class), + ); + + $user ->expects(static::once()) ->method('getRoles') ->willReturn($roles = ['ROLE_USER']) + ->seal() ; - $this->roleHierarchy + $roleHierarchy ->expects(static::once()) ->method('getReachableRoleNames') ->with($roles) ->willReturn($roles) + ->seal() ; $this->expectException(CustomUserMessageAuthenticationException::class); $this->expectExceptionMessage('Access denied.'); - $this->service - ->checkPassport($this->createCheckPassportEvent([new RoleRestrictedBadge(uniqid('ROLE_'))])) + $service + ->checkPassport($this->createCheckPassportEvent($user, [new RoleRestrictedBadge(uniqid('ROLE_'))])) ; } public function testCheckPassportRoleMatch(): void { - $this->user + $user = $this->createMock(UserInterface::class); + + $service = new RoleRestrictedAuthenticatorListener( + $roleHierarchy = $this->createMock(RoleHierarchyInterface::class), + ); + + $user ->expects(static::once()) ->method('getRoles') ->willReturn($roles = ['ROLE_USER']) + ->seal() ; - $this->roleHierarchy + $roleHierarchy ->expects(static::once()) ->method('getReachableRoleNames') ->with($roles) ->willReturn([...$roles, ...[$role = uniqid('ROLE_')]]) + ->seal() ; $badge = new RoleRestrictedBadge($role); - $this->service - ->checkPassport($this->createCheckPassportEvent([$badge])) + $service + ->checkPassport($this->createCheckPassportEvent($user, [$badge])) ; static::assertTrue($badge->isResolved()); } - private function createCheckPassportEvent(array $badges = []): CheckPassportEvent + private function createCheckPassportEvent(UserInterface $user, array $badges = []): CheckPassportEvent { return new CheckPassportEvent( - $this->createMock(AuthenticatorInterface::class), + static::createStub(AuthenticatorInterface::class), new SelfValidatingPassport( new UserBadge( uniqid('user-identifier-'), - fn () => $this->user + static fn (): UserInterface => $user ), $badges ) diff --git a/packages/security/composer.json b/packages/security/composer.json index a72a748ea..7ede1478c 100644 --- a/packages/security/composer.json +++ b/packages/security/composer.json @@ -24,7 +24,7 @@ "draw/messenger": "^0.39", "draw/tester": "^0.39", "firebase/php-jwt": "^6.1", - "phpunit/phpunit": "^11.3 || ^12.0", + "phpunit/phpunit": "^11.3 || ^12.0 || ^13.0", "symfony/console": "^6.4.0", "symfony/messenger": "^6.4.0", "symfony/security-http": "^6.4.0", diff --git a/packages/sonata-extra-bundle/PreventDelete/PreventDeleteRelationLoader.php b/packages/sonata-extra-bundle/PreventDelete/PreventDeleteRelationLoader.php index 623b37ad1..c59205c1a 100644 --- a/packages/sonata-extra-bundle/PreventDelete/PreventDeleteRelationLoader.php +++ b/packages/sonata-extra-bundle/PreventDelete/PreventDeleteRelationLoader.php @@ -26,7 +26,10 @@ public function getRelationsForObject(object $object): array { $relations = []; foreach ($this->getRelations() as $relation) { - $class = $relation->getClass(); + if (null === $class = $relation->getClass()) { + continue; + } + if ($object instanceof $class) { $relations[] = $relation; } diff --git a/packages/sonata-extra-bundle/Tests/EventListener/SessionTimeoutRequestListenerTest.php b/packages/sonata-extra-bundle/Tests/EventListener/SessionTimeoutRequestListenerTest.php index f8ac452af..4cfbdc130 100644 --- a/packages/sonata-extra-bundle/Tests/EventListener/SessionTimeoutRequestListenerTest.php +++ b/packages/sonata-extra-bundle/Tests/EventListener/SessionTimeoutRequestListenerTest.php @@ -4,13 +4,11 @@ use Draw\Bundle\SonataExtraBundle\EventListener\SessionTimeoutRequestListener; use Draw\Component\Security\Core\Security; -use Draw\Component\Tester\MockTrait; +use Draw\Component\Tester\DoubleTrait; use PHPUnit\Framework\Attributes\CoversClass; use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\Attributes\DoesNotPerformAssertions; -use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; -use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\ResponseHeaderBag; @@ -29,32 +27,15 @@ #[CoversClass(SessionTimeoutRequestListener::class)] class SessionTimeoutRequestListenerTest extends TestCase { - use MockTrait; + use DoubleTrait; - private SessionTimeoutRequestListener $object; - - private MockObject&UrlGeneratorInterface $urlGenerator; - - private MockObject&Security $security; - - protected function setUp(): void - { - $this->object = new SessionTimeoutRequestListener( - $this->security = $this->createMock(Security::class), - $this->urlGenerator = $this->createMock(UrlGeneratorInterface::class), - ); - } - - public function testConstruct(): void + public function testGetSubscribedEvents(): void { - static::assertInstanceOf( - EventSubscriberInterface::class, - $this->object + $object = new SessionTimeoutRequestListener( + static::createStub(Security::class), + static::createStub(UrlGeneratorInterface::class), ); - } - public function testGetSubscribedEvents(): void - { static::assertSame( [ RequestEvent::class => [ @@ -65,14 +46,19 @@ public function testGetSubscribedEvents(): void ['onKernelResponseAddDialog', -2000], ], ], - $this->object::getSubscribedEvents() + $object::getSubscribedEvents() ); } public function testOnKernelRequestInvalidate(): void { + $object = new SessionTimeoutRequestListener( + static::createStub(Security::class), + static::createStub(UrlGeneratorInterface::class), + ); + $requestEvent = new RequestEvent( - $this->createMock(HttpKernelInterface::class), + static::createStub(HttpKernelInterface::class), $request = new Request(), HttpKernelInterface::MAIN_REQUEST ); @@ -87,22 +73,28 @@ public function testOnKernelRequestInvalidate(): void $session->expects(static::once()) ->method('invalidate') + ->seal() ; - $this->object->onKernelRequestInvalidate($requestEvent); + $object->onKernelRequestInvalidate($requestEvent); } #[DoesNotPerformAssertions] #[DataProvider('provideOnKernelRequestInvalidateNotInvalidateCases')] public function testOnKernelRequestInvalidateNotInvalidate(Request $request, int $requestType): void { + $object = new SessionTimeoutRequestListener( + static::createStub(Security::class), + static::createStub(UrlGeneratorInterface::class), + ); + $requestEvent = new RequestEvent( - $this->createMock(HttpKernelInterface::class), + static::createStub(HttpKernelInterface::class), $request, $requestType ); - $this->object->onKernelRequestInvalidate($requestEvent); + $object->onKernelRequestInvalidate($requestEvent); } public static function provideOnKernelRequestInvalidateNotInvalidateCases(): iterable @@ -175,8 +167,13 @@ public function getSession(): SessionInterface public function testOnKernelResponseSetLastUsed(): void { + $object = new SessionTimeoutRequestListener( + static::createStub(Security::class), + static::createStub(UrlGeneratorInterface::class), + ); + $event = new ResponseEvent( - $this->createMock(HttpKernelInterface::class), + static::createStub(HttpKernelInterface::class), $request = new Request(), HttpKernelInterface::MAIN_REQUEST, new Response() @@ -184,7 +181,7 @@ public function testOnKernelResponseSetLastUsed(): void $request->setSession($session = new Session(new MockArraySessionStorage())); - $this->object->onKernelResponseSetLastUsed($event); + $object->onKernelResponseSetLastUsed($event); static::assertEqualsWithDelta( time(), @@ -199,14 +196,19 @@ public function testOnKernelResponseSetLastUsedNoSet( Request $request, int $requestType = HttpKernelInterface::MAIN_REQUEST, ): void { + $object = new SessionTimeoutRequestListener( + static::createStub(Security::class), + static::createStub(UrlGeneratorInterface::class), + ); + $event = new ResponseEvent( - $this->createMock(HttpKernelInterface::class), + static::createStub(HttpKernelInterface::class), $request, $requestType, new Response() ); - $this->object->onKernelResponseSetLastUsed($event); + $object->onKernelResponseSetLastUsed($event); } public static function provideOnKernelResponseSetLastUsedNoSetCases(): iterable @@ -247,8 +249,13 @@ public function getSession(): SessionInterface public function testOnKernelResponseAddDialog(): void { + $object = new SessionTimeoutRequestListener( + $security = $this->createMock(Security::class), + $urlGenerator = $this->createMock(UrlGeneratorInterface::class), + ); + $event = new ResponseEvent( - $this->createMock(HttpKernelInterface::class), + static::createStub(HttpKernelInterface::class), new Request(), HttpKernelInterface::MAIN_REQUEST, $response = new Response() @@ -258,12 +265,13 @@ public function testOnKernelResponseAddDialog(): void $response->setContent('value'); - $this->security->expects(static::once()) + $security->expects(static::once()) ->method('getUser') - ->willReturn($this->createMock(UserInterface::class)) + ->willReturn(static::createStub(UserInterface::class)) + ->seal() ; - $this->urlGenerator->expects(static::exactly(2)) + $urlGenerator->expects(static::exactly(2)) ->method('generate') ->with( ...static::withConsecutive( @@ -275,9 +283,10 @@ public function testOnKernelResponseAddDialog(): void '/admin/keep-alive', '/admin/login' ) + ->seal() ; - $this->object->onKernelResponseAddDialog($event); + $object->onKernelResponseAddDialog($event); static::assertSame( ' @@ -296,20 +305,27 @@ public function testOnKernelResponseAddDialogNoInjection( ?UserInterface $user = null, int $requestType = HttpKernelInterface::MAIN_REQUEST, ): void { - $this->security->expects(static::once()) + $object = new SessionTimeoutRequestListener( + $security = $this->createMock(Security::class), + $urlGenerator = $this->createMock(UrlGeneratorInterface::class), + ); + + $security->expects(static::once()) ->method('getUser') ->willReturn($user) + ->seal() ; - $this->urlGenerator->expects(static::never()) + $urlGenerator->expects(static::never()) ->method('generate') + ->seal() ; $previousContent = $response->getContent(); - $this->object->onKernelResponseAddDialog( + $object->onKernelResponseAddDialog( new ResponseEvent( - $this->createMock(HttpKernelInterface::class), + static::createStub(HttpKernelInterface::class), new Request(), $requestType, $response @@ -334,12 +350,12 @@ public function getRoles(): array return []; } - public function getPassword(): ?string + public function getPassword(): null { return null; } - public function getSalt(): ?string + public function getSalt(): null { return null; } @@ -348,7 +364,7 @@ public function eraseCredentials(): void { } - public function getUsername(): ?string + public function getUsername(): null { return null; } diff --git a/packages/sonata-extra-bundle/Tests/PreventDeletion/Extension/PreventDeleteExtensionTest.php b/packages/sonata-extra-bundle/Tests/PreventDeletion/Extension/PreventDeleteExtensionTest.php index 4c4bef32e..0cba0e21d 100644 --- a/packages/sonata-extra-bundle/Tests/PreventDeletion/Extension/PreventDeleteExtensionTest.php +++ b/packages/sonata-extra-bundle/Tests/PreventDeletion/Extension/PreventDeleteExtensionTest.php @@ -29,7 +29,7 @@ protected function setUp(): void { $this->object = new PreventDeleteExtension( $this->preventDeleteRelationLoader = $this->createMock(PreventDeleteRelationLoader::class), - $this->createMock(ManagerRegistry::class), + static::createStub(ManagerRegistry::class), $this->security = $this->createMock(Security::class), ); } @@ -47,17 +47,19 @@ public function testConfigureShowFieldsNoAccess(): void ->method('isGranted') ->with('ROLE_ADMIN') ->willReturn(false) + ->seal() ; $this->preventDeleteRelationLoader ->expects(static::never()) ->method('getRelationsForObject') + ->seal() ; $showMapper = new ShowMapper( - $this->createMock(ShowBuilderInterface::class), + static::createStub(ShowBuilderInterface::class), new FieldDescriptionCollection(), - $this->createMock(AdminInterface::class), + static::createStub(AdminInterface::class), ); $this->object->configureShowFields($showMapper); diff --git a/packages/sonata-extra-bundle/composer.json b/packages/sonata-extra-bundle/composer.json index e03a37704..4413968be 100644 --- a/packages/sonata-extra-bundle/composer.json +++ b/packages/sonata-extra-bundle/composer.json @@ -19,7 +19,7 @@ "cweagans/composer-patches": "^1.7", "draw/tester": "^0.39", "draw/security": "^0.39", - "phpunit/phpunit": "^11.3 || ^12.0", + "phpunit/phpunit": "^11.3 || ^12.0 || ^13.0", "sonata-project/admin-bundle": "^4.8", "sonata-project/doctrine-orm-admin-bundle": "^4.2", "symfony/notifier": "^6.4.0" diff --git a/packages/sonata-import-bundle/Import/Importer.php b/packages/sonata-import-bundle/Import/Importer.php index 3060805df..204296e44 100644 --- a/packages/sonata-import-bundle/Import/Importer.php +++ b/packages/sonata-import-bundle/Import/Importer.php @@ -65,10 +65,10 @@ public function buildFromFile(Import $import, \SplFileInfo $file): void $handle = fopen($file->getRealPath(), 'r'); - $headers = fgetcsv($handle); + $headers = fgetcsv($handle, escape: '\\'); $samples = []; for ($i = 0; $i < 10; ++$i) { - $row = fgetcsv($handle); + $row = fgetcsv($handle, escape: '\\'); if (!$row) { break; } @@ -90,7 +90,7 @@ public function processImport(Import $import): bool file_put_contents($file, $import->getFileContent()); register_shutdown_function('unlink', $file); $handle = fopen($file, 'r+'); - $headers = fgetcsv($handle); + $headers = fgetcsv($handle, escape: '\\'); $identifierHeaderName = $import->getIdentifierHeaderName(); $columnMapping = $import->getColumnMapping(); @@ -104,7 +104,7 @@ public function processImport(Import $import): bool $identifierHeaderNames[$column->getHeaderName()] = $column->getMappedTo(); } - while (($row = fgetcsv($handle)) !== false) { + while (($row = fgetcsv($handle, escape: '\\')) !== false) { ++$line; $data = array_combine($headers, $row); $id = $data[$identifierHeaderName]; diff --git a/packages/sonata-import-bundle/Tests/Column/Bridge/Doctrine/Extractor/DoctrineAssociationColumnExtractorTest.php b/packages/sonata-import-bundle/Tests/Column/Bridge/Doctrine/Extractor/DoctrineAssociationColumnExtractorTest.php index 7565bbd17..4592d6196 100644 --- a/packages/sonata-import-bundle/Tests/Column/Bridge/Doctrine/Extractor/DoctrineAssociationColumnExtractorTest.php +++ b/packages/sonata-import-bundle/Tests/Column/Bridge/Doctrine/Extractor/DoctrineAssociationColumnExtractorTest.php @@ -4,7 +4,6 @@ use Doctrine\ORM\EntityManagerInterface; use Draw\Bundle\SonataImportBundle\Column\Bridge\Doctrine\Extractor\DoctrineAssociationColumnExtractor; -use Draw\Bundle\SonataImportBundle\Column\ColumnExtractorInterface; use Draw\Bundle\SonataImportBundle\Entity\Column; use Draw\Bundle\SonataImportBundle\Entity\Import; use Draw\Component\Tester\DoctrineOrmTrait; @@ -32,14 +31,6 @@ protected function setUp(): void ); } - public function testConstruct(): void - { - static::assertInstanceOf( - ColumnExtractorInterface::class, - $this->object - ); - } - public function testGetDefaultPriority(): void { static::assertSame( diff --git a/packages/sonata-import-bundle/Tests/Column/Bridge/Doctrine/Extractor/DoctrineFieldColumnExtractorTest.php b/packages/sonata-import-bundle/Tests/Column/Bridge/Doctrine/Extractor/DoctrineFieldColumnExtractorTest.php index 9d81505c1..9dff7157a 100644 --- a/packages/sonata-import-bundle/Tests/Column/Bridge/Doctrine/Extractor/DoctrineFieldColumnExtractorTest.php +++ b/packages/sonata-import-bundle/Tests/Column/Bridge/Doctrine/Extractor/DoctrineFieldColumnExtractorTest.php @@ -3,7 +3,6 @@ namespace Draw\Bundle\SonataImportBundle\Tests\Column\Bridge\Doctrine\Extractor; use Draw\Bundle\SonataImportBundle\Column\Bridge\Doctrine\Extractor\DoctrineFieldColumnExtractor; -use Draw\Bundle\SonataImportBundle\Column\ColumnExtractorInterface; use Draw\Bundle\SonataImportBundle\Entity\Column; use Draw\Bundle\SonataImportBundle\Entity\Import; use Draw\Component\Tester\DoctrineOrmTrait; @@ -29,14 +28,6 @@ protected function setUp(): void ); } - public function testConstruct(): void - { - static::assertInstanceOf( - ColumnExtractorInterface::class, - $this->object - ); - } - public function testGetDefaultPriority(): void { static::assertSame( diff --git a/packages/sonata-import-bundle/Tests/Column/Bridge/KnpDoctrineBehaviors/Extractor/DoctrineTranslationColumnExtractorTest.php b/packages/sonata-import-bundle/Tests/Column/Bridge/KnpDoctrineBehaviors/Extractor/DoctrineTranslationColumnExtractorTest.php index e36116ac5..a545e6acf 100644 --- a/packages/sonata-import-bundle/Tests/Column/Bridge/KnpDoctrineBehaviors/Extractor/DoctrineTranslationColumnExtractorTest.php +++ b/packages/sonata-import-bundle/Tests/Column/Bridge/KnpDoctrineBehaviors/Extractor/DoctrineTranslationColumnExtractorTest.php @@ -3,7 +3,6 @@ namespace Draw\Bundle\SonataImportBundle\Tests\Column\Bridge\KnpDoctrineBehaviors\Extractor; use Draw\Bundle\SonataImportBundle\Column\Bridge\KnpDoctrineBehaviors\Extractor\DoctrineTranslationColumnExtractor; -use Draw\Bundle\SonataImportBundle\Column\ColumnExtractorInterface; use Draw\Bundle\SonataImportBundle\Entity\Column; use Draw\Bundle\SonataImportBundle\Entity\Import; use Draw\Bundle\SonataImportBundle\Tests\Column\Bridge\KnpDoctrineBehaviors\Extractor\Fixtures\TranslatableEntity; @@ -31,14 +30,6 @@ protected function setUp(): void ); } - public function testConstruct(): void - { - static::assertInstanceOf( - ColumnExtractorInterface::class, - $this->object - ); - } - public function testGetDefaultPriority(): void { static::assertSame( diff --git a/packages/sonata-import-bundle/Tests/Column/Extractor/ExactMatchColumnExtractorTest.php b/packages/sonata-import-bundle/Tests/Column/Extractor/ExactMatchColumnExtractorTest.php index ac67632d7..e26c5e339 100644 --- a/packages/sonata-import-bundle/Tests/Column/Extractor/ExactMatchColumnExtractorTest.php +++ b/packages/sonata-import-bundle/Tests/Column/Extractor/ExactMatchColumnExtractorTest.php @@ -2,12 +2,10 @@ namespace Draw\Bundle\SonataImportBundle\Tests\Column\Extractor; -use Draw\Bundle\SonataImportBundle\Column\ColumnExtractorInterface; use Draw\Bundle\SonataImportBundle\Column\Extractor\ExactMatchColumnExtractor; use Draw\Bundle\SonataImportBundle\Entity\Column; use Draw\Bundle\SonataImportBundle\Import\Importer; use PHPUnit\Framework\Attributes\CoversClass; -use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; /** @@ -16,38 +14,27 @@ #[CoversClass(ExactMatchColumnExtractor::class)] class ExactMatchColumnExtractorTest extends TestCase { - private ExactMatchColumnExtractor $object; - - private Importer&MockObject $importer; - - protected function setUp(): void - { - $this->object = new ExactMatchColumnExtractor( - $this->importer = $this->createMock(Importer::class) - ); - } - - public function testConstruct(): void + public function testGetDefaultPriority(): void { - static::assertInstanceOf( - ColumnExtractorInterface::class, - $this->object + $object = new ExactMatchColumnExtractor( + static::createStub(Importer::class) ); - } - public function testGetDefaultPriority(): void - { static::assertSame( -1000, - $this->object::getDefaultPriority() + $object::getDefaultPriority() ); } public function testGetOptions(): void { + $object = new ExactMatchColumnExtractor( + static::createStub(Importer::class) + ); + static::assertSame( ['test'], - $this->object->getOptions( + $object->getOptions( new Column(), ['test'] ) @@ -56,14 +43,19 @@ public function testGetOptions(): void public function testExtractDefaultValueAlreadySet(): void { - $this->importer + $object = new ExactMatchColumnExtractor( + $importer = $this->createMock(Importer::class) + ); + + $importer ->expects(static::never()) ->method('getOptions') + ->seal() ; static::assertNull( - $this->object->extractDefaultValue( - (new Column()) + $object->extractDefaultValue( + new Column() ->setHeaderName('headerName') ->setMappedTo('mappedTo'), ['sample1', 'sample2'] @@ -73,15 +65,20 @@ public function testExtractDefaultValueAlreadySet(): void public function testExtractDefaultValueNotInOptions(): void { - $this->importer + $object = new ExactMatchColumnExtractor( + $importer = $this->createMock(Importer::class) + ); + + $importer ->expects(static::once()) ->method('getOptions') ->willReturn(['headerName1', 'headerName2']) + ->seal() ; static::assertNull( - $this->object->extractDefaultValue( - (new Column()) + $object->extractDefaultValue( + new Column() ->setHeaderName('headerName'), ['sample3', 'sample4'] ) @@ -90,17 +87,22 @@ public function testExtractDefaultValueNotInOptions(): void public function testExtractDefaultValueInOptions(): void { - $this->importer + $object = new ExactMatchColumnExtractor( + $importer = $this->createMock(Importer::class) + ); + + $importer ->expects(static::once()) ->method('getOptions') ->willReturn(['headerName']) + ->seal() ; - $column = (new Column()) + $column = new Column() ->setHeaderName('headerName') ; - $column = $this->object->extractDefaultValue( + $column = $object->extractDefaultValue( $column, ['sample5', 'sample6'] ); diff --git a/packages/sonata-import-bundle/Tests/Column/Extractor/PropertyPathColumnExtractorTest.php b/packages/sonata-import-bundle/Tests/Column/Extractor/PropertyPathColumnExtractorTest.php index 9731324a6..2a6550006 100644 --- a/packages/sonata-import-bundle/Tests/Column/Extractor/PropertyPathColumnExtractorTest.php +++ b/packages/sonata-import-bundle/Tests/Column/Extractor/PropertyPathColumnExtractorTest.php @@ -2,7 +2,6 @@ namespace Draw\Bundle\SonataImportBundle\Tests\Column\Extractor; -use Draw\Bundle\SonataImportBundle\Column\ColumnExtractorInterface; use Draw\Bundle\SonataImportBundle\Column\Extractor\PropertyPathColumnExtractor; use Draw\Bundle\SonataImportBundle\Entity\Column; use PHPUnit\Framework\TestCase; @@ -19,14 +18,6 @@ protected function setUp(): void $this->object = new PropertyPathColumnExtractor(); } - public function testConstruct(): void - { - static::assertInstanceOf( - ColumnExtractorInterface::class, - $this->object - ); - } - public function testGetDefaultPriority(): void { static::assertSame( diff --git a/packages/sonata-import-bundle/Tests/Column/Extractor/SetterMethodReflectionColumnExtractorTest.php b/packages/sonata-import-bundle/Tests/Column/Extractor/SetterMethodReflectionColumnExtractorTest.php index dda54ec8e..1d24bc938 100644 --- a/packages/sonata-import-bundle/Tests/Column/Extractor/SetterMethodReflectionColumnExtractorTest.php +++ b/packages/sonata-import-bundle/Tests/Column/Extractor/SetterMethodReflectionColumnExtractorTest.php @@ -2,7 +2,6 @@ namespace Draw\Bundle\SonataImportBundle\Tests\Column\Extractor; -use Draw\Bundle\SonataImportBundle\Column\ColumnExtractorInterface; use Draw\Bundle\SonataImportBundle\Column\Extractor\SetterMethodReflectionColumnExtractor; use Draw\Bundle\SonataImportBundle\Entity\Column; use Draw\Bundle\SonataImportBundle\Entity\Import; @@ -22,14 +21,6 @@ protected function setUp(): void $this->object = new SetterMethodReflectionColumnExtractor(); } - public function testConstruct(): void - { - static::assertInstanceOf( - ColumnExtractorInterface::class, - $this->object - ); - } - public function testGetDefaultPriority(): void { static::assertSame( diff --git a/packages/sonata-import-bundle/Tests/Entity/ImportTest.php b/packages/sonata-import-bundle/Tests/Entity/ImportTest.php index 0a0f555af..88614bd5d 100644 --- a/packages/sonata-import-bundle/Tests/Entity/ImportTest.php +++ b/packages/sonata-import-bundle/Tests/Entity/ImportTest.php @@ -2,17 +2,14 @@ namespace Draw\Bundle\SonataImportBundle\Tests\Entity; -use Doctrine\Common\Collections\Collection; use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\Event\PreUpdateEventArgs; use Doctrine\Persistence\Event\LifecycleEventArgs; use Doctrine\Persistence\ObjectManager; use Draw\Bundle\SonataImportBundle\Entity\Column; use Draw\Bundle\SonataImportBundle\Entity\Import; -use Draw\Component\Tester\MockTrait; use PHPUnit\Framework\TestCase; use Symfony\Component\Validator\Constraints\Callback; -use Symfony\Component\Validator\GroupSequenceProviderInterface; use Symfony\Component\Validator\Validation; /** @@ -20,8 +17,6 @@ */ class ImportTest extends TestCase { - use MockTrait; - private Import $entity; protected function setUp(): void @@ -29,11 +24,6 @@ protected function setUp(): void $this->entity = new Import(); } - public function testConstruct(): void - { - static::assertInstanceOf(GroupSequenceProviderInterface::class, $this->entity); - } - public function testIdMutator(): void { static::assertNull($this->entity->getId()); @@ -82,7 +72,7 @@ public function testStateMutator(): void public function testColumnsMutator(): void { - static::assertInstanceOf(Collection::class, $collection = $this->entity->getColumns()); + $collection = $this->entity->getColumns(); static::assertCount(0, $collection); static::assertSame( @@ -134,7 +124,7 @@ public function testUpdateTimeStamp(): void $this->entity->updateTimestamp( new LifecycleEventArgs( $this->entity, - $this->createMock(EntityManagerInterface::class) + static::createStub(EntityManagerInterface::class) ) ); @@ -144,17 +134,18 @@ public function testUpdateTimeStamp(): void $this->entity->updateTimestamp( new LifecycleEventArgs( $this->entity, - $this->createMock(ObjectManager::class) + static::createStub(ObjectManager::class) ) ); static::assertNotSame($dateTime, $dateTime = $this->entity->getUpdatedAt()); + /** @var array> $changeSet */ $changeSet = ['updatedAt' => []]; $this->entity->updateTimestamp( new PreUpdateEventArgs( $this->entity, - $this->createMock(EntityManagerInterface::class), + static::createStub(EntityManagerInterface::class), $changeSet ) ); diff --git a/packages/sonata-import-bundle/composer.json b/packages/sonata-import-bundle/composer.json index e40edbea2..4fd80d9fa 100644 --- a/packages/sonata-import-bundle/composer.json +++ b/packages/sonata-import-bundle/composer.json @@ -27,7 +27,7 @@ "require-dev": { "draw/tester": "^0.39", "knplabs/doctrine-behaviors": "*", - "phpunit/phpunit": "^11.3 || ^12.0" + "phpunit/phpunit": "^11.3 || ^12.0 || ^13.0" }, "minimum-stability": "dev", "prefer-stable": true, diff --git a/packages/sonata-integration-bundle/Tests/User/Action/TwoFactorAuthenticationResendCodeActionTest.php b/packages/sonata-integration-bundle/Tests/User/Action/TwoFactorAuthenticationResendCodeActionTest.php index acf09bd75..efdc22a07 100644 --- a/packages/sonata-integration-bundle/Tests/User/Action/TwoFactorAuthenticationResendCodeActionTest.php +++ b/packages/sonata-integration-bundle/Tests/User/Action/TwoFactorAuthenticationResendCodeActionTest.php @@ -60,12 +60,12 @@ public function getRoles(): array return []; } - public function getPassword(): ?string + public function getPassword(): null { return null; } - public function getSalt(): ?string + public function getSalt(): null { return null; } @@ -84,6 +84,7 @@ public function getUserIdentifier(): string ->expects(static::once()) ->method('generateAndSend') ->with($user) + ->seal() ; $this->urlGenerator @@ -91,6 +92,7 @@ public function getUserIdentifier(): string ->method('generate') ->with('admin_2fa_login', ['preferProvider' => 'email']) ->willReturn($url = uniqid('https://')) + ->seal() ; $securityMock = $this->createMock(Security::class); @@ -98,6 +100,7 @@ public function getUserIdentifier(): string ->expects(static::once()) ->method('getUser') ->willReturn($user) + ->seal() ; $result = \call_user_func( diff --git a/packages/sonata-integration-bundle/composer.json b/packages/sonata-integration-bundle/composer.json index 241bd0385..a9ad72465 100644 --- a/packages/sonata-integration-bundle/composer.json +++ b/packages/sonata-integration-bundle/composer.json @@ -24,7 +24,7 @@ "draw/tester": "^0.39", "draw/user-bundle": "^0.39", "firebase/php-jwt": "^6.1", - "phpunit/phpunit": "^11.3 || ^12.0", + "phpunit/phpunit": "^11.3 || ^12.0 || ^13.0", "scheb/2fa-bundle": "^7.6", "scheb/2fa-email": "^7.6", "endroid/qr-code": "^6.0", diff --git a/packages/tester-bundle/PHPUnit/Extension/SetUpAutowire/AutowireServiceMock.php b/packages/tester-bundle/PHPUnit/Extension/SetUpAutowire/AutowireServiceDouble.php similarity index 96% rename from packages/tester-bundle/PHPUnit/Extension/SetUpAutowire/AutowireServiceMock.php rename to packages/tester-bundle/PHPUnit/Extension/SetUpAutowire/AutowireServiceDouble.php index 5db2ba188..2516f5c48 100644 --- a/packages/tester-bundle/PHPUnit/Extension/SetUpAutowire/AutowireServiceMock.php +++ b/packages/tester-bundle/PHPUnit/Extension/SetUpAutowire/AutowireServiceDouble.php @@ -2,12 +2,12 @@ namespace Draw\Bundle\TesterBundle\PHPUnit\Extension\SetUpAutowire; -use Draw\Component\Tester\PHPUnit\Extension\SetUpAutowire\AutowireMock; +use Draw\Component\Tester\PHPUnit\Extension\SetUpAutowire\AutowireDouble; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; #[\Attribute(\Attribute::TARGET_PROPERTY)] -class AutowireServiceMock extends AutowireMock +class AutowireServiceDouble extends AutowireDouble { use KernelTestCaseAutowireDependentTrait; diff --git a/packages/tester-bundle/README.md b/packages/tester-bundle/README.md index ee17963ed..c40c4a835 100644 --- a/packages/tester-bundle/README.md +++ b/packages/tester-bundle/README.md @@ -114,12 +114,13 @@ use Draw\Bundle\TesterBundle\PHPUnit\Extension\SetUpAutowire\AutowireEntity; use Draw\Bundle\TesterBundle\PHPUnit\Extension\SetUpAutowire\AutowireLoggerTester; use Draw\Bundle\TesterBundle\PHPUnit\Extension\SetUpAutowire\AutowireParameter; use Draw\Bundle\TesterBundle\PHPUnit\Extension\SetUpAutowire\AutowireReloadedEntity;use Draw\Bundle\TesterBundle\PHPUnit\Extension\SetUpAutowire\AutowireService; -use Draw\Bundle\TesterBundle\PHPUnit\Extension\SetUpAutowire\AutowireServiceMock; +use Draw\Bundle\TesterBundle\PHPUnit\Extension\SetUpAutowire\AutowireServiceDouble; use Draw\Bundle\TesterBundle\PHPUnit\Extension\SetUpAutowire\AutowireTransportTester; use Draw\Component\Tester\PHPUnit\Extension\SetUpAutowire\AutowiredInterface; -use Draw\Component\Tester\PHPUnit\Extension\SetUpAutowire\AutowireMock; +use Draw\Component\Tester\PHPUnit\Extension\SetUpAutowire\AutowireDouble; use Monolog\Handler\TestHandler; use PHPUnit\Framework\MockObject\MockObject; +use PHPUnit\Framework\MockObject\Stub; use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; class MyTest extends KernelTestCase implements AutowiredInterface @@ -131,15 +132,15 @@ class MyTest extends KernelTestCase implements AutowiredInterface static private ?User $user = null; // Create a mock of an interface - #[AutowireMock] + #[AutowireDouble] private AServiceInterface&MockObject $aService // Will hook MyService from the test container. Your test need to extend KernelTestCase. // - // The AutowireMockProperty will replace the aService property of $myService. + // The AutowireDoubleProperty will replace the aService property of $myService. // By defaults, it will use the same property name in the current test case but you can specify a different one using the second parameter. #[AutowireService] - #[AutowireMockProperty('aService')] + #[AutowireDoubleProperty('aService')] private MyService $myService; // Will hook the parameter from the container using ParameterBagInterface::resolveValue @@ -157,10 +158,10 @@ class MyTest extends KernelTestCase implements AutowiredInterface #[AutowireEntity(['email' => 'test@example.com'])] private User $user; - // Will create a mock object of MyOtherService and call container->set(MyOtherService::class, $mockObject) + // Will create a stub of MyOtherService and call container->set(MyOtherService::class, $stub) // You can also set the service id to use in the container as the first parameter of the attribute. - #[AutowireServiceMock] - private MyOtherService&MockObject $myOtherService; + #[AutowireServiceDouble] + private MyOtherService&Stub $myOtherService; } ``` @@ -174,7 +175,10 @@ created before the other service preventing the exception: ```php namespace App\Tests; -use App\MyService;use Draw\Bundle\TesterBundle\PHPUnit\Extension\SetUpAutowire\AutowireClient;use Draw\Component\Tester\PHPUnit\Extension\SetUpAutowire\AutowiredInterface;use Symfony\Bundle\FrameworkBundle\KernelBrowser;use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; +use Draw\Bundle\TesterBundle\PHPUnit\Extension\SetUpAutowire\AutowireClient; +use Draw\Component\Tester\PHPUnit\Extension\SetUpAutowire\AutowiredInterface; +use Symfony\Bundle\FrameworkBundle\KernelBrowser; +use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; class MyTest extends WebTestCase implements AutowiredInterface { diff --git a/packages/tester-bundle/composer.json b/packages/tester-bundle/composer.json index ff69b392d..8e80585e0 100644 --- a/packages/tester-bundle/composer.json +++ b/packages/tester-bundle/composer.json @@ -22,7 +22,7 @@ }, "require-dev": { "draw/profiling": "^0.39", - "phpunit/phpunit": "^11.3 || ^12.0", + "phpunit/phpunit": "^11.3 || ^12.0 || ^13.0", "symfony/messenger": "^6.4.0", "symfony/yaml": "^6.4.0" }, diff --git a/packages/tester/.phpstorm.meta.php b/packages/tester/.phpstorm.meta.php index 4d9d562f2..4c08950d9 100644 --- a/packages/tester/.phpstorm.meta.php +++ b/packages/tester/.phpstorm.meta.php @@ -3,6 +3,6 @@ namespace PHPSTORM_META; override( - \Draw\Component\Tester\MockTrait::mockProperty(2), + \Draw\Component\Tester\DoubleTrait::mockProperty(2), map([""=>"$2"]) ); diff --git a/packages/tester/AssertTrait.php b/packages/tester/AssertTrait.php index 99f948c78..89eda7d8f 100644 --- a/packages/tester/AssertTrait.php +++ b/packages/tester/AssertTrait.php @@ -38,18 +38,6 @@ public function assertNotContains($needle, string $message = ''): self } // example-end: assertNotContains - // example-start: assertContainsOnly - /** - * Asserts that a haystack contains only values of a given type. - */ - public function assertContainsOnly(string $type, ?bool $isNativeType = null, string $message = ''): self - { - Assert::assertContainsOnly($type, $this->getData(), $isNativeType, $message); - - return $this; - } - // example-end: assertContainsOnly - // example-start: assertContainsOnlyInstancesOf /** * Asserts that a haystack contains only instances of a given class name. @@ -62,18 +50,6 @@ public function assertContainsOnlyInstancesOf(string $className, string $message } // example-end: assertContainsOnlyInstancesOf - // example-start: assertNotContainsOnly - /** - * Asserts that a haystack does not contain only values of a given type. - */ - public function assertNotContainsOnly(string $type, ?bool $isNativeType = null, string $message = ''): self - { - Assert::assertNotContainsOnly($type, $this->getData(), $isNativeType, $message); - - return $this; - } - // example-end: assertNotContainsOnly - // example-start: assertCount /** * Asserts the number of elements of an array, Countable or Traversable. @@ -396,18 +372,6 @@ public function assertStringMatchesFormat(string $format, string $message = ''): } // example-end: assertStringMatchesFormat - // example-start: assertStringNotMatchesFormat - /** - * Asserts that a string does not match a given format string. - */ - public function assertStringNotMatchesFormat(string $format, string $message = ''): self - { - Assert::assertStringNotMatchesFormat($format, $this->getData(), $message); - - return $this; - } - // example-end: assertStringNotMatchesFormat - // example-start: assertStringStartsWith /** * Asserts that a string starts with a given prefix. diff --git a/packages/tester/DoctrineOrmTrait.php b/packages/tester/DoctrineOrmTrait.php index 01582d070..15ac15424 100644 --- a/packages/tester/DoctrineOrmTrait.php +++ b/packages/tester/DoctrineOrmTrait.php @@ -110,7 +110,7 @@ public function getRepository(string $persistentObject, ?string $persistentManag return $this->entityManager->getRepository($persistentObject); } - public function getManagerForClass(string $class): ?ObjectManager + public function getManagerForClass(string $class): ObjectManager { return $this->entityManager; } diff --git a/packages/tester/MockTrait.php b/packages/tester/DoubleTrait.php similarity index 87% rename from packages/tester/MockTrait.php rename to packages/tester/DoubleTrait.php index 05ec5f8df..752371a2a 100644 --- a/packages/tester/MockTrait.php +++ b/packages/tester/DoubleTrait.php @@ -7,13 +7,16 @@ use PHPUnit\Framework\Constraint\Constraint; use PHPUnit\Framework\MockObject\MockBuilder; use PHPUnit\Framework\MockObject\MockObject; +use PHPUnit\Framework\MockObject\Stub; -trait MockTrait +trait DoubleTrait { abstract public function getMockBuilder(string $className): MockBuilder; abstract protected function createMock(string $originalClassName): MockObject; + abstract protected static function createStub(string $type): Stub; + /** * @template T of object * @@ -32,6 +35,17 @@ public function mockProperty(object $object, string $property, string $originalC return $mock; } + public function stubProperty(object $object, string $property, string $type): Stub + { + ReflectionAccessor::setPropertyValue( + $object, + $property, + $stub = static::createStub($type) + ); + + return $stub; + } + public static function withConsecutive(array $firstCallArguments, array ...$consecutiveCallsArguments): iterable { foreach ($consecutiveCallsArguments as $consecutiveCallArguments) { diff --git a/packages/tester/PHPUnit/Extension/SetUpAutowire/AsMock.php b/packages/tester/PHPUnit/Extension/SetUpAutowire/AsMock.php new file mode 100644 index 000000000..2d368a715 --- /dev/null +++ b/packages/tester/PHPUnit/Extension/SetUpAutowire/AsMock.php @@ -0,0 +1,35 @@ + $propertyNames + */ + public function __construct( + private string|array $propertyNames, + ) { + } + + /** + * @return array + */ + public function getPropertyNames(): array + { + return (array) $this->propertyNames; + } + + /** + * @return array + */ + public function getOptions(): array + { + return [ + 'asMock' => true, + ]; + } +} diff --git a/packages/tester/PHPUnit/Extension/SetUpAutowire/AutowireDouble.php b/packages/tester/PHPUnit/Extension/SetUpAutowire/AutowireDouble.php new file mode 100644 index 000000000..425f7eaf3 --- /dev/null +++ b/packages/tester/PHPUnit/Extension/SetUpAutowire/AutowireDouble.php @@ -0,0 +1,72 @@ +getName(); + $reflectionPropertyType = $reflectionProperty->getType(); + + if (!$reflectionPropertyType instanceof \ReflectionIntersectionType) { + throw new \RuntimeException('Property '.$propertyName.' (class '.$testCase::class.') must have a type hint intersection with '.MockObject::class.' or '.Stub::class.'.'); + } + + if (2 !== \count($reflectionPropertyTypes = $reflectionPropertyType->getTypes())) { + throw new \RuntimeException('Property '.$propertyName.' (class '.$testCase::class.') must have a type hint intersection with '.MockObject::class.' or '.Stub::class.'.'); + } + + $targetType = null; + $doubleType = null; + + /** @var \ReflectionNamedType $reflectionPropertyType */ + foreach ($reflectionPropertyTypes as $reflectionPropertyType) { + if (\in_array($reflectionPropertyType->getName(), [MockObject::class, Stub::class], true)) { + $doubleType = $reflectionPropertyType; + } else { + $targetType = $reflectionPropertyType; + } + } + + if (!$targetType instanceof \ReflectionNamedType) { + throw new \RuntimeException('Target type of property '.$propertyName.' (class '.$testCase::class.') could not be determined.'); + } + + if (!$doubleType instanceof \ReflectionNamedType) { + throw new \RuntimeException('Double type of property '.$propertyName.' (class '.$testCase::class.') could not be determined.'); + } + + $reflectionProperty->setValue( + $testCase, + ReflectionAccessor::callMethod( + $testCase, + MockObject::class === $doubleType->getName() || ($this->options['asMock'] ?? false) + ? 'createMock' + : 'createStub', + $targetType->getName() + ) + ); + } + + public function setOptions(array $options): void + { + $this->options = $options; + } +} diff --git a/packages/tester/PHPUnit/Extension/SetUpAutowire/AutowireMockProperty.php b/packages/tester/PHPUnit/Extension/SetUpAutowire/AutowireDoubleProperty.php similarity index 94% rename from packages/tester/PHPUnit/Extension/SetUpAutowire/AutowireMockProperty.php rename to packages/tester/PHPUnit/Extension/SetUpAutowire/AutowireDoubleProperty.php index 093740e81..86038179a 100644 --- a/packages/tester/PHPUnit/Extension/SetUpAutowire/AutowireMockProperty.php +++ b/packages/tester/PHPUnit/Extension/SetUpAutowire/AutowireDoubleProperty.php @@ -6,7 +6,7 @@ use PHPUnit\Framework\TestCase; #[\Attribute(\Attribute::TARGET_PROPERTY | \Attribute::IS_REPEATABLE)] -class AutowireMockProperty implements AutowireInterface +class AutowireDoubleProperty implements AutowireInterface { public static function getPriority(): int { diff --git a/packages/tester/PHPUnit/Extension/SetUpAutowire/AutowireMock.php b/packages/tester/PHPUnit/Extension/SetUpAutowire/AutowireMock.php deleted file mode 100644 index 56931b053..000000000 --- a/packages/tester/PHPUnit/Extension/SetUpAutowire/AutowireMock.php +++ /dev/null @@ -1,49 +0,0 @@ -getName(); - $type = $reflectionProperty->getType(); - - if (!$type instanceof \ReflectionIntersectionType) { - throw new \RuntimeException('Property '.$propertyName.' of class '.$testCase::class.' must have a type hint intersection with Mock.'); - } - - $types = $type->getTypes(); - - if (2 !== \count($types)) { - throw new \RuntimeException('Property '.$propertyName.' of class '.$testCase::class.' can only have 2 intersection types.'); - } - - foreach ($types as $type) { - if (!$type instanceof \ReflectionNamedType) { - throw new \RuntimeException('Property '.$propertyName.' of class '.$testCase::class.' intersection must be of named type.'); - } - - if (MockObject::class === $type->getName()) { - continue; - } - - $reflectionProperty->setValue( - $testCase, - ReflectionAccessor::callMethod($testCase, 'createMock', $type->getName()) - ); - - return; - } - } -} diff --git a/packages/tester/PHPUnit/Extension/SetUpAutowire/OptionAwareAutowireInterface.php b/packages/tester/PHPUnit/Extension/SetUpAutowire/OptionAwareAutowireInterface.php new file mode 100644 index 000000000..2fabdf8a6 --- /dev/null +++ b/packages/tester/PHPUnit/Extension/SetUpAutowire/OptionAwareAutowireInterface.php @@ -0,0 +1,10 @@ + + */ + public function getPropertyNames(): array; + + /** + * @return array + */ + public function getOptions(): array; +} diff --git a/packages/tester/PHPUnit/Extension/SetUpAutowire/SetUpAutowireExtension.php b/packages/tester/PHPUnit/Extension/SetUpAutowire/SetUpAutowireExtension.php index 6e852e4bc..ed9011e7e 100644 --- a/packages/tester/PHPUnit/Extension/SetUpAutowire/SetUpAutowireExtension.php +++ b/packages/tester/PHPUnit/Extension/SetUpAutowire/SetUpAutowireExtension.php @@ -22,6 +22,11 @@ public function bootstrap(Configuration $configuration, Facade $facade, Paramete */ private array $propertyAttributes = []; + /** + * @var array> + */ + private array $propertyOptionsMap = []; + public function __construct( private ParameterCollection $parameters, ) { @@ -50,6 +55,8 @@ public function notify(TestPrepared $event): void return; } + $propertyOptionsMap = $this->getPropertyOptionsMap($testCase, $test->methodName()); + foreach ($this->getPropertyAttributes($testCase) as [$property, $autowire]) { \assert($autowire instanceof AutowireInterface); @@ -57,6 +64,10 @@ public function notify(TestPrepared $event): void $autowire->configure($this->parameters); } + if ($autowire instanceof OptionAwareAutowireInterface) { + $autowire->setOptions($propertyOptionsMap[$property->getName()] ?? []); + } + $autowire->autowire($testCase, $property); } @@ -75,11 +86,11 @@ private function getPropertyAttributes(TestCase $testCase): iterable if (!\array_key_exists($className, $this->propertyAttributes)) { $autowireAttributes = []; - foreach ((new \ReflectionObject($testCase))->getProperties() as $property) { + foreach (new \ReflectionObject($testCase)->getProperties() as $property) { foreach ($property->getAttributes() as $attribute) { - $attributeClass = $attribute->getName(); + $reflectionClass = new \ReflectionClass($attribute->getName()); - if (!(new \ReflectionClass($attributeClass))->implementsInterface(AutowireInterface::class)) { + if (!$reflectionClass->implementsInterface(AutowireInterface::class)) { continue; } @@ -97,6 +108,44 @@ private function getPropertyAttributes(TestCase $testCase): iterable yield $property; } } + + /** + * @return iterable> + */ + private function getPropertyOptionsMap(AutowiredInterface $testCase, string $methodName): iterable + { + $key = $testCase::class.'::'.$methodName; + + if (!\array_key_exists($key, $this->propertyOptionsMap)) { + $reflectionClass = new \ReflectionClass($testCase); + $reflectionMethod = $reflectionClass->getMethod($methodName); + + $optionsMap = []; + + foreach ($reflectionMethod->getAttributes() as $attribute) { + $attributeInstance = $attribute->newInstance(); + + if (!$attributeInstance instanceof PropertyOptionAwareMethodAttributeInterface) { + continue; + } + + foreach ($attributeInstance->getPropertyNames() as $propertyName) { + if (!\array_key_exists($propertyName, $optionsMap)) { + $optionsMap[$propertyName] = []; + } + + $optionsMap[$propertyName] = array_merge( + $optionsMap[$propertyName], + $attributeInstance->getOptions() + ); + } + } + + $this->propertyOptionsMap[$key] = $optionsMap; + } + + return $this->propertyOptionsMap[$key]; + } }, ); } diff --git a/packages/tester/README.md b/packages/tester/README.md index b8c43bd79..c80825be6 100644 --- a/packages/tester/README.md +++ b/packages/tester/README.md @@ -76,7 +76,8 @@ Once this is done, your test need to implement the `AutowiredInterface` interfac ```php namespace App\Tests; -use Draw\Component\Tester\PHPUnit\Extension\SetUpAutowire\AutowiredInterface;use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; +use Draw\Component\Tester\PHPUnit\Extension\SetUpAutowire\AutowiredInterface; +use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; class MyTest extends KernelTestCase implements AutowiredInterface { @@ -94,23 +95,23 @@ use App\MyInterface; use App\MyObject; use App\MySecondObject; use Draw\Component\Tester\PHPUnit\Extension\SetUpAutowire\AutowiredInterface; -use Draw\Component\Tester\PHPUnit\Extension\SetUpAutowire\AutowireMock; -use PHPUnit\Framework\MockObject\MockObject; +use Draw\Component\Tester\PHPUnit\Extension\SetUpAutowire\AutowireDouble; +use PHPUnit\Framework\MockObject\Stub; use PHPUnit\Framework\TestCase; class MyTest extends TestCase implements AutowiredInterface { - // Will create a mock object of MyInterface and assigned it to property. - // This can be used in conjunction with the AutowireMockProperty (see below). - #[AutowireMock] - private MyInterface&MockObject $aService + // Will create a stub of MyInterface and assigned it to property. + // This can be used in conjunction with the AutowireDoubleProperty (see below). + #[AutowireDouble] + private MyInterface&Stub $aService - // The AutowireMockProperty will replace the aService property of $myObject. - #[AutowireMockProperty('aService')] + // The AutowireDoubleProperty will replace the aService property of $myObject. + #[AutowireDoubleProperty('aService')] private MyObject $myObject; // By defaults, it will use the same property name in the current test case, but you can specify a different one using the second parameter. - #[AutowireMockProperty('aService', 'anotherProperty')] + #[AutowireDoubleProperty('aService', 'anotherProperty')] private MySecondObject $mySecondObject; public function setUp(): void @@ -130,11 +131,14 @@ If you need to access those property in your `setUp` method, you can use the `Au ```php namespace App\Tests; -use App\MyService;use Draw\Bundle\TesterBundle\PHPUnit\Extension\SetUpAutowire\AutowireService;use Draw\Component\Tester\PHPUnit\Extension\SetUpAutowire\AutowiredCompletionAwareInterface;use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; +use Draw\Component\Tester\PHPUnit\Extension\SetUpAutowire\AutowiredCompletionAwareInterface; +use Draw\Component\Tester\PHPUnit\Extension\SetUpAutowire\AutowireDouble; +use PHPUnit\Framework\MockObject\MockObject; +use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; class MyTest extends KernelTestCase implements AutowiredCompletionAwareInterface { - #[AutowireMock] + #[AutowireDouble] private MyInterface&MockObject $aService public function postAutowire(): void @@ -147,6 +151,87 @@ class MyTest extends KernelTestCase implements AutowiredCompletionAwareInterface } ``` +#### Handling test doubles (Stubs vs. Mocks) + +PHPUnit 13 introduces a strict distinction between **Stubs** and **Mocks**. If you use a `MockObject` but do not configure any +expectations on it, PHPUnit will throw a deprecation warning: +> *No expectations were configured for the mock object for App\MyInterface. Consider refactoring your test code to use a test stub +> instead. The #[AllowMockObjectsWithoutExpectations] attribute can be used to opt out of this check.* + +To prevent this warning, this extension allows a property defined as a `Stub` to dynamically morph into a `MockObject` on a per-test +basis. + +The extension automatically looks at the intersection type of your property to decide whether to call `createStub` or `createMock`: + +```php +namespace App\Tests; + +use App\MyInterface; +use Draw\Component\Tester\PHPUnit\Extension\SetUpAutowire\AutowiredInterface; +use Draw\Component\Tester\PHPUnit\Extension\SetUpAutowire\AutowireDouble; +use PHPUnit\Framework\MockObject\MockObject; +use PHPUnit\Framework\MockObject\Stub; +use PHPUnit\Framework\TestCase; + +class MyTest extends TestCase implements AutowiredInterface +{ + // The extension detects `&Stub` and initializes a PHPUnit Stub + #[AutowireDouble] + private MyInterface&Stub $aService; + + // The extension detects `&MockObject` and initializes a PHPUnit MockObject + #[AutowireDouble] + private MyInterface&MockObject $anotherService; +} +``` + +For dependencies that act as a `Stub` in most tests but require expectations in a few, type-hint the property with `&Stub`. +This ensures it safely stays a lightweight Stub by default, protecting you from PHPUnit warning mentioned above. When a +specific test method requires it to be a Mock, add the `#[AsMock]` attribute to that method. Inside the test, use native +PHP `assert` to instantly unlock full IDE autocomplete for `expects()`: + +```php +namespace App\Tests; + +use App\MyInterface; +use Draw\Component\Tester\PHPUnit\Extension\SetUpAutowire\AsMock; +use Draw\Component\Tester\PHPUnit\Extension\SetUpAutowire\AutowiredInterface; +use Draw\Component\Tester\PHPUnit\Extension\SetUpAutowire\AutowireDouble; +use PHPUnit\Framework\MockObject\MockObject; +use PHPUnit\Framework\MockObject\Stub; +use PHPUnit\Framework\TestCase; + +class MyTest extends TestCase implements AutowiredInterface +{ + #[AutowireDouble] + private MyInterface&Stub $aService; + + public function test1(): void + { + $this->aService + ->method('method1') + ->willReturn(1) + ; + + // assertions + } + + #[AsMock('aService')] + public function test2(): void + { + \assert($this->aService instanceof MockObject); + + $this->aService + ->expects(self::once()) + ->method('method1') + ->willReturn(2) + ; + + // assertions + } +} +``` + #### Creating you own Autowire attribute You can create your own attribute to autowire your own property. @@ -156,7 +241,8 @@ You just need to create an attribute that implement the `AutowireInterface` inte ```php namespace App\Test\PHPUnit\SetUpAutowire; -use Draw\Component\Tester\PHPUnit\Extension\SetUpAutowire\AutowireInterface;use PHPUnit\Framework\TestCase; +use Draw\Component\Tester\PHPUnit\Extension\SetUpAutowire\AutowireInterface; +use PHPUnit\Framework\TestCase; #[\Attribute(\Attribute::TARGET_PROPERTY)] class AutowireRandomInt implements AutowireInterface diff --git a/packages/tester/Tests/DataTesterTest.php b/packages/tester/Tests/DataTesterTest.php index 22aa64c6c..fa505b942 100644 --- a/packages/tester/Tests/DataTesterTest.php +++ b/packages/tester/Tests/DataTesterTest.php @@ -42,7 +42,7 @@ public function testPath(): void 'Return value of path must be a new object.' ); - static::assertInstanceOf(DataTester::class, $tester); + static::assertInstanceOf(DataTester::class, $newTester); static::assertSame('value', $newTester->getData()); } diff --git a/packages/tester/composer.json b/packages/tester/composer.json index e5e4d2bc2..328910a2f 100644 --- a/packages/tester/composer.json +++ b/packages/tester/composer.json @@ -19,7 +19,7 @@ "ext-simplexml": "*", "draw/core": "^0.39", "guzzlehttp/psr7": "^1.8 || ^2.0", - "phpunit/phpunit": "^11.3 || ^12.0", + "phpunit/phpunit": "^11.3 || ^12.0 || ^13.0", "psr/http-message": "^1.0 || ^2.0", "symfony/property-access": "^6.4.0" }, diff --git a/packages/user-bundle/Tests/AccountLocker/Entity/UserLockTest.php b/packages/user-bundle/Tests/AccountLocker/Entity/UserLockTest.php index 5ed1426b1..a83d4757c 100644 --- a/packages/user-bundle/Tests/AccountLocker/Entity/UserLockTest.php +++ b/packages/user-bundle/Tests/AccountLocker/Entity/UserLockTest.php @@ -22,14 +22,8 @@ protected function setUp(): void public function testConstructorDefault(): void { - static::assertNotNull($this->entity->getId(), 'Id will always have a value'); static::assertNull($this->entity->getUser(), 'User must be null'); static::assertNull($this->entity->getReason(), 'Reason must be null'); - static::assertInstanceOf( - \DateTimeInterface::class, - $this->entity->getCreatedAt(), - 'Created at must be a datetime interface' - ); static::assertNull($this->entity->getLockOn(), 'Lock on must be null'); static::assertNull($this->entity->getExpiresAt(), 'Expires at must be null'); static::assertNull($this->entity->getUnlockUntil(), 'Unlock until must be null'); diff --git a/packages/user-bundle/Tests/EventListener/TwoFactorAuthenticationListenerTest.php b/packages/user-bundle/Tests/EventListener/TwoFactorAuthenticationListenerTest.php index 6696eb93e..383b0af75 100644 --- a/packages/user-bundle/Tests/EventListener/TwoFactorAuthenticationListenerTest.php +++ b/packages/user-bundle/Tests/EventListener/TwoFactorAuthenticationListenerTest.php @@ -12,9 +12,7 @@ use Draw\Bundle\UserBundle\Security\TwoFactorAuthentication\Entity\TwoFactorAuthenticationUserInterface; use Draw\Component\Security\Core\Security; use PHPUnit\Framework\Attributes\DataProvider; -use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; -use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\Routing\Generator\UrlGeneratorInterface; @@ -25,39 +23,16 @@ */ class TwoFactorAuthenticationListenerTest extends TestCase { - private const ENABLE_ROUTE = 'route'; + private const string ENABLE_ROUTE = 'route'; - private TwoFactorAuthenticationListener $object; - - /** - * @var UrlGeneratorInterface|MockObject - */ - private UrlGeneratorInterface $urlGenerator; - - /** - * @var Security|MockObject - */ - private Security $security; - - protected function setUp(): void + public function testGetSubscribedEvents(): void { - $this->object = new TwoFactorAuthenticationListener( - $this->urlGenerator = $this->createMock(UrlGeneratorInterface::class), - $this->security = $this->createMock(Security::class), + $object = new TwoFactorAuthenticationListener( + static::createStub(UrlGeneratorInterface::class), + static::createStub(Security::class), self::ENABLE_ROUTE ); - } - public function testConstruct(): void - { - static::assertInstanceOf( - EventSubscriberInterface::class, - $this->object - ); - } - - public function testGetSubscribedEvents(): void - { static::assertSame( [ UserRequestInterceptionEvent::class => [ @@ -65,7 +40,7 @@ public function testGetSubscribedEvents(): void ['allowHandlingRequestWhenTwoFactorAuthenticationInProgress', 1000], ], ], - $this->object::getSubscribedEvents() + $object::getSubscribedEvents() ); } @@ -75,13 +50,16 @@ public function testCheckNeedToEnableTwoFactorAuthentication( bool $allowHandingRequest, bool $redirect, ): void { + $urlGenerator = static::createStub(UrlGeneratorInterface::class); $url = null; + if ($redirect) { $user = $event->getUser(); static::assertInstanceOf(SecurityUserInterface::class, $user); - $this->urlGenerator + $urlGenerator = $this->createMock(UrlGeneratorInterface::class); + $urlGenerator ->expects(static::once()) ->method('generate') ->with( @@ -89,10 +67,17 @@ public function testCheckNeedToEnableTwoFactorAuthentication( ['id' => $user->getId()] ) ->willReturn($url = uniqid('url')) + ->seal() ; } - $this->object->checkNeedToEnableTwoFactorAuthentication($event); + $object = new TwoFactorAuthenticationListener( + $urlGenerator, + static::createStub(Security::class), + self::ENABLE_ROUTE + ); + + $object->checkNeedToEnableTwoFactorAuthentication($event); static::assertSame($allowHandingRequest, $event->getAllowHandlingRequest()); @@ -122,12 +107,12 @@ public function getRoles(): array return []; } - public function getPassword(): ?string + public function getPassword(): null { return null; } - public function getSalt(): ?string + public function getSalt(): null { return null; } @@ -291,16 +276,23 @@ public function isForceEnablingTwoFactorAuthentication(): bool public function testAllowHandlingRequestWhenTwoFactorAuthenticationInProgressTrue(): void { - $this->security + $object = new TwoFactorAuthenticationListener( + static::createStub(UrlGeneratorInterface::class), + $security = $this->createMock(Security::class), + self::ENABLE_ROUTE + ); + + $security ->expects(static::once()) ->method('isGranted') ->with('IS_AUTHENTICATED_2FA_IN_PROGRESS') ->willReturn(true) + ->seal() ; - $this->object->allowHandlingRequestWhenTwoFactorAuthenticationInProgress( + $object->allowHandlingRequestWhenTwoFactorAuthenticationInProgress( $event = new UserRequestInterceptionEvent( - $this->createMock(SecurityUserInterface::class), + static::createStub(SecurityUserInterface::class), new Request() ) ); @@ -310,16 +302,23 @@ public function testAllowHandlingRequestWhenTwoFactorAuthenticationInProgressTru public function testAllowHandlingRequestWhenTwoFactorAuthenticationInProgressFalse(): void { - $this->security + $object = new TwoFactorAuthenticationListener( + static::createStub(UrlGeneratorInterface::class), + $security = $this->createMock(Security::class), + self::ENABLE_ROUTE + ); + + $security ->expects(static::once()) ->method('isGranted') ->with('IS_AUTHENTICATED_2FA_IN_PROGRESS') ->willReturn(false) + ->seal() ; - $this->object->allowHandlingRequestWhenTwoFactorAuthenticationInProgress( + $object->allowHandlingRequestWhenTwoFactorAuthenticationInProgress( $event = new UserRequestInterceptionEvent( - $this->createMock(SecurityUserInterface::class), + static::createStub(SecurityUserInterface::class), new Request() ) ); diff --git a/packages/user-bundle/composer.json b/packages/user-bundle/composer.json index b3caf7731..463d820f3 100644 --- a/packages/user-bundle/composer.json +++ b/packages/user-bundle/composer.json @@ -31,7 +31,7 @@ "draw/tester": "^0.39", "endroid/qr-code": "^6.0", "firebase/php-jwt": "^6.1", - "phpunit/phpunit": "^11.3 || ^12.0", + "phpunit/phpunit": "^11.3 || ^12.0 || ^13.0", "scheb/2fa-bundle": "^7.6", "scheb/2fa-totp": "^7.6" }, diff --git a/packages/validator/Constraints/RemoteFileExistsValidator.php b/packages/validator/Constraints/RemoteFileExistsValidator.php index f9414ecd2..40371cf30 100644 --- a/packages/validator/Constraints/RemoteFileExistsValidator.php +++ b/packages/validator/Constraints/RemoteFileExistsValidator.php @@ -24,12 +24,21 @@ public function validate($value, Constraint $constraint): void public function remoteFileExists(string $url): bool { - if ($handle = @fopen($url, 'r')) { - fclose($handle); + $ch = curl_init($url); - return true; - } + curl_setopt($ch, \CURLOPT_NOBODY, true); + curl_setopt($ch, \CURLOPT_RETURNTRANSFER, true); + curl_setopt($ch, \CURLOPT_CONNECTTIMEOUT, 3); + curl_setopt($ch, \CURLOPT_TIMEOUT, 3); + curl_setopt($ch, \CURLOPT_FOLLOWLOCATION, true); + curl_setopt($ch, \CURLOPT_MAXREDIRS, 3); + + curl_exec($ch); + + $httpCode = curl_getinfo($ch, \CURLINFO_HTTP_CODE); + + unset($ch); - return false; + return $httpCode >= 200 && $httpCode < 300; } } diff --git a/packages/validator/Tests/Constraints/PhpCallableTest.php b/packages/validator/Tests/Constraints/PhpCallableTest.php index 288962799..09fb0c66b 100644 --- a/packages/validator/Tests/Constraints/PhpCallableTest.php +++ b/packages/validator/Tests/Constraints/PhpCallableTest.php @@ -6,7 +6,6 @@ use Draw\Component\Validator\Constraints\PhpCallableValidator; use PHPUnit\Framework\Attributes\CoversClass; use PHPUnit\Framework\TestCase; -use Symfony\Component\Validator\Constraint; /** * @internal @@ -23,11 +22,6 @@ protected function setUp(): void public function testConstruct(): void { - static::assertInstanceOf( - Constraint::class, - $this->object - ); - static::assertSame( 'Execution of function with {{ value }} does not return expected result.', $this->object->message diff --git a/packages/validator/Tests/Constraints/PhpCallableValidatorTest.php b/packages/validator/Tests/Constraints/PhpCallableValidatorTest.php index e1e1f99c6..bf5483691 100644 --- a/packages/validator/Tests/Constraints/PhpCallableValidatorTest.php +++ b/packages/validator/Tests/Constraints/PhpCallableValidatorTest.php @@ -10,7 +10,6 @@ use Symfony\Component\Validator\Constraint; use Symfony\Component\Validator\Constraints\IsTrue; use Symfony\Component\Validator\Constraints\NotNull; -use Symfony\Component\Validator\ConstraintValidatorInterface; use Symfony\Component\Validator\Exception\UnexpectedTypeException; use Symfony\Component\Validator\Validation; @@ -27,14 +26,6 @@ protected function setUp(): void $this->object = new PhpCallableValidator(); } - public function testConstruct(): void - { - static::assertInstanceOf( - ConstraintValidatorInterface::class, - $this->object - ); - } - public function testValidateInvalidConstraint(): void { $this->expectException(UnexpectedTypeException::class); diff --git a/packages/validator/Tests/Constraints/RemoteFileExistsTest.php b/packages/validator/Tests/Constraints/RemoteFileExistsTest.php index b7e0cfc45..1c41ecea2 100644 --- a/packages/validator/Tests/Constraints/RemoteFileExistsTest.php +++ b/packages/validator/Tests/Constraints/RemoteFileExistsTest.php @@ -5,7 +5,6 @@ use Draw\Component\Validator\Constraints\RemoteFileExists; use PHPUnit\Framework\Attributes\CoversClass; use PHPUnit\Framework\TestCase; -use Symfony\Component\Validator\Constraint; /** * @internal @@ -20,14 +19,6 @@ protected function setUp(): void $this->object = new RemoteFileExists(); } - public function testConstruct(): void - { - static::assertInstanceOf( - Constraint::class, - $this->object - ); - } - public function testGetTargets(): void { static::assertSame( diff --git a/packages/validator/Tests/Constraints/RemoteFileExistsValidatorTest.php b/packages/validator/Tests/Constraints/RemoteFileExistsValidatorTest.php index 7428a266b..fe8f0b16e 100644 --- a/packages/validator/Tests/Constraints/RemoteFileExistsValidatorTest.php +++ b/packages/validator/Tests/Constraints/RemoteFileExistsValidatorTest.php @@ -8,7 +8,6 @@ use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; use Symfony\Component\Validator\Constraints\NotNull; -use Symfony\Component\Validator\ConstraintValidatorInterface; use Symfony\Component\Validator\Exception\UnexpectedTypeException; use Symfony\Component\Validator\Validation; @@ -25,14 +24,6 @@ protected function setUp(): void $this->object = new RemoteFileExistsValidator(); } - public function testConstruct(): void - { - static::assertInstanceOf( - ConstraintValidatorInterface::class, - $this->object - ); - } - public function testValidateInvalidConstraint(): void { $this->expectException(UnexpectedTypeException::class); diff --git a/packages/validator/Tests/Constraints/StrtotimeTest.php b/packages/validator/Tests/Constraints/StrtotimeTest.php index b877c3eaf..aacd9b85b 100644 --- a/packages/validator/Tests/Constraints/StrtotimeTest.php +++ b/packages/validator/Tests/Constraints/StrtotimeTest.php @@ -2,7 +2,6 @@ namespace Draw\Component\Validator\Tests\Constraints; -use Draw\Component\Validator\Constraints\PhpCallable; use Draw\Component\Validator\Constraints\Strtotime; use PHPUnit\Framework\Attributes\CoversClass; use PHPUnit\Framework\TestCase; @@ -21,11 +20,6 @@ protected function setUp(): void $this->object = new Strtotime(); } - public function testConstruct(): void - { - static::assertInstanceOf(PhpCallable::class, $this->object); - } - public function testCallable(): void { static::assertSame( diff --git a/packages/validator/composer.json b/packages/validator/composer.json index d5fade379..ed09a228f 100644 --- a/packages/validator/composer.json +++ b/packages/validator/composer.json @@ -17,7 +17,7 @@ "symfony/validator": "^6.4.0" }, "require-dev": { - "phpunit/phpunit": "^11.3 || ^12.0", + "phpunit/phpunit": "^11.3 || ^12.0 || ^13.0", "doctrine/persistence": "^2.2 || ^3.0", "draw/dependency-injection": "^0.39" }, diff --git a/packages/workflow/Tests/EventListener/AddTransitionNameToContextListenerTest.php b/packages/workflow/Tests/EventListener/AddTransitionNameToContextListenerTest.php index 0a56ae0d1..b339c16fb 100644 --- a/packages/workflow/Tests/EventListener/AddTransitionNameToContextListenerTest.php +++ b/packages/workflow/Tests/EventListener/AddTransitionNameToContextListenerTest.php @@ -4,7 +4,6 @@ use Draw\Component\Workflow\EventListener\AddTransitionNameToContextListener; use PHPUnit\Framework\TestCase; -use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\Workflow\Event\TransitionEvent; use Symfony\Component\Workflow\Marking; use Symfony\Component\Workflow\Transition; @@ -21,14 +20,6 @@ protected function setUp(): void $this->object = new AddTransitionNameToContextListener(); } - public function testConstruct(): void - { - static::assertInstanceOf( - EventSubscriberInterface::class, - $this->object - ); - } - public function testGetSubscribedEvents(): void { static::assertSame( diff --git a/packages/workflow/Tests/EventListener/AddUserToContextListenerTest.php b/packages/workflow/Tests/EventListener/AddUserToContextListenerTest.php index fdc3d113e..d64025242 100644 --- a/packages/workflow/Tests/EventListener/AddUserToContextListenerTest.php +++ b/packages/workflow/Tests/EventListener/AddUserToContextListenerTest.php @@ -4,9 +4,7 @@ use Draw\Component\Security\Core\Security; use Draw\Component\Workflow\EventListener\AddUserToContextListener; -use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; -use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\Security\Core\User\UserInterface; use Symfony\Component\Workflow\Event\TransitionEvent; use Symfony\Component\Workflow\Marking; @@ -16,45 +14,34 @@ */ class AddUserToContextListenerTest extends TestCase { - private AddUserToContextListener $object; - - private MockObject&Security $security; - - protected function setUp(): void - { - $this->object = new AddUserToContextListener( - $this->security = $this->createMock(Security::class) - ); - } - - public function testConstruct(): void + public function testGetSubscribedEvents(): void { - static::assertInstanceOf( - EventSubscriberInterface::class, - $this->object + $object = new AddUserToContextListener( + static::createStub(Security::class) ); - } - public function testGetSubscribedEvents(): void - { static::assertSame( ['workflow.transition' => 'addUserToContext'], - $this->object::getSubscribedEvents() + $object::getSubscribedEvents() ); } public function testAddUserToContextNoUser(): void { + $object = new AddUserToContextListener( + static::createStub(Security::class) + ); + $transitionEvent = new TransitionEvent( new \stdClass(), - $this->createMock(Marking::class), + static::createStub(Marking::class), ); $transitionEvent->setContext($originalContext = [ uniqid('key-') => uniqid('value-'), ]); - $this->object->addUserToContext($transitionEvent); + $object->addUserToContext($transitionEvent); static::assertSame( $originalContext, @@ -64,22 +51,27 @@ public function testAddUserToContextNoUser(): void public function testAddUserToContextProperUser(): void { + $object = new AddUserToContextListener( + $security = $this->createMock(Security::class) + ); + $transitionEvent = new TransitionEvent( new \stdClass(), - $this->createMock(Marking::class), + static::createStub(Marking::class), ); $transitionEvent->setContext($originalContext = [ uniqid('key-') => uniqid('value-'), ]); - $this->security + $security ->expects(static::once()) ->method('getUser') - ->willReturn($user = $this->createMock(UserInterface::class)) + ->willReturn($user = static::createStub(UserInterface::class)) + ->seal() ; - $this->object->addUserToContext($transitionEvent); + $object->addUserToContext($transitionEvent); static::assertSame( array_merge( diff --git a/packages/workflow/composer.json b/packages/workflow/composer.json index c343ef472..bf5cc9cce 100644 --- a/packages/workflow/composer.json +++ b/packages/workflow/composer.json @@ -21,7 +21,7 @@ "require-dev": { "draw/security": "^0.39", "draw/dependency-injection": "^0.39", - "phpunit/phpunit": "^11.3 || ^12.0", + "phpunit/phpunit": "^11.3 || ^12.0 || ^13.0", "symfony/security-core": "^6.4.0" }, "minimum-stability": "dev", diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 1a1ffebc8..1e7771d68 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -1,47 +1,212 @@ parameters: ignoreErrors: - - message: "#^Parameter \\#1 \\$node of method Symfony\\\\Component\\\\Config\\\\Definition\\\\Builder\\\\NodeBuilder\\:\\:append\\(\\) expects Symfony\\\\Component\\\\Config\\\\Definition\\\\Builder\\\\NodeDefinition, Symfony\\\\Component\\\\Config\\\\Definition\\\\Builder\\\\NodeParentInterface\\|null given\\.$#" + message: '#^Property App\\Entity\\UserAddress\:\:\$id \(int\|null\) is never assigned int so it can be removed from the property type\.$#' + identifier: property.unusedType + count: 1 + path: app/src/Entity/UserAddress.php + + - + message: '#^Property App\\Entity\\UserTag\:\:\$id \(int\|null\) is never assigned int so it can be removed from the property type\.$#' + identifier: property.unusedType + count: 1 + path: app/src/Entity/UserTag.php + + - + message: '#^Property App\\Message\\NewUserMessage\:\:\$user \(App\\Entity\\User\|Draw\\Component\\Messenger\\DoctrineEnvelopeEntityReference\\Stamp\\PropertyReferenceStamp\|null\) is never assigned Draw\\Component\\Messenger\\DoctrineEnvelopeEntityReference\\Stamp\\PropertyReferenceStamp so it can be removed from the property type\.$#' + identifier: property.unusedType + count: 1 + path: app/src/Message/NewUserMessage.php + + - + message: '#^Property App\\Message\\NewUserMessage\:\:\$user \(App\\Entity\\User\|Draw\\Component\\Messenger\\DoctrineEnvelopeEntityReference\\Stamp\\PropertyReferenceStamp\|null\) is never assigned null so it can be removed from the property type\.$#' + identifier: property.unusedType + count: 1 + path: app/src/Message/NewUserMessage.php + + - + message: '#^Property Draw\\Component\\CronJob\\Entity\\CronJob\:\:\$id \(int\|null\) is never assigned int so it can be removed from the property type\.$#' + identifier: property.unusedType + count: 1 + path: packages/cron-job/Entity/CronJob.php + + - + message: '#^Property Draw\\Component\\CronJob\\Entity\\CronJobExecution\:\:\$id \(int\|null\) is never assigned int so it can be removed from the property type\.$#' + identifier: property.unusedType + count: 1 + path: packages/cron-job/Entity/CronJobExecution.php + + - + message: '#^Property Draw\\Component\\CronJob\\Message\\ExecuteCronJobMessage\:\:\$execution \(Draw\\Component\\CronJob\\Entity\\CronJobExecution\|Draw\\Component\\Messenger\\DoctrineEnvelopeEntityReference\\Stamp\\PropertyReferenceStamp\|null\) is never assigned Draw\\Component\\Messenger\\DoctrineEnvelopeEntityReference\\Stamp\\PropertyReferenceStamp so it can be removed from the property type\.$#' + identifier: property.unusedType + count: 1 + path: packages/cron-job/Message/ExecuteCronJobMessage.php + + - + message: '#^Property Draw\\Component\\CronJob\\Message\\ExecuteCronJobMessage\:\:\$execution \(Draw\\Component\\CronJob\\Entity\\CronJobExecution\|Draw\\Component\\Messenger\\DoctrineEnvelopeEntityReference\\Stamp\\PropertyReferenceStamp\|null\) is never assigned null so it can be removed from the property type\.$#' + identifier: property.unusedType + count: 1 + path: packages/cron-job/Message/ExecuteCronJobMessage.php + + - + message: '#^Property Draw\\Component\\EntityMigrator\\Message\\MigrateEntityCommand\:\:\$entity \(Draw\\Component\\EntityMigrator\\Entity\\EntityMigrationInterface\|Draw\\Component\\Messenger\\DoctrineEnvelopeEntityReference\\Stamp\\PropertyReferenceStamp\|null\) is never assigned null so it can be removed from the property type\.$#' + identifier: property.unusedType + count: 1 + path: packages/entity-migrator/Message/MigrateEntityCommand.php + + - + message: '#^Call to function method_exists\(\) with Symfony\\Component\\DependencyInjection\\Definition and ''getBindings'' will always evaluate to true\.$#' + identifier: function.alreadyNarrowedType + count: 1 + path: packages/log/DependencyInjection/Compiler/LoggerDecoratorPass.php + + - + message: '#^Parameter \#1 \$node of method Symfony\\Component\\Config\\Definition\\Builder\\NodeBuilder\:\:append\(\) expects Symfony\\Component\\Config\\Definition\\Builder\\NodeDefinition, Symfony\\Component\\Config\\Definition\\Builder\\NodeParentInterface\|null given\.$#' + identifier: argument.type count: 1 path: packages/log/DependencyInjection/LogIntegration.php - - message: "#^Call to static method PHPUnit\\\\Framework\\\\Assert\\:\\:assertEmpty\\(\\) with array\\{object\\{\\}&stdClass, object\\{\\}&stdClass\\} will always evaluate to false\\.$#" + message: '#^Property Draw\\Component\\Messenger\\Tests\\EventListener\\StopOnNewVersionListenerTest\:\:\$deployedVersion \(string\|null\) is never assigned string so it can be removed from the property type\.$#' + identifier: property.unusedType + count: 1 + path: packages/messenger/Tests/EventListener/StopOnNewVersionListenerTest.php + + - + message: '#^Call to static method PHPUnit\\Framework\\Assert\:\:assertTrue\(\) with true will always evaluate to true\.$#' + identifier: staticMethod.alreadyNarrowedType + count: 1 + path: packages/messenger/Tests/Transport/DrawTransportTest.php + + - + message: '#^Call to function class_exists\(\) with ''Doctrine\\\\Persistence\\\\Proxy'' will always evaluate to false\.$#' + identifier: function.impossibleType count: 1 - path: packages/messenger/Tests/DoctrineMessageBusHook/Entity/MessageHolderTraitTest.php + path: packages/open-api/EventListener/SerializationControllerListener.php - - message: "#^Parameter \\$param of method Draw\\\\Component\\\\OpenApi\\\\Tests\\\\Extraction\\\\Extractor\\\\PhpDoc\\\\PhpDocOperationExtractorStubService\\:\\:invalidTypeParameter\\(\\) has invalid type Draw\\\\Component\\\\OpenApi\\\\Tests\\\\Extraction\\\\Extractor\\\\PhpDoc\\\\toto\\.$#" + message: '#^Call to static method PHPUnit\\Framework\\Assert\:\:assertTrue\(\) with true will always evaluate to true\.$#' + identifier: staticMethod.alreadyNarrowedType + count: 1 + path: packages/open-api/Tests/Extraction/Extractor/JmsSerializer/PropertiesExtractorTest.php + + - + message: '#^Call to static method PHPUnit\\Framework\\Assert\:\:assertTrue\(\) with true will always evaluate to true\.$#' + identifier: staticMethod.alreadyNarrowedType + count: 2 + path: packages/open-api/Tests/Extraction/Extractor/OpenApi/RootSchemaExtractorTest.php + + - + message: '#^Parameter \$param of method Draw\\Component\\OpenApi\\Tests\\Extraction\\Extractor\\PhpDoc\\PhpDocOperationExtractorStubService\:\:invalidTypeParameter\(\) has invalid type Draw\\Component\\OpenApi\\Tests\\Extraction\\Extractor\\PhpDoc\\toto\.$#' + identifier: class.notFound count: 1 path: packages/open-api/Tests/Extraction/Extractor/PhpDoc/OperationExtractorTest.php - - message: "#^Property Draw\\\\Component\\\\OpenApi\\\\Tests\\\\Mock\\\\Model\\\\TestClass\\:\\:\\$propertyFromBody is unused\\.$#" + message: '#^Property Draw\\Component\\OpenApi\\Tests\\Mock\\Model\\TestClass\:\:\$propertyFromBody is unused\.$#' + identifier: property.unused count: 1 path: packages/open-api/Tests/Mock/Model/TestClass.php - - message: "#^Property Draw\\\\Component\\\\OpenApi\\\\Tests\\\\Mock\\\\Model\\\\TestClass\\:\\:\\$propertyGroupExclusion is unused\\.$#" + message: '#^Property Draw\\Component\\OpenApi\\Tests\\Mock\\Model\\TestClass\:\:\$propertyGroupExclusion is unused\.$#' + identifier: property.unused count: 1 path: packages/open-api/Tests/Mock/Model/TestClass.php - - message: "#^Call to static method PHPUnit\\\\Framework\\\\Assert\\:\\:assertInstanceOf\\(\\) with 'DateTime' and null will always evaluate to false\\.$#" - count: 2 + message: '#^Using nullsafe property access "\?\-\>joinColumns" on left side of \?\? is unnecessary\. Use \-\> instead\.$#' + identifier: nullsafe.neverNull + count: 1 + path: packages/sonata-extra-bundle/PreventDelete/PreventDeleteRelationLoader.php + + - + message: '#^Trait Draw\\Bundle\\SonataExtraBundle\\Test\\AdminTestHelperTrait is used zero times and is not analysed\.$#' + identifier: trait.unused + count: 1 + path: packages/sonata-extra-bundle/Test/AdminTestHelperTrait.php + + - + message: '#^Call to function class_exists\(\) with ''Knp\\\\DoctrineBehaviors\\\\Contract\\\\Entity\\\\TranslatableInterface'' will always evaluate to false\.$#' + identifier: function.impossibleType + count: 1 + path: packages/sonata-import-bundle/DependencyInjection/Configuration.php + + - + message: '#^Call to static method PHPUnit\\Framework\\Assert\:\:assertSame\(\) with \*NEVER\* and DateTime\|null will always evaluate to false\.$#' + identifier: staticMethod.impossibleType + count: 1 + path: packages/sonata-import-bundle/Tests/Entity/ImportTest.php + + - + message: '#^Parameter \#1 \$expected of static method PHPUnit\\Framework\\Assert\:\:assertSame\(\) contains unresolvable type\.$#' + identifier: argument.unresolvableType + count: 1 path: packages/sonata-import-bundle/Tests/Entity/ImportTest.php - - message: "#^Class Draw\\\\Bundle\\\\SonataIntegrationBundle\\\\User\\\\Security\\\\AdminLoginAuthenticator extends @final class Symfony\\\\Component\\\\Security\\\\Http\\\\Authenticator\\\\FormLoginAuthenticator\\.$#" + message: '#^Class Draw\\Bundle\\SonataIntegrationBundle\\User\\Security\\AdminLoginAuthenticator extends @final class Symfony\\Component\\Security\\Http\\Authenticator\\FormLoginAuthenticator\.$#' + identifier: class.extendsFinalByPhpDoc count: 1 path: packages/sonata-integration-bundle/User/Security/AdminLoginAuthenticator.php - - message: "#^Parameter \\#1 \\$callback of function set_error_handler expects \\(callable\\(int, string, string, int\\)\\: bool\\)\\|null, Closure\\(\\)\\: null given\\.$#" + message: '#^Trait Draw\\Bundle\\TesterBundle\\Messenger\\MessageHandlerAssertionTrait is used zero times and is not analysed\.$#' + identifier: trait.unused + count: 1 + path: packages/tester-bundle/Messenger/MessageHandlerAssertionTrait.php + + - + message: '#^Parameter \#1 \$callback of function set_error_handler expects \(callable\(int, string, string, int\)\: bool\)\|null, Closure\(\)\: null given\.$#' + identifier: argument.type count: 1 path: packages/tester-bundle/Tests/bootstrap.php - - message: "#^Parameter \\#1 \\$callback of function set_error_handler expects \\(callable\\(int, string, string, int\\)\\: bool\\)\\|null, Closure\\(\\)\\: null given\\.$#" + message: '#^Call to function method_exists\(\) with Symfony\\Component\\Console\\Application and ''addCommand'' will always evaluate to false\.$#' + identifier: function.impossibleType + count: 1 + path: packages/tester/Application/CommandTestTrait.php + + - + message: '#^Strict comparison using \!\=\= between null and Draw\\Component\\Tester\\DataTester will always evaluate to true\.$#' + identifier: notIdentical.alwaysTrue + count: 1 + path: packages/tester/Tests/DataTesterTest.php + + - + message: '#^Call to static method PHPUnit\\Framework\\Assert\:\:assertTrue\(\) with true will always evaluate to true\.$#' + identifier: staticMethod.alreadyNarrowedType + count: 1 + path: packages/tester/Tests/ExampleTest.php + + - + message: '#^Property Draw\\Bundle\\UserBundle\\DTO\\Credential\:\:\$password \(string\|null\) is never assigned string so it can be removed from the property type\.$#' + identifier: property.unusedType + count: 1 + path: packages/user-bundle/DTO/Credential.php + + - + message: '#^Property Draw\\Bundle\\UserBundle\\DTO\\Credential\:\:\$username \(string\|null\) is never assigned string so it can be removed from the property type\.$#' + identifier: property.unusedType + count: 1 + path: packages/user-bundle/DTO/Credential.php + + - + message: '#^Call to static method PHPUnit\\Framework\\Assert\:\:assertInstanceOf\(\) with ''Doctrine\\\\Persistence\\\\ManagerRegistry'' and Doctrine\\Persistence\\ManagerRegistry&PHPUnit\\Framework\\MockObject\\Stub will always evaluate to true\.$#' + identifier: staticMethod.alreadyNarrowedType + count: 1 + path: tests/TesterBundle/PHPUnit/Extension/SetUpAutoWire/SetUpAutowireExtensionTest.php + + - + message: '#^Call to static method PHPUnit\\Framework\\Assert\:\:assertInstanceOf\(\) with ''PHPUnit\\\\Framework\\\\MockObject\\\\Stub'' and Doctrine\\Persistence\\ManagerRegistry&PHPUnit\\Framework\\MockObject\\Stub will always evaluate to true\.$#' + identifier: staticMethod.alreadyNarrowedType + count: 1 + path: tests/TesterBundle/PHPUnit/Extension/SetUpAutoWire/SetUpAutowireExtensionTest.php + + - + message: '#^Parameter \#1 \$callback of function set_error_handler expects \(callable\(int, string, string, int\)\: bool\)\|null, Closure\(\)\: null given\.$#' + identifier: argument.type count: 1 path: tests/bootstrap.php diff --git a/phpunit.xml.dist b/phpunit.dist.xml similarity index 97% rename from phpunit.xml.dist rename to phpunit.dist.xml index 9bd98aa3a..6e03acfe2 100644 --- a/phpunit.xml.dist +++ b/phpunit.dist.xml @@ -1,12 +1,13 @@ diff --git a/symfony.lock b/symfony.lock index b0a592c68..665fb5b5e 100644 --- a/symfony.lock +++ b/symfony.lock @@ -148,12 +148,12 @@ "version": "v5.4.0" }, "friendsofphp/php-cs-fixer": { - "version": "3.13", + "version": "3.95", "recipe": { "repo": "github.com/symfony/recipes", "branch": "main", - "version": "3.0", - "ref": "be2103eb4a20942e28a6dd87736669b757132435" + "version": "3.39", + "ref": "97aaf9026490db73b86c23d49e5774bc89d2b232" }, "files": [ ".php-cs-fixer.dist.php" @@ -198,9 +198,6 @@ "mtdowling/jmespath.php": { "version": "2.6.1" }, - "myclabs/deep-copy": { - "version": "1.10.2" - }, "nelmio/cors-bundle": { "version": "2.1", "recipe": { @@ -222,12 +219,6 @@ "pelago/emogrifier": { "version": "v6.0.0" }, - "phar-io/manifest": { - "version": "2.0.3" - }, - "phar-io/version": { - "version": "3.1.0" - }, "phpdocumentor/reflection-common": { "version": "2.2.0" }, @@ -244,44 +235,30 @@ "version": "0.5.7" }, "phpstan/phpstan": { - "version": "1.10", + "version": "2.2", "recipe": { "repo": "github.com/symfony/recipes-contrib", "branch": "main", "version": "1.0", - "ref": "f10b8054de1a94a3b9e8806a6453fd5c98491c44" + "ref": "5e490cc197fb6bb1ae22e5abbc531ddc633b6767" }, "files": [ "phpstan.dist.neon" ] }, - "phpunit/php-code-coverage": { - "version": "9.2.7" - }, - "phpunit/php-file-iterator": { - "version": "3.0.5" - }, - "phpunit/php-invoker": { - "version": "3.1.1" - }, - "phpunit/php-text-template": { - "version": "2.0.4" - }, - "phpunit/php-timer": { - "version": "5.0.3" - }, "phpunit/phpunit": { - "version": "9.5", + "version": "13.2", "recipe": { "repo": "github.com/symfony/recipes", - "branch": "master", - "version": "9.3", - "ref": "a6249a6c4392e9169b87abf93225f7f9f59025e6" + "branch": "main", + "version": "11.1", + "ref": "ca0bc067abfb40a8de1b2561b96cbfc2b833c314" }, "files": [ ".env.test", - "phpunit.xml.dist", - "tests/bootstrap.php" + "phpunit.dist.xml", + "tests/bootstrap.php", + "bin/phpunit" ] }, "psr/cache": { @@ -333,51 +310,6 @@ "scheb/2fa-totp": { "version": "v5.12.1" }, - "sebastian/cli-parser": { - "version": "1.0.1" - }, - "sebastian/code-unit": { - "version": "1.0.8" - }, - "sebastian/code-unit-reverse-lookup": { - "version": "2.0.3" - }, - "sebastian/comparator": { - "version": "4.0.6" - }, - "sebastian/complexity": { - "version": "2.0.2" - }, - "sebastian/diff": { - "version": "4.0.4" - }, - "sebastian/environment": { - "version": "5.1.3" - }, - "sebastian/exporter": { - "version": "4.0.3" - }, - "sebastian/global-state": { - "version": "5.0.3" - }, - "sebastian/lines-of-code": { - "version": "1.0.3" - }, - "sebastian/object-enumerator": { - "version": "4.0.4" - }, - "sebastian/object-reflector": { - "version": "2.0.4" - }, - "sebastian/recursion-context": { - "version": "4.0.4" - }, - "sebastian/type": { - "version": "2.3.4" - }, - "sebastian/version": { - "version": "3.0.2" - }, "sensiolabs/ansi-to-html": { "version": "1.2", "recipe": { @@ -826,9 +758,6 @@ "symfony/yaml": { "version": "v5.3.6" }, - "theseer/tokenizer": { - "version": "1.2.1" - }, "twig/string-extra": { "version": "v3.3.3" }, diff --git a/tests/SonataExtraBundle/Security/Voter/RelationPreventDeleteCanVoterTest.php b/tests/SonataExtraBundle/Security/Voter/RelationPreventDeleteCanVoterTest.php index 1c3600b9f..f825aea84 100644 --- a/tests/SonataExtraBundle/Security/Voter/RelationPreventDeleteCanVoterTest.php +++ b/tests/SonataExtraBundle/Security/Voter/RelationPreventDeleteCanVoterTest.php @@ -31,7 +31,7 @@ public function testVoteNoSubject(): void static::assertSame( VoterInterface::ACCESS_ABSTAIN, $this->object->vote( - $this->createMock(TokenInterface::class), + static::createStub(TokenInterface::class), null, ['SONATA_CAN_DELETE'] ) @@ -43,7 +43,7 @@ public function testVoteNotProperSubject(): void static::assertSame( VoterInterface::ACCESS_ABSTAIN, $this->object->vote( - $this->createMock(TokenInterface::class), + static::createStub(TokenInterface::class), new User(), ['SONATA_CAN_DELETE'] ) @@ -55,7 +55,7 @@ public function testVoteWithRelationOtherAttribute(): void static::assertSame( VoterInterface::ACCESS_ABSTAIN, $this->object->vote( - $this->createMock(TokenInterface::class), + static::createStub(TokenInterface::class), $this->entityManager->getRepository(Tag::class)->findOneBy(['name' => 'admin']), ['SONATA_CAN_CREATE'] ) @@ -67,7 +67,7 @@ public function testVoteWithRelation(): void static::assertSame( VoterInterface::ACCESS_DENIED, $this->object->vote( - $this->createMock(TokenInterface::class), + static::createStub(TokenInterface::class), $this->entityManager->getRepository(Tag::class)->findOneBy(['name' => 'admin']), ['SONATA_CAN_DELETE'] ) @@ -79,7 +79,7 @@ public function testVoteNoRelation(): void static::assertSame( VoterInterface::ACCESS_ABSTAIN, $this->object->vote( - $this->createMock(TokenInterface::class), + static::createStub(TokenInterface::class), $this->entityManager->getRepository(Tag::class)->findOneBy(['name' => 'NotUse']), ['SONATA_CAN_DELETE'] ) diff --git a/tests/SonataImportBundle/ImporterTest.php b/tests/SonataImportBundle/ImporterTest.php index 7d9692bb9..02eca5133 100644 --- a/tests/SonataImportBundle/ImporterTest.php +++ b/tests/SonataImportBundle/ImporterTest.php @@ -30,9 +30,9 @@ public function testImport(): void register_shutdown_function('unlink', $fileName); - fputcsv($file, ['name', 'active', 'translation#en.label', 'translation#fr.label']); + fputcsv($file, ['name', 'active', 'translation#en.label', 'translation#fr.label'], escape: '\\'); - fputcsv($file, [$name = 'test'.uniqid(), '1', 'testEn', 'testFr']); + fputcsv($file, [$name = 'test'.uniqid(), '1', 'testEn', 'testFr'], escape: '\\'); $import = (new Import()) ->setEntityClass(Tag::class) diff --git a/tests/TesterBundle/PHPUnit/Extension/SetUpAutoWire/AutowireServiceMockTest.php b/tests/TesterBundle/PHPUnit/Extension/SetUpAutoWire/AutowireServiceDoubleTest.php similarity index 70% rename from tests/TesterBundle/PHPUnit/Extension/SetUpAutoWire/AutowireServiceMockTest.php rename to tests/TesterBundle/PHPUnit/Extension/SetUpAutoWire/AutowireServiceDoubleTest.php index 878403956..786e9afe2 100644 --- a/tests/TesterBundle/PHPUnit/Extension/SetUpAutoWire/AutowireServiceMockTest.php +++ b/tests/TesterBundle/PHPUnit/Extension/SetUpAutoWire/AutowireServiceDoubleTest.php @@ -5,23 +5,25 @@ use App\Entity\User; use Draw\Bundle\TesterBundle\PHPUnit\Extension\SetUpAutowire\AutowireClient; use Draw\Bundle\TesterBundle\PHPUnit\Extension\SetUpAutowire\AutowireService; -use Draw\Bundle\TesterBundle\PHPUnit\Extension\SetUpAutowire\AutowireServiceMock; +use Draw\Bundle\TesterBundle\PHPUnit\Extension\SetUpAutowire\AutowireServiceDouble; use Draw\Bundle\TesterBundle\WebTestCase; +use Draw\Component\Tester\PHPUnit\Extension\SetUpAutowire\AsMock; use Draw\Component\Tester\PHPUnit\Extension\SetUpAutowire\AutowiredInterface; use Draw\DoctrineExtra\ORM\EntityHandler; use PHPUnit\Framework\MockObject\MockObject; +use PHPUnit\Framework\MockObject\Stub; use Symfony\Bundle\FrameworkBundle\KernelBrowser; /** * @internal */ -class AutowireServiceMockTest extends WebTestCase implements AutowiredInterface +class AutowireServiceDoubleTest extends WebTestCase implements AutowiredInterface { #[AutowireClient] private KernelBrowser $client; - #[AutowireServiceMock] - private EntityHandler&MockObject $entityHandlerMock; + #[AutowireServiceDouble] + private EntityHandler&Stub $entityHandlerDouble; #[AutowireService] private EntityHandler $entityHandler; @@ -29,18 +31,22 @@ class AutowireServiceMockTest extends WebTestCase implements AutowiredInterface public function testInstanceOfEntityHandler(): void { static::assertSame( - $this->entityHandlerMock, + $this->entityHandlerDouble, $this->entityHandler ); } + #[AsMock('entityHandlerDouble')] public function testUsersAction(): void { - $this->entityHandlerMock + \assert($this->entityHandlerDouble instanceof MockObject); + + $this->entityHandlerDouble ->expects(static::once()) ->method('findAll') ->with(User::class) ->willReturn([]) + ->seal() ; $this->client diff --git a/tests/TesterBundle/PHPUnit/Extension/SetUpAutoWire/SetUpAutowireExtensionTest.php b/tests/TesterBundle/PHPUnit/Extension/SetUpAutoWire/SetUpAutowireExtensionTest.php index d32a5b7e6..4a5c2ce48 100644 --- a/tests/TesterBundle/PHPUnit/Extension/SetUpAutoWire/SetUpAutowireExtensionTest.php +++ b/tests/TesterBundle/PHPUnit/Extension/SetUpAutoWire/SetUpAutowireExtensionTest.php @@ -10,9 +10,9 @@ use Draw\Bundle\TesterBundle\PHPUnit\Extension\SetUpAutowire\AutowireService; use Draw\Bundle\TesterBundle\PHPUnit\Extension\SetUpAutowire\AutowireTransportTester; use Draw\Component\Tester\PHPUnit\Extension\SetUpAutowire\AutowiredInterface; -use Draw\Component\Tester\PHPUnit\Extension\SetUpAutowire\AutowireMock; -use Draw\Component\Tester\PHPUnit\Extension\SetUpAutowire\AutowireMockProperty; -use PHPUnit\Framework\MockObject\MockObject; +use Draw\Component\Tester\PHPUnit\Extension\SetUpAutowire\AutowireDouble; +use Draw\Component\Tester\PHPUnit\Extension\SetUpAutowire\AutowireDoubleProperty; +use PHPUnit\Framework\MockObject\Stub; use Symfony\Bundle\FrameworkBundle\KernelBrowser; use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; @@ -23,12 +23,12 @@ class SetUpAutowireExtensionTest extends WebTestCase implements AutowiredInterfa { #[ AutowireService, - AutowireMockProperty('managerRegistry') + AutowireDoubleProperty('managerRegistry') ] private UserSetCommentNullMigration $userSetCommentNullMigration; - #[AutowireMock] - private ManagerRegistry&MockObject $managerRegistry; + #[AutowireDouble] + private ManagerRegistry&Stub $managerRegistry; #[AutowireClient] private KernelBrowser $client; @@ -55,7 +55,7 @@ public function testAutowiredClient(): void ); } - public function testAutowiredMock(): void + public function testAutowiredDouble(): void { static::assertInstanceOf( ManagerRegistry::class, @@ -63,15 +63,15 @@ public function testAutowiredMock(): void ); static::assertInstanceOf( - MockObject::class, + Stub::class, $this->managerRegistry ); } - public function testAutowireMockProperty(): void + public function testAutowireDoubleProperty(): void { static::assertSame( - (new \ReflectionProperty($this->userSetCommentNullMigration, 'managerRegistry')) + new \ReflectionProperty($this->userSetCommentNullMigration, 'managerRegistry') ->getValue($this->userSetCommentNullMigration), $this->managerRegistry );