diff --git a/.gitignore b/.gitignore index dcd4a9d..e4a1df5 100644 --- a/.gitignore +++ b/.gitignore @@ -8,13 +8,9 @@ /vendor/ ###< symfony/framework-bundle ### -###> phpunit/phpunit ### -/phpunit.xml -.phpunit.result.cache -###< phpunit/phpunit ### - ###> symfony/phpunit-bridge ### .phpunit.result.cache +.phpunit.cache /phpunit.xml ###< symfony/phpunit-bridge ### diff --git a/composer.json b/composer.json index 77c7718..79940c9 100644 --- a/composer.json +++ b/composer.json @@ -129,13 +129,13 @@ "phpstan/phpstan": "^2.1", "phpstan/phpstan-doctrine": "^2.0", "phpstan/phpstan-symfony": "^2.0", - "phpunit/phpunit": "^9.5", + "phpunit/phpunit": "^12", "rector/rector": "^2.4", "symfony/browser-kit": "7.4.*", "symfony/css-selector": "7.4.*", "symfony/debug-bundle": "7.4.*", "symfony/maker-bundle": "^1.0", - "symfony/phpunit-bridge": "^7.1", + "symfony/phpunit-bridge": "^7.4", "symfony/stopwatch": "7.4.*", "symfony/web-profiler-bundle": "7.4.*" } diff --git a/composer.lock b/composer.lock index 9aa9040..3771297 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": "6a0cf88f72de9d58a0f6930d58f7635e", + "content-hash": "48214c3fb3ebf33fc3f5606f1ed70d57", "packages": [ { "name": "carbonphp/carbon-doctrine-types", @@ -12765,35 +12765,33 @@ }, { "name": "phpunit/php-code-coverage", - "version": "9.2.32", + "version": "12.5.7", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "85402a822d1ecf1db1096959413d35e1c37cf1a5" + "reference": "186dab580576598076de6818596d12b61801880e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/85402a822d1ecf1db1096959413d35e1c37cf1a5", - "reference": "85402a822d1ecf1db1096959413d35e1c37cf1a5", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/186dab580576598076de6818596d12b61801880e", + "reference": "186dab580576598076de6818596d12b61801880e", "shasum": "" }, "require": { "ext-dom": "*", "ext-libxml": "*", "ext-xmlwriter": "*", - "nikic/php-parser": "^4.19.1 || ^5.1.0", - "php": ">=7.3", - "phpunit/php-file-iterator": "^3.0.6", - "phpunit/php-text-template": "^2.0.4", - "sebastian/code-unit-reverse-lookup": "^2.0.3", - "sebastian/complexity": "^2.0.3", - "sebastian/environment": "^5.1.5", - "sebastian/lines-of-code": "^1.0.4", - "sebastian/version": "^3.0.2", - "theseer/tokenizer": "^1.2.3" + "nikic/php-parser": "^5.7.0", + "php": ">=8.3", + "phpunit/php-text-template": "^5.0", + "sebastian/complexity": "^5.0", + "sebastian/environment": "^8.1.2", + "sebastian/lines-of-code": "^4.0.1", + "sebastian/version": "^6.0", + "theseer/tokenizer": "^2.0.1" }, "require-dev": { - "phpunit/phpunit": "^9.6" + "phpunit/phpunit": "^12.5.28" }, "suggest": { "ext-pcov": "PHP extension that provides line coverage", @@ -12802,7 +12800,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "9.2.x-dev" + "dev-main": "12.5.x-dev" } }, "autoload": { @@ -12831,40 +12829,52 @@ "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/9.2.32" + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/12.5.7" }, "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-code-coverage", + "type": "tidelift" } ], - "time": "2024-08-22T04:23:01+00:00" + "time": "2026-06-01T13:24:19+00:00" }, { "name": "phpunit/php-file-iterator", - "version": "3.0.6", + "version": "6.0.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-file-iterator.git", - "reference": "cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf" + "reference": "a248d1640ab059b075f53a2ef0f9856e864e06b5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf", - "reference": "cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/a248d1640ab059b075f53a2ef0f9856e864e06b5", + "reference": "a248d1640ab059b075f53a2ef0f9856e864e06b5", "shasum": "" }, "require": { - "php": ">=7.3" + "php": ">=8.3" }, "require-dev": { - "phpunit/phpunit": "^9.3" + "phpunit/phpunit": "^12.5.33" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.0-dev" + "dev-main": "6.0-dev" } }, "autoload": { @@ -12891,36 +12901,49 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/php-file-iterator/issues", - "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/3.0.6" + "security": "https://github.com/sebastianbergmann/php-file-iterator/security/policy", + "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/6.0.2" }, "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-file-iterator", + "type": "tidelift" } ], - "time": "2021-12-02T12:48:52+00:00" + "time": "2026-08-25T14:40:53+00:00" }, { "name": "phpunit/php-invoker", - "version": "3.1.1", + "version": "6.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-invoker.git", - "reference": "5a10147d0aaf65b58940a0b72f71c9ac0423cc67" + "reference": "12b54e689b07a25a9b41e57736dfab6ec9ae5406" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/5a10147d0aaf65b58940a0b72f71c9ac0423cc67", - "reference": "5a10147d0aaf65b58940a0b72f71c9ac0423cc67", + "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/12b54e689b07a25a9b41e57736dfab6ec9ae5406", + "reference": "12b54e689b07a25a9b41e57736dfab6ec9ae5406", "shasum": "" }, "require": { - "php": ">=7.3" + "php": ">=8.3" }, "require-dev": { "ext-pcntl": "*", - "phpunit/phpunit": "^9.3" + "phpunit/phpunit": "^12.0" }, "suggest": { "ext-pcntl": "*" @@ -12928,7 +12951,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "3.1-dev" + "dev-main": "6.0-dev" } }, "autoload": { @@ -12954,7 +12977,8 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/php-invoker/issues", - "source": "https://github.com/sebastianbergmann/php-invoker/tree/3.1.1" + "security": "https://github.com/sebastianbergmann/php-invoker/security/policy", + "source": "https://github.com/sebastianbergmann/php-invoker/tree/6.0.0" }, "funding": [ { @@ -12962,32 +12986,32 @@ "type": "github" } ], - "time": "2020-09-28T05:58:55+00:00" + "time": "2025-02-07T04:58:58+00:00" }, { "name": "phpunit/php-text-template", - "version": "2.0.4", + "version": "5.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-text-template.git", - "reference": "5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28" + "reference": "e1367a453f0eda562eedb4f659e13aa900d66c53" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28", - "reference": "5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28", + "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/e1367a453f0eda562eedb4f659e13aa900d66c53", + "reference": "e1367a453f0eda562eedb4f659e13aa900d66c53", "shasum": "" }, "require": { - "php": ">=7.3" + "php": ">=8.3" }, "require-dev": { - "phpunit/phpunit": "^9.3" + "phpunit/phpunit": "^12.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0-dev" + "dev-main": "5.0-dev" } }, "autoload": { @@ -13013,7 +13037,8 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/php-text-template/issues", - "source": "https://github.com/sebastianbergmann/php-text-template/tree/2.0.4" + "security": "https://github.com/sebastianbergmann/php-text-template/security/policy", + "source": "https://github.com/sebastianbergmann/php-text-template/tree/5.0.0" }, "funding": [ { @@ -13021,32 +13046,32 @@ "type": "github" } ], - "time": "2020-10-26T05:33:50+00:00" + "time": "2025-02-07T04:59:16+00:00" }, { "name": "phpunit/php-timer", - "version": "5.0.3", + "version": "8.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-timer.git", - "reference": "5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2" + "reference": "f258ce36aa457f3aa3339f9ed4c81fc66dc8c2cc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2", - "reference": "5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/f258ce36aa457f3aa3339f9ed4c81fc66dc8c2cc", + "reference": "f258ce36aa457f3aa3339f9ed4c81fc66dc8c2cc", "shasum": "" }, "require": { - "php": ">=7.3" + "php": ">=8.3" }, "require-dev": { - "phpunit/phpunit": "^9.3" + "phpunit/phpunit": "^12.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "5.0-dev" + "dev-main": "8.0-dev" } }, "autoload": { @@ -13072,7 +13097,8 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/php-timer/issues", - "source": "https://github.com/sebastianbergmann/php-timer/tree/5.0.3" + "security": "https://github.com/sebastianbergmann/php-timer/security/policy", + "source": "https://github.com/sebastianbergmann/php-timer/tree/8.0.0" }, "funding": [ { @@ -13080,54 +13106,49 @@ "type": "github" } ], - "time": "2020-10-26T13:16:10+00:00" + "time": "2025-02-07T04:59:38+00:00" }, { "name": "phpunit/phpunit", - "version": "9.6.36", + "version": "12.5.34", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "abab27ed286d3e1246fbbfe6b56bfd732d945ec9" + "reference": "6cbff63d670de92cb1cb3d2ff9f40327e9da9c7f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/abab27ed286d3e1246fbbfe6b56bfd732d945ec9", - "reference": "abab27ed286d3e1246fbbfe6b56bfd732d945ec9", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/6cbff63d670de92cb1cb3d2ff9f40327e9da9c7f", + "reference": "6cbff63d670de92cb1cb3d2ff9f40327e9da9c7f", "shasum": "" }, "require": { - "doctrine/instantiator": "^1.5.0 || ^2", "ext-dom": "*", "ext-filter": "*", "ext-json": "*", "ext-libxml": "*", "ext-mbstring": "*", "ext-xmlwriter": "*", - "myclabs/deep-copy": "^1.13.4", + "myclabs/deep-copy": "^1.14.0", "phar-io/manifest": "^2.0.4", "phar-io/version": "^3.2.1", - "php": ">=7.3", - "phpunit/php-code-coverage": "^9.2.32", - "phpunit/php-file-iterator": "^3.0.6", - "phpunit/php-invoker": "^3.1.1", - "phpunit/php-text-template": "^2.0.4", - "phpunit/php-timer": "^5.0.3", - "sebastian/cli-parser": "^1.0.2", - "sebastian/code-unit": "^1.0.8", - "sebastian/comparator": "^4.0.10", - "sebastian/diff": "^4.0.6", - "sebastian/environment": "^5.1.5", - "sebastian/exporter": "^4.0.9", - "sebastian/global-state": "^5.0.8", - "sebastian/object-enumerator": "^4.0.4", - "sebastian/resource-operations": "^3.0.4", - "sebastian/type": "^3.2.1", - "sebastian/version": "^3.0.2" - }, - "suggest": { - "ext-soap": "To be able to generate mocks based on WSDL files", - "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage" + "php": ">=8.3", + "phpunit/php-code-coverage": "^12.5.7", + "phpunit/php-file-iterator": "^6.0.2", + "phpunit/php-invoker": "^6.0.0", + "phpunit/php-text-template": "^5.0.0", + "phpunit/php-timer": "^8.0.0", + "sebastian/cli-parser": "^4.2.1", + "sebastian/comparator": "^7.1.8", + "sebastian/diff": "^7.0.1", + "sebastian/environment": "^8.1.2", + "sebastian/exporter": "^7.0.3", + "sebastian/global-state": "^8.0.3", + "sebastian/object-enumerator": "^7.0.0", + "sebastian/recursion-context": "^7.0.1", + "sebastian/type": "^6.0.4", + "sebastian/version": "^6.0.0", + "staabm/side-effects-detector": "^1.0.5" }, "bin": [ "phpunit" @@ -13135,7 +13156,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "9.6-dev" + "dev-main": "12.5-dev" } }, "autoload": { @@ -13167,7 +13188,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", "security": "https://github.com/sebastianbergmann/phpunit/security/policy", - "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.36" + "source": "https://github.com/sebastianbergmann/phpunit/tree/12.5.34" }, "funding": [ { @@ -13175,7 +13196,7 @@ "type": "other" } ], - "time": "2026-08-11T06:25:15+00:00" + "time": "2026-08-27T08:38:28+00:00" }, { "name": "react/cache", @@ -13762,28 +13783,28 @@ }, { "name": "sebastian/cli-parser", - "version": "1.0.2", + "version": "4.2.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/cli-parser.git", - "reference": "2b56bea83a09de3ac06bb18b92f068e60cc6f50b" + "reference": "7d05781b13f7dec9043a629a21d086ed74582a15" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/2b56bea83a09de3ac06bb18b92f068e60cc6f50b", - "reference": "2b56bea83a09de3ac06bb18b92f068e60cc6f50b", + "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/7d05781b13f7dec9043a629a21d086ed74582a15", + "reference": "7d05781b13f7dec9043a629a21d086ed74582a15", "shasum": "" }, "require": { - "php": ">=7.3" + "php": ">=8.3" }, "require-dev": { - "phpunit/phpunit": "^9.3" + "phpunit/phpunit": "^12.5.25" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0-dev" + "dev-main": "4.2-dev" } }, "autoload": { @@ -13806,153 +13827,60 @@ "homepage": "https://github.com/sebastianbergmann/cli-parser", "support": { "issues": "https://github.com/sebastianbergmann/cli-parser/issues", - "source": "https://github.com/sebastianbergmann/cli-parser/tree/1.0.2" + "security": "https://github.com/sebastianbergmann/cli-parser/security/policy", + "source": "https://github.com/sebastianbergmann/cli-parser/tree/4.2.1" }, "funding": [ { "url": "https://github.com/sebastianbergmann", "type": "github" - } - ], - "time": "2024-03-02T06:27:43+00:00" - }, - { - "name": "sebastian/code-unit", - "version": "1.0.8", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/code-unit.git", - "reference": "1fc9f64c0927627ef78ba436c9b17d967e68e120" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/code-unit/zipball/1fc9f64c0927627ef78ba436c9b17d967e68e120", - "reference": "1fc9f64c0927627ef78ba436c9b17d967e68e120", - "shasum": "" - }, - "require": { - "php": ">=7.3" - }, - "require-dev": { - "phpunit/phpunit": "^9.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ + }, { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "Collection of value objects that represent the PHP code units", - "homepage": "https://github.com/sebastianbergmann/code-unit", - "support": { - "issues": "https://github.com/sebastianbergmann/code-unit/issues", - "source": "https://github.com/sebastianbergmann/code-unit/tree/1.0.8" - }, - "funding": [ + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2020-10-26T13:08:54+00:00" - }, - { - "name": "sebastian/code-unit-reverse-lookup", - "version": "2.0.3", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", - "reference": "ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5", - "reference": "ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5", - "shasum": "" - }, - "require": { - "php": ">=7.3" - }, - "require-dev": { - "phpunit/phpunit": "^9.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" + "url": "https://tidelift.com/funding/github/packagist/sebastian/cli-parser", + "type": "tidelift" } ], - "description": "Looks up which function or method a line of code belongs to", - "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", - "support": { - "issues": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/issues", - "source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/2.0.3" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2020-09-28T05:30:19+00:00" + "time": "2026-05-17T05:29:34+00:00" }, { "name": "sebastian/comparator", - "version": "4.0.10", + "version": "7.1.8", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/comparator.git", - "reference": "e4df00b9b3571187db2831ae9aada2c6efbd715d" + "reference": "7c65c1e79836812819705b473a90c12399542485" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/e4df00b9b3571187db2831ae9aada2c6efbd715d", - "reference": "e4df00b9b3571187db2831ae9aada2c6efbd715d", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/7c65c1e79836812819705b473a90c12399542485", + "reference": "7c65c1e79836812819705b473a90c12399542485", "shasum": "" }, "require": { - "php": ">=7.3", - "sebastian/diff": "^4.0", - "sebastian/exporter": "^4.0" + "ext-dom": "*", + "ext-mbstring": "*", + "php": ">=8.3", + "sebastian/diff": "^7.0", + "sebastian/exporter": "^7.0.3" }, "require-dev": { - "phpunit/phpunit": "^9.3" + "phpunit/phpunit": "^12.5.25" + }, + "suggest": { + "ext-bcmath": "For comparing BcMath\\Number objects" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "4.0-dev" + "dev-main": "7.1-dev" } }, "autoload": { @@ -13991,7 +13919,8 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/comparator/issues", - "source": "https://github.com/sebastianbergmann/comparator/tree/4.0.10" + "security": "https://github.com/sebastianbergmann/comparator/security/policy", + "source": "https://github.com/sebastianbergmann/comparator/tree/7.1.8" }, "funding": [ { @@ -14011,33 +13940,33 @@ "type": "tidelift" } ], - "time": "2026-01-24T09:22:56+00:00" + "time": "2026-05-21T04:45:25+00:00" }, { "name": "sebastian/complexity", - "version": "2.0.3", + "version": "5.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/complexity.git", - "reference": "25f207c40d62b8b7aa32f5ab026c53561964053a" + "reference": "bad4316aba5303d0221f43f8cee37eb58d384bbb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/25f207c40d62b8b7aa32f5ab026c53561964053a", - "reference": "25f207c40d62b8b7aa32f5ab026c53561964053a", + "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/bad4316aba5303d0221f43f8cee37eb58d384bbb", + "reference": "bad4316aba5303d0221f43f8cee37eb58d384bbb", "shasum": "" }, "require": { - "nikic/php-parser": "^4.18 || ^5.0", - "php": ">=7.3" + "nikic/php-parser": "^5.0", + "php": ">=8.3" }, "require-dev": { - "phpunit/phpunit": "^9.3" + "phpunit/phpunit": "^12.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0-dev" + "dev-main": "5.0-dev" } }, "autoload": { @@ -14060,7 +13989,8 @@ "homepage": "https://github.com/sebastianbergmann/complexity", "support": { "issues": "https://github.com/sebastianbergmann/complexity/issues", - "source": "https://github.com/sebastianbergmann/complexity/tree/2.0.3" + "security": "https://github.com/sebastianbergmann/complexity/security/policy", + "source": "https://github.com/sebastianbergmann/complexity/tree/5.0.0" }, "funding": [ { @@ -14068,33 +13998,33 @@ "type": "github" } ], - "time": "2023-12-22T06:19:30+00:00" + "time": "2025-02-07T04:55:25+00:00" }, { "name": "sebastian/diff", - "version": "4.0.6", + "version": "7.0.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/diff.git", - "reference": "ba01945089c3a293b01ba9badc29ad55b106b0bc" + "reference": "cd4cabe39f8a4e8ee6818ba99f10a05561ea4ad6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/ba01945089c3a293b01ba9badc29ad55b106b0bc", - "reference": "ba01945089c3a293b01ba9badc29ad55b106b0bc", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/cd4cabe39f8a4e8ee6818ba99f10a05561ea4ad6", + "reference": "cd4cabe39f8a4e8ee6818ba99f10a05561ea4ad6", "shasum": "" }, "require": { - "php": ">=7.3" + "php": ">=8.3" }, "require-dev": { - "phpunit/phpunit": "^9.3", - "symfony/process": "^4.2 || ^5" + "phpunit/phpunit": "^12.5.33", + "symfony/process": "^7.4.17" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "4.0-dev" + "dev-main": "7.0-dev" } }, "autoload": { @@ -14126,35 +14056,48 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/diff/issues", - "source": "https://github.com/sebastianbergmann/diff/tree/4.0.6" + "security": "https://github.com/sebastianbergmann/diff/security/policy", + "source": "https://github.com/sebastianbergmann/diff/tree/7.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/diff", + "type": "tidelift" } ], - "time": "2024-03-02T06:30:58+00:00" + "time": "2026-08-25T15:35:54+00:00" }, { "name": "sebastian/environment", - "version": "5.1.5", + "version": "8.1.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/environment.git", - "reference": "830c43a844f1f8d5b7a1f6d6076b784454d8b7ed" + "reference": "9d32c685773823b1983e256ae4ecd48a10d6e439" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/830c43a844f1f8d5b7a1f6d6076b784454d8b7ed", - "reference": "830c43a844f1f8d5b7a1f6d6076b784454d8b7ed", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/9d32c685773823b1983e256ae4ecd48a10d6e439", + "reference": "9d32c685773823b1983e256ae4ecd48a10d6e439", "shasum": "" }, "require": { - "php": ">=7.3" + "php": ">=8.3" }, "require-dev": { - "phpunit/phpunit": "^9.3" + "phpunit/phpunit": "^12.5.26" }, "suggest": { "ext-posix": "*" @@ -14162,7 +14105,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "5.1-dev" + "dev-main": "8.1-dev" } }, "autoload": { @@ -14181,7 +14124,7 @@ } ], "description": "Provides functionality to handle HHVM/PHP environments", - "homepage": "http://www.github.com/sebastianbergmann/environment", + "homepage": "https://github.com/sebastianbergmann/environment", "keywords": [ "Xdebug", "environment", @@ -14189,42 +14132,55 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/environment/issues", - "source": "https://github.com/sebastianbergmann/environment/tree/5.1.5" + "security": "https://github.com/sebastianbergmann/environment/security/policy", + "source": "https://github.com/sebastianbergmann/environment/tree/8.1.2" }, "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/environment", + "type": "tidelift" } ], - "time": "2023-02-03T06:03:51+00:00" + "time": "2026-05-25T13:40:20+00:00" }, { "name": "sebastian/exporter", - "version": "4.0.9", + "version": "7.0.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/exporter.git", - "reference": "4352c1a3df741a7ba9e61af6fed51d1fee41cbf7" + "reference": "c5e21b5de653ce0a769fb36f5cdfcb5e7a32cf23" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/4352c1a3df741a7ba9e61af6fed51d1fee41cbf7", - "reference": "4352c1a3df741a7ba9e61af6fed51d1fee41cbf7", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/c5e21b5de653ce0a769fb36f5cdfcb5e7a32cf23", + "reference": "c5e21b5de653ce0a769fb36f5cdfcb5e7a32cf23", "shasum": "" }, "require": { - "php": ">=7.3", - "sebastian/recursion-context": "^4.0" + "ext-mbstring": "*", + "php": ">=8.3", + "sebastian/recursion-context": "^7.0.1" }, "require-dev": { - "ext-mbstring": "*", - "phpunit/phpunit": "^9.3" + "phpunit/phpunit": "^12.5.25" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "4.0-dev" + "dev-main": "7.0-dev" } }, "autoload": { @@ -14266,7 +14222,8 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/exporter/issues", - "source": "https://github.com/sebastianbergmann/exporter/tree/4.0.9" + "security": "https://github.com/sebastianbergmann/exporter/security/policy", + "source": "https://github.com/sebastianbergmann/exporter/tree/7.0.3" }, "funding": [ { @@ -14286,38 +14243,35 @@ "type": "tidelift" } ], - "time": "2026-08-11T04:55:59+00:00" + "time": "2026-05-20T04:37:17+00:00" }, { "name": "sebastian/global-state", - "version": "5.0.8", + "version": "8.0.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/global-state.git", - "reference": "b6781316bdcd28260904e7cc18ec983d0d2ef4f6" + "reference": "b164d3274d6537ab462591c5755f76a8f5b1aae9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/b6781316bdcd28260904e7cc18ec983d0d2ef4f6", - "reference": "b6781316bdcd28260904e7cc18ec983d0d2ef4f6", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/b164d3274d6537ab462591c5755f76a8f5b1aae9", + "reference": "b164d3274d6537ab462591c5755f76a8f5b1aae9", "shasum": "" }, "require": { - "php": ">=7.3", - "sebastian/object-reflector": "^2.0", - "sebastian/recursion-context": "^4.0" + "php": ">=8.3", + "sebastian/object-reflector": "^5.0", + "sebastian/recursion-context": "^7.0.1" }, "require-dev": { "ext-dom": "*", - "phpunit/phpunit": "^9.3" - }, - "suggest": { - "ext-uopz": "*" + "phpunit/phpunit": "^12.5.28" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "5.0-dev" + "dev-main": "8.0-dev" } }, "autoload": { @@ -14336,13 +14290,14 @@ } ], "description": "Snapshotting of global state", - "homepage": "http://www.github.com/sebastianbergmann/global-state", + "homepage": "https://www.github.com/sebastianbergmann/global-state", "keywords": [ "global state" ], "support": { "issues": "https://github.com/sebastianbergmann/global-state/issues", - "source": "https://github.com/sebastianbergmann/global-state/tree/5.0.8" + "security": "https://github.com/sebastianbergmann/global-state/security/policy", + "source": "https://github.com/sebastianbergmann/global-state/tree/8.0.3" }, "funding": [ { @@ -14362,33 +14317,33 @@ "type": "tidelift" } ], - "time": "2025-08-10T07:10:35+00:00" + "time": "2026-06-01T15:10:33+00:00" }, { "name": "sebastian/lines-of-code", - "version": "1.0.4", + "version": "4.0.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/lines-of-code.git", - "reference": "e1e4a170560925c26d424b6a03aed157e7dcc5c5" + "reference": "d543b8ef219dcd8da262cbb958639a96bedba10e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/e1e4a170560925c26d424b6a03aed157e7dcc5c5", - "reference": "e1e4a170560925c26d424b6a03aed157e7dcc5c5", + "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/d543b8ef219dcd8da262cbb958639a96bedba10e", + "reference": "d543b8ef219dcd8da262cbb958639a96bedba10e", "shasum": "" }, "require": { - "nikic/php-parser": "^4.18 || ^5.0", - "php": ">=7.3" + "nikic/php-parser": "^5.7.0", + "php": ">=8.3" }, "require-dev": { - "phpunit/phpunit": "^9.3" + "phpunit/phpunit": "^12.5.25" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0-dev" + "dev-main": "4.0-dev" } }, "autoload": { @@ -14411,42 +14366,55 @@ "homepage": "https://github.com/sebastianbergmann/lines-of-code", "support": { "issues": "https://github.com/sebastianbergmann/lines-of-code/issues", - "source": "https://github.com/sebastianbergmann/lines-of-code/tree/1.0.4" + "security": "https://github.com/sebastianbergmann/lines-of-code/security/policy", + "source": "https://github.com/sebastianbergmann/lines-of-code/tree/4.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": "2023-12-22T06:20:34+00:00" + "time": "2026-05-19T16:22:07+00:00" }, { "name": "sebastian/object-enumerator", - "version": "4.0.4", + "version": "7.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/object-enumerator.git", - "reference": "5c9eeac41b290a3712d88851518825ad78f45c71" + "reference": "1effe8e9b8e068e9ae228e542d5d11b5d16db894" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/5c9eeac41b290a3712d88851518825ad78f45c71", - "reference": "5c9eeac41b290a3712d88851518825ad78f45c71", + "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/1effe8e9b8e068e9ae228e542d5d11b5d16db894", + "reference": "1effe8e9b8e068e9ae228e542d5d11b5d16db894", "shasum": "" }, "require": { - "php": ">=7.3", - "sebastian/object-reflector": "^2.0", - "sebastian/recursion-context": "^4.0" + "php": ">=8.3", + "sebastian/object-reflector": "^5.0", + "sebastian/recursion-context": "^7.0" }, "require-dev": { - "phpunit/phpunit": "^9.3" + "phpunit/phpunit": "^12.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "4.0-dev" + "dev-main": "7.0-dev" } }, "autoload": { @@ -14468,7 +14436,8 @@ "homepage": "https://github.com/sebastianbergmann/object-enumerator/", "support": { "issues": "https://github.com/sebastianbergmann/object-enumerator/issues", - "source": "https://github.com/sebastianbergmann/object-enumerator/tree/4.0.4" + "security": "https://github.com/sebastianbergmann/object-enumerator/security/policy", + "source": "https://github.com/sebastianbergmann/object-enumerator/tree/7.0.0" }, "funding": [ { @@ -14476,32 +14445,32 @@ "type": "github" } ], - "time": "2020-10-26T13:12:34+00:00" + "time": "2025-02-07T04:57:48+00:00" }, { "name": "sebastian/object-reflector", - "version": "2.0.4", + "version": "5.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/object-reflector.git", - "reference": "b4f479ebdbf63ac605d183ece17d8d7fe49c15c7" + "reference": "4bfa827c969c98be1e527abd576533293c634f6a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/b4f479ebdbf63ac605d183ece17d8d7fe49c15c7", - "reference": "b4f479ebdbf63ac605d183ece17d8d7fe49c15c7", + "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/4bfa827c969c98be1e527abd576533293c634f6a", + "reference": "4bfa827c969c98be1e527abd576533293c634f6a", "shasum": "" }, "require": { - "php": ">=7.3" + "php": ">=8.3" }, "require-dev": { - "phpunit/phpunit": "^9.3" + "phpunit/phpunit": "^12.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0-dev" + "dev-main": "5.0-dev" } }, "autoload": { @@ -14523,7 +14492,8 @@ "homepage": "https://github.com/sebastianbergmann/object-reflector/", "support": { "issues": "https://github.com/sebastianbergmann/object-reflector/issues", - "source": "https://github.com/sebastianbergmann/object-reflector/tree/2.0.4" + "security": "https://github.com/sebastianbergmann/object-reflector/security/policy", + "source": "https://github.com/sebastianbergmann/object-reflector/tree/5.0.0" }, "funding": [ { @@ -14531,32 +14501,32 @@ "type": "github" } ], - "time": "2020-10-26T13:14:26+00:00" + "time": "2025-02-07T04:58:17+00:00" }, { "name": "sebastian/recursion-context", - "version": "4.0.7", + "version": "7.0.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/recursion-context.git", - "reference": "c85be6922b7fd365942b986b9a50397d65407611" + "reference": "0b01998a7d5b1f122911a66bebcb8d46f0c82d8c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/c85be6922b7fd365942b986b9a50397d65407611", - "reference": "c85be6922b7fd365942b986b9a50397d65407611", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/0b01998a7d5b1f122911a66bebcb8d46f0c82d8c", + "reference": "0b01998a7d5b1f122911a66bebcb8d46f0c82d8c", "shasum": "" }, "require": { - "php": ">=7.3" + "php": ">=8.3" }, "require-dev": { - "phpunit/phpunit": "^9.3" + "phpunit/phpunit": "^12.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "4.0-dev" + "dev-main": "7.0-dev" } }, "autoload": { @@ -14586,7 +14556,8 @@ "homepage": "https://github.com/sebastianbergmann/recursion-context", "support": { "issues": "https://github.com/sebastianbergmann/recursion-context/issues", - "source": "https://github.com/sebastianbergmann/recursion-context/tree/4.0.7" + "security": "https://github.com/sebastianbergmann/recursion-context/security/policy", + "source": "https://github.com/sebastianbergmann/recursion-context/tree/7.0.1" }, "funding": [ { @@ -14606,86 +14577,32 @@ "type": "tidelift" } ], - "time": "2026-08-11T05:25:24+00:00" - }, - { - "name": "sebastian/resource-operations", - "version": "3.0.4", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/resource-operations.git", - "reference": "05d5692a7993ecccd56a03e40cd7e5b09b1d404e" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/05d5692a7993ecccd56a03e40cd7e5b09b1d404e", - "reference": "05d5692a7993ecccd56a03e40cd7e5b09b1d404e", - "shasum": "" - }, - "require": { - "php": ">=7.3" - }, - "require-dev": { - "phpunit/phpunit": "^9.0" - }, - "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" - } - ], - "description": "Provides a list of PHP built-in functions that operate on resources", - "homepage": "https://www.github.com/sebastianbergmann/resource-operations", - "support": { - "source": "https://github.com/sebastianbergmann/resource-operations/tree/3.0.4" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2024-03-14T16:00:52+00:00" + "time": "2025-08-13T04:44:59+00:00" }, { "name": "sebastian/type", - "version": "3.2.1", + "version": "6.0.4", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/type.git", - "reference": "75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7" + "reference": "82ff822c2edc46724be9f7411d3163021f602773" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7", - "reference": "75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7", + "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/82ff822c2edc46724be9f7411d3163021f602773", + "reference": "82ff822c2edc46724be9f7411d3163021f602773", "shasum": "" }, "require": { - "php": ">=7.3" + "php": ">=8.3" }, "require-dev": { - "phpunit/phpunit": "^9.5" + "phpunit/phpunit": "^12.5.25" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.2-dev" + "dev-main": "6.0-dev" } }, "autoload": { @@ -14708,37 +14625,50 @@ "homepage": "https://github.com/sebastianbergmann/type", "support": { "issues": "https://github.com/sebastianbergmann/type/issues", - "source": "https://github.com/sebastianbergmann/type/tree/3.2.1" + "security": "https://github.com/sebastianbergmann/type/security/policy", + "source": "https://github.com/sebastianbergmann/type/tree/6.0.4" }, "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/type", + "type": "tidelift" } ], - "time": "2023-02-03T06:13:03+00:00" + "time": "2026-05-20T06:45:45+00:00" }, { "name": "sebastian/version", - "version": "3.0.2", + "version": "6.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/version.git", - "reference": "c6c1022351a901512170118436c764e473f6de8c" + "reference": "3e6ccf7657d4f0a59200564b08cead899313b53c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/c6c1022351a901512170118436c764e473f6de8c", - "reference": "c6c1022351a901512170118436c764e473f6de8c", + "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/3e6ccf7657d4f0a59200564b08cead899313b53c", + "reference": "3e6ccf7657d4f0a59200564b08cead899313b53c", "shasum": "" }, "require": { - "php": ">=7.3" + "php": ">=8.3" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.0-dev" + "dev-main": "6.0-dev" } }, "autoload": { @@ -14761,7 +14691,8 @@ "homepage": "https://github.com/sebastianbergmann/version", "support": { "issues": "https://github.com/sebastianbergmann/version/issues", - "source": "https://github.com/sebastianbergmann/version/tree/3.0.2" + "security": "https://github.com/sebastianbergmann/version/security/policy", + "source": "https://github.com/sebastianbergmann/version/tree/6.0.0" }, "funding": [ { @@ -14769,7 +14700,59 @@ "type": "github" } ], - "time": "2020-09-28T06:39:44+00:00" + "time": "2025-02-07T05:00:38+00:00" + }, + { + "name": "staabm/side-effects-detector", + "version": "1.0.5", + "source": { + "type": "git", + "url": "https://github.com/staabm/side-effects-detector.git", + "reference": "d8334211a140ce329c13726d4a715adbddd0a163" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/staabm/side-effects-detector/zipball/d8334211a140ce329c13726d4a715adbddd0a163", + "reference": "d8334211a140ce329c13726d4a715adbddd0a163", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "php": "^7.4 || ^8.0" + }, + "require-dev": { + "phpstan/extension-installer": "^1.4.3", + "phpstan/phpstan": "^1.12.6", + "phpunit/phpunit": "^9.6.21", + "symfony/var-dumper": "^5.4.43", + "tomasvotruba/type-coverage": "1.0.0", + "tomasvotruba/unused-public": "1.0.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "lib/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "A static analysis tool to detect side effects in PHP code", + "keywords": [ + "static analysis" + ], + "support": { + "issues": "https://github.com/staabm/side-effects-detector/issues", + "source": "https://github.com/staabm/side-effects-detector/tree/1.0.5" + }, + "funding": [ + { + "url": "https://github.com/staabm", + "type": "github" + } + ], + "time": "2024-10-20T05:08:20+00:00" }, { "name": "symfony/browser-kit", @@ -15264,23 +15247,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": { @@ -15302,7 +15285,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": [ { @@ -15310,7 +15293,7 @@ "type": "github" } ], - "time": "2025-11-17T20:03:58+00:00" + "time": "2025-12-08T11:19:18+00:00" } ], "aliases": [], diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 6c4bfed..2a54677 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -1,20 +1,20 @@ - + - - @@ -23,16 +23,13 @@ - + src - - - - - + + diff --git a/tests/BusProNet/ApiClientReceiveTest.php b/tests/BusProNet/ApiClientReceiveTest.php index 8213b56..519c7fe 100644 --- a/tests/BusProNet/ApiClientReceiveTest.php +++ b/tests/BusProNet/ApiClientReceiveTest.php @@ -17,19 +17,22 @@ use Symfony\Component\Serializer\SerializerInterface; class ApiClientReceiveTest extends TestCase { - private ApiClient $apiClient; + private ?ApiClient $apiClient = null; private LoggerInterface $logger; protected function setUp(): void { - $this->logger = $this->createMock(LoggerInterface::class); + $this->logger = $this->createStub(LoggerInterface::class); + } - $this->apiClient = new ApiClient( - $this->createMock(SerializerInterface::class), - $this->createMock(ApiResponseParser::class), - $this->createMock(FilesystemOperator::class), + private function apiClient(): ApiClient + { + return $this->apiClient ??= new ApiClient( + $this->createStub(SerializerInterface::class), + $this->createStub(ApiResponseParser::class), + $this->createStub(FilesystemOperator::class), $this->logger, - $this->createMock(BookingDataProcessor::class), + $this->createStub(BookingDataProcessor::class), new RequestStack(), new RequestIdGenerator(), [ @@ -43,6 +46,8 @@ class ApiClientReceiveTest extends TestCase public function testEmptyResponseThrowsImmediateConnectionCloseException(): void { + $this->logger = $this->createMock(LoggerInterface::class); + $stream = fopen('php://memory', 'r+'); // Write nothing — stream is immediately at EOF rewind($stream); @@ -82,18 +87,18 @@ class ApiClientReceiveTest extends TestCase { $method = new \ReflectionMethod(ApiClient::class, 'receive'); - return $method->invoke($this->apiClient, $socket); + return $method->invoke($this->apiClient(), $socket); } private function setOperationStartTime(): void { $property = new \ReflectionProperty(ApiClient::class, 'operationStartTime'); - $property->setValue($this->apiClient, microtime(true)); + $property->setValue($this->apiClient(), microtime(true)); } private function setSelectedPort(int $port): void { $property = new \ReflectionProperty(ApiClient::class, 'selectedPort'); - $property->setValue($this->apiClient, $port); + $property->setValue($this->apiClient(), $port); } } diff --git a/tests/BusProNet/DataLoader/TravelDataLoaderTest.php b/tests/BusProNet/DataLoader/TravelDataLoaderTest.php index ea54609..0b5a893 100644 --- a/tests/BusProNet/DataLoader/TravelDataLoaderTest.php +++ b/tests/BusProNet/DataLoader/TravelDataLoaderTest.php @@ -34,7 +34,7 @@ class TravelDataLoaderTest extends TestCase ->with('test_file.xml') ->willReturn($xmlContent); - $hotelLoader = $this->createMock(HotelLoader::class); + $hotelLoader = $this->createStub(HotelLoader::class); $travelParser = $this->createMock(TravelParser::class); $expectedTravel = new Travel(); diff --git a/tests/BusProNet/DataProcessor/BookingDataProcessorTest.php b/tests/BusProNet/DataProcessor/BookingDataProcessorTest.php index 03d6c36..6b46bca 100644 --- a/tests/BusProNet/DataProcessor/BookingDataProcessorTest.php +++ b/tests/BusProNet/DataProcessor/BookingDataProcessorTest.php @@ -40,8 +40,8 @@ class BookingDataProcessorTest extends TestCase protected function setUp(): void { // Create a mock InsuranceManager - $insuranceService = $this->createMock(InsuranceManager::class); - $priceCalculatorService = $this->createMock(BookingPriceCalculator::class); + $insuranceService = $this->createStub(InsuranceManager::class); + $priceCalculatorService = $this->createStub(BookingPriceCalculator::class); // Mock getSelectableInsurances to return empty array (not used in these tests) $insuranceService->method('getSelectableInsurances') @@ -851,7 +851,7 @@ class BookingDataProcessorTest extends TestCase $bookingDto = new BookingDto($this->createMockTravel(), 1); $bookingDto->participants = [$applicant, $dependent]; - $insuranceService = $this->createMock(InsuranceManager::class); + $insuranceService = $this->createStub(InsuranceManager::class); // Both insurances must already look eligible, otherwise the submit-time // reconciliation step (added for stale-insurance re-validation) would clear // them before propagation even runs - this test is only about propagation. @@ -864,11 +864,11 @@ class BookingDataProcessorTest extends TestCase 1 => null, ]); - $priceCalculatorService = $this->createMock(BookingPriceCalculator::class); + $priceCalculatorService = $this->createStub(BookingPriceCalculator::class); $priceCalculatorService->method('calculateIndividualParticipantPriceExcludingInsurance')->willReturn(0.0); $priceCalculatorService->method('resolveInsuranceTravelPrice')->willReturn(0.0); - $payloadBuilder = $this->createMock(BookingPayloadBuilder::class); + $payloadBuilder = $this->createStub(BookingPayloadBuilder::class); $payloadBuilder->method('buildCreatePayload')->willReturn([]); $processor = new BookingDataProcessor( @@ -911,14 +911,14 @@ class BookingDataProcessorTest extends TestCase $dependent = $formData->participants[1]; $dependent->insurance = $dependentInsurance; - $insuranceService = $this->createMock(InsuranceManager::class); + $insuranceService = $this->createStub(InsuranceManager::class); $insuranceService->method('getSelectableInsurances')->willReturn([]); $insuranceService->method('batchAssignInsuranceToParticipants')->willReturn([ 0 => $familyInsurance, 1 => null, ]); - $priceCalculatorService = $this->createMock(BookingPriceCalculator::class); + $priceCalculatorService = $this->createStub(BookingPriceCalculator::class); $priceCalculatorService->method('calculateIndividualParticipantPriceExcludingInsurance')->willReturn(0.0); $processor = new BookingDataProcessor( @@ -961,18 +961,18 @@ class BookingDataProcessorTest extends TestCase $bookingDto = new BookingDto($this->createMockTravel(), 1); $bookingDto->participants = [$applicant]; - $insuranceService = $this->createMock(InsuranceManager::class); + $insuranceService = $this->createStub(InsuranceManager::class); $insuranceService->method('getSelectableInsurances')->willReturn([$staleInsurance, $correctTierInsurance]); // Only the higher tier is eligible at the current (updated) price. $insuranceService->method('getEligibleInsurances')->willReturn([$correctTierInsurance]); $insuranceService->method('reassignInsuranceForPriceChange')->willReturn($correctTierInsurance); $insuranceService->method('batchAssignInsuranceToParticipants')->willReturn([0 => $correctTierInsurance]); - $priceCalculatorService = $this->createMock(BookingPriceCalculator::class); + $priceCalculatorService = $this->createStub(BookingPriceCalculator::class); $priceCalculatorService->method('calculateIndividualParticipantPriceExcludingInsurance')->willReturn(0.0); $priceCalculatorService->method('resolveInsuranceTravelPrice')->willReturn(2600.0); - $payloadBuilder = $this->createMock(BookingPayloadBuilder::class); + $payloadBuilder = $this->createStub(BookingPayloadBuilder::class); $payloadBuilder->method('buildCreatePayload')->willReturn([]); $processor = new BookingDataProcessor( @@ -1009,17 +1009,17 @@ class BookingDataProcessorTest extends TestCase $bookingDto = new BookingDto($this->createMockTravel(), 1); $bookingDto->participants = [$applicant]; - $insuranceService = $this->createMock(InsuranceManager::class); + $insuranceService = $this->createStub(InsuranceManager::class); $insuranceService->method('getSelectableInsurances')->willReturn([$staleInsurance]); $insuranceService->method('getEligibleInsurances')->willReturn([]); $insuranceService->method('reassignInsuranceForPriceChange')->willReturn(null); $insuranceService->method('batchAssignInsuranceToParticipants')->willReturn([0 => null]); - $priceCalculatorService = $this->createMock(BookingPriceCalculator::class); + $priceCalculatorService = $this->createStub(BookingPriceCalculator::class); $priceCalculatorService->method('calculateIndividualParticipantPriceExcludingInsurance')->willReturn(0.0); $priceCalculatorService->method('resolveInsuranceTravelPrice')->willReturn(9999.0); - $payloadBuilder = $this->createMock(BookingPayloadBuilder::class); + $payloadBuilder = $this->createStub(BookingPayloadBuilder::class); $payloadBuilder->method('buildCreatePayload')->willReturn([]); $processor = new BookingDataProcessor( @@ -1056,16 +1056,16 @@ class BookingDataProcessorTest extends TestCase $bookingDto = new BookingDto($this->createMockTravel(), 1); $bookingDto->participants = [$applicant]; - $insuranceService = $this->createMock(InsuranceManager::class); + $insuranceService = $this->createStub(InsuranceManager::class); $insuranceService->method('getSelectableInsurances')->willReturn([$insurance]); $insuranceService->method('getEligibleInsurances')->willReturn([$insurance]); $insuranceService->method('batchAssignInsuranceToParticipants')->willReturn([0 => $insurance]); - $priceCalculatorService = $this->createMock(BookingPriceCalculator::class); + $priceCalculatorService = $this->createStub(BookingPriceCalculator::class); $priceCalculatorService->method('calculateIndividualParticipantPriceExcludingInsurance')->willReturn(0.0); $priceCalculatorService->method('resolveInsuranceTravelPrice')->willReturn(500.0); - $payloadBuilder = $this->createMock(BookingPayloadBuilder::class); + $payloadBuilder = $this->createStub(BookingPayloadBuilder::class); $payloadBuilder->method('buildCreatePayload')->willReturn([]); $processor = new BookingDataProcessor( diff --git a/tests/BusProNet/Service/BookingStatusRuleRegistryTest.php b/tests/BusProNet/Service/BookingStatusRuleRegistryTest.php index c610ee6..9a6a0b2 100644 --- a/tests/BusProNet/Service/BookingStatusRuleRegistryTest.php +++ b/tests/BusProNet/Service/BookingStatusRuleRegistryTest.php @@ -15,7 +15,7 @@ class BookingStatusRuleRegistryTest extends TestCase { public function testReturnsDefaultStatusWhenNoRulesMatch(): void { - $rule = $this->createMock(BookingStatusRuleInterface::class); + $rule = $this->createStub(BookingStatusRuleInterface::class); $rule->method('evaluate')->willReturn(false); $rule->method('getPriority')->willReturn(100); @@ -27,7 +27,7 @@ class BookingStatusRuleRegistryTest extends TestCase public function testReturnsMatchingRuleStatus(): void { - $rule = $this->createMock(BookingStatusRuleInterface::class); + $rule = $this->createStub(BookingStatusRuleInterface::class); $rule->method('evaluate')->willReturn(true); $rule->method('getStatus')->willReturn('O'); $rule->method('getPriority')->willReturn(100); @@ -40,12 +40,12 @@ class BookingStatusRuleRegistryTest extends TestCase public function testHigherPriorityRuleTakesPrecedence(): void { - $lowPriorityRule = $this->createMock(BookingStatusRuleInterface::class); + $lowPriorityRule = $this->createStub(BookingStatusRuleInterface::class); $lowPriorityRule->method('evaluate')->willReturn(true); $lowPriorityRule->method('getStatus')->willReturn('L'); $lowPriorityRule->method('getPriority')->willReturn(50); - $highPriorityRule = $this->createMock(BookingStatusRuleInterface::class); + $highPriorityRule = $this->createStub(BookingStatusRuleInterface::class); $highPriorityRule->method('evaluate')->willReturn(true); $highPriorityRule->method('getStatus')->willReturn('H'); $highPriorityRule->method('getPriority')->willReturn(100); @@ -66,12 +66,12 @@ class BookingStatusRuleRegistryTest extends TestCase public function testFirstMatchingRuleWinsForSamePriority(): void { - $firstMatchingRule = $this->createMock(BookingStatusRuleInterface::class); + $firstMatchingRule = $this->createStub(BookingStatusRuleInterface::class); $firstMatchingRule->method('evaluate')->willReturn(true); $firstMatchingRule->method('getStatus')->willReturn('A'); $firstMatchingRule->method('getPriority')->willReturn(100); - $secondMatchingRule = $this->createMock(BookingStatusRuleInterface::class); + $secondMatchingRule = $this->createStub(BookingStatusRuleInterface::class); $secondMatchingRule->method('evaluate')->willReturn(true); $secondMatchingRule->method('getStatus')->willReturn('B'); $secondMatchingRule->method('getPriority')->willReturn(100); @@ -84,12 +84,12 @@ class BookingStatusRuleRegistryTest extends TestCase public function testNonMatchingHighPriorityRuleDoesNotBlockLowerPriority(): void { - $highPriorityRule = $this->createMock(BookingStatusRuleInterface::class); + $highPriorityRule = $this->createStub(BookingStatusRuleInterface::class); $highPriorityRule->method('evaluate')->willReturn(false); $highPriorityRule->method('getStatus')->willReturn('H'); $highPriorityRule->method('getPriority')->willReturn(100); - $lowPriorityRule = $this->createMock(BookingStatusRuleInterface::class); + $lowPriorityRule = $this->createStub(BookingStatusRuleInterface::class); $lowPriorityRule->method('evaluate')->willReturn(true); $lowPriorityRule->method('getStatus')->willReturn('L'); $lowPriorityRule->method('getPriority')->willReturn(50); @@ -102,7 +102,7 @@ class BookingStatusRuleRegistryTest extends TestCase public function testSelection1473RuleWinsOverLowerPriorityRule(): void { - $lowerPriorityRule = $this->createMock(BookingStatusRuleInterface::class); + $lowerPriorityRule = $this->createStub(BookingStatusRuleInterface::class); $lowerPriorityRule->method('evaluate')->willReturn(true); $lowerPriorityRule->method('getStatus')->willReturn('X'); $lowerPriorityRule->method('getPriority')->willReturn(100); diff --git a/tests/BusProNet/Utility/DayTimeUtilityTest.php b/tests/BusProNet/Utility/DayTimeUtilityTest.php index 8cc9598..0579062 100644 --- a/tests/BusProNet/Utility/DayTimeUtilityTest.php +++ b/tests/BusProNet/Utility/DayTimeUtilityTest.php @@ -3,13 +3,12 @@ namespace App\Tests\BusProNet\Utility; use App\BusProNet\Utility\DayTimeUtility; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; class DayTimeUtilityTest extends TestCase { - /** - * @dataProvider dayTimeProvider - */ + #[DataProvider('dayTimeProvider')] public function testMapTime(?string $time, ?string $dayTime): void { $utility = new DayTimeUtility(); @@ -18,7 +17,7 @@ class DayTimeUtilityTest extends TestCase $this->assertEquals($dayTime, $result); } - public function dayTimeProvider(): array + public static function dayTimeProvider(): array { return [ [null, null], diff --git a/tests/BusProNet/XmlLoader/PickupLoaderTest.php b/tests/BusProNet/XmlLoader/PickupLoaderTest.php index 74afc5b..1c891d0 100644 --- a/tests/BusProNet/XmlLoader/PickupLoaderTest.php +++ b/tests/BusProNet/XmlLoader/PickupLoaderTest.php @@ -7,7 +7,9 @@ namespace App\Tests\BusProNet\XmlLoader; use App\BusProNet\Model\Pickup; use App\BusProNet\Model\Travel; use App\BusProNet\XmlLoader\PickupLoader; +use League\Flysystem\FilesystemOperator; use PHPUnit\Framework\TestCase; +use Symfony\Contracts\Cache\CacheInterface; class PickupLoaderTest extends TestCase { @@ -15,17 +17,21 @@ class PickupLoaderTest extends TestCase protected function setUp(): void { - $this->loader = $this->createPartialMock(PickupLoader::class, ['loadById']); - $this->loader->method('loadById')->willReturnCallback(function (int $id): Pickup { - $pickup = new Pickup(); - $pickup->id = $id; - $pickup->code = 'Z'.$id; - $pickup->city = 'City '.$id; - $pickup->postalCode = '0000'.$id; - $pickup->street = 'Street '.$id; + // patchPickupsDetails() is the unit under test; loadById() only has to hand back + // a Pickup per id, so a subclass beats a partial mock over the XML/cache stack. + $this->loader = new class($this->createStub(CacheInterface::class), $this->createStub(FilesystemOperator::class)) extends PickupLoader { + public function loadById(int $id, ?string $filename = 'zustiege.xml'): ?Pickup + { + $pickup = new Pickup(); + $pickup->id = $id; + $pickup->code = 'Z'.$id; + $pickup->city = 'City '.$id; + $pickup->postalCode = '0000'.$id; + $pickup->street = 'Street '.$id; - return $pickup; - }); + return $pickup; + } + }; } public function testDropOffsAreOrderedInReverseOfSortedPickups(): void diff --git a/tests/Command/BpnSyncContingentsCommandTest.php b/tests/Command/BpnSyncContingentsCommandTest.php index 9a6f3f9..0f92427 100644 --- a/tests/Command/BpnSyncContingentsCommandTest.php +++ b/tests/Command/BpnSyncContingentsCommandTest.php @@ -71,18 +71,18 @@ class BpnSyncContingentsCommandTest extends TestCase $hotelCodes, ); - $accommodationRepository = $this->createMock(AccommodationRepository::class); + $accommodationRepository = $this->createStub(AccommodationRepository::class); $accommodationRepository->method('findAllWithCalendarCode')->willReturn($accommodations); - $manager = $this->createMock(ContingentSnapshotManager::class); + $manager = $this->createStub(ContingentSnapshotManager::class); if ([] !== $results) { $manager->method('sync')->willReturnOnConsecutiveCalls(...$results); } $command = new BpnSyncContingentsCommand( $accommodationRepository, - $this->createMock(ContingentSyncStateRepository::class), - $this->createMock(ContingentDayRepository::class), + $this->createStub(ContingentSyncStateRepository::class), + $this->createStub(ContingentDayRepository::class), $manager, new NullLogger(), ); diff --git a/tests/Command/BpnXmlSyncCommandTest.php b/tests/Command/BpnXmlSyncCommandTest.php index 86218a1..40586ad 100644 --- a/tests/Command/BpnXmlSyncCommandTest.php +++ b/tests/Command/BpnXmlSyncCommandTest.php @@ -27,12 +27,14 @@ class BpnXmlSyncCommandTest extends TestCase private TravelLoader $travelLoader; private TravelDataProvider $travelDataService; private TravelSnapshotManager $travelSnapshotService; - private BpnXmlSnapshotRefreshManager $snapshotRefreshManager; - private BpnXmlSyncManager $syncManager; - private BpnXmlSyncCommand $command; + private ?BpnXmlSyncCommand $command = null; protected function tearDown(): void { + if (null === $this->command) { + return; + } + $release = new \ReflectionMethod($this->command, 'release'); $release->setAccessible(true); $release->invoke($this->command); @@ -40,30 +42,30 @@ class BpnXmlSyncCommandTest extends TestCase protected function setUp(): void { - $this->xmlSource = $this->createMock(FilesystemOperator::class); - $this->xmlExport = $this->createMock(FilesystemOperator::class); + $this->xmlSource = $this->createStub(FilesystemOperator::class); + $this->xmlExport = $this->createStub(FilesystemOperator::class); $this->cache = $this->createMock(TagAwareCacheInterface::class); - $this->logger = $this->createMock(LoggerInterface::class); + $this->logger = $this->createStub(LoggerInterface::class); $this->travelLoader = $this->createMock(TravelLoader::class); $this->travelDataService = $this->createMock(TravelDataProvider::class); $this->travelSnapshotService = $this->createMock(TravelSnapshotManager::class); - $this->snapshotRefreshManager = new BpnXmlSnapshotRefreshManager( - $this->travelLoader, - $this->travelDataService, - $this->travelSnapshotService, - $this->logger, - ); + } - $this->syncManager = new BpnXmlSyncManager( - $this->xmlSource, - $this->xmlExport, - $this->cache, - $this->logger, - ); - - $this->command = new BpnXmlSyncCommand( - $this->syncManager, - $this->snapshotRefreshManager, + private function command(): BpnXmlSyncCommand + { + return $this->command ??= new BpnXmlSyncCommand( + new BpnXmlSyncManager( + $this->xmlSource, + $this->xmlExport, + $this->cache, + $this->logger, + ), + new BpnXmlSnapshotRefreshManager( + $this->travelLoader, + $this->travelDataService, + $this->travelSnapshotService, + $this->logger, + ), $this->logger, ); } @@ -101,7 +103,7 @@ class BpnXmlSyncCommandTest extends TestCase ->method('invalidateTags') ->with(['xml-sync']); - $tester = new CommandTester($this->command); + $tester = new CommandTester($this->command()); $tester->execute([]); $this->assertSame(Command::SUCCESS, $tester->getStatusCode()); @@ -121,7 +123,7 @@ class BpnXmlSyncCommandTest extends TestCase $this->travelSnapshotService->expects($this->never())->method('purgeOrphanedFutureSnapshots'); $this->cache->expects($this->never())->method('invalidateTags'); - $tester = new CommandTester($this->command); + $tester = new CommandTester($this->command()); $tester->execute([]); $this->assertSame(Command::SUCCESS, $tester->getStatusCode()); @@ -129,6 +131,8 @@ class BpnXmlSyncCommandTest extends TestCase public function testSnapshotSyncIsSkippedAndWarningLoggedWhenFileMapGenerationFails(): void { + $this->logger = $this->createMock(LoggerInterface::class); + $newerTimestamp = "24.03.2026 12:00:00\nExport\n3 Dateien\n"; $olderTimestamp = "24.03.2026 10:00:00\nExport\n3 Dateien\n"; @@ -153,7 +157,7 @@ class BpnXmlSyncCommandTest extends TestCase $this->travelSnapshotService->expects($this->never())->method('purgeOrphanedFutureSnapshots'); $this->cache->expects($this->once())->method('invalidateTags')->with(['xml-sync']); - $tester = new CommandTester($this->command); + $tester = new CommandTester($this->command()); $tester->execute([]); $this->assertSame(Command::SUCCESS, $tester->getStatusCode()); diff --git a/tests/Command/DbAnonymizeCommandTest.php b/tests/Command/DbAnonymizeCommandTest.php index 3918690..61ecdca 100644 --- a/tests/Command/DbAnonymizeCommandTest.php +++ b/tests/Command/DbAnonymizeCommandTest.php @@ -51,7 +51,7 @@ class DbAnonymizeCommandTest extends TestCase { return new DbAnonymizeCommand( $anonymizer, - $this->createMock(LoggerInterface::class), + $this->createStub(LoggerInterface::class), $environment, ); } diff --git a/tests/Command/MailjetNewsletterWebhookCommandTest.php b/tests/Command/MailjetNewsletterWebhookCommandTest.php index 9b85f63..f3ca468 100644 --- a/tests/Command/MailjetNewsletterWebhookCommandTest.php +++ b/tests/Command/MailjetNewsletterWebhookCommandTest.php @@ -90,7 +90,7 @@ class MailjetNewsletterWebhookCommandTest extends TestCase $mailjetApiClient, 'https://my.ep-reisen.de', 'secret', - $this->createMock(LoggerInterface::class), + $this->createStub(LoggerInterface::class), ); } } diff --git a/tests/Controller/Account/PersonalDataControllerTest.php b/tests/Controller/Account/PersonalDataControllerTest.php index 2dea230..8879040 100644 --- a/tests/Controller/Account/PersonalDataControllerTest.php +++ b/tests/Controller/Account/PersonalDataControllerTest.php @@ -27,7 +27,10 @@ class PersonalDataControllerTest extends TestCase { public function testIndexRendersNewsletterSubscribeCtaWhenNotSubscribed(): void { - $controller = $this->createController(); + $controller = $this->createController( + apiClient: $this->createMock(ApiClient::class), + newsletterManager: $this->createMock(NewsletterManager::class), + ); $controller->apiClient ->expects(self::once()) ->method('getPersonalData') @@ -55,7 +58,10 @@ class PersonalDataControllerTest extends TestCase public function testIndexStillTracksPendingNewsletterConfirmationWhenSubscribed(): void { - $controller = $this->createController(); + $controller = $this->createController( + apiClient: $this->createMock(ApiClient::class), + newsletterManager: $this->createMock(NewsletterManager::class), + ); $controller->apiClient ->expects(self::once()) ->method('getPersonalData') @@ -82,7 +88,10 @@ class PersonalDataControllerTest extends TestCase public function testNewsletterActionReturnsHtmxRedirectAndFlash(): void { - $controller = $this->createController(); + $controller = $this->createController( + apiClient: $this->createMock(ApiClient::class), + newsletterManager: $this->createMock(NewsletterManager::class), + ); $controller->apiClient ->expects(self::once()) ->method('getPersonalData') @@ -122,7 +131,10 @@ class PersonalDataControllerTest extends TestCase public function testNewsletterActionResendsPendingConfirmation(): void { - $controller = $this->createController(); + $controller = $this->createController( + apiClient: $this->createMock(ApiClient::class), + newsletterManager: $this->createMock(NewsletterManager::class), + ); $controller->apiClient ->expects(self::once()) ->method('getPersonalData') @@ -173,7 +185,10 @@ class PersonalDataControllerTest extends TestCase */ public function testIndexDoesNotSubmitTheFormWhenPersonalDataCouldNotBeLoaded(): void { - $controller = $this->createController(); + $controller = $this->createController( + apiClient: $this->createMock(ApiClient::class), + form: $this->createMock(FormInterface::class), + ); $controller->apiClient ->expects(self::once()) ->method('getPersonalData') @@ -194,20 +209,25 @@ class PersonalDataControllerTest extends TestCase self::assertSame('account/personal_data.html.twig', $controller->renderedView); } - private function createController(): TestablePersonalDataController - { + /** + * Collaborators default to stubs; a test passes its own mock for whatever it sets + * expectations on, and reaches it again through the controller's public property. + */ + private function createController( + ?ApiClient $apiClient = null, + ?NewsletterManager $newsletterManager = null, + ?FormInterface $form = null, + ): TestablePersonalDataController { $user = new User('customer@example.com'); $user->setPassword('secret'); - $apiClient = $this->createMock(ApiClient::class); - $crypt = $this->createMock(Crypt::class); $crypt ->method('decrypt') ->with('secret') ->willReturn('secret'); - $form = $this->createMock(FormInterface::class); + $form ??= $this->createStub(FormInterface::class); $form ->method('handleRequest') ->willReturnSelf(); @@ -216,13 +236,13 @@ class PersonalDataControllerTest extends TestCase ->willReturn(false); return new TestablePersonalDataController( - $apiClient, + $apiClient ?? $this->createStub(ApiClient::class), $crypt, - $this->createMock(BookingEditDataLoader::class), - $this->createMock(ProfileCompletenessChecker::class), - $this->createMock(EntityManagerInterface::class), - $this->createMock(NewsletterManager::class), - $this->createMock(LoggerInterface::class), + $this->createStub(BookingEditDataLoader::class), + $this->createStub(ProfileCompletenessChecker::class), + $this->createStub(EntityManagerInterface::class), + $newsletterManager ?? $this->createStub(NewsletterManager::class), + $this->createStub(LoggerInterface::class), $user, $form, ); diff --git a/tests/Controller/Admin/AccommodationBooking/ChangeAccommodationControllerTest.php b/tests/Controller/Admin/AccommodationBooking/ChangeAccommodationControllerTest.php index 66f2233..f53936d 100644 --- a/tests/Controller/Admin/AccommodationBooking/ChangeAccommodationControllerTest.php +++ b/tests/Controller/Admin/AccommodationBooking/ChangeAccommodationControllerTest.php @@ -9,6 +9,7 @@ use App\Entity\Groups\Accommodation; use App\Entity\Groups\AccommodationBooking; use App\Enum\Groups\AccommodationBookingStatus; use App\Service\AccommodationBookingService; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; use Psr\Log\LoggerInterface; use Symfony\Component\Form\FormInterface; @@ -34,9 +35,7 @@ class ChangeAccommodationControllerTest extends TestCase self::assertSame('admin/accommodation_booking/modal_change_accommodation.html.twig', $controller->renderedView); } - /** - * @dataProvider lockedStatuses - */ + #[DataProvider('lockedStatuses')] public function testABookingThatHasLeftEntwurfCannotMoveHouse(AccommodationBookingStatus $status): void { // The customer may already be looking at the offer under their access link. @@ -127,7 +126,7 @@ class ChangeAccommodationControllerTest extends TestCase private function unsubmittedForm(): FormInterface { - $form = $this->createMock(FormInterface::class); + $form = $this->createStub(FormInterface::class); $form->method('handleRequest')->willReturn($form); $form->method('isSubmitted')->willReturn(false); @@ -136,7 +135,7 @@ class ChangeAccommodationControllerTest extends TestCase private function submittedForm(Accommodation $selected): FormInterface { - $field = $this->createMock(FormInterface::class); + $field = $this->createStub(FormInterface::class); $field->method('getData')->willReturn($selected); $form = $this->createMock(FormInterface::class); @@ -154,7 +153,7 @@ class ChangeAccommodationControllerTest extends TestCase ): TestableChangeAccommodationController { return new TestableChangeAccommodationController( $bookingService, - $this->createMock(LoggerInterface::class), + $this->createStub(LoggerInterface::class), $form, ); } diff --git a/tests/Controller/Admin/AccommodationBooking/ConfirmControllerTest.php b/tests/Controller/Admin/AccommodationBooking/ConfirmControllerTest.php index e885a7c..ec52e6c 100644 --- a/tests/Controller/Admin/AccommodationBooking/ConfirmControllerTest.php +++ b/tests/Controller/Admin/AccommodationBooking/ConfirmControllerTest.php @@ -9,6 +9,7 @@ use App\Entity\Groups\AccommodationBooking; use App\Enum\Groups\AccommodationBookingStatus; use App\Message\CreateClickUpBookingTaskMessage; use App\Service\AccommodationBookingService; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Psr\Log\LoggerInterface; @@ -29,7 +30,7 @@ class ConfirmControllerTest extends TestCase $bookingService = $this->createMock(AccommodationBookingService::class); $bookingService->expects(self::never())->method('confirmBooking'); - $controller = new TestableConfirmController($bookingService, $this->neverDispatchingBus(), $this->createMock(LoggerInterface::class)); + $controller = new TestableConfirmController($bookingService, $this->neverDispatchingBus(), $this->createStub(LoggerInterface::class)); $response = $controller->index($this->receivedBooking(), Request::create('/admin/accommodation-booking/1/confirm')); @@ -51,7 +52,7 @@ class ConfirmControllerTest extends TestCase ->with(self::isInstanceOf(CreateClickUpBookingTaskMessage::class)) ->willReturnCallback(static fn (object $message): Envelope => new Envelope($message)); - $controller = new TestableConfirmController($bookingService, $messageBus, $this->createMock(LoggerInterface::class)); + $controller = new TestableConfirmController($bookingService, $messageBus, $this->createStub(LoggerInterface::class)); $response = $controller->index($booking, Request::create('/admin/accommodation-booking/1/confirm', 'POST')); @@ -63,16 +64,14 @@ class ConfirmControllerTest extends TestCase $bookingService = $this->createMock(AccommodationBookingService::class); $bookingService->expects(self::never())->method('confirmBooking'); - $controller = new TestableConfirmController($bookingService, $this->neverDispatchingBus(), $this->createMock(LoggerInterface::class), tokenValid: false); + $controller = new TestableConfirmController($bookingService, $this->neverDispatchingBus(), $this->createStub(LoggerInterface::class), tokenValid: false); $this->expectException(AccessDeniedException::class); $controller->index($this->receivedBooking(), Request::create('/admin/accommodation-booking/1/confirm', 'POST')); } - /** - * @dataProvider nonReceivedStatuses - */ + #[DataProvider('nonReceivedStatuses')] public function testABookingThatIsNotAwaitingValidationCannotBeConfirmed(AccommodationBookingStatus $status): void { $booking = $this->receivedBooking(); @@ -81,7 +80,7 @@ class ConfirmControllerTest extends TestCase $bookingService = $this->createMock(AccommodationBookingService::class); $bookingService->expects(self::never())->method('confirmBooking'); - $controller = new TestableConfirmController($bookingService, $this->neverDispatchingBus(), $this->createMock(LoggerInterface::class)); + $controller = new TestableConfirmController($bookingService, $this->neverDispatchingBus(), $this->createStub(LoggerInterface::class)); $response = $controller->index($booking, Request::create('/admin/accommodation-booking/1/confirm', 'POST')); @@ -108,7 +107,7 @@ class ConfirmControllerTest extends TestCase $bookingService = $this->createMock(AccommodationBookingService::class); $bookingService->expects(self::never())->method('confirmBooking'); - $controller = new TestableConfirmController($bookingService, $this->neverDispatchingBus(), $this->createMock(LoggerInterface::class)); + $controller = new TestableConfirmController($bookingService, $this->neverDispatchingBus(), $this->createStub(LoggerInterface::class)); $response = $controller->index($booking, Request::create('/admin/accommodation-booking/1/confirm', 'POST')); diff --git a/tests/Controller/Admin/AccommodationBooking/CreateControllerTest.php b/tests/Controller/Admin/AccommodationBooking/CreateControllerTest.php index ce733f0..9f71d7b 100644 --- a/tests/Controller/Admin/AccommodationBooking/CreateControllerTest.php +++ b/tests/Controller/Admin/AccommodationBooking/CreateControllerTest.php @@ -34,14 +34,14 @@ class CreateControllerTest extends TestCase private function buildController(?UserInterface $user): TestableCreateController { - $form = $this->createMock(FormInterface::class); + $form = $this->createStub(FormInterface::class); $form->method('handleRequest')->willReturn($form); $form->method('isSubmitted')->willReturn(false); return new TestableCreateController( - $this->createMock(EntityManagerInterface::class), - $this->createMock(LoggerInterface::class), - $this->createMock(AccommodationBookingService::class), + $this->createStub(EntityManagerInterface::class), + $this->createStub(LoggerInterface::class), + $this->createStub(AccommodationBookingService::class), $form, $user, ); diff --git a/tests/Controller/Admin/AccommodationBooking/DeleteControllerTest.php b/tests/Controller/Admin/AccommodationBooking/DeleteControllerTest.php index 7fd70e6..fcdf9e4 100644 --- a/tests/Controller/Admin/AccommodationBooking/DeleteControllerTest.php +++ b/tests/Controller/Admin/AccommodationBooking/DeleteControllerTest.php @@ -9,6 +9,7 @@ use App\Entity\Groups\Accommodation; use App\Entity\Groups\AccommodationBooking; use App\Enum\Groups\AccommodationBookingStatus; use Doctrine\ORM\EntityManagerInterface; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; use Psr\Log\LoggerInterface; use Symfony\Component\HttpFoundation\Request; @@ -53,9 +54,7 @@ class DeleteControllerTest extends TestCase self::assertSame('success', $controller->flashes[0]['type']); } - /** - * @dataProvider undeletableStatuses - */ + #[DataProvider('undeletableStatuses')] public function testOnlyADraftCanBeDeleted(AccommodationBookingStatus $status): void { // Anything past Entwurf has been in contact with the customer and is closed by an @@ -126,7 +125,7 @@ class DeleteControllerTest extends TestCase ): TestableBookingDeleteController { return new TestableBookingDeleteController( $entityManager, - $this->createMock(LoggerInterface::class), + $this->createStub(LoggerInterface::class), $tokenValid, ); } diff --git a/tests/Controller/Admin/AccommodationBooking/DiscardControllerTest.php b/tests/Controller/Admin/AccommodationBooking/DiscardControllerTest.php index 7af2246..3eae528 100644 --- a/tests/Controller/Admin/AccommodationBooking/DiscardControllerTest.php +++ b/tests/Controller/Admin/AccommodationBooking/DiscardControllerTest.php @@ -8,6 +8,7 @@ use App\Controller\Admin\AccommodationBooking\DiscardController; use App\Entity\Groups\AccommodationBooking; use App\Enum\Groups\AccommodationBookingStatus; use App\Service\AccommodationBookingService; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; use Psr\Log\LoggerInterface; use Symfony\Component\HttpFoundation\Request; @@ -25,7 +26,7 @@ class DiscardControllerTest extends TestCase $bookingService = $this->createMock(AccommodationBookingService::class); $bookingService->expects(self::never())->method('discardBooking'); - $controller = new TestableDiscardController($bookingService, $this->createMock(LoggerInterface::class)); + $controller = new TestableDiscardController($bookingService, $this->createStub(LoggerInterface::class)); $response = $controller->index($this->openBooking(), Request::create('/admin/accommodation-booking/1/discard')); @@ -33,9 +34,7 @@ class DiscardControllerTest extends TestCase self::assertSame('admin/accommodation_booking/modal_discard.html.twig', $controller->renderedView); } - /** - * @dataProvider discardableStatuses - */ + #[DataProvider('discardableStatuses')] public function testPostDiscardsTheBookingAndRedirectsTheBrowser(AccommodationBookingStatus $status): void { $booking = $this->openBooking(); @@ -44,7 +43,7 @@ class DiscardControllerTest extends TestCase $bookingService = $this->createMock(AccommodationBookingService::class); $bookingService->expects(self::once())->method('discardBooking')->with($booking); - $controller = new TestableDiscardController($bookingService, $this->createMock(LoggerInterface::class)); + $controller = new TestableDiscardController($bookingService, $this->createStub(LoggerInterface::class)); $response = $controller->index($booking, Request::create('/admin/accommodation-booking/1/discard', 'POST')); @@ -62,9 +61,7 @@ class DiscardControllerTest extends TestCase yield 'received' => [AccommodationBookingStatus::Received]; } - /** - * @dataProvider closedStatuses - */ + #[DataProvider('closedStatuses')] public function testAClosedBookingCannotBeDiscarded(AccommodationBookingStatus $status): void { // A released confirmation is binding, and an Absage is already the end of the line. @@ -74,7 +71,7 @@ class DiscardControllerTest extends TestCase $bookingService = $this->createMock(AccommodationBookingService::class); $bookingService->expects(self::never())->method('discardBooking'); - $controller = new TestableDiscardController($bookingService, $this->createMock(LoggerInterface::class)); + $controller = new TestableDiscardController($bookingService, $this->createStub(LoggerInterface::class)); $response = $controller->index($booking, Request::create('/admin/accommodation-booking/1/discard', 'POST')); @@ -95,7 +92,7 @@ class DiscardControllerTest extends TestCase $bookingService = $this->createMock(AccommodationBookingService::class); $bookingService->expects(self::never())->method('discardBooking'); - $controller = new TestableDiscardController($bookingService, $this->createMock(LoggerInterface::class), tokenValid: false); + $controller = new TestableDiscardController($bookingService, $this->createStub(LoggerInterface::class), tokenValid: false); $this->expectException(AccessDeniedException::class); diff --git a/tests/Controller/Admin/AccommodationBooking/EditControllerTest.php b/tests/Controller/Admin/AccommodationBooking/EditControllerTest.php index a3e254d..45d12bf 100644 --- a/tests/Controller/Admin/AccommodationBooking/EditControllerTest.php +++ b/tests/Controller/Admin/AccommodationBooking/EditControllerTest.php @@ -13,6 +13,7 @@ use App\Repository\Groups\BoardServiceRepository; use App\Repository\UserRepository; use App\Service\AccommodationBookingService; use Doctrine\ORM\EntityManagerInterface; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; use Psr\Log\LoggerInterface; use Symfony\Component\Form\FormInterface; @@ -26,9 +27,7 @@ use Symfony\Component\HttpFoundation\Response; */ class EditControllerTest extends TestCase { - /** - * @dataProvider everyStatus - */ + #[DataProvider('everyStatus')] public function testSavingNeverNotifiesTheCustomer(AccommodationBookingStatus $status): void { // Sending used to be a side effect of saving a status change, which is how an inquiry @@ -59,7 +58,7 @@ class EditControllerTest extends TestCase private function submitEdit(AccommodationBooking $booking, AccommodationBookingService $bookingService): void { - $form = $this->createMock(FormInterface::class); + $form = $this->createStub(FormInterface::class); $form->method('handleRequest')->willReturn($form); $form->method('isSubmitted')->willReturn(true); $form->method('isValid')->willReturn(true); @@ -70,10 +69,10 @@ class EditControllerTest extends TestCase $controller = new TestableEditController( $entityManager, - $this->createMock(LoggerInterface::class), - $this->createMock(BoardServiceRepository::class), - $this->createMock(AdditionalServiceRepository::class), - $this->createMock(UserRepository::class), + $this->createStub(LoggerInterface::class), + $this->createStub(BoardServiceRepository::class), + $this->createStub(AdditionalServiceRepository::class), + $this->createStub(UserRepository::class), $bookingService, $form, ); @@ -97,7 +96,7 @@ class EditControllerTest extends TestCase public function testAdminGetsTheGroupsStaffAsBetreuerChoices(): void { $staff = [new User('manager@example.test')]; - $userRepo = $this->createMock(UserRepository::class); + $userRepo = $this->createStub(UserRepository::class); $userRepo->method('findGroupsStaff')->willReturn($staff); $controller = $this->buildController($userRepo, granted: true); @@ -111,7 +110,7 @@ class EditControllerTest extends TestCase $formerManager = new User('former@example.test'); $staff = [new User('manager@example.test')]; - $userRepo = $this->createMock(UserRepository::class); + $userRepo = $this->createStub(UserRepository::class); $userRepo->method('findGroupsStaff')->willReturn($staff); $booking = new AccommodationBooking(); @@ -127,17 +126,17 @@ class EditControllerTest extends TestCase { // An unsubmitted form: index() falls through to render() and only the options // handed to createForm() are of interest here. - $form = $this->createMock(FormInterface::class); + $form = $this->createStub(FormInterface::class); $form->method('handleRequest')->willReturn($form); $form->method('isSubmitted')->willReturn(false); return new TestableEditController( - $this->createMock(EntityManagerInterface::class), - $this->createMock(LoggerInterface::class), - $this->createMock(BoardServiceRepository::class), - $this->createMock(AdditionalServiceRepository::class), + $this->createStub(EntityManagerInterface::class), + $this->createStub(LoggerInterface::class), + $this->createStub(BoardServiceRepository::class), + $this->createStub(AdditionalServiceRepository::class), $userRepo, - $this->createMock(AccommodationBookingService::class), + $this->createStub(AccommodationBookingService::class), $form, $granted, ); diff --git a/tests/Controller/Admin/AccommodationBooking/GenerateAccessLinkControllerTest.php b/tests/Controller/Admin/AccommodationBooking/GenerateAccessLinkControllerTest.php index e812249..5e8b04f 100644 --- a/tests/Controller/Admin/AccommodationBooking/GenerateAccessLinkControllerTest.php +++ b/tests/Controller/Admin/AccommodationBooking/GenerateAccessLinkControllerTest.php @@ -8,6 +8,7 @@ use App\Controller\Admin\AccommodationBooking\GenerateAccessLinkController; use App\Entity\Groups\AccommodationBooking; use App\Enum\Groups\AccommodationBookingStatus; use App\Service\AccommodationBookingService; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; use Psr\Log\LoggerInterface; use Symfony\Component\HttpFoundation\Request; @@ -25,7 +26,7 @@ class GenerateAccessLinkControllerTest extends TestCase $bookingService = $this->createMock(AccommodationBookingService::class); $bookingService->expects(self::never())->method('generateAccessLink'); - $controller = new TestableGenerateAccessLinkController($bookingService, $this->createMock(LoggerInterface::class)); + $controller = new TestableGenerateAccessLinkController($bookingService, $this->createStub(LoggerInterface::class)); $response = $controller->index($this->requestedBooking(), Request::create('/admin/accommodation-booking/1/generate-access-link')); @@ -33,9 +34,7 @@ class GenerateAccessLinkControllerTest extends TestCase self::assertSame('admin/accommodation_booking/modal_generate_access_link.html.twig', $controller->renderedView); } - /** - * @dataProvider statusesAwaitingAnOffer - */ + #[DataProvider('statusesAwaitingAnOffer')] public function testPostGeneratesTheLinkAndRedirectsTheBrowser(AccommodationBookingStatus $status): void { $booking = $this->requestedBooking(); @@ -44,7 +43,7 @@ class GenerateAccessLinkControllerTest extends TestCase $bookingService = $this->createMock(AccommodationBookingService::class); $bookingService->expects(self::once())->method('generateAccessLink')->with($booking); - $controller = new TestableGenerateAccessLinkController($bookingService, $this->createMock(LoggerInterface::class)); + $controller = new TestableGenerateAccessLinkController($bookingService, $this->createStub(LoggerInterface::class)); $response = $controller->index($booking, Request::create('/admin/accommodation-booking/1/generate-access-link', 'POST')); @@ -60,9 +59,7 @@ class GenerateAccessLinkControllerTest extends TestCase yield 'requested' => [AccommodationBookingStatus::Requested]; } - /** - * @dataProvider statusesPastTheOffer - */ + #[DataProvider('statusesPastTheOffer')] public function testABookingThatIsNotAwaitingAnOfferGetsNoLink(AccommodationBookingStatus $status): void { $booking = $this->requestedBooking(); @@ -71,7 +68,7 @@ class GenerateAccessLinkControllerTest extends TestCase $bookingService = $this->createMock(AccommodationBookingService::class); $bookingService->expects(self::never())->method('generateAccessLink'); - $controller = new TestableGenerateAccessLinkController($bookingService, $this->createMock(LoggerInterface::class)); + $controller = new TestableGenerateAccessLinkController($bookingService, $this->createStub(LoggerInterface::class)); $response = $controller->index($booking, Request::create('/admin/accommodation-booking/1/generate-access-link', 'POST')); @@ -94,7 +91,7 @@ class GenerateAccessLinkControllerTest extends TestCase $bookingService = $this->createMock(AccommodationBookingService::class); $bookingService->expects(self::never())->method('generateAccessLink'); - $controller = new TestableGenerateAccessLinkController($bookingService, $this->createMock(LoggerInterface::class), tokenValid: false); + $controller = new TestableGenerateAccessLinkController($bookingService, $this->createStub(LoggerInterface::class), tokenValid: false); $this->expectException(AccessDeniedException::class); diff --git a/tests/Controller/Admin/AccommodationBooking/PdfControllerTest.php b/tests/Controller/Admin/AccommodationBooking/PdfControllerTest.php index c7bcdcc..4d5519c 100644 --- a/tests/Controller/Admin/AccommodationBooking/PdfControllerTest.php +++ b/tests/Controller/Admin/AccommodationBooking/PdfControllerTest.php @@ -8,6 +8,7 @@ use App\Controller\Admin\AccommodationBooking\PdfController; use App\Entity\Groups\AccommodationBooking; use App\Enum\Groups\AccommodationBookingStatus; use App\Service\AccommodationBookingPdfGenerator; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; use Symfony\Component\HttpFoundation\Response; @@ -32,9 +33,7 @@ class PdfControllerTest extends TestCase self::assertSame(Response::HTTP_OK, $response->getStatusCode()); } - /** - * @dataProvider nonConfirmedStatuses - */ + #[DataProvider('nonConfirmedStatuses')] public function testABookingThatIsNotConfirmedCannotBeDownloaded(AccommodationBookingStatus $status): void { $generator = $this->createMock(AccommodationBookingPdfGenerator::class); @@ -61,7 +60,7 @@ class PdfControllerTest extends TestCase public function testAFailingGeneratorRedirectsWithAFlash(): void { - $generator = $this->createMock(AccommodationBookingPdfGenerator::class); + $generator = $this->createStub(AccommodationBookingPdfGenerator::class); $generator->method('createDownloadResponse')->willThrowException(new \RuntimeException('keine Preise')); $controller = new TestablePdfController($generator); diff --git a/tests/Controller/Admin/AccommodationBooking/SendAccessLinkControllerTest.php b/tests/Controller/Admin/AccommodationBooking/SendAccessLinkControllerTest.php index 55c2632..cef0957 100644 --- a/tests/Controller/Admin/AccommodationBooking/SendAccessLinkControllerTest.php +++ b/tests/Controller/Admin/AccommodationBooking/SendAccessLinkControllerTest.php @@ -8,6 +8,7 @@ use App\Controller\Admin\AccommodationBooking\SendAccessLinkController; use App\Entity\Groups\AccommodationBooking; use App\Enum\Groups\AccommodationBookingStatus; use App\Service\AccommodationBookingService; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; use Psr\Log\LoggerInterface; use Symfony\Component\HttpFoundation\Request; @@ -25,7 +26,7 @@ class SendAccessLinkControllerTest extends TestCase $bookingService = $this->createMock(AccommodationBookingService::class); $bookingService->expects(self::never())->method('sendAccessLink'); - $controller = new TestableSendAccessLinkController($bookingService, $this->createMock(LoggerInterface::class)); + $controller = new TestableSendAccessLinkController($bookingService, $this->createStub(LoggerInterface::class)); $response = $controller->index($this->openBooking(), Request::create('/admin/accommodation-booking/1/send-access-link')); @@ -40,7 +41,7 @@ class SendAccessLinkControllerTest extends TestCase $bookingService = $this->createMock(AccommodationBookingService::class); $bookingService->expects(self::once())->method('sendAccessLink')->with($booking); - $controller = new TestableSendAccessLinkController($bookingService, $this->createMock(LoggerInterface::class)); + $controller = new TestableSendAccessLinkController($bookingService, $this->createStub(LoggerInterface::class)); $response = $controller->index($booking, Request::create('/admin/accommodation-booking/1/send-access-link', 'POST')); @@ -55,7 +56,7 @@ class SendAccessLinkControllerTest extends TestCase $bookingService = $this->createMock(AccommodationBookingService::class); $bookingService->expects(self::never())->method('sendAccessLink'); - $controller = new TestableSendAccessLinkController($bookingService, $this->createMock(LoggerInterface::class)); + $controller = new TestableSendAccessLinkController($bookingService, $this->createStub(LoggerInterface::class)); $response = $controller->index($booking, Request::create('/admin/accommodation-booking/1/send-access-link', 'POST')); @@ -65,9 +66,8 @@ class SendAccessLinkControllerTest extends TestCase /** * Drafts are held back even when a link is on the record — a booking pushed back into * Entwurf keeps its accessLinkIssuedAt, and it must not be handed out again. - * - * @dataProvider requestMethods */ + #[DataProvider('requestMethods')] public function testADraftLinkIsNeverSentEvenIfOneWasIssuedEarlier(string $method): void { $booking = $this->openBooking(); @@ -76,7 +76,7 @@ class SendAccessLinkControllerTest extends TestCase $bookingService = $this->createMock(AccommodationBookingService::class); $bookingService->expects(self::never())->method('sendAccessLink'); - $controller = new TestableSendAccessLinkController($bookingService, $this->createMock(LoggerInterface::class)); + $controller = new TestableSendAccessLinkController($bookingService, $this->createStub(LoggerInterface::class)); $response = $controller->index($booking, Request::create('/admin/accommodation-booking/1/send-access-link', $method)); @@ -98,7 +98,7 @@ class SendAccessLinkControllerTest extends TestCase $bookingService = $this->createMock(AccommodationBookingService::class); $bookingService->expects(self::never())->method('sendAccessLink'); - $controller = new TestableSendAccessLinkController($bookingService, $this->createMock(LoggerInterface::class), tokenValid: false); + $controller = new TestableSendAccessLinkController($bookingService, $this->createStub(LoggerInterface::class), tokenValid: false); $this->expectException(AccessDeniedException::class); @@ -113,7 +113,7 @@ class SendAccessLinkControllerTest extends TestCase $bookingService = $this->createMock(AccommodationBookingService::class); $bookingService->expects(self::never())->method('sendAccessLink'); - $controller = new TestableSendAccessLinkController($bookingService, $this->createMock(LoggerInterface::class)); + $controller = new TestableSendAccessLinkController($bookingService, $this->createStub(LoggerInterface::class)); $response = $controller->index($booking, Request::create('/admin/accommodation-booking/1/send-access-link', 'POST')); diff --git a/tests/Controller/Admin/AccommodationBooking/SendOfferControllerTest.php b/tests/Controller/Admin/AccommodationBooking/SendOfferControllerTest.php index a95f904..8effee3 100644 --- a/tests/Controller/Admin/AccommodationBooking/SendOfferControllerTest.php +++ b/tests/Controller/Admin/AccommodationBooking/SendOfferControllerTest.php @@ -8,6 +8,7 @@ use App\Controller\Admin\AccommodationBooking\SendOfferController; use App\Entity\Groups\AccommodationBooking; use App\Enum\Groups\AccommodationBookingStatus; use App\Service\AccommodationBookingService; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; use Psr\Log\LoggerInterface; use Symfony\Component\HttpFoundation\Request; @@ -25,7 +26,7 @@ class SendOfferControllerTest extends TestCase $bookingService = $this->createMock(AccommodationBookingService::class); $bookingService->expects(self::never())->method('sendOffer'); - $controller = new TestableSendOfferController($bookingService, $this->createMock(LoggerInterface::class)); + $controller = new TestableSendOfferController($bookingService, $this->createStub(LoggerInterface::class)); $response = $controller->index($this->requestedBooking(), Request::create('/admin/accommodation-booking/1/send-offer')); @@ -33,9 +34,7 @@ class SendOfferControllerTest extends TestCase self::assertSame('admin/accommodation_booking/modal_send_offer.html.twig', $controller->renderedView); } - /** - * @dataProvider statusesAwaitingAnOffer - */ + #[DataProvider('statusesAwaitingAnOffer')] public function testPostSendsTheOfferAndRedirectsTheBrowser(AccommodationBookingStatus $status): void { $booking = $this->requestedBooking(); @@ -44,7 +43,7 @@ class SendOfferControllerTest extends TestCase $bookingService = $this->createMock(AccommodationBookingService::class); $bookingService->expects(self::once())->method('sendOffer')->with($booking); - $controller = new TestableSendOfferController($bookingService, $this->createMock(LoggerInterface::class)); + $controller = new TestableSendOfferController($bookingService, $this->createStub(LoggerInterface::class)); $response = $controller->index($booking, Request::create('/admin/accommodation-booking/1/send-offer', 'POST')); @@ -61,9 +60,7 @@ class SendOfferControllerTest extends TestCase yield 'requested' => [AccommodationBookingStatus::Requested]; } - /** - * @dataProvider statusesPastTheOffer - */ + #[DataProvider('statusesPastTheOffer')] public function testABookingThatIsNotAwaitingAnOfferGetsNone(AccommodationBookingStatus $status): void { $booking = $this->requestedBooking(); @@ -72,7 +69,7 @@ class SendOfferControllerTest extends TestCase $bookingService = $this->createMock(AccommodationBookingService::class); $bookingService->expects(self::never())->method('sendOffer'); - $controller = new TestableSendOfferController($bookingService, $this->createMock(LoggerInterface::class)); + $controller = new TestableSendOfferController($bookingService, $this->createStub(LoggerInterface::class)); $response = $controller->index($booking, Request::create('/admin/accommodation-booking/1/send-offer', 'POST')); @@ -95,7 +92,7 @@ class SendOfferControllerTest extends TestCase $bookingService = $this->createMock(AccommodationBookingService::class); $bookingService->expects(self::never())->method('sendOffer'); - $controller = new TestableSendOfferController($bookingService, $this->createMock(LoggerInterface::class), tokenValid: false); + $controller = new TestableSendOfferController($bookingService, $this->createStub(LoggerInterface::class), tokenValid: false); $this->expectException(AccessDeniedException::class); @@ -113,7 +110,7 @@ class SendOfferControllerTest extends TestCase $bookingService = $this->createMock(AccommodationBookingService::class); $bookingService->expects(self::never())->method('sendOffer'); - $controller = new TestableSendOfferController($bookingService, $this->createMock(LoggerInterface::class)); + $controller = new TestableSendOfferController($bookingService, $this->createStub(LoggerInterface::class)); $response = $controller->index($booking, Request::create('/admin/accommodation-booking/1/send-offer', 'POST')); diff --git a/tests/Controller/Admin/User/ApproveRoleControllerTest.php b/tests/Controller/Admin/User/ApproveRoleControllerTest.php index 73c4712..86ce260 100644 --- a/tests/Controller/Admin/User/ApproveRoleControllerTest.php +++ b/tests/Controller/Admin/User/ApproveRoleControllerTest.php @@ -31,7 +31,7 @@ class ApproveRoleControllerTest extends TestCase $entityManager = $this->createMock(EntityManagerInterface::class); $entityManager->expects(self::never())->method('flush'); - $controller = new TestableApproveRoleController($entityManager, $this->createMock(LoggerInterface::class)); + $controller = new TestableApproveRoleController($entityManager, $this->createStub(LoggerInterface::class)); $response = $controller->index($user, Role::GROUPS_ADMIN, Request::create('/admin/user/1/approve/ROLE_GROUPS_ADMIN')); @@ -47,7 +47,7 @@ class ApproveRoleControllerTest extends TestCase $entityManager = $this->createMock(EntityManagerInterface::class); $entityManager->expects(self::once())->method('flush'); - $controller = new TestableApproveRoleController($entityManager, $this->createMock(LoggerInterface::class)); + $controller = new TestableApproveRoleController($entityManager, $this->createStub(LoggerInterface::class)); $response = $controller->index($user, Role::GROUPS_ADMIN, Request::create('/admin/user/1/approve/ROLE_GROUPS_ADMIN', 'POST')); @@ -61,7 +61,7 @@ class ApproveRoleControllerTest extends TestCase $entityManager = $this->createMock(EntityManagerInterface::class); $entityManager->expects(self::never())->method('flush'); - $controller = new TestableApproveRoleController($entityManager, $this->createMock(LoggerInterface::class)); + $controller = new TestableApproveRoleController($entityManager, $this->createStub(LoggerInterface::class)); $this->expectException(NotFoundHttpException::class); @@ -76,7 +76,7 @@ class ApproveRoleControllerTest extends TestCase $entityManager = $this->createMock(EntityManagerInterface::class); $entityManager->expects(self::never())->method('flush'); - $controller = new TestableApproveRoleController($entityManager, $this->createMock(LoggerInterface::class), currentUser: $user); + $controller = new TestableApproveRoleController($entityManager, $this->createStub(LoggerInterface::class), currentUser: $user); $this->expectException(AccessDeniedException::class); @@ -90,7 +90,7 @@ class ApproveRoleControllerTest extends TestCase $entityManager = $this->createMock(EntityManagerInterface::class); $entityManager->expects(self::once())->method('flush'); - $controller = new TestableApproveRoleController($entityManager, $this->createMock(LoggerInterface::class), currentUser: $user); + $controller = new TestableApproveRoleController($entityManager, $this->createStub(LoggerInterface::class), currentUser: $user); // Only ROLE_ADMIN needs a second pair of eyes — an approver already holds it, so the // rest grant less than they could grant themselves anyway. @@ -104,7 +104,7 @@ class ApproveRoleControllerTest extends TestCase $entityManager = $this->createMock(EntityManagerInterface::class); $entityManager->expects(self::never())->method('flush'); - $controller = new TestableApproveRoleController($entityManager, $this->createMock(LoggerInterface::class), tokenValid: false); + $controller = new TestableApproveRoleController($entityManager, $this->createStub(LoggerInterface::class), tokenValid: false); $this->expectException(AccessDeniedException::class); @@ -119,8 +119,8 @@ class ApproveRoleControllerTest extends TestCase $tokenStorage->setToken(new PostAuthenticationToken($user, 'main', $user->getRoles())); $controller = new TestableApproveRoleController( - $this->createMock(EntityManagerInterface::class), - $this->createMock(LoggerInterface::class), + $this->createStub(EntityManagerInterface::class), + $this->createStub(LoggerInterface::class), currentUser: $user, tokenStorage: $tokenStorage, ); @@ -142,8 +142,8 @@ class ApproveRoleControllerTest extends TestCase $tokenStorage->setToken($originalToken = new PostAuthenticationToken($admin, 'main', $admin->getRoles())); $controller = new TestableApproveRoleController( - $this->createMock(EntityManagerInterface::class), - $this->createMock(LoggerInterface::class), + $this->createStub(EntityManagerInterface::class), + $this->createStub(LoggerInterface::class), currentUser: $admin, tokenStorage: $tokenStorage, ); diff --git a/tests/Controller/Api/AccommodationBookingControllerTest.php b/tests/Controller/Api/AccommodationBookingControllerTest.php index fe59f15..87813a1 100644 --- a/tests/Controller/Api/AccommodationBookingControllerTest.php +++ b/tests/Controller/Api/AccommodationBookingControllerTest.php @@ -157,10 +157,10 @@ class AccommodationBookingControllerTest extends TestCase ->with(['uuid' => $booking->getUuid()]) ->willReturn($booking); - $breakdownCalculator = $this->createMock(AccommodationBookingBreakdownCalculator::class); + $breakdownCalculator = $this->createStub(AccommodationBookingBreakdownCalculator::class); $breakdownCalculator->method('compute')->willReturn(null); - $controller = new AccommodationBookingController($bookingRepository, $breakdownCalculator, $this->serializer(), $this->createMock(AccommodationBookingService::class)); + $controller = new AccommodationBookingController($bookingRepository, $breakdownCalculator, $this->serializer(), $this->createStub(AccommodationBookingService::class)); $response = $controller->single($booking->getUuid()); $payload = json_decode((string) $response->getContent(), true, 512, JSON_THROW_ON_ERROR); @@ -183,7 +183,7 @@ class AccommodationBookingControllerTest extends TestCase $breakdownCalculator = $this->createMock(AccommodationBookingBreakdownCalculator::class); $breakdownCalculator->expects(self::never())->method('compute'); - $controller = new AccommodationBookingController($bookingRepository, $breakdownCalculator, $this->serializer(), $this->createMock(AccommodationBookingService::class)); + $controller = new AccommodationBookingController($bookingRepository, $breakdownCalculator, $this->serializer(), $this->createStub(AccommodationBookingService::class)); $response = $controller->single('unknown-uuid'); $payload = json_decode((string) $response->getContent(), true, 512, JSON_THROW_ON_ERROR); @@ -210,7 +210,7 @@ class AccommodationBookingControllerTest extends TestCase ->with(['uuid' => $booking->getUuid()]) ->willReturn($booking); - $breakdownCalculator = $this->createMock(AccommodationBookingBreakdownCalculator::class); + $breakdownCalculator = $this->createStub(AccommodationBookingBreakdownCalculator::class); $breakdownCalculator->method('compute')->willReturn(null); $bookingService = $this->createMock(AccommodationBookingService::class); @@ -256,7 +256,7 @@ class AccommodationBookingControllerTest extends TestCase ->with(['uuid' => $booking->getUuid()]) ->willReturn($booking); - $breakdownCalculator = $this->createMock(AccommodationBookingBreakdownCalculator::class); + $breakdownCalculator = $this->createStub(AccommodationBookingBreakdownCalculator::class); $breakdownCalculator->method('compute')->willReturn(null); $bookingService = $this->createMock(AccommodationBookingService::class); diff --git a/tests/Controller/Api/ContingentControllerTest.php b/tests/Controller/Api/ContingentControllerTest.php index 8d61893..a5618a6 100644 --- a/tests/Controller/Api/ContingentControllerTest.php +++ b/tests/Controller/Api/ContingentControllerTest.php @@ -190,7 +190,7 @@ class ContingentControllerTest extends TestCase */ private function callFullSpanCalendar(?array $bounds, array $prices, array $statuses = []): array { - $priceRepository = $this->createMock(AccommodationPriceRepository::class); + $priceRepository = $this->createStub(AccommodationPriceRepository::class); $priceRepository->method('findPricedDateBoundsByHotelCode')->willReturn($bounds); $priceRepository->method('findByHotelCodeAndDateRange')->willReturn($prices); @@ -214,13 +214,13 @@ class ContingentControllerTest extends TestCase ?array $prices = null, ?AccommodationPriceRepository $priceRepository = null, ): Response { - $accommodationRepository = $this->createMock(AccommodationRepository::class); + $accommodationRepository = $this->createStub(AccommodationRepository::class); $accommodationRepository->method('findOneBy')->willReturn((new Accommodation())->setCalendarCode('HOTEL1')->setCurrency('EUR')); - $snapshotReader = $this->createMock(ContingentSnapshotReader::class); + $snapshotReader = $this->createStub(ContingentSnapshotReader::class); $snapshotReader->method('statusesFor')->willReturn($statuses); - $priceRepository ??= $this->createMock(AccommodationPriceRepository::class); + $priceRepository ??= $this->createStub(AccommodationPriceRepository::class); if (null !== $prices) { $priceRepository->method('findByHotelCodeAndDateRange')->willReturn($prices); @@ -231,8 +231,8 @@ class ContingentControllerTest extends TestCase $priceRepository, $snapshotReader, new PriceTimelineBuilder(), - new AccommodationPriceCoverage($this->createMock(AccommodationPriceRepository::class)), - $this->createMock(LoggerInterface::class), + new AccommodationPriceCoverage($this->createStub(AccommodationPriceRepository::class)), + $this->createStub(LoggerInterface::class), ); // No 'serializer' service registered, so AbstractController::json() falls back to @@ -245,12 +245,12 @@ class ContingentControllerTest extends TestCase private function createController(): ContingentController { return new ContingentController( - $this->createMock(AccommodationRepository::class), - $this->createMock(AccommodationPriceRepository::class), - $this->createMock(ContingentSnapshotReader::class), + $this->createStub(AccommodationRepository::class), + $this->createStub(AccommodationPriceRepository::class), + $this->createStub(ContingentSnapshotReader::class), new PriceTimelineBuilder(), - new AccommodationPriceCoverage($this->createMock(AccommodationPriceRepository::class)), - $this->createMock(LoggerInterface::class), + new AccommodationPriceCoverage($this->createStub(AccommodationPriceRepository::class)), + $this->createStub(LoggerInterface::class), ); } diff --git a/tests/Controller/Booking/Edit/IndexControllerTest.php b/tests/Controller/Booking/Edit/IndexControllerTest.php index 4a9427b..80e8995 100644 --- a/tests/Controller/Booking/Edit/IndexControllerTest.php +++ b/tests/Controller/Booking/Edit/IndexControllerTest.php @@ -24,6 +24,7 @@ use App\Service\BookingEditDraftManager; use App\Service\BookingEditPreFlightChecker; use App\Service\BookingEditSubmitter; use App\Service\BookingSessionManager; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; use Psr\Log\NullLogger; use Symfony\Component\Form\FormInterface; @@ -62,7 +63,7 @@ class IndexControllerTest extends TestCase ]; $bookingData = $this->createBooking(); - $form = $this->createMock(FormInterface::class); + $form = $this->createStub(FormInterface::class); $form->method('isSubmitted')->willReturn(false); $fingerprintService = $this->createMock(BookingChangeTracker::class); @@ -110,13 +111,13 @@ class IndexControllerTest extends TestCase $controller = new TestableIndexController( $dataLoader, - $this->createMock(BookingEditDraftManager::class), + $this->createStub(BookingEditDraftManager::class), $bookingSessionService, $fingerprintService, $bookingConfigurator, $contextFactory, $preflightChecker, - $this->createMock(BookingEditSubmitter::class), + $this->createStub(BookingEditSubmitter::class), $user, $form, ); @@ -147,7 +148,7 @@ class IndexControllerTest extends TestCase ]; $bookingData = $this->createBooking(); - $form = $this->createMock(FormInterface::class); + $form = $this->createStub(FormInterface::class); $form->method('isSubmitted')->willReturn(false); $fingerprintService = $this->createMock(BookingChangeTracker::class); @@ -187,13 +188,13 @@ class IndexControllerTest extends TestCase $controller = new TestableIndexController( $dataLoader, - $this->createMock(BookingEditDraftManager::class), - $this->createMock(BookingSessionManager::class), + $this->createStub(BookingEditDraftManager::class), + $this->createStub(BookingSessionManager::class), $fingerprintService, - $this->createMock(BookingConfigurator::class), + $this->createStub(BookingConfigurator::class), $contextFactory, $preflightChecker, - $this->createMock(BookingEditSubmitter::class), + $this->createStub(BookingEditSubmitter::class), $user, $form, ); @@ -275,10 +276,10 @@ class IndexControllerTest extends TestCase $controller = new TestableIndexController( $dataLoader, - $this->createMock(BookingEditDraftManager::class), - $this->createMock(BookingSessionManager::class), + $this->createStub(BookingEditDraftManager::class), + $this->createStub(BookingSessionManager::class), $fingerprintService, - $this->createMock(BookingConfigurator::class), + $this->createStub(BookingConfigurator::class), $contextFactory, $preflightChecker, $submitter, @@ -362,10 +363,10 @@ class IndexControllerTest extends TestCase $controller = new TestableIndexController( $dataLoader, - $this->createMock(BookingEditDraftManager::class), - $this->createMock(BookingSessionManager::class), + $this->createStub(BookingEditDraftManager::class), + $this->createStub(BookingSessionManager::class), $fingerprintService, - $this->createMock(BookingConfigurator::class), + $this->createStub(BookingConfigurator::class), $contextFactory, $preflightChecker, $submitter, @@ -390,7 +391,7 @@ class IndexControllerTest extends TestCase $bookingDto->participants = [$this->createParticipant()]; $bookingData = $this->createBooking(); - $form = $this->createMock(FormInterface::class); + $form = $this->createStub(FormInterface::class); $form->method('isSubmitted')->willReturn(false); $fingerprintService = $this->createMock(BookingChangeTracker::class); @@ -433,13 +434,13 @@ class IndexControllerTest extends TestCase $controller = new TestableIndexController( $dataLoader, - $this->createMock(BookingEditDraftManager::class), - $this->createMock(BookingSessionManager::class), + $this->createStub(BookingEditDraftManager::class), + $this->createStub(BookingSessionManager::class), $fingerprintService, $bookingConfigurator, $contextFactory, $this->createPreflightChecker($bookingDto), - $this->createMock(BookingEditSubmitter::class), + $this->createStub(BookingEditSubmitter::class), $user, $form, ); @@ -460,7 +461,7 @@ class IndexControllerTest extends TestCase $bookingDto->participants = [$this->createParticipant()]; $bookingData = $this->createBooking(); - $form = $this->createMock(FormInterface::class); + $form = $this->createStub(FormInterface::class); $form->method('isSubmitted')->willReturn(false); $fingerprintService = $this->createMock(BookingChangeTracker::class); @@ -501,13 +502,13 @@ class IndexControllerTest extends TestCase $controller = new TestableIndexController( $dataLoader, - $this->createMock(BookingEditDraftManager::class), - $this->createMock(BookingSessionManager::class), + $this->createStub(BookingEditDraftManager::class), + $this->createStub(BookingSessionManager::class), $fingerprintService, $bookingConfigurator, $contextFactory, $this->createPreflightChecker($bookingDto), - $this->createMock(BookingEditSubmitter::class), + $this->createStub(BookingEditSubmitter::class), $user, $form, ); @@ -543,13 +544,13 @@ class IndexControllerTest extends TestCase $dataLoader, $draftService, $bookingSessionService, - $this->createMock(BookingChangeTracker::class), - $this->createMock(BookingConfigurator::class), - $this->createMock(BookingEditContextFactory::class), - $this->createMock(BookingEditPreFlightChecker::class), - $this->createMock(BookingEditSubmitter::class), + $this->createStub(BookingChangeTracker::class), + $this->createStub(BookingConfigurator::class), + $this->createStub(BookingEditContextFactory::class), + $this->createStub(BookingEditPreFlightChecker::class), + $this->createStub(BookingEditSubmitter::class), $user, - $this->createMock(FormInterface::class), + $this->createStub(FormInterface::class), ); $response = $controller->reloadFromApi(42, $request); @@ -560,11 +561,11 @@ class IndexControllerTest extends TestCase } /** - * @dataProvider submissionResultProvider - * * @param array $expectedFlashes + * * @phpstan-param array $expectedFlashes */ + #[DataProvider('submissionResultProvider')] public function testIndexAppliesErrorSubmissionResultFlashesAndRedirectsBackToEditPage( BookingEditSubmissionResult $submissionResult, array $expectedFlashes, @@ -673,7 +674,7 @@ class IndexControllerTest extends TestCase bookingDto: $bookingDto, bookingData: $bookingData, mutableData: null, - summaryData: $this->createMock(BookingSummaryDto::class), + summaryData: $this->createStub(BookingSummaryDto::class), cardsData: [ 0 => new ParticipantCardDataDto( 'One', @@ -755,11 +756,11 @@ class IndexControllerTest extends TestCase $controller = new TestableIndexController( $dataLoader, - $this->createMock(BookingEditDraftManager::class), - $this->createMock(BookingSessionManager::class), + $this->createStub(BookingEditDraftManager::class), + $this->createStub(BookingSessionManager::class), $fingerprintService, - $this->createMock(BookingConfigurator::class), - $this->createMock(BookingEditContextFactory::class), + $this->createStub(BookingConfigurator::class), + $this->createStub(BookingEditContextFactory::class), $preflightChecker, $submitter, $user, diff --git a/tests/Controller/Booking/Edit/ParticipantControllerTest.php b/tests/Controller/Booking/Edit/ParticipantControllerTest.php index 1983d39..89d9511 100644 --- a/tests/Controller/Booking/Edit/ParticipantControllerTest.php +++ b/tests/Controller/Booking/Edit/ParticipantControllerTest.php @@ -86,9 +86,9 @@ class ParticipantControllerTest extends TestCase ->with($user, 42, $bookingDto); $prepopulationService = new ParticipantDataPrefiller( - $this->createMock(ApiClient::class), - $this->createMock(Crypt::class), - $this->createMock(LoggerInterface::class), + $this->createStub(ApiClient::class), + $this->createStub(Crypt::class), + $this->createStub(LoggerInterface::class), ); $participantFormSupportService = $this->createMock(ParticipantFormSupport::class); @@ -115,7 +115,7 @@ class ParticipantControllerTest extends TestCase ], ]); - $summaryData = $this->createMock(BookingSummaryDto::class); + $summaryData = $this->createStub(BookingSummaryDto::class); $context = new BookingEditContext($bookingDto, $bookingData, null, $summaryData); $contextFactory = $this->createMock(BookingEditContextFactory::class); @@ -131,7 +131,7 @@ class ParticipantControllerTest extends TestCase $dataLoader, $draftService, $contextFactory, - $this->createMock(BookingConfigurator::class), + $this->createStub(BookingConfigurator::class), $bookingSessionService, $prepopulationService, $participantFormSupportService, @@ -217,7 +217,7 @@ class ParticipantControllerTest extends TestCase ->with($bookingDto) ->willReturn([]); - $summaryData = $this->createMock(BookingSummaryDto::class); + $summaryData = $this->createStub(BookingSummaryDto::class); $context = new BookingEditContext($bookingDto, $bookingData, null, $summaryData); $contextFactory = $this->createMock(BookingEditContextFactory::class); @@ -230,14 +230,14 @@ class ParticipantControllerTest extends TestCase ->willReturn($context); $prepopulationService = new ParticipantDataPrefiller( - $this->createMock(ApiClient::class), - $this->createMock(Crypt::class), - $this->createMock(LoggerInterface::class), + $this->createStub(ApiClient::class), + $this->createStub(Crypt::class), + $this->createStub(LoggerInterface::class), ); $controller = new TestableParticipantController( $dataLoader, - $this->createMock(BookingEditDraftManager::class), + $this->createStub(BookingEditDraftManager::class), $contextFactory, $bookingConfigurator, $bookingSessionService, @@ -286,17 +286,17 @@ class ParticipantControllerTest extends TestCase $bookingDto->originalFingerprint = $changeTracker->generateFingerprint($bookingDto); $this->assertFalse($changeTracker->isDirty($bookingDto), 'Baseline must start clean'); - $form = $this->createMock(FormInterface::class); + $form = $this->createStub(FormInterface::class); $form->method('handleRequest')->willReturnSelf(); $form->method('createView')->willReturn(new FormView()); - $dataLoader = $this->createMock(BookingEditDataLoader::class); + $dataLoader = $this->createStub(BookingEditDataLoader::class); $dataLoader->method('fetchBookingData')->willReturn($bookingData); - $bookingSessionService = $this->createMock(BookingSessionManager::class); + $bookingSessionService = $this->createStub(BookingSessionManager::class); $bookingSessionService->method('getBookingDto')->willReturn($bookingDto); - $participantFormSupportService = $this->createMock(ParticipantFormSupport::class); + $participantFormSupportService = $this->createStub(ParticipantFormSupport::class); $participantFormSupportService->method('ensureParticipantExists')->willReturn($participant); $participantFormSupportService->method('createParticipantEditDto') ->willReturn(new ParticipantEditDto($participant, $bookingDto)); @@ -306,21 +306,21 @@ class ParticipantControllerTest extends TestCase ]); $participantFormSupportService->method('collectAndClearNotifications')->willReturn([]); - $summaryData = $this->createMock(BookingSummaryDto::class); - $contextFactory = $this->createMock(BookingEditContextFactory::class); + $summaryData = $this->createStub(BookingSummaryDto::class); + $contextFactory = $this->createStub(BookingEditContextFactory::class); $contextFactory->method('createParticipantContext') ->willReturn(new BookingEditContext($bookingDto, $bookingData, null, $summaryData)); $controller = new TestableParticipantController( $dataLoader, - $this->createMock(BookingEditDraftManager::class), + $this->createStub(BookingEditDraftManager::class), $contextFactory, - $this->createMock(BookingConfigurator::class), + $this->createStub(BookingConfigurator::class), $bookingSessionService, new ParticipantDataPrefiller( - $this->createMock(ApiClient::class), - $this->createMock(Crypt::class), - $this->createMock(LoggerInterface::class), + $this->createStub(ApiClient::class), + $this->createStub(Crypt::class), + $this->createStub(LoggerInterface::class), ), $participantFormSupportService, $user, diff --git a/tests/Controller/Groups/Booking/IndexControllerTest.php b/tests/Controller/Groups/Booking/IndexControllerTest.php index 29fbcff..50ef90c 100644 --- a/tests/Controller/Groups/Booking/IndexControllerTest.php +++ b/tests/Controller/Groups/Booking/IndexControllerTest.php @@ -53,8 +53,8 @@ class IndexControllerTest extends TestCase private function makeController(): TestableAccommodationIndexController { return new TestableAccommodationIndexController( - $this->createMock(AccommodationBookingService::class), - $this->createMock(AccommodationSessionManager::class), + $this->createStub(AccommodationBookingService::class), + $this->createStub(AccommodationSessionManager::class), ); } } diff --git a/tests/Controller/Groups/Booking/Step1CalendarDataTest.php b/tests/Controller/Groups/Booking/Step1CalendarDataTest.php index 6f4c1bb..1bae631 100644 --- a/tests/Controller/Groups/Booking/Step1CalendarDataTest.php +++ b/tests/Controller/Groups/Booking/Step1CalendarDataTest.php @@ -106,20 +106,20 @@ class Step1CalendarDataTest extends TestCase string $dateFrom, string $dateTo, ): array { - $snapshotReader = $this->createMock(ContingentSnapshotReader::class); + $snapshotReader = $this->createStub(ContingentSnapshotReader::class); $snapshotReader->method('statusesFor')->willReturn($statuses); - $priceRepository = $this->createMock(AccommodationPriceRepository::class); + $priceRepository = $this->createStub(AccommodationPriceRepository::class); $priceRepository->method('findByHotelCodeAndDateRange')->willReturn($prices); $controller = new Step1Controller( - $this->createMock(AccommodationBookingService::class), - $this->createMock(AccommodationSessionManager::class), + $this->createStub(AccommodationBookingService::class), + $this->createStub(AccommodationSessionManager::class), $priceRepository, new PriceTimelineBuilder(), $snapshotReader, - $this->createMock(CalendarGridBuilder::class), - $this->createMock(GroupsPriceCalculator::class), + $this->createStub(CalendarGridBuilder::class), + $this->createStub(GroupsPriceCalculator::class), new AccommodationPriceCoverage($priceRepository), ); diff --git a/tests/Controller/Groups/Booking/Step1ControllerTest.php b/tests/Controller/Groups/Booking/Step1ControllerTest.php index 50a8b4c..6337162 100644 --- a/tests/Controller/Groups/Booking/Step1ControllerTest.php +++ b/tests/Controller/Groups/Booking/Step1ControllerTest.php @@ -88,7 +88,7 @@ class Step1ControllerTest extends TestCase $sessionManager = new AccommodationSessionManager(); $sessionManager->save($request, $dto); - $bookingService = $this->createMock(AccommodationBookingService::class); + $bookingService = $this->createStub(AccommodationBookingService::class); $bookingService ->method('applyDates') ->willThrowException(new \InvalidArgumentException('Ungültiges Datumsformat. Erwartet: YYYY-MM-DD.')); @@ -105,14 +105,14 @@ class Step1ControllerTest extends TestCase AccommodationBookingService $bookingService, AccommodationSessionManager $sessionManager, ): TestableAccommodationStep1Controller { - $priceRepository = $this->createMock(AccommodationPriceRepository::class); + $priceRepository = $this->createStub(AccommodationPriceRepository::class); return new TestableAccommodationStep1Controller( $bookingService, $sessionManager, $priceRepository, new PriceTimelineBuilder(), - $this->createMock(ContingentSnapshotReader::class), + $this->createStub(ContingentSnapshotReader::class), new CalendarGridBuilder(), new GroupsPriceCalculator(new PriceTimelineBuilder(), ['runningCostsEur' => 0, 'runningCostsChf' => 0, 'undersubscription30Eur' => 0, 'undersubscription30Chf' => 0, 'undersubscription40Eur' => 0, 'undersubscription40Chf' => 0]), new AccommodationPriceCoverage($priceRepository), diff --git a/tests/Controller/Groups/Booking/Step2ControllerTest.php b/tests/Controller/Groups/Booking/Step2ControllerTest.php index 3070ff4..39fa438 100644 --- a/tests/Controller/Groups/Booking/Step2ControllerTest.php +++ b/tests/Controller/Groups/Booking/Step2ControllerTest.php @@ -38,7 +38,7 @@ class Step2ControllerTest extends TestCase $sessionManager = new AccommodationSessionManager(); $sessionManager->save($request, $dto); - $form = $this->createMock(FormInterface::class); + $form = $this->createStub(FormInterface::class); $form ->method('handleRequest') ->willReturnCallback(function () use ($dto, $form): FormInterface { diff --git a/tests/Controller/Groups/Booking/Step3ControllerTest.php b/tests/Controller/Groups/Booking/Step3ControllerTest.php index 2a1edc1..c6e2741 100644 --- a/tests/Controller/Groups/Booking/Step3ControllerTest.php +++ b/tests/Controller/Groups/Booking/Step3ControllerTest.php @@ -156,7 +156,7 @@ class Step3ControllerTest extends TestCase private function createFormMock(bool $submitted, bool $valid): FormInterface { - $form = $this->createMock(FormInterface::class); + $form = $this->createStub(FormInterface::class); $form->method('handleRequest')->willReturnSelf(); $form->method('isSubmitted')->willReturn($submitted); $form->method('isValid')->willReturn($valid); diff --git a/tests/Controller/Groups/Booking/Step4ControllerTest.php b/tests/Controller/Groups/Booking/Step4ControllerTest.php index 3f66098..a89e98a 100644 --- a/tests/Controller/Groups/Booking/Step4ControllerTest.php +++ b/tests/Controller/Groups/Booking/Step4ControllerTest.php @@ -50,7 +50,7 @@ class Step4ControllerTest extends TestCase 'ungroupedAdditionalServices' => [], ]); - $controller = new TestableStep4Controller($bookingService, $sessionManager, $this->createMock(FormInterface::class)); + $controller = new TestableStep4Controller($bookingService, $sessionManager, $this->createStub(FormInterface::class)); $response = $controller->index($request); @@ -73,9 +73,9 @@ class Step4ControllerTest extends TestCase $sessionManager->save($request, $dto); $controller = new TestableStep4Controller( - $this->createMock(AccommodationBookingService::class), + $this->createStub(AccommodationBookingService::class), $sessionManager, - $this->createMock(FormInterface::class), + $this->createStub(FormInterface::class), ); $response = $controller->index($request); @@ -115,7 +115,7 @@ class Step4ControllerTest extends TestCase $bookingService->method('loadPrices')->willReturn([]); $bookingService->expects(self::once())->method('finalizeBooking')->willReturn($booking); - $inquiryForm = $this->createMock(FormInterface::class); + $inquiryForm = $this->createStub(FormInterface::class); $inquiryForm->method('handleRequest')->willReturnSelf(); $inquiryForm->method('isSubmitted')->willReturn(true); $inquiryForm->method('isValid')->willReturn(true); @@ -158,7 +158,7 @@ class Step4ControllerTest extends TestCase ]); $bookingService->expects(self::never())->method('finalizeBooking'); - $inquiryForm = $this->createMock(FormInterface::class); + $inquiryForm = $this->createStub(FormInterface::class); $inquiryForm->method('handleRequest')->willReturnSelf(); $inquiryForm->method('isSubmitted')->willReturn(true); $inquiryForm->method('isValid')->willReturn(false); @@ -184,9 +184,9 @@ class Step4ControllerTest extends TestCase $sessionManager->save($request, $dto); $controller = new TestableStep4Controller( - $this->createMock(AccommodationBookingService::class), + $this->createStub(AccommodationBookingService::class), $sessionManager, - $this->createMock(FormInterface::class), + $this->createStub(FormInterface::class), ); $response = $controller->confirmInquiry($request); @@ -209,9 +209,9 @@ class Step4ControllerTest extends TestCase $sessionManager->save($request, $dto); $controller = new TestableStep4Controller( - $this->createMock(AccommodationBookingService::class), + $this->createStub(AccommodationBookingService::class), $sessionManager, - $this->createMock(FormInterface::class), + $this->createStub(FormInterface::class), ); $response = $controller->confirmInquiry($request); @@ -242,7 +242,7 @@ class Step4ControllerTest extends TestCase $bookingService->method('loadAccommodation')->with(1)->willReturn($accommodation); $bookingService->expects(self::never())->method('finalizeBooking'); - $confirmationForm = $this->createMock(FormInterface::class); + $confirmationForm = $this->createStub(FormInterface::class); $confirmationForm->method('handleRequest')->willReturnSelf(); $confirmationForm->method('isSubmitted')->willReturn(false); @@ -288,7 +288,7 @@ class Step4ControllerTest extends TestCase $bookingService->method('loadPrices')->willReturn([]); $bookingService->expects(self::once())->method('finalizeBooking')->willReturn($booking); - $confirmationForm = $this->createMock(FormInterface::class); + $confirmationForm = $this->createStub(FormInterface::class); $confirmationForm->method('handleRequest')->willReturnSelf(); $confirmationForm->method('isSubmitted')->willReturn(true); $confirmationForm->method('isValid')->willReturn(true); @@ -324,7 +324,7 @@ class Step4ControllerTest extends TestCase $bookingService->method('loadAccommodation')->with(1)->willReturn($accommodation); $bookingService->expects(self::never())->method('finalizeBooking'); - $confirmationForm = $this->createMock(FormInterface::class); + $confirmationForm = $this->createStub(FormInterface::class); $confirmationForm->method('handleRequest')->willReturnSelf(); $confirmationForm->method('isSubmitted')->willReturn(true); $confirmationForm->method('isValid')->willReturn(false); diff --git a/tests/Controller/Groups/Offer/IndexControllerTest.php b/tests/Controller/Groups/Offer/IndexControllerTest.php index 5f3523c..9b31e92 100644 --- a/tests/Controller/Groups/Offer/IndexControllerTest.php +++ b/tests/Controller/Groups/Offer/IndexControllerTest.php @@ -14,6 +14,7 @@ use App\Service\AccommodationBookingBreakdownCalculator; use App\Service\AccommodationBookingLinkSigner; use App\Service\AccommodationBookingService; use App\Service\AccommodationTermsUrlProvider; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; use Symfony\Component\Form\FormInterface; use Symfony\Component\HttpFoundation\RedirectResponse; @@ -39,8 +40,8 @@ class IndexControllerTest extends TestCase $controller = new TestableOfferController( $bookingRepository, $linkSigner, - $this->createMock(AccommodationBookingBreakdownCalculator::class), - $this->createMock(AccommodationBookingService::class), + $this->createStub(AccommodationBookingBreakdownCalculator::class), + $this->createStub(AccommodationBookingService::class), ); $response = $controller->access($booking->getUuid(), Request::create('/groups/booking/offer/'.$booking->getUuid())); @@ -53,7 +54,7 @@ class IndexControllerTest extends TestCase { $booking = new AccommodationBooking(); - $bookingRepository = $this->createMock(AccommodationBookingRepository::class); + $bookingRepository = $this->createStub(AccommodationBookingRepository::class); $bookingRepository->method('findOneBy')->willReturn($booking); $linkSigner = $this->createMock(AccommodationBookingLinkSigner::class); @@ -63,8 +64,8 @@ class IndexControllerTest extends TestCase $controller = new TestableOfferController( $bookingRepository, $linkSigner, - $this->createMock(AccommodationBookingBreakdownCalculator::class), - $this->createMock(AccommodationBookingService::class), + $this->createStub(AccommodationBookingBreakdownCalculator::class), + $this->createStub(AccommodationBookingService::class), ); $response = $controller->access($booking->getUuid(), Request::create('/groups/booking/offer/'.$booking->getUuid())); @@ -75,7 +76,7 @@ class IndexControllerTest extends TestCase public function testAccessRendersUnavailableForUnknownUuid(): void { - $bookingRepository = $this->createMock(AccommodationBookingRepository::class); + $bookingRepository = $this->createStub(AccommodationBookingRepository::class); $bookingRepository->method('findOneBy')->willReturn(null); $linkSigner = $this->createMock(AccommodationBookingLinkSigner::class); @@ -84,8 +85,8 @@ class IndexControllerTest extends TestCase $controller = new TestableOfferController( $bookingRepository, $linkSigner, - $this->createMock(AccommodationBookingBreakdownCalculator::class), - $this->createMock(AccommodationBookingService::class), + $this->createStub(AccommodationBookingBreakdownCalculator::class), + $this->createStub(AccommodationBookingService::class), ); $response = $controller->access('unknown-uuid', Request::create('/groups/booking/offer/unknown-uuid')); @@ -94,15 +95,13 @@ class IndexControllerTest extends TestCase self::assertSame('groups/offer/unavailable.html.twig', $controller->renderedView); } - /** - * @dataProvider statusesTheCustomerMustNotSee - */ + #[DataProvider('statusesTheCustomerMustNotSee')] public function testAccessRendersUnavailableForABookingThatIsNotOfferedYet(AccommodationBookingStatus $status): void { $booking = new AccommodationBooking(); $booking->setStatus($status); - $bookingRepository = $this->createMock(AccommodationBookingRepository::class); + $bookingRepository = $this->createStub(AccommodationBookingRepository::class); $bookingRepository->method('findOneBy')->willReturn($booking); $linkSigner = $this->createMock(AccommodationBookingLinkSigner::class); @@ -112,8 +111,8 @@ class IndexControllerTest extends TestCase $controller = new TestableOfferController( $bookingRepository, $linkSigner, - $this->createMock(AccommodationBookingBreakdownCalculator::class), - $this->createMock(AccommodationBookingService::class), + $this->createStub(AccommodationBookingBreakdownCalculator::class), + $this->createStub(AccommodationBookingService::class), ); $response = $controller->access($booking->getUuid(), Request::create('/groups/booking/offer/'.$booking->getUuid())); @@ -137,19 +136,18 @@ class IndexControllerTest extends TestCase /** * The status is re-read on every view, so an authorized session is no free pass: a * booking pushed back into Entwurf stops showing the offer from that moment on. - * - * @dataProvider statusesTheCustomerMustNotSee */ + #[DataProvider('statusesTheCustomerMustNotSee')] public function testViewRendersUnavailableForABookingTheCustomerMustNotSee(AccommodationBookingStatus $status): void { $booking = new AccommodationBooking(); $booking->setStatus($status); $booking->setAccommodation(new Accommodation()); - $bookingRepository = $this->createMock(AccommodationBookingRepository::class); + $bookingRepository = $this->createStub(AccommodationBookingRepository::class); $bookingRepository->method('findOneBy')->willReturn($booking); - $linkSigner = $this->createMock(AccommodationBookingLinkSigner::class); + $linkSigner = $this->createStub(AccommodationBookingLinkSigner::class); $linkSigner->method('isSessionAuthorized')->willReturn(true); $breakdownCalculator = $this->createMock(AccommodationBookingBreakdownCalculator::class); @@ -159,7 +157,7 @@ class IndexControllerTest extends TestCase $bookingRepository, $linkSigner, $breakdownCalculator, - $this->createMock(AccommodationBookingService::class), + $this->createStub(AccommodationBookingService::class), ); $request = Request::create('/groups/booking/offer/'.$booking->getUuid().'/view'); @@ -179,7 +177,7 @@ class IndexControllerTest extends TestCase $bookingRepository = $this->createMock(AccommodationBookingRepository::class); $bookingRepository->method('findOneBy')->with(['uuid' => $booking->getUuid()])->willReturn($booking); - $linkSigner = $this->createMock(AccommodationBookingLinkSigner::class); + $linkSigner = $this->createStub(AccommodationBookingLinkSigner::class); $linkSigner->method('isSessionAuthorized')->willReturn(true); $breakdownCalculator = $this->createMock(AccommodationBookingBreakdownCalculator::class); @@ -207,17 +205,17 @@ class IndexControllerTest extends TestCase { $booking = new AccommodationBooking(); - $bookingRepository = $this->createMock(AccommodationBookingRepository::class); + $bookingRepository = $this->createStub(AccommodationBookingRepository::class); $bookingRepository->method('findOneBy')->willReturn($booking); - $linkSigner = $this->createMock(AccommodationBookingLinkSigner::class); + $linkSigner = $this->createStub(AccommodationBookingLinkSigner::class); $linkSigner->method('isSessionAuthorized')->willReturn(false); $controller = new TestableOfferController( $bookingRepository, $linkSigner, - $this->createMock(AccommodationBookingBreakdownCalculator::class), - $this->createMock(AccommodationBookingService::class), + $this->createStub(AccommodationBookingBreakdownCalculator::class), + $this->createStub(AccommodationBookingService::class), ); $response = $controller->view($booking->getUuid(), Request::create('/groups/booking/offer/'.$booking->getUuid().'/view')); @@ -235,18 +233,18 @@ class IndexControllerTest extends TestCase $bookingRepository = $this->createMock(AccommodationBookingRepository::class); $bookingRepository->method('findOneBy')->with(['uuid' => $booking->getUuid()])->willReturn($booking); - $linkSigner = $this->createMock(AccommodationBookingLinkSigner::class); + $linkSigner = $this->createStub(AccommodationBookingLinkSigner::class); $linkSigner->method('isSessionAuthorized')->willReturn(true); - $confirmationForm = $this->createMock(FormInterface::class); + $confirmationForm = $this->createStub(FormInterface::class); $confirmationForm->method('handleRequest')->willReturnSelf(); $confirmationForm->method('isSubmitted')->willReturn(false); $controller = new TestableOfferController( $bookingRepository, $linkSigner, - $this->createMock(AccommodationBookingBreakdownCalculator::class), - $this->createMock(AccommodationBookingService::class), + $this->createStub(AccommodationBookingBreakdownCalculator::class), + $this->createStub(AccommodationBookingService::class), $confirmationForm, ); @@ -268,16 +266,16 @@ class IndexControllerTest extends TestCase $booking->setStatus(AccommodationBookingStatus::Open); $booking->setRemarks('Bitte Zimmer im EG'); - $bookingRepository = $this->createMock(AccommodationBookingRepository::class); + $bookingRepository = $this->createStub(AccommodationBookingRepository::class); $bookingRepository->method('findOneBy')->willReturn($booking); - $linkSigner = $this->createMock(AccommodationBookingLinkSigner::class); + $linkSigner = $this->createStub(AccommodationBookingLinkSigner::class); $linkSigner->method('isSessionAuthorized')->willReturn(true); $bookingService = $this->createMock(AccommodationBookingService::class); $bookingService->expects(self::once())->method('acceptBooking')->with($booking, 'Bitte Zimmer im EG'); - $confirmationForm = $this->createMock(FormInterface::class); + $confirmationForm = $this->createStub(FormInterface::class); $confirmationForm->method('handleRequest')->willReturnSelf(); $confirmationForm->method('isSubmitted')->willReturn(true); $confirmationForm->method('isValid')->willReturn(true); @@ -285,7 +283,7 @@ class IndexControllerTest extends TestCase $controller = new TestableOfferController( $bookingRepository, $linkSigner, - $this->createMock(AccommodationBookingBreakdownCalculator::class), + $this->createStub(AccommodationBookingBreakdownCalculator::class), $bookingService, $confirmationForm, ); @@ -303,17 +301,17 @@ class IndexControllerTest extends TestCase $booking = new AccommodationBooking(); $booking->setStatus(AccommodationBookingStatus::Open); - $bookingRepository = $this->createMock(AccommodationBookingRepository::class); + $bookingRepository = $this->createStub(AccommodationBookingRepository::class); $bookingRepository->method('findOneBy')->willReturn($booking); - $linkSigner = $this->createMock(AccommodationBookingLinkSigner::class); + $linkSigner = $this->createStub(AccommodationBookingLinkSigner::class); $linkSigner->method('isSessionAuthorized')->willReturn(true); $bookingService = $this->createMock(AccommodationBookingService::class); // No remark on the booking and none submitted: the empty string clears rather than keeps. $bookingService->expects(self::once())->method('acceptBooking')->with($booking, ''); - $confirmationForm = $this->createMock(FormInterface::class); + $confirmationForm = $this->createStub(FormInterface::class); $confirmationForm->method('handleRequest')->willReturnSelf(); $confirmationForm->method('isSubmitted')->willReturn(true); $confirmationForm->method('isValid')->willReturn(true); @@ -321,7 +319,7 @@ class IndexControllerTest extends TestCase $controller = new TestableOfferController( $bookingRepository, $linkSigner, - $this->createMock(AccommodationBookingBreakdownCalculator::class), + $this->createStub(AccommodationBookingBreakdownCalculator::class), $bookingService, $confirmationForm, ); @@ -339,16 +337,16 @@ class IndexControllerTest extends TestCase $booking = new AccommodationBooking(); $booking->setStatus(AccommodationBookingStatus::Open); - $bookingRepository = $this->createMock(AccommodationBookingRepository::class); + $bookingRepository = $this->createStub(AccommodationBookingRepository::class); $bookingRepository->method('findOneBy')->willReturn($booking); - $linkSigner = $this->createMock(AccommodationBookingLinkSigner::class); + $linkSigner = $this->createStub(AccommodationBookingLinkSigner::class); $linkSigner->method('isSessionAuthorized')->willReturn(true); $bookingService = $this->createMock(AccommodationBookingService::class); $bookingService->expects(self::never())->method('acceptBooking'); - $confirmationForm = $this->createMock(FormInterface::class); + $confirmationForm = $this->createStub(FormInterface::class); $confirmationForm->method('handleRequest')->willReturnSelf(); $confirmationForm->method('isSubmitted')->willReturn(true); $confirmationForm->method('isValid')->willReturn(false); @@ -356,7 +354,7 @@ class IndexControllerTest extends TestCase $controller = new TestableOfferController( $bookingRepository, $linkSigner, - $this->createMock(AccommodationBookingBreakdownCalculator::class), + $this->createStub(AccommodationBookingBreakdownCalculator::class), $bookingService, $confirmationForm, ); @@ -373,17 +371,17 @@ class IndexControllerTest extends TestCase $booking = new AccommodationBooking(); $booking->setStatus(AccommodationBookingStatus::Received); - $bookingRepository = $this->createMock(AccommodationBookingRepository::class); + $bookingRepository = $this->createStub(AccommodationBookingRepository::class); $bookingRepository->method('findOneBy')->willReturn($booking); - $linkSigner = $this->createMock(AccommodationBookingLinkSigner::class); + $linkSigner = $this->createStub(AccommodationBookingLinkSigner::class); $linkSigner->method('isSessionAuthorized')->willReturn(true); $controller = new TestableOfferController( $bookingRepository, $linkSigner, - $this->createMock(AccommodationBookingBreakdownCalculator::class), - $this->createMock(AccommodationBookingService::class), + $this->createStub(AccommodationBookingBreakdownCalculator::class), + $this->createStub(AccommodationBookingService::class), ); $response = $controller->confirm($booking->getUuid(), Request::create('/groups/booking/offer/'.$booking->getUuid().'/confirm')); @@ -395,17 +393,17 @@ class IndexControllerTest extends TestCase { $booking = new AccommodationBooking(); - $bookingRepository = $this->createMock(AccommodationBookingRepository::class); + $bookingRepository = $this->createStub(AccommodationBookingRepository::class); $bookingRepository->method('findOneBy')->willReturn($booking); - $linkSigner = $this->createMock(AccommodationBookingLinkSigner::class); + $linkSigner = $this->createStub(AccommodationBookingLinkSigner::class); $linkSigner->method('isSessionAuthorized')->willReturn(false); $controller = new TestableOfferController( $bookingRepository, $linkSigner, - $this->createMock(AccommodationBookingBreakdownCalculator::class), - $this->createMock(AccommodationBookingService::class), + $this->createStub(AccommodationBookingBreakdownCalculator::class), + $this->createStub(AccommodationBookingService::class), ); $response = $controller->confirm($booking->getUuid(), Request::create('/groups/booking/offer/'.$booking->getUuid().'/confirm')); @@ -415,7 +413,7 @@ class IndexControllerTest extends TestCase public function testConfirmRedirectsForUnknownUuid(): void { - $bookingRepository = $this->createMock(AccommodationBookingRepository::class); + $bookingRepository = $this->createStub(AccommodationBookingRepository::class); $bookingRepository->method('findOneBy')->willReturn(null); $linkSigner = $this->createMock(AccommodationBookingLinkSigner::class); @@ -424,8 +422,8 @@ class IndexControllerTest extends TestCase $controller = new TestableOfferController( $bookingRepository, $linkSigner, - $this->createMock(AccommodationBookingBreakdownCalculator::class), - $this->createMock(AccommodationBookingService::class), + $this->createStub(AccommodationBookingBreakdownCalculator::class), + $this->createStub(AccommodationBookingService::class), ); $response = $controller->confirm('unknown-uuid', Request::create('/groups/booking/offer/unknown-uuid/confirm')); diff --git a/tests/Dashboard/DashboardWidgetRegistryTest.php b/tests/Dashboard/DashboardWidgetRegistryTest.php index f4a8dd7..dbd9afc 100644 --- a/tests/Dashboard/DashboardWidgetRegistryTest.php +++ b/tests/Dashboard/DashboardWidgetRegistryTest.php @@ -80,7 +80,7 @@ class DashboardWidgetRegistryTest extends TestCase private function provider(string $role, int $priority, ?DashboardWidget $widget): DashboardWidgetProviderInterface { - $provider = $this->createMock(DashboardWidgetProviderInterface::class); + $provider = $this->createStub(DashboardWidgetProviderInterface::class); $provider->method('getRequiredRole')->willReturn($role); $provider->method('getPriority')->willReturn($priority); $provider->method('build')->willReturn($widget); @@ -93,7 +93,7 @@ class DashboardWidgetRegistryTest extends TestCase */ private function securityGranting(array $grantedRoles): Security { - $security = $this->createMock(Security::class); + $security = $this->createStub(Security::class); $security->method('isGranted')->willReturnCallback( static fn (mixed $role): bool => \in_array($role, $grantedRoles, true), ); diff --git a/tests/Dashboard/PendingRoleApprovalsWidgetProviderTest.php b/tests/Dashboard/PendingRoleApprovalsWidgetProviderTest.php index bee24e5..596aa22 100644 --- a/tests/Dashboard/PendingRoleApprovalsWidgetProviderTest.php +++ b/tests/Dashboard/PendingRoleApprovalsWidgetProviderTest.php @@ -64,10 +64,10 @@ class PendingRoleApprovalsWidgetProviderTest extends TestCase */ private function provider(array $pending): PendingRoleApprovalsWidgetProvider { - $repository = $this->createMock(UserRepository::class); + $repository = $this->createStub(UserRepository::class); $repository->method('findWithPendingRoles')->willReturn($pending); - $urlGenerator = $this->createMock(UrlGeneratorInterface::class); + $urlGenerator = $this->createStub(UrlGeneratorInterface::class); $urlGenerator->method('generate')->willReturnCallback( static function (string $route, array $parameters = []): string { $path = '/'.str_replace('_', '/', substr($route, \strlen('app_'))); diff --git a/tests/Dashboard/RecentLogEntriesWidgetProviderTest.php b/tests/Dashboard/RecentLogEntriesWidgetProviderTest.php index 0321a18..9cf866b 100644 --- a/tests/Dashboard/RecentLogEntriesWidgetProviderTest.php +++ b/tests/Dashboard/RecentLogEntriesWidgetProviderTest.php @@ -66,7 +66,7 @@ class RecentLogEntriesWidgetProviderTest extends TestCase */ private function provider(array $entries): RecentLogEntriesWidgetProvider { - $repository = $this->createMock(LogEntryRepository::class); + $repository = $this->createStub(LogEntryRepository::class); $repository->method('findLatest')->willReturn($entries); return new RecentLogEntriesWidgetProvider($repository, $this->urlGenerator()); @@ -74,7 +74,7 @@ class RecentLogEntriesWidgetProviderTest extends TestCase private function urlGenerator(): UrlGeneratorInterface { - $urlGenerator = $this->createMock(UrlGeneratorInterface::class); + $urlGenerator = $this->createStub(UrlGeneratorInterface::class); $urlGenerator->method('generate')->willReturnCallback( static fn (string $route): string => '/'.str_replace('_', '/', substr($route, \strlen('app_'))), ); diff --git a/tests/Entity/Groups/AccommodationBookingTest.php b/tests/Entity/Groups/AccommodationBookingTest.php index deba69e..72b1bfe 100644 --- a/tests/Entity/Groups/AccommodationBookingTest.php +++ b/tests/Entity/Groups/AccommodationBookingTest.php @@ -7,6 +7,7 @@ namespace App\Tests\Entity\Groups; use App\Entity\Groups\AccommodationBooking; use App\Enum\Groups\AccommodationBookingOrigin; use App\Enum\Groups\AccommodationBookingStatus; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; class AccommodationBookingTest extends TestCase @@ -14,9 +15,8 @@ class AccommodationBookingTest extends TestCase /** * The label is what the backoffice prints next to the status, so it must never * contradict it — "Angebot · Bestätigt" is the shape of mistake this replaces. - * - * @dataProvider statusesBeforeTheCustomerCommits */ + #[DataProvider('statusesBeforeTheCustomerCommits')] public function testARecordIsCalledAnOfferUntilTheCustomerCommits(AccommodationBookingStatus $status): void { $booking = new AccommodationBooking(); @@ -36,9 +36,7 @@ class AccommodationBookingTest extends TestCase yield 'open' => [AccommodationBookingStatus::Open]; } - /** - * @dataProvider statusesAfterTheCustomerCommits - */ + #[DataProvider('statusesAfterTheCustomerCommits')] public function testARecordIsCalledABookingOnceTheCustomerHasCommitted(AccommodationBookingStatus $status): void { $booking = new AccommodationBooking(); diff --git a/tests/EventListener/AccessDeniedListenerTest.php b/tests/EventListener/AccessDeniedListenerTest.php index d3888a1..9c3c30c 100644 --- a/tests/EventListener/AccessDeniedListenerTest.php +++ b/tests/EventListener/AccessDeniedListenerTest.php @@ -104,20 +104,20 @@ class AccessDeniedListenerTest extends TestCase private function dispatch(Request $request, ?UserInterface $user): ExceptionEvent { - $security = $this->createMock(Security::class); + $security = $this->createStub(Security::class); $security->method('getUser')->willReturn($user); - $resolver = $this->createMock(DefaultRouteResolver::class); + $resolver = $this->createStub(DefaultRouteResolver::class); $resolver->method('resolveUrl')->willReturn('/admin/dashboard'); $listener = new AccessDeniedListener( $security, - $this->createMock(LoggerInterface::class), + $this->createStub(LoggerInterface::class), $resolver, ); $event = new ExceptionEvent( - $this->createMock(HttpKernelInterface::class), + $this->createStub(HttpKernelInterface::class), $request, HttpKernelInterface::MAIN_REQUEST, new AccessDeniedException(), diff --git a/tests/EventListener/DomainThemeListenerTest.php b/tests/EventListener/DomainThemeListenerTest.php index ceb1927..0beb4fa 100644 --- a/tests/EventListener/DomainThemeListenerTest.php +++ b/tests/EventListener/DomainThemeListenerTest.php @@ -19,7 +19,7 @@ class DomainThemeListenerTest extends TestCase protected function setUp(): void { - $this->kernel = $this->createMock(HttpKernelInterface::class); + $this->kernel = $this->createStub(HttpKernelInterface::class); } public function testSetsThemeAttributeForMatchingDomain(): void diff --git a/tests/Form/Admin/Groups/AccommodationBookingChangeAccommodationTypeTest.php b/tests/Form/Admin/Groups/AccommodationBookingChangeAccommodationTypeTest.php index 64da942..dc6be52 100644 --- a/tests/Form/Admin/Groups/AccommodationBookingChangeAccommodationTypeTest.php +++ b/tests/Form/Admin/Groups/AccommodationBookingChangeAccommodationTypeTest.php @@ -52,7 +52,7 @@ class AccommodationBookingChangeAccommodationTypeTest extends TestCase { $fields = []; - $builder = $this->createMock(FormBuilderInterface::class); + $builder = $this->createStub(FormBuilderInterface::class); $builder->method('add')->willReturnCallback( static function (string $name, ?string $type = null, array $fieldOptions = []) use (&$fields, $builder) { $fields[$name] = $fieldOptions; diff --git a/tests/Form/Admin/Groups/AccommodationBookingCreateTypeTest.php b/tests/Form/Admin/Groups/AccommodationBookingCreateTypeTest.php index bb1ef8f..ecd6309 100644 --- a/tests/Form/Admin/Groups/AccommodationBookingCreateTypeTest.php +++ b/tests/Form/Admin/Groups/AccommodationBookingCreateTypeTest.php @@ -75,7 +75,7 @@ class AccommodationBookingCreateTypeTest extends TestCase { $names = []; - $builder = $this->createMock(FormBuilderInterface::class); + $builder = $this->createStub(FormBuilderInterface::class); $builder->method('add')->willReturnCallback(static function (string $name) use (&$names, $builder) { $names[] = $name; diff --git a/tests/Form/Admin/Groups/AccommodationBookingTypeTest.php b/tests/Form/Admin/Groups/AccommodationBookingTypeTest.php index 8bb2f72..6ca5b9d 100644 --- a/tests/Form/Admin/Groups/AccommodationBookingTypeTest.php +++ b/tests/Form/Admin/Groups/AccommodationBookingTypeTest.php @@ -7,6 +7,7 @@ namespace App\Tests\Form\Admin\Groups; use App\Entity\Groups\AccommodationBooking; use App\Enum\Groups\AccommodationBookingStatus; use App\Form\Admin\Groups\AccommodationBookingType; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; use Symfony\Component\Form\FormInterface; use Symfony\Component\OptionsResolver\OptionsResolver; @@ -17,17 +18,13 @@ use Symfony\Component\Validator\Validation; class AccommodationBookingTypeTest extends TestCase { - /** - * @dataProvider statusesWithoutMandatoryFields - */ + #[DataProvider('statusesWithoutMandatoryFields')] public function testDraftAndDiscardedAreValidatedWithoutTheEditGroup(AccommodationBookingStatus $status): void { self::assertSame(['Default'], $this->resolveValidationGroups($status)); } - /** - * @dataProvider customerFacingStatuses - */ + #[DataProvider('customerFacingStatuses')] public function testCustomerFacingStatusesAddTheEditGroup(AccommodationBookingStatus $status): void { self::assertSame(['Default', 'edit'], $this->resolveValidationGroups($status)); @@ -52,9 +49,7 @@ class AccommodationBookingTypeTest extends TestCase yield 'confirmed' => [AccommodationBookingStatus::Confirmed]; } - /** - * @dataProvider statusesWithoutMandatoryFields - */ + #[DataProvider('statusesWithoutMandatoryFields')] public function testEmptyContactDataPassesValidation(AccommodationBookingStatus $status): void { $booking = new AccommodationBooking(); @@ -89,7 +84,7 @@ class AccommodationBookingTypeTest extends TestCase $booking = new AccommodationBooking(); $booking->setStatus($status); - $form = $this->createMock(FormInterface::class); + $form = $this->createStub(FormInterface::class); $form->method('getData')->willReturn($booking); return ($resolver->resolve()['validation_groups'])($form); diff --git a/tests/Form/Model/ParticipantEditDtoTest.php b/tests/Form/Model/ParticipantEditDtoTest.php index aea49ea..7b56c78 100644 --- a/tests/Form/Model/ParticipantEditDtoTest.php +++ b/tests/Form/Model/ParticipantEditDtoTest.php @@ -5,13 +5,13 @@ declare(strict_types=1); namespace App\Tests\Form\Model; use App\BusProNet\Constants; -use App\BusProNet\Model\Booking; use App\BusProNet\Model\Address; -use App\Form\Model\AddressDto; -use App\BusProNet\Model\Service; +use App\BusProNet\Model\Booking; use App\BusProNet\Model\Insurance; +use App\BusProNet\Model\Service; use App\BusProNet\Model\Travel; use App\BusProNet\XmlLoader\AgencyLoader; +use App\Form\Model\AddressDto; use App\Form\Model\BookingDto; use App\Form\Model\ParticipantDto; use App\Form\Model\ParticipantEditDto; @@ -47,10 +47,10 @@ class ParticipantEditDtoTest extends TestCase protected function setUp(): void { // Create mock services for validator dependencies - $mockVoucherService = $this->createMock(VoucherValidator::class); - $mockPriceCalculatorService = $this->createMock(BookingPriceCalculator::class); - $mockParticipantEligibilityChecker = $this->createMock(ParticipantEligibilityChecker::class); - $mockServiceAgeEvaluator = $this->createMock(ServiceAgeEvaluator::class); + $mockVoucherService = $this->createStub(VoucherValidator::class); + $mockPriceCalculatorService = $this->createStub(BookingPriceCalculator::class); + $mockParticipantEligibilityChecker = $this->createStub(ParticipantEligibilityChecker::class); + $mockServiceAgeEvaluator = $this->createStub(ServiceAgeEvaluator::class); // Ski pass validation is exercised against the real gate, not a mock: which participant // needs a pass is exactly the behaviour under test here. diff --git a/tests/Form/PersonalDataTypeTest.php b/tests/Form/PersonalDataTypeTest.php index e798be5..c49c61d 100644 --- a/tests/Form/PersonalDataTypeTest.php +++ b/tests/Form/PersonalDataTypeTest.php @@ -91,7 +91,7 @@ class PersonalDataTypeTest extends TestCase */ private function createForm(PersonalData $personalData, array $options = []): FormInterface { - $countries = $this->createMock(CountryDataProvider::class); + $countries = $this->createStub(CountryDataProvider::class); $countries->method('getAll')->willReturn([]); return Forms::createFormFactoryBuilder() diff --git a/tests/Form/Service/ParticipantFieldOptionsProviderBabyTest.php b/tests/Form/Service/ParticipantFieldOptionsProviderBabyTest.php index e6de7f1..dcb29bb 100644 --- a/tests/Form/Service/ParticipantFieldOptionsProviderBabyTest.php +++ b/tests/Form/Service/ParticipantFieldOptionsProviderBabyTest.php @@ -28,17 +28,17 @@ class ParticipantFieldOptionsProviderBabyTest extends TestCase protected function setUp(): void { - $this->serviceAvailabilityCalculator = $this->createMock(ServiceAvailabilityCalculator::class); + $this->serviceAvailabilityCalculator = $this->createStub(ServiceAvailabilityCalculator::class); // These tests target age filtering, so availability filtering passes everything through // unless a test stubs it explicitly $this->serviceAvailabilityCalculator ->method('filterAvailableServices') ->willReturnArgument(0) ; - $insuranceService = $this->createMock(InsuranceManager::class); - $priceCalculatorService = $this->createMock(BookingPriceCalculator::class); + $insuranceService = $this->createStub(InsuranceManager::class); + $priceCalculatorService = $this->createStub(BookingPriceCalculator::class); $serviceLabelFormatter = new ServiceLabelFormatter(); - $translator = $this->createMock(TranslatorInterface::class); + $translator = $this->createStub(TranslatorInterface::class); $translator->method('trans')->willReturnCallback( function (string $message, array $parameters = []): string { return match ($message) { diff --git a/tests/Form/Service/ParticipantFieldOptionsProviderInsuranceTest.php b/tests/Form/Service/ParticipantFieldOptionsProviderInsuranceTest.php index b42f22e..8f0b1db 100644 --- a/tests/Form/Service/ParticipantFieldOptionsProviderInsuranceTest.php +++ b/tests/Form/Service/ParticipantFieldOptionsProviderInsuranceTest.php @@ -29,13 +29,13 @@ class ParticipantFieldOptionsProviderInsuranceTest extends TestCase protected function setUp(): void { - $serviceAvailabilityCalculator = $this->createMock(ServiceAvailabilityCalculator::class); + $serviceAvailabilityCalculator = $this->createStub(ServiceAvailabilityCalculator::class); // InsuranceManager is stateless - use the real implementation so actual // eligibility/price-tier filtering runs, not a stubbed-out mock. $insuranceService = new InsuranceManager(); - $this->priceCalculatorService = $this->createMock(BookingPriceCalculator::class); + $this->priceCalculatorService = $this->createStub(BookingPriceCalculator::class); $serviceLabelFormatter = new ServiceLabelFormatter(); - $translator = $this->createMock(TranslatorInterface::class); + $translator = $this->createStub(TranslatorInterface::class); $translator->method('trans')->willReturnCallback(fn (string $message) => $message); $this->provider = new ParticipantFieldOptionsProvider( diff --git a/tests/Form/Service/ParticipantFieldOptionsProviderMandatoryServiceTest.php b/tests/Form/Service/ParticipantFieldOptionsProviderMandatoryServiceTest.php index f8e2db4..8fe95b3 100644 --- a/tests/Form/Service/ParticipantFieldOptionsProviderMandatoryServiceTest.php +++ b/tests/Form/Service/ParticipantFieldOptionsProviderMandatoryServiceTest.php @@ -28,11 +28,11 @@ class ParticipantFieldOptionsProviderMandatoryServiceTest extends TestCase protected function setUp(): void { - $serviceAvailabilityCalculator = $this->createMock(ServiceAvailabilityCalculator::class); - $insuranceService = $this->createMock(InsuranceManager::class); - $priceCalculatorService = $this->createMock(BookingPriceCalculator::class); + $serviceAvailabilityCalculator = $this->createStub(ServiceAvailabilityCalculator::class); + $insuranceService = $this->createStub(InsuranceManager::class); + $priceCalculatorService = $this->createStub(BookingPriceCalculator::class); $serviceLabelFormatter = new ServiceLabelFormatter(); - $translator = $this->createMock(TranslatorInterface::class); + $translator = $this->createStub(TranslatorInterface::class); $this->provider = new ParticipantFieldOptionsProvider( $serviceAvailabilityCalculator, @@ -159,10 +159,10 @@ class ParticipantFieldOptionsProviderMandatoryServiceTest extends TestCase $provider = new ParticipantFieldOptionsProvider( $serviceAvailabilityCalculator, - $this->createMock(InsuranceManager::class), - $this->createMock(BookingPriceCalculator::class), + $this->createStub(InsuranceManager::class), + $this->createStub(BookingPriceCalculator::class), new ServiceLabelFormatter(), - $this->createMock(TranslatorInterface::class) + $this->createStub(TranslatorInterface::class) ); $options = $provider->getFieldOptions('parking', $bookingDto, 0); diff --git a/tests/Form/Service/ParticipantFieldOptionsProviderSkiPassAvailabilityTest.php b/tests/Form/Service/ParticipantFieldOptionsProviderSkiPassAvailabilityTest.php index cd4ac78..0ea8b52 100644 --- a/tests/Form/Service/ParticipantFieldOptionsProviderSkiPassAvailabilityTest.php +++ b/tests/Form/Service/ParticipantFieldOptionsProviderSkiPassAvailabilityTest.php @@ -30,13 +30,13 @@ class ParticipantFieldOptionsProviderSkiPassAvailabilityTest extends TestCase protected function setUp(): void { - $translator = $this->createMock(TranslatorInterface::class); + $translator = $this->createStub(TranslatorInterface::class); $translator->method('trans')->willReturnArgument(0); $this->provider = new ParticipantFieldOptionsProvider( new ServiceAvailabilityCalculator(), - $this->createMock(InsuranceManager::class), - $this->createMock(BookingPriceCalculator::class), + $this->createStub(InsuranceManager::class), + $this->createStub(BookingPriceCalculator::class), new ServiceLabelFormatter(), $translator ); diff --git a/tests/Form/Service/ParticipantInsuranceFieldHandlerTest.php b/tests/Form/Service/ParticipantInsuranceFieldHandlerTest.php index 0910a4e..fc9edc9 100644 --- a/tests/Form/Service/ParticipantInsuranceFieldHandlerTest.php +++ b/tests/Form/Service/ParticipantInsuranceFieldHandlerTest.php @@ -12,32 +12,46 @@ use App\Form\Service\ParticipantInsuranceFieldHandler; use App\Service\BookingPriceCalculator; use App\Service\FamilyInsuranceAvailabilityChecker; use App\Service\InsuranceManager; +use PHPUnit\Framework\MockObject\Stub; use PHPUnit\Framework\TestCase; class ParticipantInsuranceFieldHandlerTest extends TestCase { - private ParticipantInsuranceFieldHandler $handler; + private ?ParticipantInsuranceFieldHandler $handler = null; private InsuranceManager $insuranceService; private BookingPriceCalculator $priceCalculatorService; protected function setUp(): void { - $this->insuranceService = $this->createMock(InsuranceManager::class); - $this->priceCalculatorService = $this->createMock(BookingPriceCalculator::class); + $this->useInsuranceService($this->createStub(InsuranceManager::class)); - // Mock getSelectableInsurances to return input array - $this->insuranceService->method('getSelectableInsurances') - ->willReturnCallback(fn (Travel $travel) => $travel->insurances ?? []); + $this->priceCalculatorService = $this->createStub(BookingPriceCalculator::class); - // Mock price calculator to return a default price + // Price calculator returns a default price $this->priceCalculatorService->method('calculateIndividualParticipantPriceExcludingInsurance') ->willReturn(500.0); $this->priceCalculatorService->method('resolveInsuranceTravelPrice') ->willReturn(500.0); + } - // Real checker over the mocked collaborators - the selection-time recording below is + /** + * Installs the insurance service every test runs against, applying the + * getSelectableInsurances() pass-through they all rely on. Tests that set + * expectations pass a mock in here instead of the setUp() stub. + */ + private function useInsuranceService(InsuranceManager&Stub $insuranceService): void + { + $insuranceService->method('getSelectableInsurances') + ->willReturnCallback(fn (Travel $travel) => $travel->insurances ?? []); + + $this->insuranceService = $insuranceService; + } + + private function handler(): ParticipantInsuranceFieldHandler + { + // Real checker over the doubled collaborators - the selection-time recording below is // only meaningful against the actual "is a family insurance available" definition - $this->handler = new ParticipantInsuranceFieldHandler( + return $this->handler ??= new ParticipantInsuranceFieldHandler( $this->insuranceService, $this->priceCalculatorService, new FamilyInsuranceAvailabilityChecker($this->insuranceService, $this->priceCalculatorService), @@ -46,12 +60,12 @@ class ParticipantInsuranceFieldHandlerTest extends TestCase public function testGetFieldName(): void { - $this->assertEquals('insurance', $this->handler->getFieldName()); + $this->assertEquals('insurance', $this->handler()->getFieldName()); } public function testGetDependencies(): void { - $dependencies = $this->handler->getDependencies(); + $dependencies = $this->handler()->getDependencies(); // Insurance handler depends on all price-affecting fields to ensure accurate reassignment $expectedDependencies = [ @@ -72,14 +86,14 @@ class ParticipantInsuranceFieldHandlerTest extends TestCase public function testShouldProcessReturnsTrueInCreateMode(): void { - $result = $this->handler->shouldProcess([], BookingDto::MODE_CREATE, 0); + $result = $this->handler()->shouldProcess([], BookingDto::MODE_CREATE, 0); $this->assertTrue($result); } public function testShouldProcessReturnsFalseInEditMode(): void { - $result = $this->handler->shouldProcess([], BookingDto::MODE_EDIT, 0); + $result = $this->handler()->shouldProcess([], BookingDto::MODE_EDIT, 0); $this->assertFalse($result, 'Insurance handler should not process in edit mode as API does not return insurance data'); } @@ -89,7 +103,7 @@ class ParticipantInsuranceFieldHandlerTest extends TestCase $bookingDto = $this->createMockBookingDto(); $bookingDto->method('getParticipant')->with(0)->willReturn(null); - $this->handler->processField(['insurance' => '123'], $bookingDto, 0); + $this->handler()->processField(['insurance' => '123'], $bookingDto, 0); // No assertions needed - just ensure no exceptions are thrown $this->addToAssertionCount(1); @@ -107,7 +121,7 @@ class ParticipantInsuranceFieldHandlerTest extends TestCase $bookingDto->method('getParticipant')->with(0)->willReturn($participant); $bookingDto->travel = $travel; - $this->handler->processField(['insurance' => null], $bookingDto, 0); + $this->handler()->processField(['insurance' => null], $bookingDto, 0); $this->assertNull($participant->insurance); } @@ -124,7 +138,7 @@ class ParticipantInsuranceFieldHandlerTest extends TestCase $bookingDto->method('getParticipant')->with(0)->willReturn($participant); $bookingDto->travel = $travel; - $this->handler->processField(['insurance' => ''], $bookingDto, 0); + $this->handler()->processField(['insurance' => ''], $bookingDto, 0); $this->assertNull($participant->insurance); } @@ -141,7 +155,7 @@ class ParticipantInsuranceFieldHandlerTest extends TestCase $bookingDto->method('getParticipant')->with(0)->willReturn($participant); $bookingDto->travel = $travel; - $this->handler->processField([], $bookingDto, 0); + $this->handler()->processField([], $bookingDto, 0); $this->assertNull($participant->insurance); } @@ -156,13 +170,15 @@ class ParticipantInsuranceFieldHandlerTest extends TestCase $bookingDto->method('getParticipant')->with(0)->willReturn($participant); $bookingDto->travel = $travel; - $this->handler->processField(['insurance' => '123'], $bookingDto, 0); + $this->handler()->processField(['insurance' => '123'], $bookingDto, 0); $this->assertNull($participant->insurance); } public function testProcessFieldSetsInsuranceWhenEligible(): void { + $this->useInsuranceService($this->createMock(InsuranceManager::class)); + $insurance = $this->createInsurance('123'); $participant = new ParticipantDto(); $travel = new Travel(); @@ -178,13 +194,15 @@ class ParticipantInsuranceFieldHandlerTest extends TestCase ->with([$insurance], $participant, $bookingDto, 500.0) ->willReturn([$insurance]); - $this->handler->processField(['insurance' => '123'], $bookingDto, 0); + $this->handler()->processField(['insurance' => '123'], $bookingDto, 0); $this->assertSame($insurance, $participant->insurance); } public function testProcessFieldClearsInsuranceWhenNotEligible(): void { + $this->useInsuranceService($this->createMock(InsuranceManager::class)); + $insurance = $this->createInsurance('123'); $participant = new ParticipantDto(); $travel = new Travel(); @@ -200,13 +218,15 @@ class ParticipantInsuranceFieldHandlerTest extends TestCase ->with([$insurance], $participant, $bookingDto, 500.0) ->willReturn([]); // Not eligible - $this->handler->processField(['insurance' => '123'], $bookingDto, 0); + $this->handler()->processField(['insurance' => '123'], $bookingDto, 0); $this->assertNull($participant->insurance); } public function testProcessFieldSwitchingToNewInsuranceIsNotOverwrittenByStaleResubmissionCheck(): void { + $this->useInsuranceService($this->createMock(InsuranceManager::class)); + // Regression: switching from one already-selected insurance to a different one must // not be re-validated (and potentially overwritten) against the OLD, now-stale // insurance by the "form resubmission" block afterward. @@ -230,13 +250,15 @@ class ParticipantInsuranceFieldHandlerTest extends TestCase ->method('getEligibleInsurances') ->willReturn([$newInsurance]); - $this->handler->processField(['insurance' => '2'], $bookingDto, 0); + $this->handler()->processField(['insurance' => '2'], $bookingDto, 0); $this->assertSame($newInsurance, $participant->insurance); } public function testProcessFieldWorksWithStringAndIntegerIds(): void { + $this->useInsuranceService($this->createMock(InsuranceManager::class)); + $insurance = $this->createInsurance(123); // Integer ID $participant = new ParticipantDto(); $travel = new Travel(); @@ -251,7 +273,7 @@ class ParticipantInsuranceFieldHandlerTest extends TestCase ->method('getEligibleInsurances') ->willReturn([$insurance]); - $this->handler->processField(['insurance' => '123'], $bookingDto, 0); // String selection + $this->handler()->processField(['insurance' => '123'], $bookingDto, 0); // String selection $this->assertSame($insurance, $participant->insurance); } @@ -266,7 +288,7 @@ class ParticipantInsuranceFieldHandlerTest extends TestCase $bookingDto->method('getParticipant')->with(0)->willReturn($participant); $bookingDto->travel = $travel; - $this->handler->processField(['insurance' => '123'], $bookingDto, 0); + $this->handler()->processField(['insurance' => '123'], $bookingDto, 0); $this->assertNull($participant->insurance); } @@ -281,7 +303,7 @@ class ParticipantInsuranceFieldHandlerTest extends TestCase $bookingDto->method('getParticipant')->with(0)->willReturn($participant); $bookingDto->travel = $travel; - $this->handler->processField(['insurance' => '123'], $bookingDto, 0); + $this->handler()->processField(['insurance' => '123'], $bookingDto, 0); $this->assertNull($participant->insurance); } @@ -306,7 +328,7 @@ class ParticipantInsuranceFieldHandlerTest extends TestCase $this->insuranceService->method('getEligibleInsurances')->willReturn([$nonFamilyInsurance]); - $this->handler->processField(['insurance' => '1'], $bookingDto, 0); + $this->handler()->processField(['insurance' => '1'], $bookingDto, 0); $this->assertTrue( $bookingDto->applicantInsuranceChosenWhileFamilyIneligible, @@ -346,7 +368,7 @@ class ParticipantInsuranceFieldHandlerTest extends TestCase fn (array $insurances) => $insurances ); - $this->handler->processField(['insurance' => '1'], $bookingDto, 0); + $this->handler()->processField(['insurance' => '1'], $bookingDto, 0); $this->assertFalse( $bookingDto->applicantInsuranceChosenWhileFamilyIneligible, @@ -389,7 +411,7 @@ class ParticipantInsuranceFieldHandlerTest extends TestCase fn (array $insurances) => array_values(array_filter($insurances, fn ($i) => false === $i->familyInsurance)) ); - $this->handler->processField(['insurance' => '1'], $bookingDto, 0); + $this->handler()->processField(['insurance' => '1'], $bookingDto, 0); $this->assertTrue( $bookingDto->applicantInsuranceChosenWhileFamilyIneligible, @@ -399,9 +421,9 @@ class ParticipantInsuranceFieldHandlerTest extends TestCase public function testGetFieldStateModificationsReturnsEmptyArray(): void { - $bookingDto = $this->createMockBookingDto(); + $bookingDto = $this->createStub(BookingDto::class); - $result = $this->handler->getFieldStateModifications([], $bookingDto, 0); + $result = $this->handler()->getFieldStateModifications([], $bookingDto, 0); $this->assertIsArray($result); $this->assertEmpty($result); @@ -409,7 +431,7 @@ class ParticipantInsuranceFieldHandlerTest extends TestCase public function testGetAffectedFieldNamesReturnsEmptyArray(): void { - $result = $this->handler->getAffectedFieldNames(); + $result = $this->handler()->getAffectedFieldNames(); $this->assertIsArray($result); $this->assertEmpty($result); diff --git a/tests/Form/Service/ParticipantParkingFieldHandlerTest.php b/tests/Form/Service/ParticipantParkingFieldHandlerTest.php index 589b255..0acca61 100644 --- a/tests/Form/Service/ParticipantParkingFieldHandlerTest.php +++ b/tests/Form/Service/ParticipantParkingFieldHandlerTest.php @@ -4,14 +4,15 @@ declare(strict_types=1); namespace App\Tests\Form\Service; +use App\BusProNet\Constants; use App\BusProNet\Model\Service; use App\BusProNet\Model\Travel; use App\BusProNet\Utility\DirectionMapper; -use App\BusProNet\Constants; use App\Form\Model\BookingDto; use App\Form\Model\ParticipantDto; use App\Form\Service\ParticipantParkingFieldHandler; use App\Service\ServiceAvailabilityCalculator; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; class ParticipantParkingFieldHandlerTest extends TestCase @@ -39,17 +40,13 @@ class ParticipantParkingFieldHandlerTest extends TestCase $this->assertTrue($this->handler->shouldProcess(['some' => 'data'], BookingDto::MODE_EDIT, 5)); } - /** - * @dataProvider normalizeCheckboxValueCheckedProvider - */ + #[DataProvider('normalizeCheckboxValueCheckedProvider')] public function testNormalizeCheckboxValueReturnsTrueWhenChecked(mixed $value): void { $this->assertTrue($this->invokeNormalizeCheckboxValue($value)); } - /** - * @dataProvider normalizeCheckboxValueUncheckedProvider - */ + #[DataProvider('normalizeCheckboxValueUncheckedProvider')] public function testNormalizeCheckboxValueReturnsFalseWhenUnchecked(mixed $value): void { $this->assertFalse($this->invokeNormalizeCheckboxValue($value)); diff --git a/tests/Form/Service/ParticipantTransportationDiscountReplacementFieldHandlerTest.php b/tests/Form/Service/ParticipantTransportationDiscountReplacementFieldHandlerTest.php index 064ba46..34ece7c 100644 --- a/tests/Form/Service/ParticipantTransportationDiscountReplacementFieldHandlerTest.php +++ b/tests/Form/Service/ParticipantTransportationDiscountReplacementFieldHandlerTest.php @@ -15,31 +15,35 @@ use PHPUnit\Framework\TestCase; class ParticipantTransportationDiscountReplacementFieldHandlerTest extends TestCase { - private ParticipantTransportationDiscountReplacementFieldHandler $handler; + private ?ParticipantTransportationDiscountReplacementFieldHandler $handler = null; private ServiceAvailabilityCalculator $serviceAvailabilityCalculator; protected function setUp(): void { - $this->serviceAvailabilityCalculator = $this->createMock(ServiceAvailabilityCalculator::class); - $this->handler = new ParticipantTransportationDiscountReplacementFieldHandler( + $this->serviceAvailabilityCalculator = $this->createStub(ServiceAvailabilityCalculator::class); + } + + private function handler(): ParticipantTransportationDiscountReplacementFieldHandler + { + return $this->handler ??= new ParticipantTransportationDiscountReplacementFieldHandler( $this->serviceAvailabilityCalculator ); } public function testGetFieldName(): void { - $this->assertSame('transportationDiscountReplacement', $this->handler->getFieldName()); + $this->assertSame('transportationDiscountReplacement', $this->handler()->getFieldName()); } public function testGetDependencies(): void { - $this->assertSame(['transportationOutbound', 'transportationInbound'], $this->handler->getDependencies()); + $this->assertSame(['transportationOutbound', 'transportationInbound'], $this->handler()->getDependencies()); } public function testShouldProcessAlwaysReturnsTrue(): void { - $this->assertTrue($this->handler->shouldProcess([], BookingDto::MODE_CREATE, 0)); - $this->assertTrue($this->handler->shouldProcess(['some' => 'data'], BookingDto::MODE_EDIT, 5)); + $this->assertTrue($this->handler()->shouldProcess([], BookingDto::MODE_CREATE, 0)); + $this->assertTrue($this->handler()->shouldProcess(['some' => 'data'], BookingDto::MODE_EDIT, 5)); } public function testProcessFieldReplacesDiscountedWithRegularWhenInboundIsBus(): void @@ -62,7 +66,7 @@ class ParticipantTransportationDiscountReplacementFieldHandlerTest extends TestC $submittedData = []; // Process - $this->handler->processField($submittedData, $bookingDto, 0); + $this->handler()->processField($submittedData, $bookingDto, 0); // Assert outbound was replaced with regular PKW $this->assertSame($regularPkw->id, $participant->transportationOutbound->id); @@ -79,6 +83,8 @@ class ParticipantTransportationDiscountReplacementFieldHandlerTest extends TestC public function testProcessFieldRestoresDiscountedPkwWhenInboundChangesToPkw(): void { + $this->serviceAvailabilityCalculator = $this->createMock(ServiceAvailabilityCalculator::class); + // Setup services $discountedPkw = $this->createPkwService(100, 'Selbstorganisiert (-15€ Rabatt)', -15.0); $regularPkw = $this->createPkwService(101, 'Selbstorganisiert', 0.0); @@ -104,7 +110,7 @@ class ParticipantTransportationDiscountReplacementFieldHandlerTest extends TestC $submittedData = []; // Process - $this->handler->processField($submittedData, $bookingDto, 0); + $this->handler()->processField($submittedData, $bookingDto, 0); // Assert outbound was replaced with discounted PKW $this->assertSame($discountedPkw->id, $participant->transportationOutbound->id); @@ -120,6 +126,8 @@ class ParticipantTransportationDiscountReplacementFieldHandlerTest extends TestC public function testProcessFieldDoesNotRestoreDiscountWhenUnavailable(): void { + $this->serviceAvailabilityCalculator = $this->createMock(ServiceAvailabilityCalculator::class); + // Setup services $discountedPkw = $this->createPkwService(100, 'Selbstorganisiert (-15€ Rabatt)', -15.0); $regularPkw = $this->createPkwService(101, 'Selbstorganisiert', 0.0); @@ -145,7 +153,7 @@ class ParticipantTransportationDiscountReplacementFieldHandlerTest extends TestC $submittedData = []; // Process - $this->handler->processField($submittedData, $bookingDto, 0); + $this->handler()->processField($submittedData, $bookingDto, 0); // Assert outbound remains regular PKW $this->assertSame($regularPkw, $participant->transportationOutbound); @@ -174,7 +182,7 @@ class ParticipantTransportationDiscountReplacementFieldHandlerTest extends TestC $submittedData = []; // Process - $this->handler->processField($submittedData, $bookingDto, 0); + $this->handler()->processField($submittedData, $bookingDto, 0); // Assert outbound remains BUS (no replacement) $this->assertSame($busOutbound, $participant->transportationOutbound); @@ -203,7 +211,7 @@ class ParticipantTransportationDiscountReplacementFieldHandlerTest extends TestC $submittedData = []; // Process - $this->handler->processField($submittedData, $bookingDto, 0); + $this->handler()->processField($submittedData, $bookingDto, 0); // Assert outbound remains regular PKW (already correct) $this->assertSame($regularPkw, $participant->transportationOutbound); @@ -232,7 +240,7 @@ class ParticipantTransportationDiscountReplacementFieldHandlerTest extends TestC $submittedData = []; // Process - $this->handler->processField($submittedData, $bookingDto, 0); + $this->handler()->processField($submittedData, $bookingDto, 0); // Assert outbound remains discounted PKW (already optimal) $this->assertSame($discountedPkw, $participant->transportationOutbound); @@ -256,7 +264,7 @@ class ParticipantTransportationDiscountReplacementFieldHandlerTest extends TestC $submittedData = []; // Process - should handle gracefully - $this->handler->processField($submittedData, $bookingDto, 0); + $this->handler()->processField($submittedData, $bookingDto, 0); // Assert no error and no notification $this->assertNull($participant->transportationOutbound); @@ -265,6 +273,8 @@ class ParticipantTransportationDiscountReplacementFieldHandlerTest extends TestC public function testProcessFieldHandlesNullInbound(): void { + $this->serviceAvailabilityCalculator = $this->createMock(ServiceAvailabilityCalculator::class); + // Setup services $discountedPkw = $this->createPkwService(100, 'Selbstorganisiert (-15€ Rabatt)', -15.0); $regularPkw = $this->createPkwService(101, 'Selbstorganisiert', 0.0); @@ -289,7 +299,7 @@ class ParticipantTransportationDiscountReplacementFieldHandlerTest extends TestC $submittedData = []; // Process - null inbound is treated as non-BUS, should attempt restoration - $this->handler->processField($submittedData, $bookingDto, 0); + $this->handler()->processField($submittedData, $bookingDto, 0); // Assert outbound was replaced with discounted PKW $this->assertSame($discountedPkw->id, $participant->transportationOutbound->id); @@ -306,7 +316,7 @@ class ParticipantTransportationDiscountReplacementFieldHandlerTest extends TestC $submittedData = []; // Process - should handle gracefully - $this->handler->processField($submittedData, $bookingDto, 0); + $this->handler()->processField($submittedData, $bookingDto, 0); // Should not throw error $this->expectNotToPerformAssertions(); @@ -314,6 +324,8 @@ class ParticipantTransportationDiscountReplacementFieldHandlerTest extends TestC public function testProcessFieldSkipsDiscountRestorationForBabyParticipant(): void { + $this->serviceAvailabilityCalculator = $this->createMock(ServiceAvailabilityCalculator::class); + // Setup services $discountedPkw = $this->createPkwService(100, 'Selbstorganisiert (-15€ Rabatt)', -15.0); $regularPkw = $this->createPkwService(101, 'Selbstorganisiert', 0.0); @@ -339,7 +351,7 @@ class ParticipantTransportationDiscountReplacementFieldHandlerTest extends TestC $submittedData = []; // Process - $this->handler->processField($submittedData, $bookingDto, 0); + $this->handler()->processField($submittedData, $bookingDto, 0); // Assert outbound remains regular PKW (no discount restoration for babies) $this->assertSame($regularPkw->id, $participant->transportationOutbound->id); @@ -350,6 +362,8 @@ class ParticipantTransportationDiscountReplacementFieldHandlerTest extends TestC public function testProcessFieldSkipsDiscountRestorationForTwoYearOldParticipant(): void { + $this->serviceAvailabilityCalculator = $this->createMock(ServiceAvailabilityCalculator::class); + // Setup services $discountedPkw = $this->createPkwService(100, 'Selbstorganisiert (-15€ Rabatt)', -15.0); $regularPkw = $this->createPkwService(101, 'Selbstorganisiert', 0.0); @@ -375,7 +389,7 @@ class ParticipantTransportationDiscountReplacementFieldHandlerTest extends TestC $submittedData = []; // Process - $this->handler->processField($submittedData, $bookingDto, 0); + $this->handler()->processField($submittedData, $bookingDto, 0); // Assert outbound remains regular PKW $this->assertSame($regularPkw->id, $participant->transportationOutbound->id); @@ -386,6 +400,8 @@ class ParticipantTransportationDiscountReplacementFieldHandlerTest extends TestC public function testProcessFieldRestoresDiscountForThreeYearOldParticipant(): void { + $this->serviceAvailabilityCalculator = $this->createMock(ServiceAvailabilityCalculator::class); + // Setup services $discountedPkw = $this->createPkwService(100, 'Selbstorganisiert (-15€ Rabatt)', -15.0); $regularPkw = $this->createPkwService(101, 'Selbstorganisiert', 0.0); @@ -414,7 +430,7 @@ class ParticipantTransportationDiscountReplacementFieldHandlerTest extends TestC $submittedData = []; // Process - $this->handler->processField($submittedData, $bookingDto, 0); + $this->handler()->processField($submittedData, $bookingDto, 0); // Assert outbound was replaced with discounted PKW (3-year-old is eligible) $this->assertSame($discountedPkw->id, $participant->transportationOutbound->id); diff --git a/tests/Form/Service/ParticipantVegFieldHandlerTest.php b/tests/Form/Service/ParticipantVegFieldHandlerTest.php index f8bac71..ae1b3b5 100644 --- a/tests/Form/Service/ParticipantVegFieldHandlerTest.php +++ b/tests/Form/Service/ParticipantVegFieldHandlerTest.php @@ -204,7 +204,7 @@ class ParticipantVegFieldHandlerTest extends TestCase private function createMockBookingDto(?Travel $travel = null): BookingDto { - $bookingDto = $this->createMock(BookingDto::class); + $bookingDto = $this->createStub(BookingDto::class); if (null !== $travel) { $bookingDto->travel = $travel; diff --git a/tests/Logger/DatabaseHandlerTest.php b/tests/Logger/DatabaseHandlerTest.php index d97800c..719705e 100644 --- a/tests/Logger/DatabaseHandlerTest.php +++ b/tests/Logger/DatabaseHandlerTest.php @@ -111,7 +111,7 @@ class DatabaseHandlerTest extends TestCase */ private function connection(?string &$table, ?array &$data, ?array &$types): Connection { - $connection = $this->createMock(Connection::class); + $connection = $this->createStub(Connection::class); $connection ->method('insert') ->willReturnCallback( diff --git a/tests/MessageHandler/CreateClickUpBookingTaskHandlerTest.php b/tests/MessageHandler/CreateClickUpBookingTaskHandlerTest.php index 1878b9a..5592b44 100644 --- a/tests/MessageHandler/CreateClickUpBookingTaskHandlerTest.php +++ b/tests/MessageHandler/CreateClickUpBookingTaskHandlerTest.php @@ -11,6 +11,7 @@ use App\Entity\Groups\AccommodationBooking; use App\Message\CreateClickUpBookingTaskMessage; use App\MessageHandler\CreateClickUpBookingTaskHandler; use App\Repository\Groups\AccommodationBookingRepository; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; use Psr\Log\NullLogger; @@ -48,7 +49,7 @@ class CreateClickUpBookingTaskHandlerTest extends TestCase public function testAVanishedBookingIsSkipped(): void { - $repository = $this->createMock(AccommodationBookingRepository::class); + $repository = $this->createStub(AccommodationBookingRepository::class); $repository->method('find')->willReturn(null); $client = $this->createMock(ApiClient::class); @@ -58,15 +59,13 @@ class CreateClickUpBookingTaskHandlerTest extends TestCase $this->handler($repository, $client)(new CreateClickUpBookingTaskMessage(42)); } - /** - * @dataProvider incompleteBookings - */ + #[DataProvider('incompleteBookings')] public function testABookingWithoutTheDataForATaskNameIsSkipped(callable $mutate): void { $booking = $this->booking(); $mutate($booking); - $repository = $this->createMock(AccommodationBookingRepository::class); + $repository = $this->createStub(AccommodationBookingRepository::class); $repository->method('find')->willReturn($booking); $client = $this->createMock(ApiClient::class); @@ -94,10 +93,10 @@ class CreateClickUpBookingTaskHandlerTest extends TestCase public function testAFailingStatusUpdateDoesNotRetryTheTaskCreation(): void { - $repository = $this->createMock(AccommodationBookingRepository::class); + $repository = $this->createStub(AccommodationBookingRepository::class); $repository->method('find')->willReturn($this->booking()); - $client = $this->createMock(ApiClient::class); + $client = $this->createStub(ApiClient::class); $client->method('isConfigured')->willReturn(true); $client->method('createTaskFromTemplate')->willReturn('abc123'); $client->method('updateTaskStatus')->willThrowException(new ClickUpException('boom')); diff --git a/tests/MessageHandler/MailjetNewsletterEventHandlerTest.php b/tests/MessageHandler/MailjetNewsletterEventHandlerTest.php index bcc17ea..55d661a 100644 --- a/tests/MessageHandler/MailjetNewsletterEventHandlerTest.php +++ b/tests/MessageHandler/MailjetNewsletterEventHandlerTest.php @@ -81,7 +81,7 @@ class MailjetNewsletterEventHandlerTest extends TestCase $consent = new NewsletterConsent('customer@example.com', 123); $consent->markRevoked(new \DateTimeImmutable('2026-04-29T11:00:00+00:00')); - $repository = $this->createMock(NewsletterConsentRepository::class); + $repository = $this->createStub(NewsletterConsentRepository::class); $repository->method('findOneByEmailAndListId')->willReturn($consent); $entityManager = $this->createMock(EntityManagerInterface::class); @@ -103,7 +103,7 @@ class MailjetNewsletterEventHandlerTest extends TestCase $consent = new NewsletterConsent('customer@example.com', 123); $consent->markConfirmed(new \DateTimeImmutable('2026-04-29T11:00:00+00:00')); - $repository = $this->createMock(NewsletterConsentRepository::class); + $repository = $this->createStub(NewsletterConsentRepository::class); $repository->method('findOneByEmailAndListId')->willReturn($consent); $entityManager = $this->createMock(EntityManagerInterface::class); @@ -126,7 +126,7 @@ class MailjetNewsletterEventHandlerTest extends TestCase $consent = new NewsletterConsent('customer@example.com', 123); $consent->markRevoked(new \DateTimeImmutable('2026-04-29T11:00:00+00:00')); - $repository = $this->createMock(NewsletterConsentRepository::class); + $repository = $this->createStub(NewsletterConsentRepository::class); $repository->method('findOneByEmailAndListId')->willReturn($consent); $entityManager = $this->createMock(EntityManagerInterface::class); diff --git a/tests/Model/ContingentQueryTest.php b/tests/Model/ContingentQueryTest.php index 8be3049..0d2f771 100644 --- a/tests/Model/ContingentQueryTest.php +++ b/tests/Model/ContingentQueryTest.php @@ -6,6 +6,7 @@ namespace App\Tests\Model; use App\Model\ContingentCalendarQuery; use App\Model\ContingentPricesQuery; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; use Symfony\Component\Validator\Validation; @@ -30,15 +31,13 @@ class ContingentQueryTest extends TestCase self::assertNull($query->dateToDate()); } - /** - * @dataProvider invalidCalendarQueries - */ + #[DataProvider('invalidCalendarQueries')] public function testCalendarQueryRejectsInvalidInput(ContingentCalendarQuery $query): void { self::assertGreaterThan(0, $this->validator()->validate($query)->count()); } - public function invalidCalendarQueries(): iterable + public static function invalidCalendarQueries(): iterable { yield 'normalized invalid date' => [new ContingentCalendarQuery('HOTEL', '2026-02-31', '2026-03-01')]; yield 'reversed range' => [new ContingentCalendarQuery('HOTEL', '2026-03-02', '2026-03-01')]; diff --git a/tests/Model/NewsletterSubscriptionRequestTest.php b/tests/Model/NewsletterSubscriptionRequestTest.php index 3c845a6..9a341dc 100644 --- a/tests/Model/NewsletterSubscriptionRequestTest.php +++ b/tests/Model/NewsletterSubscriptionRequestTest.php @@ -4,13 +4,14 @@ declare(strict_types=1); namespace App\Tests\Model; -use PHPUnit\Framework\TestCase; use App\Model\NewsletterSubscriptionRequest; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\TestCase; use Symfony\Component\Validator\Constraint; -use Symfony\Component\Validator\ConstraintValidatorFactory; -use Symfony\Component\Validator\ConstraintValidatorInterface; use Symfony\Component\Validator\Constraints\Email; use Symfony\Component\Validator\Constraints\EmailValidator; +use Symfony\Component\Validator\ConstraintValidatorFactory; +use Symfony\Component\Validator\ConstraintValidatorInterface; use Symfony\Component\Validator\Validation; use Symfony\Component\Validator\Validator\ValidatorInterface; @@ -43,10 +44,9 @@ class NewsletterSubscriptionRequestTest extends TestCase } /** - * @dataProvider invalidRequests - * * @param list $listIds */ + #[DataProvider('invalidRequests')] public function testInvalidRequestFailsValidation(?string $email, array $listIds): void { $request = new NewsletterSubscriptionRequest(); @@ -61,7 +61,7 @@ class NewsletterSubscriptionRequestTest extends TestCase /** * @return iterable}> */ - public function invalidRequests(): iterable + public static function invalidRequests(): iterable { yield 'invalid email' => ['not-an-email', [10321569]]; yield 'empty list ids' => ['customer@example.com', []]; diff --git a/tests/Repository/Filter/AppliesListFiltersTraitTest.php b/tests/Repository/Filter/AppliesListFiltersTraitTest.php index 0bd69b9..1037f19 100644 --- a/tests/Repository/Filter/AppliesListFiltersTraitTest.php +++ b/tests/Repository/Filter/AppliesListFiltersTraitTest.php @@ -8,6 +8,7 @@ use App\Repository\Filter\AppliesListFiltersTrait; use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\Query\Expr; use Doctrine\ORM\QueryBuilder; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; class AppliesListFiltersTraitTest extends TestCase @@ -25,9 +26,7 @@ class AppliesListFiltersTraitTest extends TestCase self::assertSame('%bonn%', $qb->getParameter('searchTerm1')?->getValue()); } - /** - * @dataProvider emptyTerms - */ + #[DataProvider('emptyTerms')] public function testAnEmptyTermNarrowsNothing(?string $term): void { $qb = $this->queryBuilder(); @@ -119,7 +118,7 @@ class AppliesListFiltersTraitTest extends TestCase private function queryBuilder(): QueryBuilder { - $em = $this->createMock(EntityManagerInterface::class); + $em = $this->createStub(EntityManagerInterface::class); $em->method('getExpressionBuilder')->willReturn(new Expr()); return (new QueryBuilder($em))->select('b')->from('Booking', 'b'); diff --git a/tests/Security/BpnAuthenticatorTest.php b/tests/Security/BpnAuthenticatorTest.php index 4ce20c7..df9b51e 100644 --- a/tests/Security/BpnAuthenticatorTest.php +++ b/tests/Security/BpnAuthenticatorTest.php @@ -206,14 +206,14 @@ class BpnAuthenticatorTest extends TestCase $personalData->personId = 42; $personalData->addressId = 4711; - $apiClient = $this->createMock(ApiClient::class); + $apiClient = $this->createStub(ApiClient::class); $apiClient->method('getPersonalData')->willReturn($personalData); $apiClient->method('getCrmAttributes')->willReturn($crmAttributes); - $repository = $this->createMock(EntityRepository::class); + $repository = $this->createStub(EntityRepository::class); $repository->method('findOneBy')->willReturn($existing); - $entityManager = $this->createMock(EntityManagerInterface::class); + $entityManager = $this->createStub(EntityManagerInterface::class); $entityManager->method('getRepository')->willReturn($repository); $entityManager ->method('persist') @@ -225,19 +225,19 @@ class BpnAuthenticatorTest extends TestCase }) ; - $crypt = $this->createMock(Crypt::class); + $crypt = $this->createStub(Crypt::class); $crypt->method('encrypt')->willReturn('encrypted'); - $completenessChecker = $this->createMock(ProfileCompletenessChecker::class); + $completenessChecker = $this->createStub(ProfileCompletenessChecker::class); $completenessChecker->method('isComplete')->willReturn(true); return new BpnAuthenticator( - $this->createMock(UrlGeneratorInterface::class), + $this->createStub(UrlGeneratorInterface::class), $apiClient, $entityManager, $crypt, $completenessChecker, - $this->createMock(LoggerInterface::class), + $this->createStub(LoggerInterface::class), ); } diff --git a/tests/Security/DefaultRouteResolverTest.php b/tests/Security/DefaultRouteResolverTest.php index cbdd97c..35d466b 100644 --- a/tests/Security/DefaultRouteResolverTest.php +++ b/tests/Security/DefaultRouteResolverTest.php @@ -36,7 +36,7 @@ class DefaultRouteResolverTest extends TestCase ->willReturn($hasAdministrativeAccess) ; - $urlGenerator = $this->createMock(UrlGeneratorInterface::class); + $urlGenerator = $this->createStub(UrlGeneratorInterface::class); $urlGenerator ->method('generate') ->willReturnCallback(static fn (string $route): string => match ($route) { diff --git a/tests/Service/AccommodationBookingBreakdownCalculatorTest.php b/tests/Service/AccommodationBookingBreakdownCalculatorTest.php index 246222b..ab254af 100644 --- a/tests/Service/AccommodationBookingBreakdownCalculatorTest.php +++ b/tests/Service/AccommodationBookingBreakdownCalculatorTest.php @@ -141,7 +141,7 @@ class AccommodationBookingBreakdownCalculatorTest extends TestCase 'undersubscription40Eur' => 0, 'undersubscription40Chf' => 0, ]), - $priceRepository ?? $this->createMock(AccommodationPriceRepository::class), + $priceRepository ?? $this->createStub(AccommodationPriceRepository::class), ); } } diff --git a/tests/Service/AccommodationBookingLinkSignerTest.php b/tests/Service/AccommodationBookingLinkSignerTest.php index db91149..acd75e3 100644 --- a/tests/Service/AccommodationBookingLinkSignerTest.php +++ b/tests/Service/AccommodationBookingLinkSignerTest.php @@ -178,7 +178,7 @@ class AccommodationBookingLinkSignerTest extends TestCase private function createSigner(): AccommodationBookingLinkSigner { - $urlGenerator = $this->createMock(UrlGeneratorInterface::class); + $urlGenerator = $this->createStub(UrlGeneratorInterface::class); $urlGenerator ->method('generate') ->willReturnCallback(static fn (string $name, array $parameters) => sprintf( diff --git a/tests/Service/AccommodationBookingPdfGeneratorTest.php b/tests/Service/AccommodationBookingPdfGeneratorTest.php index b0a4707..3d480a9 100644 --- a/tests/Service/AccommodationBookingPdfGeneratorTest.php +++ b/tests/Service/AccommodationBookingPdfGeneratorTest.php @@ -64,7 +64,7 @@ class AccommodationBookingPdfGeneratorTest extends TestCase $twig = new Environment(new FilesystemLoader(__DIR__.'/../../templates')); $twig->addExtension(new IntlExtension()); - $calculator = $this->createMock(AccommodationBookingBreakdownCalculator::class); + $calculator = $this->createStub(AccommodationBookingBreakdownCalculator::class); $calculator->method('compute')->willReturn($breakdown); return new AccommodationBookingPdfGenerator($twig, $calculator, \dirname(__DIR__, 2)); diff --git a/tests/Service/AccommodationBookingServiceTest.php b/tests/Service/AccommodationBookingServiceTest.php index 4e4b3e9..22fa3c9 100644 --- a/tests/Service/AccommodationBookingServiceTest.php +++ b/tests/Service/AccommodationBookingServiceTest.php @@ -25,6 +25,7 @@ use App\Service\AccommodationBookingService; use App\Service\CmsDataProvider; use App\Service\PriceTimelineBuilder; use Doctrine\ORM\EntityManagerInterface; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; use Psr\Log\LoggerInterface; @@ -153,10 +154,10 @@ class AccommodationBookingServiceTest extends TestCase $booking->setStatus(AccommodationBookingStatus::Open); $booking->setAccessLinkIssuedAt(new \DateTimeImmutable()); - $linkSigner = $this->createMock(AccommodationBookingLinkSigner::class); + $linkSigner = $this->createStub(AccommodationBookingLinkSigner::class); $linkSigner->method('sign')->willReturn('https://example.com/offer/signed-link'); - $breakdownCalculator = $this->createMock(AccommodationBookingBreakdownCalculator::class); + $breakdownCalculator = $this->createStub(AccommodationBookingBreakdownCalculator::class); $breakdownCalculator->method('compute')->willReturn(null); $mailer = $this->createMock(Mailer::class); @@ -183,7 +184,7 @@ class AccommodationBookingServiceTest extends TestCase $linkSigner = $this->createMock(AccommodationBookingLinkSigner::class); $linkSigner->method('sign')->with($booking)->willReturn('https://example.com/offer/signed-link'); - $breakdownCalculator = $this->createMock(AccommodationBookingBreakdownCalculator::class); + $breakdownCalculator = $this->createStub(AccommodationBookingBreakdownCalculator::class); $breakdownCalculator->method('compute')->willReturn(['total' => 1000, 'currency' => 'EUR']); $mailer = $this->createMock(Mailer::class); @@ -208,7 +209,7 @@ class AccommodationBookingServiceTest extends TestCase $booking->setEmail('customer@example.com'); $booking->setStatus(AccommodationBookingStatus::Open); - $breakdownCalculator = $this->createMock(AccommodationBookingBreakdownCalculator::class); + $breakdownCalculator = $this->createStub(AccommodationBookingBreakdownCalculator::class); $breakdownCalculator->method('compute')->willReturn(null); $mailer = $this->createMock(Mailer::class); @@ -231,10 +232,10 @@ class AccommodationBookingServiceTest extends TestCase $booking->setEmail('customer@example.com'); $booking->setStatus(AccommodationBookingStatus::Open); - $breakdownCalculator = $this->createMock(AccommodationBookingBreakdownCalculator::class); + $breakdownCalculator = $this->createStub(AccommodationBookingBreakdownCalculator::class); $breakdownCalculator->method('compute')->willReturn(null); - $mailer = $this->createMock(Mailer::class); + $mailer = $this->createStub(Mailer::class); $mailer->method('createAndSendEmail')->willThrowException(new \RuntimeException('SMTP down')); $logger = $this->createMock(LoggerInterface::class); @@ -258,7 +259,7 @@ class AccommodationBookingServiceTest extends TestCase $entityManager = $this->createMock(EntityManagerInterface::class); $entityManager->expects(self::once())->method('flush'); - $breakdownCalculator = $this->createMock(AccommodationBookingBreakdownCalculator::class); + $breakdownCalculator = $this->createStub(AccommodationBookingBreakdownCalculator::class); $breakdownCalculator->method('compute')->willReturn(null); $mailer = $this->createMock(Mailer::class); @@ -416,9 +417,7 @@ class AccommodationBookingServiceTest extends TestCase self::assertSame($issuedAt, $booking->getAccessLinkIssuedAt()); } - /** - * @dataProvider statusesThatAreNotAwaitingAnOffer - */ + #[DataProvider('statusesThatAreNotAwaitingAnOffer')] public function testSendOfferNoOpsOnceTheOfferIsOut(AccommodationBookingStatus $status): void { $entityManager = $this->createMock(EntityManagerInterface::class); @@ -495,9 +494,7 @@ class AccommodationBookingServiceTest extends TestCase self::assertSame($issuedAt, $booking->getAccessLinkIssuedAt()); } - /** - * @dataProvider statusesThatAreNotAwaitingAnOffer - */ + #[DataProvider('statusesThatAreNotAwaitingAnOffer')] public function testGenerateAccessLinkNoOpsOnceTheOfferIsOut(AccommodationBookingStatus $status): void { $entityManager = $this->createMock(EntityManagerInterface::class); @@ -533,9 +530,7 @@ class AccommodationBookingServiceTest extends TestCase self::assertSame(AccommodationBookingStatus::Discarded, $booking->getStatus()); } - /** - * @dataProvider closedStatuses - */ + #[DataProvider('closedStatuses')] public function testDiscardBookingNoOpsForAClosedBooking(AccommodationBookingStatus $status): void { $entityManager = $this->createMock(EntityManagerInterface::class); @@ -643,7 +638,7 @@ class AccommodationBookingServiceTest extends TestCase $booking->setEmail('customer@example.com'); $booking->setRemarks('vom Telefonat'); - $service = $this->createServiceWithAccommodation(mailer: $this->createMock(Mailer::class)); + $service = $this->createServiceWithAccommodation(mailer: $this->createStub(Mailer::class)); $service->acceptBooking($booking, " Bitte Zimmer im EG\nund Frühstück um 8 \n"); @@ -657,7 +652,7 @@ class AccommodationBookingServiceTest extends TestCase $booking->setEmail('customer@example.com'); $booking->setRemarks('vom Telefonat'); - $service = $this->createServiceWithAccommodation(mailer: $this->createMock(Mailer::class)); + $service = $this->createServiceWithAccommodation(mailer: $this->createStub(Mailer::class)); $service->acceptBooking($booking, ' '); @@ -671,7 +666,7 @@ class AccommodationBookingServiceTest extends TestCase $booking->setEmail('customer@example.com'); $booking->setRemarks('vom Telefonat'); - $service = $this->createServiceWithAccommodation(mailer: $this->createMock(Mailer::class)); + $service = $this->createServiceWithAccommodation(mailer: $this->createStub(Mailer::class)); $service->acceptBooking($booking); @@ -684,7 +679,7 @@ class AccommodationBookingServiceTest extends TestCase $booking->setStatus(AccommodationBookingStatus::Received); $booking->setRemarks('vom Telefonat'); - $service = $this->createServiceWithAccommodation(mailer: $this->createMock(Mailer::class)); + $service = $this->createServiceWithAccommodation(mailer: $this->createStub(Mailer::class)); $service->acceptBooking($booking, 'zu spät'); @@ -693,7 +688,7 @@ class AccommodationBookingServiceTest extends TestCase public function testConfirmBookingConfirmsReceivedBookingAndNotifiesTheCustomer(): void { - $entityManager = $this->createMock(EntityManagerInterface::class); + $entityManager = $this->createStub(EntityManagerInterface::class); $booking = new AccommodationBooking(); $booking->setStatus(AccommodationBookingStatus::Received); @@ -835,7 +830,7 @@ class AccommodationBookingServiceTest extends TestCase $booking = new AccommodationBooking(); $booking->setStatus(AccommodationBookingStatus::Received); - $mailer = $this->createMock(Mailer::class); + $mailer = $this->createStub(Mailer::class); $mailer->method('createAndSendEmail')->willThrowException(new \RuntimeException('SMTP down')); $logger = $this->createMock(LoggerInterface::class); @@ -852,7 +847,7 @@ class AccommodationBookingServiceTest extends TestCase $booking->setEmail('customer@example.com'); $booking->setStatus(AccommodationBookingStatus::Confirmed); - $mailer = $this->createMock(Mailer::class); + $mailer = $this->createStub(Mailer::class); $mailer->method('createAndSendEmail')->willThrowException(new \RuntimeException('SMTP down')); $logger = $this->createMock(LoggerInterface::class); @@ -894,7 +889,7 @@ class AccommodationBookingServiceTest extends TestCase $booking->setEmail('customer@example.com'); $booking->setStatus(AccommodationBookingStatus::Confirmed); - $pdfGenerator = $this->createMock(AccommodationBookingPdfGenerator::class); + $pdfGenerator = $this->createStub(AccommodationBookingPdfGenerator::class); $pdfGenerator->method('createAttachment')->willThrowException(new \RuntimeException('no prices')); $mailer = $this->createMock(Mailer::class); @@ -1038,7 +1033,7 @@ class AccommodationBookingServiceTest extends TestCase ->with(['calendarCode' => 'HOTEL']) ->willReturn($accommodation); - $priceRepo = $this->createMock(AccommodationPriceRepository::class); + $priceRepo = $this->createStub(AccommodationPriceRepository::class); $priceRepo ->method('findByHotelCodeAndDateRange') ->willReturn($prices); @@ -1046,16 +1041,16 @@ class AccommodationBookingServiceTest extends TestCase return new AccommodationBookingService( $accommodationRepo, $priceRepo, - $this->createMock(AdditionalServiceRepository::class), - $this->createMock(BoardServiceRepository::class), + $this->createStub(AdditionalServiceRepository::class), + $this->createStub(BoardServiceRepository::class), new PriceTimelineBuilder(), - $entityManager ?? $this->createMock(EntityManagerInterface::class), - $mailer ?? $this->createMock(Mailer::class), - $logger ?? $this->createMock(LoggerInterface::class), - $this->createMock(CmsDataProvider::class), - $linkSigner ?? $this->createMock(AccommodationBookingLinkSigner::class), - $breakdownCalculator ?? $this->createMock(AccommodationBookingBreakdownCalculator::class), - $pdfGenerator ?? $this->createMock(AccommodationBookingPdfGenerator::class), + $entityManager ?? $this->createStub(EntityManagerInterface::class), + $mailer ?? $this->createStub(Mailer::class), + $logger ?? $this->createStub(LoggerInterface::class), + $this->createStub(CmsDataProvider::class), + $linkSigner ?? $this->createStub(AccommodationBookingLinkSigner::class), + $breakdownCalculator ?? $this->createStub(AccommodationBookingBreakdownCalculator::class), + $pdfGenerator ?? $this->createStub(AccommodationBookingPdfGenerator::class), 'office@example.com', ); } diff --git a/tests/Service/AccommodationPriceCoverageTest.php b/tests/Service/AccommodationPriceCoverageTest.php index 7b7a69a..fa3253b 100644 --- a/tests/Service/AccommodationPriceCoverageTest.php +++ b/tests/Service/AccommodationPriceCoverageTest.php @@ -13,7 +13,7 @@ class AccommodationPriceCoverageTest extends TestCase { public function testCoversOnlyDaysWithinPricePeriod(): void { - $coverage = new AccommodationPriceCoverage($this->createMock(AccommodationPriceRepository::class)); + $coverage = new AccommodationPriceCoverage($this->createStub(AccommodationPriceRepository::class)); $covered = $coverage->coveredDatesFor( [$this->price('2026-06-01', '2026-06-09')], @@ -30,7 +30,7 @@ class AccommodationPriceCoverageTest extends TestCase public function testGapBetweenPricePeriodsStaysUncovered(): void { - $coverage = new AccommodationPriceCoverage($this->createMock(AccommodationPriceRepository::class)); + $coverage = new AccommodationPriceCoverage($this->createStub(AccommodationPriceRepository::class)); $covered = $coverage->coveredDatesFor( [$this->price('2026-06-01', '2026-06-02'), $this->price('2026-06-05', '2026-06-06')], @@ -46,7 +46,7 @@ class AccommodationPriceCoverageTest extends TestCase public function testNoPricesMeansNoCoverage(): void { - $coverage = new AccommodationPriceCoverage($this->createMock(AccommodationPriceRepository::class)); + $coverage = new AccommodationPriceCoverage($this->createStub(AccommodationPriceRepository::class)); $covered = $coverage->coveredDatesFor( [], diff --git a/tests/Service/ApplicantInsuranceCascadeTest.php b/tests/Service/ApplicantInsuranceCascadeTest.php index 54ee81b..3d4403e 100644 --- a/tests/Service/ApplicantInsuranceCascadeTest.php +++ b/tests/Service/ApplicantInsuranceCascadeTest.php @@ -137,7 +137,7 @@ class ApplicantInsuranceCascadeTest extends TestCase $cascade = new ApplicantInsuranceCascade( $insuranceService, - $this->createMock(BookingPriceCalculator::class) + $this->createStub(BookingPriceCalculator::class) ); $cascade->apply($bookingDto); @@ -201,11 +201,11 @@ class ApplicantInsuranceCascadeTest extends TestCase */ private function createCascade(array $assignments, array $selectable): ApplicantInsuranceCascade { - $insuranceService = $this->createMock(InsuranceManager::class); + $insuranceService = $this->createStub(InsuranceManager::class); $insuranceService->method('getSelectableInsurances')->willReturn($selectable); $insuranceService->method('batchAssignInsuranceToParticipants')->willReturn($assignments); - $priceCalculator = $this->createMock(BookingPriceCalculator::class); + $priceCalculator = $this->createStub(BookingPriceCalculator::class); $priceCalculator->method('calculateIndividualParticipantPriceExcludingInsurance')->willReturn(0.0); return new ApplicantInsuranceCascade($insuranceService, $priceCalculator); diff --git a/tests/Service/BookingConfiguratorBabyTest.php b/tests/Service/BookingConfiguratorBabyTest.php index 8d52269..3689760 100644 --- a/tests/Service/BookingConfiguratorBabyTest.php +++ b/tests/Service/BookingConfiguratorBabyTest.php @@ -19,23 +19,25 @@ use PHPUnit\Framework\TestCase; class BookingConfiguratorBabyTest extends TestCase { - private BookingConfigurator $bookingService; + private ?BookingConfigurator $bookingService = null; private ParticipantEligibilityChecker $participantEligibilityService; protected function setUp(): void { - $travelDataService = $this->createMock(TravelDataProvider::class); - $this->participantEligibilityService = $this->createMock(ParticipantEligibilityChecker::class); - $bookingStatusRuleRegistry = $this->createMock(BookingStatusRuleRegistry::class); - $bookingStatusRuleRegistry->method('evaluateStatus')->willReturn('F'); - $agencyLoader = $this->createMock(AgencyLoader::class); + $this->participantEligibilityService = $this->createStub(ParticipantEligibilityChecker::class); + } - $this->bookingService = new BookingConfigurator( - $this->createMock(BookingSessionManager::class), - $travelDataService, + private function bookingService(): BookingConfigurator + { + $bookingStatusRuleRegistry = $this->createStub(BookingStatusRuleRegistry::class); + $bookingStatusRuleRegistry->method('evaluateStatus')->willReturn('F'); + + return $this->bookingService ??= new BookingConfigurator( + $this->createStub(BookingSessionManager::class), + $this->createStub(TravelDataProvider::class), $this->participantEligibilityService, $bookingStatusRuleRegistry, - $agencyLoader, + $this->createStub(AgencyLoader::class), 'F' // default booking status ); } @@ -52,7 +54,7 @@ class BookingConfiguratorBabyTest extends TestCase $participant->additionalServices = []; $bookingDto->participants[0] = $participant; - $this->bookingService->preselectDefaultServices($bookingDto); + $this->bookingService()->preselectDefaultServices($bookingDto); $this->assertEmpty($participant->additionalServices, 'Mandatory services should not be preselected for baby participants'); } @@ -69,7 +71,7 @@ class BookingConfiguratorBabyTest extends TestCase $participant->additionalServices = []; $bookingDto->participants[0] = $participant; - $this->bookingService->preselectDefaultServices($bookingDto); + $this->bookingService()->preselectDefaultServices($bookingDto); $this->assertEmpty($participant->additionalServices, 'Mandatory services should not be preselected for participants at BABY_MAX_AGE'); } @@ -91,7 +93,7 @@ class BookingConfiguratorBabyTest extends TestCase ->method('isParticipantEligible') ->willReturn(true); - $this->bookingService->preselectDefaultServices($bookingDto); + $this->bookingService()->preselectDefaultServices($bookingDto); $this->assertNotEmpty($participant->additionalServices, 'Mandatory services should be preselected for non-baby participants'); $this->assertCount(1, $participant->additionalServices); @@ -115,7 +117,7 @@ class BookingConfiguratorBabyTest extends TestCase ->method('isParticipantEligible') ->willReturn(true); - $this->bookingService->preselectDefaultServices($bookingDto); + $this->bookingService()->preselectDefaultServices($bookingDto); $this->assertNotEmpty($participant->additionalServices, 'Mandatory services should be preselected for adult participants'); $this->assertCount(1, $participant->additionalServices); @@ -123,6 +125,8 @@ class BookingConfiguratorBabyTest extends TestCase public function testPreselectMandatoryServicesHandlesMixedParticipants(): void { + $this->participantEligibilityService = $this->createMock(ParticipantEligibilityChecker::class); + $travel = $this->createTravelWithMandatoryServices(); $bookingDto = new BookingDto($travel, 1); @@ -146,7 +150,7 @@ class BookingConfiguratorBabyTest extends TestCase ->with($bookingDto, 1) // Only called for adult ->willReturn(true); - $this->bookingService->preselectDefaultServices($bookingDto); + $this->bookingService()->preselectDefaultServices($bookingDto); $this->assertEmpty($babyParticipant->additionalServices, 'Baby should not have mandatory services preselected'); $this->assertNotEmpty($adultParticipant->additionalServices, 'Adult should have mandatory services preselected'); @@ -164,7 +168,7 @@ class BookingConfiguratorBabyTest extends TestCase $participant->additionalServices = []; $bookingDto->participants[0] = $participant; - $this->bookingService->preselectDefaultServices($bookingDto); + $this->bookingService()->preselectDefaultServices($bookingDto); $this->assertEmpty($participant->additionalServices, 'Mandatory services should not be preselected for newborn babies'); } @@ -186,7 +190,7 @@ class BookingConfiguratorBabyTest extends TestCase $participant->additionalServices = []; $bookingDto->participants[0] = $participant; - $this->bookingService->preselectDefaultServices($bookingDto); + $this->bookingService()->preselectDefaultServices($bookingDto); // At age 1, participant is a baby and should be skipped $this->assertEmpty($participant->additionalServices, 'Age should be calculated at travel date, not current date'); @@ -207,7 +211,7 @@ class BookingConfiguratorBabyTest extends TestCase ->method('isParticipantEligible') ->willReturn(true); - $this->bookingService->preselectDefaultServices($bookingDto); + $this->bookingService()->preselectDefaultServices($bookingDto); $this->assertCount(1, $participant->additionalServices); $this->assertSame('Auto Book Service', $participant->additionalServices[0]->label); @@ -229,7 +233,7 @@ class BookingConfiguratorBabyTest extends TestCase ->method('isParticipantEligible') ->willReturn(true); - $this->bookingService->preselectDefaultServices($bookingDto); + $this->bookingService()->preselectDefaultServices($bookingDto); $this->assertEmpty($participant->additionalServices); } @@ -250,7 +254,7 @@ class BookingConfiguratorBabyTest extends TestCase ->method('isParticipantEligible') ->willReturn(true); - $this->bookingService->preselectDefaultServices($bookingDto); + $this->bookingService()->preselectDefaultServices($bookingDto); $this->assertCount(1, $participant->additionalServices); $this->assertSame('Mandatory And Auto Book Service', $participant->additionalServices[0]->label); @@ -270,7 +274,7 @@ class BookingConfiguratorBabyTest extends TestCase ->method('isParticipantEligible') ->willReturn(true); - $this->bookingService->preselectDefaultServices($bookingDto); + $this->bookingService()->preselectDefaultServices($bookingDto); $this->assertNotNull($participant->skiPass); $this->assertSame('Auto Book Ski Pass', $participant->skiPass?->label); @@ -291,7 +295,7 @@ class BookingConfiguratorBabyTest extends TestCase ->method('isParticipantEligible') ->willReturn(true); - $this->bookingService->preselectDefaultServices($bookingDto); + $this->bookingService()->preselectDefaultServices($bookingDto); $this->assertNull($participant->skiPass); } @@ -311,7 +315,7 @@ class BookingConfiguratorBabyTest extends TestCase ->method('isParticipantEligible') ->willReturn(true); - $this->bookingService->preselectDefaultServices($bookingDto); + $this->bookingService()->preselectDefaultServices($bookingDto); $this->assertNotNull($participant->skiPass); $this->assertSame('Mandatory And Auto Book Ski Pass', $participant->skiPass?->label); @@ -331,7 +335,7 @@ class BookingConfiguratorBabyTest extends TestCase ->method('isParticipantEligible') ->willReturn(true); - $this->bookingService->preselectDefaultServices($bookingDto); + $this->bookingService()->preselectDefaultServices($bookingDto); $this->assertCount(1, $participant->board); $this->assertSame('Auto Book Board', $participant->board[0]->label); @@ -352,7 +356,7 @@ class BookingConfiguratorBabyTest extends TestCase ->method('isParticipantEligible') ->willReturn(true); - $this->bookingService->preselectDefaultServices($bookingDto); + $this->bookingService()->preselectDefaultServices($bookingDto); $this->assertSame([], $participant->board); } @@ -372,7 +376,7 @@ class BookingConfiguratorBabyTest extends TestCase ->method('isParticipantEligible') ->willReturn(true); - $this->bookingService->preselectDefaultServices($bookingDto); + $this->bookingService()->preselectDefaultServices($bookingDto); $this->assertCount(1, $participant->board); $this->assertSame('Mandatory And Auto Book Board', $participant->board[0]->label); @@ -393,7 +397,7 @@ class BookingConfiguratorBabyTest extends TestCase ->method('isParticipantEligible') ->willReturn(true); - $this->bookingService->preselectDefaultServices($bookingDto); + $this->bookingService()->preselectDefaultServices($bookingDto); $this->assertCount(1, $participant->rentals); $this->assertSame('Auto Book Rental', $participant->rentals[0]->label); @@ -415,7 +419,7 @@ class BookingConfiguratorBabyTest extends TestCase ->method('isParticipantEligible') ->willReturn(true); - $this->bookingService->preselectDefaultServices($bookingDto); + $this->bookingService()->preselectDefaultServices($bookingDto); $this->assertSame([], $participant->rentals); } @@ -436,7 +440,7 @@ class BookingConfiguratorBabyTest extends TestCase ->method('isParticipantEligible') ->willReturn(true); - $this->bookingService->preselectDefaultServices($bookingDto); + $this->bookingService()->preselectDefaultServices($bookingDto); $this->assertCount(1, $participant->rentals); $this->assertSame('Mandatory And Auto Book Rental', $participant->rentals[0]->label); @@ -456,7 +460,7 @@ class BookingConfiguratorBabyTest extends TestCase ->method('isParticipantEligible') ->willReturn(true); - $this->bookingService->preselectDefaultServices($bookingDto); + $this->bookingService()->preselectDefaultServices($bookingDto); $this->assertSame([], $participant->rentals); } @@ -480,7 +484,7 @@ class BookingConfiguratorBabyTest extends TestCase ->method('isParticipantEligible') ->willReturn(true); - $this->bookingService->preselectDefaultServices($bookingDto); + $this->bookingService()->preselectDefaultServices($bookingDto); $this->assertSame([], $participant->rentals); } diff --git a/tests/Service/BookingConfiguratorStatusTest.php b/tests/Service/BookingConfiguratorStatusTest.php index c312820..dbc79d2 100644 --- a/tests/Service/BookingConfiguratorStatusTest.php +++ b/tests/Service/BookingConfiguratorStatusTest.php @@ -4,11 +4,9 @@ declare(strict_types=1); namespace App\Tests\Service; -use App\Form\Model\BookingDto; -use App\Form\Model\ParticipantDto; +use App\BusProNet\Constants; use App\BusProNet\Model\CrmSelection; use App\BusProNet\Model\CrmSelectionGroup; -use App\BusProNet\Constants; use App\BusProNet\Model\Room; use App\BusProNet\Model\Service; use App\BusProNet\Model\Travel; @@ -16,6 +14,8 @@ use App\BusProNet\Service\BookingStatusRuleRegistry; use App\BusProNet\Service\StatusRule\Selection1473StatusRule; use App\BusProNet\XmlLoader\AgencyLoader; use App\Exception\NoRoomsAvailableException; +use App\Form\Model\BookingDto; +use App\Form\Model\ParticipantDto; use App\Service\BookingConfigurator; use App\Service\BookingSessionManager; use App\Service\ParticipantEligibilityChecker; @@ -32,12 +32,12 @@ class BookingConfiguratorStatusTest extends TestCase protected function setUp(): void { - $bookingSessionService = $this->createMock(BookingSessionManager::class); - $this->travelDataService = $this->createMock(TravelDataProvider::class); - $participantEligibility = $this->createMock(ParticipantEligibilityChecker::class); - $bookingStatusRuleRegistry = $this->createMock(BookingStatusRuleRegistry::class); + $bookingSessionService = $this->createStub(BookingSessionManager::class); + $this->travelDataService = $this->createStub(TravelDataProvider::class); + $participantEligibility = $this->createStub(ParticipantEligibilityChecker::class); + $bookingStatusRuleRegistry = $this->createStub(BookingStatusRuleRegistry::class); $bookingStatusRuleRegistry->method('evaluateStatus')->willReturn('F'); - $agencyLoader = $this->createMock(AgencyLoader::class); + $agencyLoader = $this->createStub(AgencyLoader::class); $this->bookingService = new BookingConfigurator( $bookingSessionService, @@ -180,13 +180,13 @@ class BookingConfiguratorStatusTest extends TestCase public function testStartFreshBookingWithSelection1473UsesOptionStatus(): void { $bookingService = new BookingConfigurator( - $this->createMock(BookingSessionManager::class), + $this->createStub(BookingSessionManager::class), $this->travelDataService, - $this->createMock(ParticipantEligibilityChecker::class), + $this->createStub(ParticipantEligibilityChecker::class), new BookingStatusRuleRegistry([ new Selection1473StatusRule(), ]), - $this->createMock(AgencyLoader::class), + $this->createStub(AgencyLoader::class), 'F' ); @@ -230,15 +230,15 @@ class BookingConfiguratorStatusTest extends TestCase public function testApplyCreateBookingStatusRulesSetsOptionFromRegistry(): void { - $bookingStatusRuleRegistry = $this->createMock(BookingStatusRuleRegistry::class); + $bookingStatusRuleRegistry = $this->createStub(BookingStatusRuleRegistry::class); $bookingStatusRuleRegistry->method('evaluateStatus')->willReturn('O'); $bookingService = new BookingConfigurator( - $this->createMock(BookingSessionManager::class), + $this->createStub(BookingSessionManager::class), $this->travelDataService, - $this->createMock(ParticipantEligibilityChecker::class), + $this->createStub(ParticipantEligibilityChecker::class), $bookingStatusRuleRegistry, - $this->createMock(AgencyLoader::class), + $this->createStub(AgencyLoader::class), 'F' ); @@ -265,11 +265,11 @@ class BookingConfiguratorStatusTest extends TestCase $bookingStatusRuleRegistry->expects($this->never())->method('evaluateStatus'); $bookingService = new BookingConfigurator( - $this->createMock(BookingSessionManager::class), + $this->createStub(BookingSessionManager::class), $this->travelDataService, - $this->createMock(ParticipantEligibilityChecker::class), + $this->createStub(ParticipantEligibilityChecker::class), $bookingStatusRuleRegistry, - $this->createMock(AgencyLoader::class), + $this->createStub(AgencyLoader::class), 'F' ); diff --git a/tests/Service/BookingCreateContextFactoryTest.php b/tests/Service/BookingCreateContextFactoryTest.php index 9f4ac25..03e2e46 100644 --- a/tests/Service/BookingCreateContextFactoryTest.php +++ b/tests/Service/BookingCreateContextFactoryTest.php @@ -44,7 +44,7 @@ class BookingCreateContextFactoryTest extends TestCase $travel->rooms = [$roomByRoom, $roomByPax]; $bookingDto = new BookingDto($travel, 157047); - $summaryData = $this->createMock(BookingSummaryDto::class); + $summaryData = $this->createStub(BookingSummaryDto::class); $summaryDataService = $this->createMock(BookingSummaryAssembler::class); $summaryDataService->expects($this->once()) @@ -63,7 +63,7 @@ class BookingCreateContextFactoryTest extends TestCase $priceCalculator->expects($this->never()) ->method('calculateAllParticipantIndividualPrices'); - $familyInsuranceService = $this->createMock(FamilyInsuranceAvailabilityChecker::class); + $familyInsuranceService = $this->createStub(FamilyInsuranceAvailabilityChecker::class); $familyInsuranceService->method('isFamilyInsuranceUpgradeAvailable')->willReturn(true); $service = new BookingCreateContextFactory( @@ -101,7 +101,7 @@ class BookingCreateContextFactoryTest extends TestCase $travel->rooms = [$room]; $bookingDto = new BookingDto($travel, 157047); - $summaryData = $this->createMock(BookingSummaryDto::class); + $summaryData = $this->createStub(BookingSummaryDto::class); $cardData = new ParticipantCardDataDto( name: 'Max Mustermann', email: 'max@example.test', @@ -126,7 +126,7 @@ class BookingCreateContextFactoryTest extends TestCase $priceCalculator->expects($this->never()) ->method('calculateAllParticipantIndividualPrices'); - $familyInsuranceService = $this->createMock(FamilyInsuranceAvailabilityChecker::class); + $familyInsuranceService = $this->createStub(FamilyInsuranceAvailabilityChecker::class); $familyInsuranceService->method('isFamilyInsuranceUpgradeAvailable')->willReturn(true); $service = new BookingCreateContextFactory( @@ -162,7 +162,7 @@ class BookingCreateContextFactoryTest extends TestCase $travel->rooms = [$room]; $bookingDto = new BookingDto($travel, 157047); - $summaryData = $this->createMock(BookingSummaryDto::class); + $summaryData = $this->createStub(BookingSummaryDto::class); $summaryDataService = $this->createMock(BookingSummaryAssembler::class); $summaryDataService->expects($this->once()) @@ -180,7 +180,7 @@ class BookingCreateContextFactoryTest extends TestCase ->with($bookingDto) ->willReturn([123.45]); - $familyInsuranceService = $this->createMock(FamilyInsuranceAvailabilityChecker::class); + $familyInsuranceService = $this->createStub(FamilyInsuranceAvailabilityChecker::class); $familyInsuranceService->method('isFamilyInsuranceUpgradeAvailable')->willReturn(true); $service = new BookingCreateContextFactory( diff --git a/tests/Service/BookingEditContextFactoryTest.php b/tests/Service/BookingEditContextFactoryTest.php index a9aa366..5d3b6ea 100644 --- a/tests/Service/BookingEditContextFactoryTest.php +++ b/tests/Service/BookingEditContextFactoryTest.php @@ -32,7 +32,7 @@ class BookingEditContextFactoryTest extends TestCase $bookingData = new Booking(); $bookingData->dateId = 123; - $summaryData = $this->createMock(BookingSummaryDto::class); + $summaryData = $this->createStub(BookingSummaryDto::class); $participantCardAssembler = $this->createMock(ParticipantCardAssembler::class); $participantCardAssembler->expects($this->once()) diff --git a/tests/Service/BookingEditDraftManagerMutabilityTest.php b/tests/Service/BookingEditDraftManagerMutabilityTest.php index e2ae26e..382ee4b 100644 --- a/tests/Service/BookingEditDraftManagerMutabilityTest.php +++ b/tests/Service/BookingEditDraftManagerMutabilityTest.php @@ -34,9 +34,9 @@ class BookingEditDraftManagerMutabilityTest extends TestCase protected function setUp(): void { $this->service = new BookingEditDraftManager( - $this->createMock(BookingEditDraftRepository::class), - $this->createMock(EntityManagerInterface::class), - $this->createMock(BookingChangeTracker::class), + $this->createStub(BookingEditDraftRepository::class), + $this->createStub(EntityManagerInterface::class), + $this->createStub(BookingChangeTracker::class), new BookingEditDraftMerger(), new NullLogger(), ); @@ -544,7 +544,7 @@ class BookingEditDraftManagerMutabilityTest extends TestCase private function createDraft(array $formData): BookingEditDraft { - $user = $this->createMock(User::class); + $user = $this->createStub(User::class); return new BookingEditDraft($user, 123, new \DateTimeImmutable(), $formData); } diff --git a/tests/Service/BookingEditPreFlightCheckerTest.php b/tests/Service/BookingEditPreFlightCheckerTest.php index 6c19366..626b0f7 100644 --- a/tests/Service/BookingEditPreFlightCheckerTest.php +++ b/tests/Service/BookingEditPreFlightCheckerTest.php @@ -4,20 +4,20 @@ declare(strict_types=1); namespace App\Tests\Service; -use App\BusProNet\Model\CrmSelection; -use App\BusProNet\Model\CrmSelectionGroup; use App\BusProNet\Model\Address; use App\BusProNet\Model\Booking; +use App\BusProNet\Model\CrmSelection; +use App\BusProNet\Model\CrmSelectionGroup; use App\BusProNet\Model\Service; use App\BusProNet\Model\Travel; use App\BusProNet\XmlLoader\AgencyLoader; use App\Form\Model\BookingDto; use App\Form\Model\ParticipantDto; +use App\Form\Service\ServiceAgeEvaluator; use App\Service\BookingEditPreFlightChecker; use App\Service\BookingPriceCalculator; use App\Service\ParticipantEligibilityChecker; use App\Service\VoucherValidator; -use App\Form\Service\ServiceAgeEvaluator; use App\Validator\Constraints\MandatoryAdditionalServicesSelectedValidator; use App\Validator\Constraints\PromoVoucherValidator; use App\Validator\Constraints\PurchaseVoucherValidator; @@ -248,19 +248,14 @@ class BookingEditPreFlightCheckerTest extends TestCase private function createValidator(): ValidatorInterface { - $voucherValidator = $this->createMock(VoucherValidator::class); - $bookingPriceCalculator = $this->createMock(BookingPriceCalculator::class); - $participantEligibilityChecker = $this->createMock(ParticipantEligibilityChecker::class); + $voucherValidator = $this->createStub(VoucherValidator::class); + $bookingPriceCalculator = $this->createStub(BookingPriceCalculator::class); + $participantEligibilityChecker = $this->createStub(ParticipantEligibilityChecker::class); $participantEligibilityChecker ->method('isParticipantEligible') ->willReturn(false); - $validatorFactory = new class( - $voucherValidator, - $bookingPriceCalculator, - $participantEligibilityChecker, - new ServiceAgeEvaluator(), - ) implements ConstraintValidatorFactoryInterface { + $validatorFactory = new class($voucherValidator, $bookingPriceCalculator, $participantEligibilityChecker, new ServiceAgeEvaluator()) implements ConstraintValidatorFactoryInterface { public function __construct( private readonly VoucherValidator $voucherValidator, private readonly BookingPriceCalculator $bookingPriceCalculator, diff --git a/tests/Service/BookingEditSubmitterTest.php b/tests/Service/BookingEditSubmitterTest.php index fa1bd79..5a1ad0f 100644 --- a/tests/Service/BookingEditSubmitterTest.php +++ b/tests/Service/BookingEditSubmitterTest.php @@ -19,6 +19,7 @@ use App\Service\BookingEditSubmitGuard; use App\Service\BookingEditSubmitter; use App\Service\BookingSessionManager; use App\Service\TravelDataProvider; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; use Psr\Log\LoggerInterface; use Symfony\Component\HttpFoundation\Request; @@ -53,9 +54,7 @@ class BookingEditSubmitterTest extends TestCase $this->assertFalse($result->immutableChangesReverted); } - /** - * @dataProvider updateFailureProvider - */ + #[DataProvider('updateFailureProvider')] public function testHandleSubmissionReturnsRedirectWhenUpdateThrows( \Throwable $exception, string $expectedStatus, @@ -437,13 +436,13 @@ class BookingEditSubmitterTest extends TestCase ?BookingSessionManager $bookingSessionService = null, ): BookingEditSubmitter { return new BookingEditSubmitter( - $apiClient ?? $this->createMock(\App\BusProNet\ApiClient::class), - $dataLoader ?? $this->createMock(BookingEditDataLoader::class), - $draftService ?? $this->createMock(BookingEditDraftManager::class), - $travelDataService ?? $this->createMock(TravelDataProvider::class), - $submitGuard ?? $this->createMock(BookingEditSubmitGuard::class), - $bookingSessionService ?? $this->createMock(BookingSessionManager::class), - $this->createMock(LoggerInterface::class), + $apiClient ?? $this->createStub(\App\BusProNet\ApiClient::class), + $dataLoader ?? $this->createStub(BookingEditDataLoader::class), + $draftService ?? $this->createStub(BookingEditDraftManager::class), + $travelDataService ?? $this->createStub(TravelDataProvider::class), + $submitGuard ?? $this->createStub(BookingEditSubmitGuard::class), + $bookingSessionService ?? $this->createStub(BookingSessionManager::class), + $this->createStub(LoggerInterface::class), ); } @@ -475,5 +474,4 @@ class BookingEditSubmitterTest extends TestCase return $request; } - } diff --git a/tests/Service/BookingPriceCalculatorTest.php b/tests/Service/BookingPriceCalculatorTest.php index 5e97afd..5829a3d 100644 --- a/tests/Service/BookingPriceCalculatorTest.php +++ b/tests/Service/BookingPriceCalculatorTest.php @@ -28,7 +28,7 @@ class BookingPriceCalculatorTest extends TestCase protected function setUp(): void { - $eligibilityChecker = $this->createMock(ParticipantEligibilityChecker::class); + $eligibilityChecker = $this->createStub(ParticipantEligibilityChecker::class); $eligibilityChecker->method('isParticipantEligible')->willReturn(true); $this->roomPricingCalculator = new RoomPricingCalculator(); diff --git a/tests/Service/BookingPriceMismatchAnalyzerTest.php b/tests/Service/BookingPriceMismatchAnalyzerTest.php index 6b5af95..090e9f1 100644 --- a/tests/Service/BookingPriceMismatchAnalyzerTest.php +++ b/tests/Service/BookingPriceMismatchAnalyzerTest.php @@ -19,7 +19,7 @@ class BookingPriceMismatchAnalyzerTest extends TestCase { public function testBuildDiagnosticsProvidesDeltaBreakdown(): void { - $pricingAssembler = $this->createMock(BookingPricingAssembler::class); + $pricingAssembler = $this->createStub(BookingPricingAssembler::class); $pricingAssembler->method('getPricingBreakdown')->willReturn([ 'rooms' => [ ['roomId' => 74, 'totalPrice' => 444.0], diff --git a/tests/Service/BookingPricingAssemblerTest.php b/tests/Service/BookingPricingAssemblerTest.php index a96cd69..e2f2a65 100644 --- a/tests/Service/BookingPricingAssemblerTest.php +++ b/tests/Service/BookingPricingAssemblerTest.php @@ -24,7 +24,7 @@ class BookingPricingAssemblerTest extends TestCase protected function setUp(): void { - $this->eligibilityChecker = $this->createMock(ParticipantEligibilityChecker::class); + $this->eligibilityChecker = $this->createStub(ParticipantEligibilityChecker::class); $this->eligibilityChecker->method('isParticipantEligible')->willReturn(true); $this->assembler = $this->createAssembler($this->eligibilityChecker); @@ -176,7 +176,7 @@ class BookingPricingAssemblerTest extends TestCase $bookingDto = new BookingDto($travel, 2); $bookingDto->participants = [$participant1, $participant2]; - $eligibilityChecker = $this->createMock(ParticipantEligibilityChecker::class); + $eligibilityChecker = $this->createStub(ParticipantEligibilityChecker::class); $eligibilityChecker->method('isParticipantEligible') ->willReturnCallback(fn ($booking, int $index): bool => 0 === $index); diff --git a/tests/Service/BookingSessionManagerTest.php b/tests/Service/BookingSessionManagerTest.php index 03b88e8..f0499c8 100644 --- a/tests/Service/BookingSessionManagerTest.php +++ b/tests/Service/BookingSessionManagerTest.php @@ -19,12 +19,16 @@ use Symfony\Component\HttpFoundation\Session\Storage\MockArraySessionStorage; class BookingSessionManagerTest extends TestCase { private TravelDataProvider $travelDataService; - private BookingSessionManager $service; + private ?BookingSessionManager $service = null; protected function setUp(): void { - $this->travelDataService = $this->createMock(TravelDataProvider::class); - $this->service = new BookingSessionManager($this->travelDataService); + $this->travelDataService = $this->createStub(TravelDataProvider::class); + } + + private function service(): BookingSessionManager + { + return $this->service ??= new BookingSessionManager($this->travelDataService); } public function testGetOrCreateBookingCreateDtoThrowsWhenSessionMissing(): void @@ -33,11 +37,13 @@ class BookingSessionManagerTest extends TestCase $this->expectException(BookingSessionNotFoundException::class); - $this->service->getOrCreateBookingCreateDto($request); + $this->service()->getOrCreateBookingCreateDto($request); } public function testSaveAndLoadBookingDtoHydratesTravel(): void { + $this->travelDataService = $this->createMock(TravelDataProvider::class); + $request = $this->createRequestWithSession(); $storedTravel = new Travel(); @@ -59,8 +65,8 @@ class BookingSessionManagerTest extends TestCase ->with(12, 34) ->willReturn($hydratedTravel); - $this->service->saveBookingDto($request, $bookingDto, BookingDto::MODE_CREATE); - $loadedDto = $this->service->getBookingDto($request, BookingDto::MODE_CREATE); + $this->service()->saveBookingDto($request, $bookingDto, BookingDto::MODE_CREATE); + $loadedDto = $this->service()->getBookingDto($request, BookingDto::MODE_CREATE); $this->assertNotNull($loadedDto); $this->assertSame($hydratedTravel, $loadedDto?->travel); @@ -76,11 +82,11 @@ class BookingSessionManagerTest extends TestCase $selection->quantity = 2; $bookingDto->roomSelections = [$selection]; - $first = $this->service->getOrCreateBaselineSnapshot($request, $bookingDto); + $first = $this->service()->getOrCreateBaselineSnapshot($request, $bookingDto); $this->assertSame([[1, 2]], $first); $selection->quantity = 5; - $second = $this->service->getOrCreateBaselineSnapshot($request, $bookingDto); + $second = $this->service()->getOrCreateBaselineSnapshot($request, $bookingDto); $this->assertSame($first, $second); $this->assertSame([[1, 2]], $second); @@ -90,19 +96,19 @@ class BookingSessionManagerTest extends TestCase { $request = $this->createRequestWithSession(); - $this->service->storeReturnUrl($request, 'javascript:alert(1)'); + $this->service()->storeReturnUrl($request, 'javascript:alert(1)'); - $this->assertSame(BookingSessionManager::DEFAULT_RETURN_URL, $this->service->getReturnUrl($request)); + $this->assertSame(BookingSessionManager::DEFAULT_RETURN_URL, $this->service()->getReturnUrl($request)); } public function testClearBookingSessionPreservesReturnUrl(): void { $request = $this->createRequestWithSession(); - $this->service->storeReturnUrl($request, 'https://example.test/after-booking'); - $this->service->clearBookingSession($request); + $this->service()->storeReturnUrl($request, 'https://example.test/after-booking'); + $this->service()->clearBookingSession($request); - $this->assertSame('https://example.test/after-booking', $this->service->getReturnUrl($request)); + $this->assertSame('https://example.test/after-booking', $this->service()->getReturnUrl($request)); } private function createRequestWithSession(): Request diff --git a/tests/Service/BookingSummaryAssemblerTest.php b/tests/Service/BookingSummaryAssemblerTest.php index 79fbf80..b7ff669 100644 --- a/tests/Service/BookingSummaryAssemblerTest.php +++ b/tests/Service/BookingSummaryAssemblerTest.php @@ -72,10 +72,10 @@ class BookingSummaryAssemblerTest extends TestCase private function createService(): BookingSummaryAssembler { - $priceCalculator = $this->createMock(BookingPriceCalculator::class); + $priceCalculator = $this->createStub(BookingPriceCalculator::class); $priceCalculator->method('calculateAllParticipantIndividualPrices')->willReturn([]); - $pricingAssembler = $this->createMock(BookingPricingAssembler::class); + $pricingAssembler = $this->createStub(BookingPricingAssembler::class); $pricingAssembler->method('getPricingBreakdown')->willReturn([ 'rooms' => [], 'services' => [], @@ -86,10 +86,10 @@ class BookingSummaryAssemblerTest extends TestCase return new BookingSummaryAssembler( $priceCalculator, $pricingAssembler, - $this->createMock(CmsDataProvider::class), - $this->createMock(HotelLoader::class), - $this->createMock(CountryDataProvider::class), - $this->createMock(CacheInterface::class), + $this->createStub(CmsDataProvider::class), + $this->createStub(HotelLoader::class), + $this->createStub(CountryDataProvider::class), + $this->createStub(CacheInterface::class), new NullLogger(), ); } diff --git a/tests/Service/ContingentSnapshotManagerTest.php b/tests/Service/ContingentSnapshotManagerTest.php index c99e432..1bb1775 100644 --- a/tests/Service/ContingentSnapshotManagerTest.php +++ b/tests/Service/ContingentSnapshotManagerTest.php @@ -17,27 +17,29 @@ use App\Repository\Groups\ContingentDayRepository; use App\Repository\Groups\ContingentSyncStateRepository; use App\Service\ContingentSnapshotManager; use Doctrine\ORM\EntityManagerInterface; -use PHPUnit\Framework\MockObject\MockObject; +use PHPUnit\Framework\MockObject\Stub; use PHPUnit\Framework\TestCase; use Psr\Log\LoggerInterface; class ContingentSnapshotManagerTest extends TestCase { - private ContingentsClient&MockObject $client; - private ContingentDayRepository&MockObject $dayRepository; - private ContingentSyncStateRepository&MockObject $syncStateRepository; - private EntityManagerInterface&MockObject $entityManager; + private ContingentsClient&Stub $client; + private ContingentDayRepository&Stub $dayRepository; + private ContingentSyncStateRepository&Stub $syncStateRepository; + private EntityManagerInterface&Stub $entityManager; protected function setUp(): void { - $this->client = $this->createMock(ContingentsClient::class); - $this->dayRepository = $this->createMock(ContingentDayRepository::class); - $this->syncStateRepository = $this->createMock(ContingentSyncStateRepository::class); - $this->entityManager = $this->createMock(EntityManagerInterface::class); + $this->client = $this->createStub(ContingentsClient::class); + $this->dayRepository = $this->createStub(ContingentDayRepository::class); + $this->syncStateRepository = $this->createStub(ContingentSyncStateRepository::class); + $this->entityManager = $this->createStub(EntityManagerInterface::class); } public function testAddsMissingDaysAndMarksSnapshotChanged(): void { + $this->entityManager = $this->createMock(EntityManagerInterface::class); + $this->dayRepository->method('findByAccommodationAndDateRange')->willReturn([]); $this->dayRepository->method('findStatusFingerprintParts')->willReturn(['2026-07-01:OK', '2026-07-02:BLOCKED']); $this->client->method('getContingentCalendar')->willReturn($this->response([ @@ -58,6 +60,8 @@ class ContingentSnapshotManagerTest extends TestCase public function testUpdatesChangedStatusAndRemovesVanishedDays(): void { + $this->entityManager = $this->createMock(EntityManagerInterface::class); + $existing = [ '2026-07-01' => $this->day('2026-07-01', ContingentStatus::Ok), '2026-07-02' => $this->day('2026-07-02', ContingentStatus::Ok), @@ -104,6 +108,9 @@ class ContingentSnapshotManagerTest extends TestCase public function testUpstreamFailureKeepsSnapshotAndRecordsError(): void { + $this->dayRepository = $this->createMock(ContingentDayRepository::class); + $this->entityManager = $this->createMock(EntityManagerInterface::class); + $state = new ContingentSyncState($this->accommodation()); $this->syncStateRepository->method('findOneByAccommodation')->willReturn($state); $this->client->method('getContingentCalendar')->willThrowException(new BpnConnectException('upstream down')); @@ -121,6 +128,8 @@ class ContingentSnapshotManagerTest extends TestCase public function testEmptyUpstreamResponseDoesNotWipeAPopulatedRange(): void { + $this->entityManager = $this->createMock(EntityManagerInterface::class); + $state = new ContingentSyncState($this->accommodation()); $this->syncStateRepository->method('findOneByAccommodation')->willReturn($state); $this->dayRepository->method('findByAccommodationAndDateRange')->willReturn([ @@ -193,7 +202,7 @@ class ContingentSnapshotManagerTest extends TestCase $this->dayRepository, $this->syncStateRepository, $this->entityManager, - $this->createMock(LoggerInterface::class), + $this->createStub(LoggerInterface::class), ); return $manager->sync( diff --git a/tests/Service/ContingentSnapshotReaderTest.php b/tests/Service/ContingentSnapshotReaderTest.php index 4f02a04..fece6e7 100644 --- a/tests/Service/ContingentSnapshotReaderTest.php +++ b/tests/Service/ContingentSnapshotReaderTest.php @@ -12,23 +12,25 @@ use App\Repository\Groups\ContingentDayRepository; use App\Repository\Groups\ContingentSyncStateRepository; use App\Service\ContingentSnapshotReader; use Carbon\CarbonImmutable; -use PHPUnit\Framework\MockObject\MockObject; +use PHPUnit\Framework\MockObject\Stub; use PHPUnit\Framework\TestCase; use Psr\Log\LoggerInterface; class ContingentSnapshotReaderTest extends TestCase { - private ContingentDayRepository&MockObject $dayRepository; - private ContingentSyncStateRepository&MockObject $syncStateRepository; + private ContingentDayRepository&Stub $dayRepository; + private ContingentSyncStateRepository&Stub $syncStateRepository; protected function setUp(): void { - $this->dayRepository = $this->createMock(ContingentDayRepository::class); - $this->syncStateRepository = $this->createMock(ContingentSyncStateRepository::class); + $this->dayRepository = $this->createStub(ContingentDayRepository::class); + $this->syncStateRepository = $this->createStub(ContingentSyncStateRepository::class); } public function testReturnsNullWhenNothingHasEverSynced(): void { + $this->dayRepository = $this->createMock(ContingentDayRepository::class); + $this->syncStateRepository->method('findOneByAccommodation')->willReturn(null); $this->dayRepository->expects(self::never())->method('findByHotelCodeAndDateRange'); @@ -37,6 +39,8 @@ class ContingentSnapshotReaderTest extends TestCase public function testReturnsNullWhenTheSnapshotIsStale(): void { + $this->dayRepository = $this->createMock(ContingentDayRepository::class); + $this->syncStateRepository->method('findOneByAccommodation')->willReturn($this->state('-7 hours')); $this->dayRepository->expects(self::never())->method('findByHotelCodeAndDateRange'); @@ -67,6 +71,8 @@ class ContingentSnapshotReaderTest extends TestCase public function testReturnsNullForAnAccommodationWithoutACalendarCode(): void { + $this->syncStateRepository = $this->createMock(ContingentSyncStateRepository::class); + $this->syncStateRepository->expects(self::never())->method('findOneByAccommodation'); self::assertNull($this->read(new Accommodation())); @@ -80,7 +86,7 @@ class ContingentSnapshotReaderTest extends TestCase $reader = new ContingentSnapshotReader( $this->dayRepository, $this->syncStateRepository, - $this->createMock(LoggerInterface::class), + $this->createStub(LoggerInterface::class), ); return $reader->statusesFor( diff --git a/tests/Service/DatabaseAnonymizerTest.php b/tests/Service/DatabaseAnonymizerTest.php index 779fd6e..68cbcd4 100644 --- a/tests/Service/DatabaseAnonymizerTest.php +++ b/tests/Service/DatabaseAnonymizerTest.php @@ -18,7 +18,7 @@ class DatabaseAnonymizerTest extends TestCase public function testAnonymizeEntityMethodsReuseSharedIdentityAndPreserveDraftTimestamps(): void { $service = new DatabaseAnonymizer( - $this->createMock(EntityManagerInterface::class), + $this->createStub(EntityManagerInterface::class), new NullLogger(), ); diff --git a/tests/Service/FamilyInsuranceAvailabilityCheckerTest.php b/tests/Service/FamilyInsuranceAvailabilityCheckerTest.php index 82856b9..10ccc58 100644 --- a/tests/Service/FamilyInsuranceAvailabilityCheckerTest.php +++ b/tests/Service/FamilyInsuranceAvailabilityCheckerTest.php @@ -21,8 +21,8 @@ class FamilyInsuranceAvailabilityCheckerTest extends TestCase protected function setUp(): void { - $this->insuranceService = $this->createMock(InsuranceManager::class); - $this->priceCalculatorService = $this->createMock(BookingPriceCalculator::class); + $this->insuranceService = $this->createStub(InsuranceManager::class); + $this->priceCalculatorService = $this->createStub(BookingPriceCalculator::class); $this->insuranceService->method('getSelectableInsurances') ->willReturnCallback(fn (Travel $travel) => $travel->insurances ?? []); diff --git a/tests/Service/NewsletterManagerTest.php b/tests/Service/NewsletterManagerTest.php index 4cff18a..9b11e77 100644 --- a/tests/Service/NewsletterManagerTest.php +++ b/tests/Service/NewsletterManagerTest.php @@ -15,6 +15,7 @@ use App\Repository\NewsletterConsentRepository; use App\Repository\NewsletterOptInRequestRepository; use App\Service\NewsletterManager; use Doctrine\ORM\EntityManagerInterface; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Psr\Log\NullLogger; @@ -152,10 +153,13 @@ class NewsletterManagerTest extends TestCase $mailjet->expects(self::never())->method('isSubscribed'); $mailjet->expects(self::once())->method('upsertContact')->with('customer@example.com', 'Mia', 'Muster'); + $ensureSubscribedCalls = []; $mailjet ->expects(self::exactly(2)) ->method('ensureSubscribed') - ->withConsecutive(['customer@example.com', 1], ['customer@example.com', 2]); + ->willReturnCallback(static function (string $email, ?int $listId) use (&$ensureSubscribedCalls): void { + $ensureSubscribedCalls[] = [$email, $listId]; + }); $consents->method('findActiveByEmail')->with('customer@example.com')->willReturn($existingConsent); $consents ->method('findOneByEmailAndListId') @@ -184,6 +188,7 @@ class NewsletterManagerTest extends TestCase 1 => NewsletterSubscriptionRequestResult::LIST_STATE_ALREADY_REGISTERED, 2 => NewsletterSubscriptionRequestResult::LIST_STATE_ALREADY_REGISTERED, ], $result->listStates); + self::assertSame([['customer@example.com', 1], ['customer@example.com', 2]], $ensureSubscribedCalls); } public function testApiRequestRejectsUnknownListIdsBeforeSideEffects(): void @@ -192,7 +197,7 @@ class NewsletterManagerTest extends TestCase $consents = $this->createMock(NewsletterConsentRepository::class); $entityManager = $this->createMock(EntityManagerInterface::class); $mailjet = $this->createMock(ApiClient::class); - $mailer = $this->createMock(Mailer::class); + $mailer = $this->createStub(Mailer::class); $mailjet->expects(self::never())->method('isSubscribed'); $mailjet->expects(self::never())->method('ensureSubscribed'); @@ -252,7 +257,7 @@ class NewsletterManagerTest extends TestCase $consents = $this->createMock(NewsletterConsentRepository::class); $entityManager = $this->createMock(EntityManagerInterface::class); $mailjet = $this->createMock(ApiClient::class); - $mailer = $this->createMock(Mailer::class); + $mailer = $this->createStub(Mailer::class); $mailjet->expects(self::never())->method('isSubscribed'); $mailjet->expects(self::once())->method('upsertContact')->with('customer@example.com', 'Mia', 'Muster'); @@ -274,7 +279,7 @@ class NewsletterManagerTest extends TestCase public function testDefaultRequestCreatesDefaultListPendingConfirmation(): void { $repository = $this->createMock(NewsletterOptInRequestRepository::class); - $consents = $this->createMock(NewsletterConsentRepository::class); + $consents = $this->createStub(NewsletterConsentRepository::class); $entityManager = $this->createMock(EntityManagerInterface::class); $mailjet = $this->createMock(ApiClient::class); $mailer = $this->createMock(Mailer::class); @@ -301,7 +306,7 @@ class NewsletterManagerTest extends TestCase public function testRequestConfirmationTruncatesNamesBeforePersisting(): void { $repository = $this->createMock(NewsletterOptInRequestRepository::class); - $consents = $this->createMock(NewsletterConsentRepository::class); + $consents = $this->createStub(NewsletterConsentRepository::class); $entityManager = $this->createMock(EntityManagerInterface::class); $mailjet = $this->createMock(ApiClient::class); $mailer = $this->createMock(Mailer::class); @@ -340,7 +345,7 @@ class NewsletterManagerTest extends TestCase $consents = $this->createMock(NewsletterConsentRepository::class); $entityManager = $this->createMock(EntityManagerInterface::class); $mailjet = $this->createMock(ApiClient::class); - $mailer = $this->createMock(Mailer::class); + $mailer = $this->createStub(Mailer::class); $repository->expects(self::once())->method('findByTokenHash')->with(hash('sha256', $token))->willReturn($confirmation); $repository->expects(self::never())->method('deletePendingByEmail'); @@ -371,16 +376,19 @@ class NewsletterManagerTest extends TestCase $consents = $this->createMock(NewsletterConsentRepository::class); $entityManager = $this->createMock(EntityManagerInterface::class); $mailjet = $this->createMock(ApiClient::class); - $mailer = $this->createMock(Mailer::class); + $mailer = $this->createStub(Mailer::class); $repository->expects(self::once())->method('findByTokenHash')->with(hash('sha256', $token))->willReturn($confirmation); $repository->expects(self::never())->method('deletePendingByEmail'); $consents->method('findOneByEmailAndListId')->willReturn(null); $consents->method('findByEmailAndListIds')->with('customer@example.com', [1, 2])->willReturn([]); + $ensureSubscribedCalls = []; $mailjet ->expects(self::exactly(2)) ->method('ensureSubscribed') - ->withConsecutive(['customer@example.com', 1], ['customer@example.com', 2]); + ->willReturnCallback(static function (string $email, ?int $listId) use (&$ensureSubscribedCalls): void { + $ensureSubscribedCalls[] = [$email, $listId]; + }); $entityManager->expects(self::exactly(2))->method('persist')->with(self::isInstanceOf(NewsletterConsent::class)); $entityManager->expects(self::once())->method('remove')->with($confirmation); $entityManager->expects(self::once())->method('flush'); @@ -389,6 +397,7 @@ class NewsletterManagerTest extends TestCase ->confirmToken($token); self::assertSame(NewsletterConfirmationResult::STATUS_CONFIRMED, $result->status); + self::assertSame([['customer@example.com', 1], ['customer@example.com', 2]], $ensureSubscribedCalls); } public function testConfirmationEntityNormalizesMailjetListIds(): void @@ -403,9 +412,7 @@ class NewsletterManagerTest extends TestCase self::assertSame([1, 2], $confirmation->getMailjetListIds()); } - /** - * @dataProvider invalidEntityMailjetListIdProvider - */ + #[DataProvider('invalidEntityMailjetListIdProvider')] public function testConfirmationEntityRejectsInvalidMailjetListIds(mixed $mailjetListId): void { $this->expectException(\InvalidArgumentException::class); diff --git a/tests/Service/ParticipantCardAssemblerTest.php b/tests/Service/ParticipantCardAssemblerTest.php index b516126..7e2112a 100644 --- a/tests/Service/ParticipantCardAssemblerTest.php +++ b/tests/Service/ParticipantCardAssemblerTest.php @@ -4,9 +4,6 @@ declare(strict_types=1); namespace App\Tests\Service; -use Symfony\Component\Validator\ConstraintViolationListInterface; -use Symfony\Component\Validator\ConstraintViolationInterface; -use Symfony\Component\Validator\ConstraintViolationList; use App\BusProNet\Model\Booking; use App\BusProNet\Model\Room; use App\BusProNet\Model\Surcharge; @@ -18,19 +15,26 @@ use App\Form\Model\ParticipantEditDto; use App\Service\BookingPriceCalculator; use App\Service\ParticipantCardAssembler; use PHPUnit\Framework\TestCase; +use Symfony\Component\Validator\ConstraintViolationInterface; +use Symfony\Component\Validator\ConstraintViolationList; +use Symfony\Component\Validator\ConstraintViolationListInterface; use Symfony\Component\Validator\Validator\ValidatorInterface; class ParticipantCardAssemblerTest extends TestCase { - private ParticipantCardAssembler $service; + private ?ParticipantCardAssembler $service = null; private BookingPriceCalculator $priceCalculator; private ValidatorInterface $validator; protected function setUp(): void { - $this->priceCalculator = $this->createMock(BookingPriceCalculator::class); - $this->validator = $this->createMock(ValidatorInterface::class); - $this->service = new ParticipantCardAssembler( + $this->priceCalculator = $this->createStub(BookingPriceCalculator::class); + $this->validator = $this->createStub(ValidatorInterface::class); + } + + private function service(): ParticipantCardAssembler + { + return $this->service ??= new ParticipantCardAssembler( $this->priceCalculator, $this->validator ); @@ -38,6 +42,8 @@ class ParticipantCardAssemblerTest extends TestCase public function testGetCardDataWithFullParticipantData(): void { + $this->priceCalculator = $this->createMock(BookingPriceCalculator::class); + // Create test room $room = new Room(); $room->id = 1; @@ -63,7 +69,7 @@ class ParticipantCardAssemblerTest extends TestCase ->with($bookingDto) ->willReturn([450.50]); - $result = $this->service->getCardData($bookingDto, 0); + $result = $this->service()->getCardData($bookingDto, 0); $this->assertSame('Max Mustermann', $result->name); $this->assertSame('Doppelzimmer', $result->roomName); @@ -88,7 +94,7 @@ class ParticipantCardAssemblerTest extends TestCase ->method('calculateAllParticipantIndividualPrices') ->willReturn([0.0]); - $result = $this->service->getCardData($bookingDto, 0); + $result = $this->service()->getCardData($bookingDto, 0); $this->assertSame('Max', $result->name); } @@ -110,7 +116,7 @@ class ParticipantCardAssemblerTest extends TestCase ->method('calculateAllParticipantIndividualPrices') ->willReturn([0.0]); - $result = $this->service->getCardData($bookingDto, 0); + $result = $this->service()->getCardData($bookingDto, 0); $this->assertSame('Anmelder:in', $result->name); } @@ -132,7 +138,7 @@ class ParticipantCardAssemblerTest extends TestCase ->method('calculateAllParticipantIndividualPrices') ->willReturn([0.0]); - $result = $this->service->getCardData($bookingDto, 0); + $result = $this->service()->getCardData($bookingDto, 0); $this->assertSame('Anmelder:in', $result->name); } @@ -154,7 +160,7 @@ class ParticipantCardAssemblerTest extends TestCase ->method('calculateAllParticipantIndividualPrices') ->willReturn([0.0]); - $result = $this->service->getCardData($bookingDto, 0); + $result = $this->service()->getCardData($bookingDto, 0); $this->assertSame('Kein Zimmer zugewiesen', $result->roomName); } @@ -176,7 +182,7 @@ class ParticipantCardAssemblerTest extends TestCase ->method('calculateAllParticipantIndividualPrices') ->willReturn([0.0]); - $result = $this->service->getCardData($bookingDto, 0); + $result = $this->service()->getCardData($bookingDto, 0); $this->assertSame('Unbekanntes Zimmer', $result->roomName); } @@ -198,7 +204,7 @@ class ParticipantCardAssemblerTest extends TestCase ->method('calculateAllParticipantIndividualPrices') ->willReturn([0.0]); - $result = $this->service->getCardData($bookingDto, 0); + $result = $this->service()->getCardData($bookingDto, 0); // When no room assigned and price is zero, display dash (incomplete configuration) $this->assertNull($result->price->amount); @@ -228,7 +234,7 @@ class ParticipantCardAssemblerTest extends TestCase ->method('calculateAllParticipantIndividualPrices') ->willReturn([0.0]); - $result = $this->service->getCardData($bookingDto, 0); + $result = $this->service()->getCardData($bookingDto, 0); // When room is assigned but price is zero, display formatted zero price $this->assertSame(0.0, $result->price->amount); @@ -244,11 +250,13 @@ class ParticipantCardAssemblerTest extends TestCase $this->expectException(\InvalidArgumentException::class); $this->expectExceptionMessage('Participant at index 0 does not exist'); - $this->service->getCardData($bookingDto, 0); + $this->service()->getCardData($bookingDto, 0); } public function testGetAllCardsDataWithMultipleParticipants(): void { + $this->priceCalculator = $this->createMock(BookingPriceCalculator::class); + // Create test rooms $room1 = new Room(); $room1->id = 1; @@ -287,7 +295,7 @@ class ParticipantCardAssemblerTest extends TestCase ->with($bookingDto) ->willReturn([450.0, 500.0, 480.0]); - $result = $this->service->getAllCardsData($bookingDto); + $result = $this->service()->getAllCardsData($bookingDto); $this->assertCount(3, $result); @@ -312,6 +320,8 @@ class ParticipantCardAssemblerTest extends TestCase public function testGetAllCardsDataUsesCanceledSurchargesBeforePrecomputedActivePrices(): void { + $this->priceCalculator = $this->createMock(BookingPriceCalculator::class); + $room = new Room(); $room->id = 1; $room->label = 'Doppelzimmer'; @@ -347,7 +357,7 @@ class ParticipantCardAssemblerTest extends TestCase ->with($bookingDto) ->willReturn([0 => 450.0, 1 => 999.0]); - $result = $this->service->getAllCardsData($bookingDto); + $result = $this->service()->getAllCardsData($bookingDto); $this->assertSame(450.0, $result[0]->price->amount); $this->assertSame(75.0, $result[1]->price->amount); @@ -360,7 +370,7 @@ class ParticipantCardAssemblerTest extends TestCase $bookingDto = new BookingDto($travel, 1); $bookingDto->participants = []; - $result = $this->service->getAllCardsData($bookingDto); + $result = $this->service()->getAllCardsData($bookingDto); $this->assertEmpty($result); } @@ -381,7 +391,7 @@ class ParticipantCardAssemblerTest extends TestCase ->method('calculateAllParticipantIndividualPrices') ->willReturn([1234.56]); - $result = $this->service->getCardData($bookingDto, 0); + $result = $this->service()->getCardData($bookingDto, 0); $this->assertSame(1234.56, $result->price->amount); $this->assertFalse($result->price->showDash); @@ -403,9 +413,9 @@ class ParticipantCardAssemblerTest extends TestCase ->method('calculateAllParticipantIndividualPrices') ->willReturn([0.0, 0.0, 0.0]); - $result1 = $this->service->getCardData($bookingDto, 0); - $result2 = $this->service->getCardData($bookingDto, 1); - $result3 = $this->service->getCardData($bookingDto, 2); + $result1 = $this->service()->getCardData($bookingDto, 0); + $result2 = $this->service()->getCardData($bookingDto, 1); + $result3 = $this->service()->getCardData($bookingDto, 2); $this->assertSame('Anmelder:in', $result1->name); $this->assertSame('Teilnehmer:in', $result2->name); @@ -414,6 +424,8 @@ class ParticipantCardAssemblerTest extends TestCase public function testGetCardDataWithValidationReturnsValidCard(): void { + $this->validator = $this->createMock(ValidatorInterface::class); + $room = new Room(); $room->id = 1; $room->label = 'Doppelzimmer'; @@ -445,7 +457,7 @@ class ParticipantCardAssemblerTest extends TestCase ->method('validate') ->willReturn($violations); - $result = $this->service->getCardDataWithValidation($bookingDto, 0); + $result = $this->service()->getCardDataWithValidation($bookingDto, 0); $this->assertSame('Max Mustermann', $result->name); $this->assertSame('Doppelzimmer', $result->roomName); @@ -457,6 +469,8 @@ class ParticipantCardAssemblerTest extends TestCase public function testGetCardDataWithValidationReturnsInvalidCard(): void { + $this->validator = $this->createMock(ValidatorInterface::class); + $travel = new Travel(); $travel->rooms = []; @@ -486,7 +500,7 @@ class ParticipantCardAssemblerTest extends TestCase ->method('validate') ->willReturn($violations); - $result = $this->service->getCardDataWithValidation($bookingDto, 0); + $result = $this->service()->getCardDataWithValidation($bookingDto, 0); $this->assertSame('Max Mustermann', $result->name); $this->assertFalse($result->isValid); @@ -496,6 +510,9 @@ class ParticipantCardAssemblerTest extends TestCase public function testGetAllCardsDataWithValidationReturnsAllCards(): void { + $this->priceCalculator = $this->createMock(BookingPriceCalculator::class); + $this->validator = $this->createMock(ValidatorInterface::class); + $room = new Room(); $room->id = 1; $room->label = 'Doppelzimmer'; @@ -534,7 +551,7 @@ class ParticipantCardAssemblerTest extends TestCase ->method('validate') ->willReturn($violations); - $result = $this->service->getAllCardsDataWithValidation($bookingDto); + $result = $this->service()->getAllCardsDataWithValidation($bookingDto); $this->assertCount(2, $result); $this->assertTrue($result[0]->isValid); @@ -545,6 +562,8 @@ class ParticipantCardAssemblerTest extends TestCase public function testGetCardDataWithValidationCanForceStrictRequiredInEditMode(): void { + $this->validator = $this->createMock(ValidatorInterface::class); + $travel = new Travel(); $travel->rooms = []; @@ -556,7 +575,7 @@ class ParticipantCardAssemblerTest extends TestCase $bookingDto = new BookingDto($travel, 1); $bookingDto->agencyCode = AgencyLoader::INTERNAL_AGENCY_CODE; - $bookingDto->booking = new \App\BusProNet\Model\Booking(); + $bookingDto->booking = new Booking(); $bookingDto->participants = [$participant]; $this->priceCalculator @@ -574,16 +593,15 @@ class ParticipantCardAssemblerTest extends TestCase ->expects($this->once()) ->method('validate') ->with( - $this->isInstanceOf(\App\Form\Model\ParticipantEditDto::class), + $this->isInstanceOf(ParticipantEditDto::class), null, ['booking_edit', 'strict_required'] ) ->willReturn($violations); - $result = $this->service->getCardDataWithValidation($bookingDto, 0, true); + $result = $this->service()->getCardDataWithValidation($bookingDto, 0, true); $this->assertFalse($result->isValid); $this->assertSame(['Bitte angeben'], $result->errorMessages); } - } diff --git a/tests/Service/ParticipantDataPrefillerTest.php b/tests/Service/ParticipantDataPrefillerTest.php index ae68205..8a98713 100644 --- a/tests/Service/ParticipantDataPrefillerTest.php +++ b/tests/Service/ParticipantDataPrefillerTest.php @@ -23,15 +23,18 @@ class ParticipantDataPrefillerTest extends TestCase private ApiClient $apiClient; private Crypt $crypt; private LoggerInterface $logger; - private ParticipantDataPrefiller $service; + private ?ParticipantDataPrefiller $service = null; protected function setUp(): void { - $this->apiClient = $this->createMock(ApiClient::class); - $this->crypt = $this->createMock(Crypt::class); - $this->logger = $this->createMock(LoggerInterface::class); + $this->apiClient = $this->createStub(ApiClient::class); + $this->crypt = $this->createStub(Crypt::class); + $this->logger = $this->createStub(LoggerInterface::class); + } - $this->service = new ParticipantDataPrefiller( + private function service(): ParticipantDataPrefiller + { + return $this->service ??= new ParticipantDataPrefiller( $this->apiClient, $this->crypt, $this->logger @@ -40,6 +43,9 @@ class ParticipantDataPrefillerTest extends TestCase public function testPrepopulateApplicantWithCompletePersonalData(): void { + $this->apiClient = $this->createMock(ApiClient::class); + $this->crypt = $this->createMock(Crypt::class); + $user = $this->createUser('test@example.com', 'encrypted_password'); $applicant = new ParticipantDto(); $applicant->index = 0; @@ -56,7 +62,7 @@ class ParticipantDataPrefillerTest extends TestCase ->with('test@example.com', 'decrypted_password') ->willReturn($personalData); - $result = $this->service->prefillApplicantFromUser($user, $applicant); + $result = $this->service()->prefillApplicantFromUser($user, $applicant); // BPN API IDs for linking to existing records $this->assertSame(12345, $result->addressId); @@ -88,6 +94,9 @@ class ParticipantDataPrefillerTest extends TestCase public function testPrepopulateApplicantWithPartialPersonalData(): void { + $this->apiClient = $this->createMock(ApiClient::class); + $this->crypt = $this->createMock(Crypt::class); + $user = $this->createUser('test@example.com', 'encrypted_password'); $applicant = new ParticipantDto(); $applicant->index = 0; @@ -102,7 +111,7 @@ class ParticipantDataPrefillerTest extends TestCase ->method('getPersonalData') ->willReturn($personalData); - $result = $this->service->prefillApplicantFromUser($user, $applicant); + $result = $this->service()->prefillApplicantFromUser($user, $applicant); // Required fields should be populated $this->assertSame('Jane', $result->firstName); @@ -123,6 +132,10 @@ class ParticipantDataPrefillerTest extends TestCase public function testPrepopulateApplicantWithApiNotificationError(): void { + $this->apiClient = $this->createMock(ApiClient::class); + $this->crypt = $this->createMock(Crypt::class); + $this->logger = $this->createMock(LoggerInterface::class); + $user = $this->createUser('test@example.com', 'encrypted_password'); $applicant = new ParticipantDto(); $applicant->index = 0; @@ -148,7 +161,7 @@ class ParticipantDataPrefillerTest extends TestCase $this->logger->expects($this->never()) ->method('info'); - $result = $this->service->prefillApplicantFromUser($user, $applicant); + $result = $this->service()->prefillApplicantFromUser($user, $applicant); // Should return unchanged applicant $this->assertNull($result->firstName); @@ -158,6 +171,10 @@ class ParticipantDataPrefillerTest extends TestCase public function testPrepopulateApplicantWithDecryptionException(): void { + $this->apiClient = $this->createMock(ApiClient::class); + $this->crypt = $this->createMock(Crypt::class); + $this->logger = $this->createMock(LoggerInterface::class); + $user = $this->createUser('test@example.com', 'encrypted_password'); $applicant = new ParticipantDto(); $applicant->index = 0; @@ -176,7 +193,7 @@ class ParticipantDataPrefillerTest extends TestCase 'email' => 'test@example.com', ]); - $result = $this->service->prefillApplicantFromUser($user, $applicant); + $result = $this->service()->prefillApplicantFromUser($user, $applicant); // Should return unchanged applicant $this->assertNull($result->firstName); @@ -186,6 +203,10 @@ class ParticipantDataPrefillerTest extends TestCase public function testPrepopulateApplicantWithApiException(): void { + $this->apiClient = $this->createMock(ApiClient::class); + $this->crypt = $this->createMock(Crypt::class); + $this->logger = $this->createMock(LoggerInterface::class); + $user = $this->createUser('test@example.com', 'encrypted_password'); $applicant = new ParticipantDto(); $applicant->index = 0; @@ -205,7 +226,7 @@ class ParticipantDataPrefillerTest extends TestCase 'email' => 'test@example.com', ]); - $result = $this->service->prefillApplicantFromUser($user, $applicant); + $result = $this->service()->prefillApplicantFromUser($user, $applicant); // Should return unchanged applicant $this->assertNull($result->firstName); @@ -215,6 +236,9 @@ class ParticipantDataPrefillerTest extends TestCase public function testPrepopulatePreservesBookingSpecificFields(): void { + $this->apiClient = $this->createMock(ApiClient::class); + $this->crypt = $this->createMock(Crypt::class); + $user = $this->createUser('test@example.com', 'encrypted_password'); $applicant = new ParticipantDto(); $applicant->index = 0; @@ -231,7 +255,7 @@ class ParticipantDataPrefillerTest extends TestCase ->method('getPersonalData') ->willReturn($personalData); - $result = $this->service->prefillApplicantFromUser($user, $applicant); + $result = $this->service()->prefillApplicantFromUser($user, $applicant); // Personal data should be updated $this->assertSame('John', $result->firstName); @@ -250,8 +274,8 @@ class ParticipantDataPrefillerTest extends TestCase $filled = new ParticipantDto(); $filled->firstName = 'Already set'; - $this->assertTrue($this->service->shouldPrefillApplicant($fresh)); - $this->assertFalse($this->service->shouldPrefillApplicant($filled)); + $this->assertTrue($this->service()->shouldPrefillApplicant($fresh)); + $this->assertFalse($this->service()->shouldPrefillApplicant($filled)); } public function testDummyTokenMatchesInCreateAndEditModes(): void @@ -259,8 +283,8 @@ class ParticipantDataPrefillerTest extends TestCase $participant = new ParticipantDto(); $participant->lastName = ParticipantDataPrefiller::TOKEN; - $this->assertTrue($this->service->isDummyDataFillRequested($participant, BookingDto::MODE_CREATE)); - $this->assertTrue($this->service->isDummyDataFillRequested($participant, BookingDto::MODE_EDIT)); + $this->assertTrue($this->service()->isDummyDataFillRequested($participant, BookingDto::MODE_CREATE)); + $this->assertTrue($this->service()->isDummyDataFillRequested($participant, BookingDto::MODE_EDIT)); } public function testFillDummyParticipantSetsGeneratedData(): void @@ -268,7 +292,7 @@ class ParticipantDataPrefillerTest extends TestCase CarbonImmutable::setTestNow(CarbonImmutable::create(2026, 1, 15, 14, 30)); $participant = new ParticipantDto(); - $this->service->fillDummyParticipant($participant, 0); + $this->service()->fillDummyParticipant($participant, 0); $this->assertSame('Vorname 1', $participant->firstName); $this->assertSame('Muster 1 14:30', $participant->lastName); diff --git a/tests/Service/RoomAssignerTest.php b/tests/Service/RoomAssignerTest.php index 5ff09c2..3ef99a5 100644 --- a/tests/Service/RoomAssignerTest.php +++ b/tests/Service/RoomAssignerTest.php @@ -11,6 +11,7 @@ use App\Form\Model\BookingDto; use App\Form\Model\ParticipantDto; use App\Form\Model\RoomSelectionDto; use App\Service\RoomAssigner; +use PHPUnit\Framework\Attributes\Test; use PHPUnit\Framework\TestCase; /** @@ -25,9 +26,7 @@ class RoomAssignerTest extends TestCase $this->service = new RoomAssigner(); } - /** - * @test - */ + #[Test] public function shouldAutoAssignRoomsReturnsTrueForSingleRoomType(): void { $bookingDto = $this->createBookingDtoWithRoomSelections([ @@ -39,9 +38,7 @@ class RoomAssignerTest extends TestCase self::assertTrue($result, 'Should auto-assign when exactly one room type is selected'); } - /** - * @test - */ + #[Test] public function shouldAutoAssignRoomsReturnsFalseForMultipleRoomTypes(): void { $bookingDto = $this->createBookingDtoWithRoomSelections([ @@ -54,9 +51,7 @@ class RoomAssignerTest extends TestCase self::assertFalse($result, 'Should not auto-assign when multiple room types are selected'); } - /** - * @test - */ + #[Test] public function shouldAutoAssignRoomsReturnsFalseForNoRoomSelections(): void { $bookingDto = $this->createBookingDtoWithRoomSelections([]); @@ -66,9 +61,7 @@ class RoomAssignerTest extends TestCase self::assertFalse($result, 'Should not auto-assign when no rooms are selected'); } - /** - * @test - */ + #[Test] public function shouldAutoAssignRoomsIgnoresZeroQuantityRooms(): void { $bookingDto = $this->createBookingDtoWithRoomSelections([ @@ -82,9 +75,7 @@ class RoomAssignerTest extends TestCase self::assertTrue($result, 'Should treat zero/null quantity as not selected'); } - /** - * @test - */ + #[Test] public function assignParticipantsToRoomsWorksWithSingleRoomType(): void { $bookingDto = $this->createBookingDtoWithRoomSelections([ @@ -117,9 +108,7 @@ class RoomAssignerTest extends TestCase self::assertSame(100, $bookingDto->participants[3]->assignedRoomId); } - /** - * @test - */ + #[Test] public function assignParticipantsToRoomsSkipsAssignmentWithMultipleRoomTypes(): void { $bookingDto = $this->createBookingDtoWithRoomSelections([ @@ -159,9 +148,7 @@ class RoomAssignerTest extends TestCase self::assertNull($bookingDto->participants[3]->assignedRoomId); } - /** - * @test - */ + #[Test] public function assignParticipantsToRoomsHandlesMixedRoomCapacities(): void { $bookingDto = $this->createBookingDtoWithRoomSelections([ @@ -190,9 +177,7 @@ class RoomAssignerTest extends TestCase self::assertSame(100, $bookingDto->participants[1]->assignedRoomId); } - /** - * @test - */ + #[Test] public function validateAndResetInvalidAssignmentsResetsOrphanedAssignments(): void { // Create DTO with only room 100 selected @@ -221,9 +206,7 @@ class RoomAssignerTest extends TestCase self::assertNull($bookingDto->participants[3]->assignedRoomId, 'Invalid assignment should be reset to null'); } - /** - * @test - */ + #[Test] public function validateAndResetInvalidAssignmentsReturnsFalseWhenAllValid(): void { $bookingDto = $this->createBookingDtoWithRoomSelections([ @@ -245,9 +228,7 @@ class RoomAssignerTest extends TestCase self::assertSame(100, $bookingDto->participants[1]->assignedRoomId); } - /** - * @test - */ + #[Test] public function validateAndResetInvalidAssignmentsHandlesNullAssignments(): void { $bookingDto = $this->createBookingDtoWithRoomSelections([ @@ -267,9 +248,7 @@ class RoomAssignerTest extends TestCase self::assertFalse($result, 'Should return false when only null assignments exist'); } - /** - * @test - */ + #[Test] public function validateAndResetInvalidAssignmentsHandlesEmptySelectedRooms(): void { // All rooms have quantity 0 (none selected) diff --git a/tests/Service/TravelDataProviderTest.php b/tests/Service/TravelDataProviderTest.php index 91cc4d5..14cbbef 100644 --- a/tests/Service/TravelDataProviderTest.php +++ b/tests/Service/TravelDataProviderTest.php @@ -18,7 +18,7 @@ use Symfony\Contracts\Cache\CacheInterface; class TravelDataProviderTest extends TestCase { - private TravelDataProvider $service; + private ?TravelDataProvider $service = null; private TravelLoader $travelLoader; private ApiClient $apiClient; private CacheInterface $cache; @@ -29,15 +29,18 @@ class TravelDataProviderTest extends TestCase protected function setUp(): void { - $this->travelLoader = $this->createMock(TravelLoader::class); - $this->apiClient = $this->createMock(ApiClient::class); - $this->cache = $this->createMock(CacheInterface::class); - $this->logger = $this->createMock(LoggerInterface::class); - $this->travelSnapshotService = $this->createMock(TravelSnapshotManager::class); - $this->travelLookupService = $this->createMock(TravelIndex::class); - $this->travelEnrichmentService = $this->createMock(TravelEnricher::class); + $this->travelLoader = $this->createStub(TravelLoader::class); + $this->apiClient = $this->createStub(ApiClient::class); + $this->cache = $this->createStub(CacheInterface::class); + $this->logger = $this->createStub(LoggerInterface::class); + $this->travelSnapshotService = $this->createStub(TravelSnapshotManager::class); + $this->travelLookupService = $this->createStub(TravelIndex::class); + $this->travelEnrichmentService = $this->createStub(TravelEnricher::class); + } - $this->service = new TravelDataProvider( + private function service(): TravelDataProvider + { + return $this->service ??= new TravelDataProvider( $this->travelLoader, $this->apiClient, $this->cache, @@ -52,6 +55,10 @@ class TravelDataProviderTest extends TestCase public function testGetTravelDataFromXmlSuccess(): void { + $this->travelLoader = $this->createMock(TravelLoader::class); + $this->travelSnapshotService = $this->createMock(TravelSnapshotManager::class); + $this->travelEnrichmentService = $this->createMock(TravelEnricher::class); + $dateId = 12345; $hotelId = 67890; $travel = new Travel(); @@ -75,13 +82,17 @@ class TravelDataProviderTest extends TestCase ->method('upsertFromTravel') ->with($travel); - $result = $this->service->getTravelDataFromXml($dateId, $hotelId); + $result = $this->service()->getTravelDataFromXml($dateId, $hotelId); $this->assertSame($travel, $result); } public function testGetTravelDataFromXmlSkipsSnapshotWhenEnrichmentFails(): void { + $this->travelLoader = $this->createMock(TravelLoader::class); + $this->travelSnapshotService = $this->createMock(TravelSnapshotManager::class); + $this->travelEnrichmentService = $this->createMock(TravelEnricher::class); + $dateId = 12345; $hotelId = 67890; $travel = new Travel(); @@ -104,13 +115,16 @@ class TravelDataProviderTest extends TestCase ->expects($this->never()) ->method('upsertFromTravel'); - $result = $this->service->getTravelDataFromXml($dateId, $hotelId); + $result = $this->service()->getTravelDataFromXml($dateId, $hotelId); $this->assertSame($travel, $result); } public function testGetTravelDataFromXmlNotFound(): void { + $this->travelLoader = $this->createMock(TravelLoader::class); + $this->travelEnrichmentService = $this->createMock(TravelEnricher::class); + $dateId = 12345; $hotelId = 67890; @@ -125,11 +139,16 @@ class TravelDataProviderTest extends TestCase ->method('enrichFromXml'); $this->expectException(TravelNotFoundException::class); - $this->service->getTravelDataFromXml($dateId, $hotelId); + $this->service()->getTravelDataFromXml($dateId, $hotelId); } public function testGetTravelDataFromApiSuccess(): void { + $this->apiClient = $this->createMock(ApiClient::class); + $this->travelSnapshotService = $this->createMock(TravelSnapshotManager::class); + $this->travelLookupService = $this->createMock(TravelIndex::class); + $this->travelEnrichmentService = $this->createMock(TravelEnricher::class); + $dateId = 12345; $hotelId = 67890; $productId = 555; @@ -159,13 +178,16 @@ class TravelDataProviderTest extends TestCase ->method('upsertFromTravel') ->with($travel); - $result = $this->service->getTravelDataFromApi($dateId, $hotelId); + $result = $this->service()->getTravelDataFromApi($dateId, $hotelId); $this->assertSame($travel, $result); } public function testGetTravelDataFromApiSnapshotFailureDoesNotDiscardApiTravel(): void { + $this->logger = $this->createMock(LoggerInterface::class); + $this->travelSnapshotService = $this->createMock(TravelSnapshotManager::class); + $dateId = 12345; $hotelId = 67890; $productId = 555; @@ -191,7 +213,7 @@ class TravelDataProviderTest extends TestCase ->method('warning') ->with('Failed to persist travel snapshot after API load', $this->arrayHasKey('dateId')); - $result = $this->service->getTravelDataFromApi($dateId, $hotelId); + $result = $this->service()->getTravelDataFromApi($dateId, $hotelId); $this->assertNotNull($result); $this->assertSame($travel, $result); @@ -199,6 +221,9 @@ class TravelDataProviderTest extends TestCase public function testGetTravelDataFromApiCannotMapDateId(): void { + $this->apiClient = $this->createMock(ApiClient::class); + $this->travelLookupService = $this->createMock(TravelIndex::class); + $dateId = 12345; $hotelId = 67890; @@ -212,13 +237,15 @@ class TravelDataProviderTest extends TestCase ->expects($this->never()) ->method('getTravelData'); - $result = $this->service->getTravelDataFromApi($dateId, $hotelId); + $result = $this->service()->getTravelDataFromApi($dateId, $hotelId); $this->assertNull($result); } public function testExistsLocallyDelegatesToLookupService(): void { + $this->travelLookupService = $this->createMock(TravelIndex::class); + $dateId = 12345; $hotelId = 67890; @@ -228,11 +255,13 @@ class TravelDataProviderTest extends TestCase ->with($dateId, $hotelId) ->willReturn(true); - $this->assertTrue($this->service->existsLocally($dateId, $hotelId)); + $this->assertTrue($this->service()->existsLocally($dateId, $hotelId)); } public function testGetAvailableSourcesDelegatesToLookupService(): void { + $this->travelLookupService = $this->createMock(TravelIndex::class); + $dateId = 12345; $hotelId = 67890; $expected = ['local' => true, 'remote' => true]; @@ -243,11 +272,13 @@ class TravelDataProviderTest extends TestCase ->with($dateId, $hotelId) ->willReturn($expected); - $this->assertSame($expected, $this->service->getAvailableSources($dateId, $hotelId)); + $this->assertSame($expected, $this->service()->getAvailableSources($dateId, $hotelId)); } public function testGenerateFilesMapDelegatesToLookupService(): void { + $this->travelLookupService = $this->createMock(TravelIndex::class); + $mapping = [12345 => ['id' => 12345, 'hotels' => []]]; $this->travelLookupService @@ -255,11 +286,15 @@ class TravelDataProviderTest extends TestCase ->method('generateFilesMap') ->willReturn($mapping); - $this->assertSame($mapping, $this->service->generateFilesMap()); + $this->assertSame($mapping, $this->service()->generateFilesMap()); } public function testGetTravelDataFromLocalPrefersSnapshot(): void { + $this->travelLoader = $this->createMock(TravelLoader::class); + $this->travelSnapshotService = $this->createMock(TravelSnapshotManager::class); + $this->travelEnrichmentService = $this->createMock(TravelEnricher::class); + $dateId = 12345; $hotelId = 67890; $travel = new Travel(); @@ -281,13 +316,17 @@ class TravelDataProviderTest extends TestCase ->method('patchInsurances') ->with($travel); - $result = $this->service->getTravelDataFromLocal($dateId, $hotelId); + $result = $this->service()->getTravelDataFromLocal($dateId, $hotelId); $this->assertSame($travel, $result); } public function testGetTravelDataFromLocalFallsBackToXmlWhenSnapshotMissing(): void { + $this->travelLoader = $this->createMock(TravelLoader::class); + $this->travelSnapshotService = $this->createMock(TravelSnapshotManager::class); + $this->travelEnrichmentService = $this->createMock(TravelEnricher::class); + $dateId = 12345; $hotelId = 67890; $travel = new Travel(); @@ -322,13 +361,16 @@ class TravelDataProviderTest extends TestCase ->method('patchInsurances') ->with($travel); - $result = $this->service->getTravelDataFromLocal($dateId, $hotelId); + $result = $this->service()->getTravelDataFromLocal($dateId, $hotelId); $this->assertSame($travel, $result); } public function testGetTravelDataFromLocalPropagatesTravelNotFoundFromXmlFallback(): void { + $this->travelLoader = $this->createMock(TravelLoader::class); + $this->travelSnapshotService = $this->createMock(TravelSnapshotManager::class); + $dateId = 12345; $hotelId = 67890; @@ -345,11 +387,15 @@ class TravelDataProviderTest extends TestCase ->willThrowException(new TravelNotFoundException($dateId)); $this->expectException(TravelNotFoundException::class); - $this->service->getTravelDataFromLocal($dateId, $hotelId); + $this->service()->getTravelDataFromLocal($dateId, $hotelId); } public function testSnapshotLoadFailureFallsBackToXml(): void { + $this->travelLoader = $this->createMock(TravelLoader::class); + $this->logger = $this->createMock(LoggerInterface::class); + $this->travelSnapshotService = $this->createMock(TravelSnapshotManager::class); + $dateId = 12345; $hotelId = 67890; $travel = new Travel(); @@ -373,13 +419,17 @@ class TravelDataProviderTest extends TestCase ->with($dateId, $hotelId) ->willReturn($travel); - $result = $this->service->getTravelDataFromLocal($dateId, $hotelId); + $result = $this->service()->getTravelDataFromLocal($dateId, $hotelId); $this->assertSame($travel, $result); } public function testSnapshotPersistenceFailureDoesNotDiscardXmlTravel(): void { + $this->travelLoader = $this->createMock(TravelLoader::class); + $this->logger = $this->createMock(LoggerInterface::class); + $this->travelSnapshotService = $this->createMock(TravelSnapshotManager::class); + $dateId = 12345; $hotelId = 67890; $travel = new Travel(); @@ -406,7 +456,7 @@ class TravelDataProviderTest extends TestCase ->method('warning') ->with('Failed to persist travel snapshot after XML load', $this->arrayHasKey('dateId')); - $result = $this->service->getTravelDataFromXml($dateId, $hotelId); + $result = $this->service()->getTravelDataFromXml($dateId, $hotelId); $this->assertNotNull($result); $this->assertSame($travel, $result); @@ -414,6 +464,10 @@ class TravelDataProviderTest extends TestCase public function testGetTravelDataDelegatesToLoadUncached(): void { + $this->travelLoader = $this->createMock(TravelLoader::class); + $this->cache = $this->createMock(CacheInterface::class); + $this->travelSnapshotService = $this->createMock(TravelSnapshotManager::class); + $dateId = 12345; $hotelId = 67890; $travel = new Travel(); @@ -436,7 +490,7 @@ class TravelDataProviderTest extends TestCase ->with($dateId, $hotelId) ->willReturn($travel); - $result = $this->service->getTravelData($dateId, $hotelId, false); + $result = $this->service()->getTravelData($dateId, $hotelId, false); $this->assertSame($travel, $result); } diff --git a/tests/Service/TravelEnricherTest.php b/tests/Service/TravelEnricherTest.php index aad669d..7101d4e 100644 --- a/tests/Service/TravelEnricherTest.php +++ b/tests/Service/TravelEnricherTest.php @@ -15,7 +15,7 @@ use Psr\Log\LoggerInterface; class TravelEnricherTest extends TestCase { - private TravelEnricher $service; + private ?TravelEnricher $service = null; private PickupLoader $pickupLoader; private HotelLoader $hotelLoader; private InsuranceLoader $insuranceLoader; @@ -23,12 +23,15 @@ class TravelEnricherTest extends TestCase protected function setUp(): void { - $this->pickupLoader = $this->createMock(PickupLoader::class); - $this->hotelLoader = $this->createMock(HotelLoader::class); - $this->insuranceLoader = $this->createMock(InsuranceLoader::class); - $this->logger = $this->createMock(LoggerInterface::class); + $this->pickupLoader = $this->createStub(PickupLoader::class); + $this->hotelLoader = $this->createStub(HotelLoader::class); + $this->insuranceLoader = $this->createStub(InsuranceLoader::class); + $this->logger = $this->createStub(LoggerInterface::class); + } - $this->service = new TravelEnricher( + private function service(): TravelEnricher + { + return $this->service ??= new TravelEnricher( $this->pickupLoader, $this->hotelLoader, $this->insuranceLoader, @@ -42,6 +45,9 @@ class TravelEnricherTest extends TestCase public function testEnrichFromXmlReturnsTrueOnSuccess(): void { + $this->pickupLoader = $this->createMock(PickupLoader::class); + $this->hotelLoader = $this->createMock(HotelLoader::class); + $travel = new Travel(); $travel->id = 100; @@ -55,11 +61,13 @@ class TravelEnricherTest extends TestCase ->method('patchHotelDetails') ->with($travel); - $this->assertTrue($this->service->enrichFromXml($travel)); + $this->assertTrue($this->service()->enrichFromXml($travel)); } public function testEnrichFromXmlReturnsFalseAndLogsWarningOnFailure(): void { + $this->logger = $this->createMock(LoggerInterface::class); + $travel = new Travel(); $travel->id = 100; @@ -72,7 +80,7 @@ class TravelEnricherTest extends TestCase ->method('warning') ->with('Failed to enrich travel data', $this->arrayHasKey('travelId')); - $this->assertFalse($this->service->enrichFromXml($travel)); + $this->assertFalse($this->service()->enrichFromXml($travel)); } // ------------------------------------------------------------------------- @@ -81,6 +89,8 @@ class TravelEnricherTest extends TestCase public function testPatchInsurancesReplacesExistingInsurances(): void { + $this->insuranceLoader = $this->createMock(InsuranceLoader::class); + $travel = new Travel(); $travel->id = 100; @@ -104,7 +114,7 @@ class TravelEnricherTest extends TestCase ->method('loadAll') ->willReturn([$individual, $package]); - $this->service->patchInsurances($travel); + $this->service()->patchInsurances($travel); $this->assertSame([$individual, $package], $travel->insurances); } @@ -126,7 +136,7 @@ class TravelEnricherTest extends TestCase $this->insuranceLoader->method('loadAll')->willReturn([$individual, $package]); - $this->service->patchInsurances($travel); + $this->service()->patchInsurances($travel); $this->assertCount(1, $package->containedInsurances); $this->assertSame($individual, $package->containedInsurances[0]); @@ -134,6 +144,8 @@ class TravelEnricherTest extends TestCase public function testPatchInsurancesLogsWarningOnFailureAndDoesNotThrow(): void { + $this->logger = $this->createMock(LoggerInterface::class); + $travel = new Travel(); $travel->id = 100; $original = []; @@ -149,7 +161,7 @@ class TravelEnricherTest extends TestCase ->with('Failed to load insurance data', $this->arrayHasKey('travelId')); // Must not throw; insurances stay unchanged - $this->service->patchInsurances($travel); + $this->service()->patchInsurances($travel); $this->assertSame($original, $travel->insurances); } diff --git a/tests/Service/TravelIndexTest.php b/tests/Service/TravelIndexTest.php index 6a49b3c..9181c4e 100644 --- a/tests/Service/TravelIndexTest.php +++ b/tests/Service/TravelIndexTest.php @@ -13,7 +13,7 @@ use Psr\Log\LoggerInterface; class TravelIndexTest extends TestCase { - private TravelIndex $service; + private ?TravelIndex $service = null; private TravelLoader $travelLoader; private HotelLoader $hotelLoader; private TravelSnapshotManager $travelSnapshotService; @@ -21,12 +21,15 @@ class TravelIndexTest extends TestCase protected function setUp(): void { - $this->travelLoader = $this->createMock(TravelLoader::class); - $this->hotelLoader = $this->createMock(HotelLoader::class); - $this->travelSnapshotService = $this->createMock(TravelSnapshotManager::class); - $this->logger = $this->createMock(LoggerInterface::class); + $this->travelLoader = $this->createStub(TravelLoader::class); + $this->hotelLoader = $this->createStub(HotelLoader::class); + $this->travelSnapshotService = $this->createStub(TravelSnapshotManager::class); + $this->logger = $this->createStub(LoggerInterface::class); + } - $this->service = new TravelIndex( + private function service(): TravelIndex + { + return $this->service ??= new TravelIndex( $this->travelLoader, $this->hotelLoader, $this->travelSnapshotService, @@ -59,7 +62,7 @@ class TravelIndexTest extends TestCase $this->travelLoader->method('generateFilesMap')->willReturn($xmlMapping); $this->travelSnapshotService->method('generateMapping')->willReturn($snapshotMapping); - $result = $this->service->generateFilesMap(); + $result = $this->service()->generateFilesMap(); // XML entry is preserved $this->assertArrayHasKey($dateId, $result); @@ -73,6 +76,9 @@ class TravelIndexTest extends TestCase public function testGenerateFilesMapIsMemoizedWithinRequest(): void { + $this->travelLoader = $this->createMock(TravelLoader::class); + $this->travelSnapshotService = $this->createMock(TravelSnapshotManager::class); + $mapping = [100 => ['id' => 100, 'code' => 'A', 'hotels' => []]]; $this->travelLoader @@ -86,14 +92,16 @@ class TravelIndexTest extends TestCase ->willReturn([]); // Two calls — loaders invoked only once - $this->service->generateFilesMap(); - $result = $this->service->generateFilesMap(); + $this->service()->generateFilesMap(); + $result = $this->service()->generateFilesMap(); $this->assertSame($mapping, $result); } public function testGenerateFilesMapFallsBackToSnapshotsOnXmlFailure(): void { + $this->logger = $this->createMock(LoggerInterface::class); + $snapshotMapping = [100 => ['id' => 100, 'code' => 'A', 'hotels' => []]]; $this->travelLoader @@ -109,7 +117,7 @@ class TravelIndexTest extends TestCase ->method('warning') ->with('Failed to generate XML files mapping, fallback to snapshots only', $this->arrayHasKey('error')); - $result = $this->service->generateFilesMap(); + $result = $this->service()->generateFilesMap(); $this->assertSame($snapshotMapping, $result); } @@ -125,7 +133,7 @@ class TravelIndexTest extends TestCase ]); $this->travelSnapshotService->method('generateMapping')->willReturn([]); - $result = $this->service->mapDateCodeToId('WI25'); + $result = $this->service()->mapDateCodeToId('WI25'); $this->assertSame(42, $result); } @@ -135,7 +143,7 @@ class TravelIndexTest extends TestCase $this->travelLoader->method('generateFilesMap')->willReturn([]); $this->travelSnapshotService->method('generateMapping')->willReturn([]); - $result = $this->service->mapDateCodeToId('UNKNOWN'); + $result = $this->service()->mapDateCodeToId('UNKNOWN'); $this->assertNull($result); } @@ -146,13 +154,15 @@ class TravelIndexTest extends TestCase public function testMapHotelCodeToIdDelegatesToHotelLoader(): void { + $this->hotelLoader = $this->createMock(HotelLoader::class); + $this->hotelLoader ->expects($this->once()) ->method('mapCodeToId') ->with('HTL001') ->willReturn(77); - $result = $this->service->mapHotelCodeToId('HTL001'); + $result = $this->service()->mapHotelCodeToId('HTL001'); $this->assertSame(77, $result); } @@ -163,7 +173,7 @@ class TravelIndexTest extends TestCase ->method('mapCodeToId') ->willThrowException(new \RuntimeException('Not found')); - $result = $this->service->mapHotelCodeToId('MISSING'); + $result = $this->service()->mapHotelCodeToId('MISSING'); $this->assertNull($result); } @@ -174,6 +184,9 @@ class TravelIndexTest extends TestCase public function testMapDateIdToProductIdPrefersSnapshot(): void { + $this->travelLoader = $this->createMock(TravelLoader::class); + $this->travelSnapshotService = $this->createMock(TravelSnapshotManager::class); + $this->travelSnapshotService ->expects($this->once()) ->method('findProductIdByDateId') @@ -184,13 +197,16 @@ class TravelIndexTest extends TestCase ->expects($this->never()) ->method('mapDateIdToProductId'); - $result = $this->service->mapDateIdToProductId(100); + $result = $this->service()->mapDateIdToProductId(100); $this->assertSame(999, $result); } public function testMapDateIdToProductIdFallsBackToLoaderWhenSnapshotReturnsNull(): void { + $this->travelLoader = $this->createMock(TravelLoader::class); + $this->travelSnapshotService = $this->createMock(TravelSnapshotManager::class); + $this->travelSnapshotService ->expects($this->once()) ->method('findProductIdByDateId') @@ -203,7 +219,7 @@ class TravelIndexTest extends TestCase ->with(100) ->willReturn(42); - $result = $this->service->mapDateIdToProductId(100); + $result = $this->service()->mapDateIdToProductId(100); $this->assertSame(42, $result); } @@ -214,6 +230,9 @@ class TravelIndexTest extends TestCase public function testExistsLocallyTrueFromSnapshot(): void { + $this->travelLoader = $this->createMock(TravelLoader::class); + $this->travelSnapshotService = $this->createMock(TravelSnapshotManager::class); + $dateId = 12345; $hotelId = 67890; @@ -227,7 +246,7 @@ class TravelIndexTest extends TestCase ->expects($this->never()) ->method('generateFilesMap'); - $this->assertTrue($this->service->existsLocally($dateId, $hotelId)); + $this->assertTrue($this->service()->existsLocally($dateId, $hotelId)); } public function testExistsLocallyTrueFromXmlMap(): void @@ -245,7 +264,7 @@ class TravelIndexTest extends TestCase $this->travelLoader->method('generateFilesMap')->willReturn($mapping); $this->travelSnapshotService->method('generateMapping')->willReturn([]); - $this->assertTrue($this->service->existsLocally($dateId, $hotelId)); + $this->assertTrue($this->service()->existsLocally($dateId, $hotelId)); } public function testExistsLocallyFalseNoTravel(): void @@ -254,7 +273,7 @@ class TravelIndexTest extends TestCase $this->travelLoader->method('generateFilesMap')->willReturn([]); $this->travelSnapshotService->method('generateMapping')->willReturn([]); - $this->assertFalse($this->service->existsLocally(12345, 67890)); + $this->assertFalse($this->service()->existsLocally(12345, 67890)); } public function testExistsLocallyFalseNoHotel(): void @@ -269,7 +288,7 @@ class TravelIndexTest extends TestCase $this->travelLoader->method('generateFilesMap')->willReturn($mapping); $this->travelSnapshotService->method('generateMapping')->willReturn([]); - $this->assertFalse($this->service->existsLocally($dateId, $hotelId)); + $this->assertFalse($this->service()->existsLocally($dateId, $hotelId)); } // ------------------------------------------------------------------------- @@ -278,6 +297,8 @@ class TravelIndexTest extends TestCase public function testGetAvailableSourcesReturnsBothFlags(): void { + $this->travelLoader = $this->createMock(TravelLoader::class); + $dateId = 12345; $hotelId = 67890; $mapping = [ @@ -290,7 +311,7 @@ class TravelIndexTest extends TestCase $this->travelLoader->method('generateFilesMap')->willReturn($mapping); $this->travelLoader->method('mapDateIdToProductId')->with($dateId)->willReturn(555); - $result = $this->service->getAvailableSources($dateId, $hotelId); + $result = $this->service()->getAvailableSources($dateId, $hotelId); $this->assertEquals(['local' => true, 'remote' => true], $result); } diff --git a/tests/Service/TravelSnapshotManagerTest.php b/tests/Service/TravelSnapshotManagerTest.php index 9098b8d..8927afb 100644 --- a/tests/Service/TravelSnapshotManagerTest.php +++ b/tests/Service/TravelSnapshotManagerTest.php @@ -24,17 +24,20 @@ class TravelSnapshotManagerTest extends TestCase private ApiClient $apiClient; private LoggerInterface $logger; private SerializerInterface $serializer; - private TravelSnapshotManager $service; + private ?TravelSnapshotManager $service = null; protected function setUp(): void { - $this->snapshotRepository = $this->createMock(TravelSnapshotRepository::class); - $this->entityManager = $this->createMock(EntityManagerInterface::class); - $this->apiClient = $this->createMock(ApiClient::class); - $this->logger = $this->createMock(LoggerInterface::class); - $this->serializer = $this->createMock(SerializerInterface::class); + $this->snapshotRepository = $this->createStub(TravelSnapshotRepository::class); + $this->entityManager = $this->createStub(EntityManagerInterface::class); + $this->apiClient = $this->createStub(ApiClient::class); + $this->logger = $this->createStub(LoggerInterface::class); + $this->serializer = $this->createStub(SerializerInterface::class); + } - $this->service = new TravelSnapshotManager( + private function service(): TravelSnapshotManager + { + return $this->service ??= new TravelSnapshotManager( $this->snapshotRepository, $this->entityManager, $this->apiClient, @@ -46,6 +49,10 @@ class TravelSnapshotManagerTest extends TestCase public function testUpsertCreatesNewSnapshot(): void { + $this->snapshotRepository = $this->createMock(TravelSnapshotRepository::class); + $this->entityManager = $this->createMock(EntityManagerInterface::class); + $this->serializer = $this->createMock(SerializerInterface::class); + $travel = new Travel(); $travel->id = 100; $travel->hotelId = 200; @@ -71,11 +78,15 @@ class TravelSnapshotManagerTest extends TestCase ->expects($this->once()) ->method('flush'); - $this->service->upsertFromTravel($travel); + $this->service()->upsertFromTravel($travel); } public function testUpsertSkipsWhenHashUnchanged(): void { + $this->snapshotRepository = $this->createMock(TravelSnapshotRepository::class); + $this->entityManager = $this->createMock(EntityManagerInterface::class); + $this->serializer = $this->createMock(SerializerInterface::class); + $travel = new Travel(); $travel->id = 100; $travel->hotelId = 200; @@ -100,11 +111,15 @@ class TravelSnapshotManagerTest extends TestCase ->expects($this->never()) ->method('flush'); - $this->service->upsertFromTravel($travel); + $this->service()->upsertFromTravel($travel); } public function testUpsertUpdatesWhenHashChanged(): void { + $this->snapshotRepository = $this->createMock(TravelSnapshotRepository::class); + $this->entityManager = $this->createMock(EntityManagerInterface::class); + $this->serializer = $this->createMock(SerializerInterface::class); + $travel = new Travel(); $travel->id = 100; $travel->hotelId = 200; @@ -131,24 +146,30 @@ class TravelSnapshotManagerTest extends TestCase ->expects($this->once()) ->method('flush'); - $this->service->upsertFromTravel($travel); + $this->service()->upsertFromTravel($travel); } public function testLoadTravelReturnsNullWhenNoSnapshot(): void { + $this->snapshotRepository = $this->createMock(TravelSnapshotRepository::class); + $this->snapshotRepository ->expects($this->once()) ->method('findByDateAndHotel') ->with(100, 200) ->willReturn(null); - $result = $this->service->loadTravel(100, 200); + $result = $this->service()->loadTravel(100, 200); $this->assertNull($result); } public function testLoadTravelReturnsNullOnDeserializationError(): void { + $this->snapshotRepository = $this->createMock(TravelSnapshotRepository::class); + $this->logger = $this->createMock(LoggerInterface::class); + $this->serializer = $this->createMock(SerializerInterface::class); + $snapshot = new TravelSnapshot(100, 200, 'invalid-json', hash('sha256', 'invalid-json')); $this->snapshotRepository @@ -167,13 +188,15 @@ class TravelSnapshotManagerTest extends TestCase ->method('warning') ->with('Snapshot payload cannot be deserialized to Travel', $this->arrayHasKey('snapshotId')); - $result = $this->service->loadTravel(100, 200); + $result = $this->service()->loadTravel(100, 200); $this->assertNull($result); } public function testExistsReturnsTrueWhenSnapshotFound(): void { + $this->snapshotRepository = $this->createMock(TravelSnapshotRepository::class); + $snapshot = new TravelSnapshot(100, 200, '{}', hash('sha256', '{}')); $this->snapshotRepository @@ -182,22 +205,27 @@ class TravelSnapshotManagerTest extends TestCase ->with(100, 200) ->willReturn($snapshot); - $this->assertTrue($this->service->exists(100, 200)); + $this->assertTrue($this->service()->exists(100, 200)); } public function testExistsReturnsFalseWhenNoSnapshot(): void { + $this->snapshotRepository = $this->createMock(TravelSnapshotRepository::class); + $this->snapshotRepository ->expects($this->once()) ->method('findByDateAndHotel') ->with(100, 200) ->willReturn(null); - $this->assertFalse($this->service->exists(100, 200)); + $this->assertFalse($this->service()->exists(100, 200)); } public function testLoadTravelReturnsDeserializedTravel(): void { + $this->snapshotRepository = $this->createMock(TravelSnapshotRepository::class); + $this->serializer = $this->createMock(SerializerInterface::class); + $travel = new Travel(); $travel->id = 100; $travel->hotelId = 200; @@ -217,7 +245,7 @@ class TravelSnapshotManagerTest extends TestCase ->with($payload, Travel::class, 'json') ->willReturn($travel); - $result = $this->service->loadTravel(100, 200); + $result = $this->service()->loadTravel(100, 200); $this->assertInstanceOf(Travel::class, $result); $this->assertSame($travel, $result); @@ -225,6 +253,9 @@ class TravelSnapshotManagerTest extends TestCase public function testUpsertFromTravelSkipsWhenTravelIsIncomplete(): void { + $this->entityManager = $this->createMock(EntityManagerInterface::class); + $this->serializer = $this->createMock(SerializerInterface::class); + $travelNoId = new Travel(); $travelNoId->id = null; $travelNoId->hotelId = 200; @@ -236,25 +267,29 @@ class TravelSnapshotManagerTest extends TestCase $this->serializer->expects($this->never())->method('serialize'); $this->entityManager->expects($this->never())->method('flush'); - $this->service->upsertFromTravel($travelNoId); - $this->service->upsertFromTravel($travelNoHotel); + $this->service()->upsertFromTravel($travelNoId); + $this->service()->upsertFromTravel($travelNoHotel); } public function testFindProductIdByDateIdDelegatesToRepository(): void { + $this->snapshotRepository = $this->createMock(TravelSnapshotRepository::class); + $this->snapshotRepository ->expects($this->once()) ->method('findProductIdByDateId') ->with(42) ->willReturn(365); - $result = $this->service->findProductIdByDateId(42); + $result = $this->service()->findProductIdByDateId(42); $this->assertSame(365, $result); } public function testPurgeExpiredSnapshotsDelegatesWithCorrectDate(): void { + $this->snapshotRepository = $this->createMock(TravelSnapshotRepository::class); + $this->snapshotRepository ->expects($this->once()) ->method('deleteExpiredSnapshots') @@ -265,13 +300,18 @@ class TravelSnapshotManagerTest extends TestCase })) ->willReturn(7); - $result = $this->service->purgeExpiredSnapshots(); + $result = $this->service()->purgeExpiredSnapshots(); $this->assertSame(7, $result); } public function testRefreshExtendedSnapshotsSuccessPath(): void { + $this->snapshotRepository = $this->createMock(TravelSnapshotRepository::class); + $this->entityManager = $this->createMock(EntityManagerInterface::class); + $this->apiClient = $this->createMock(ApiClient::class); + $this->serializer = $this->createMock(SerializerInterface::class); + $travel = new Travel(); $travel->id = 100; $travel->hotelId = 200; @@ -310,13 +350,19 @@ class TravelSnapshotManagerTest extends TestCase ->expects($this->once()) ->method('flush'); - $result = $this->service->refreshExtendedSnapshots(500, false, 360, []); + $result = $this->service()->refreshExtendedSnapshots(500, false, 360, []); $this->assertSame(['processed' => 1, 'updated' => 1, 'failed' => 0], $result); } public function testRefreshExtendedSnapshotsApiFailureIncrementsFailedCount(): void { + $this->snapshotRepository = $this->createMock(TravelSnapshotRepository::class); + $this->entityManager = $this->createMock(EntityManagerInterface::class); + $this->apiClient = $this->createMock(ApiClient::class); + $this->logger = $this->createMock(LoggerInterface::class); + $this->serializer = $this->createMock(SerializerInterface::class); + $travel = new Travel(); $travel->id = 100; $travel->hotelId = 200; @@ -348,13 +394,18 @@ class TravelSnapshotManagerTest extends TestCase ->expects($this->never()) ->method('flush'); - $result = $this->service->refreshExtendedSnapshots(500, false, 360, []); + $result = $this->service()->refreshExtendedSnapshots(500, false, 360, []); $this->assertSame(['processed' => 1, 'updated' => 0, 'failed' => 1], $result); } public function testRefreshExtendedSnapshotsDeserializationFailureIncrementsFailedCount(): void { + $this->snapshotRepository = $this->createMock(TravelSnapshotRepository::class); + $this->entityManager = $this->createMock(EntityManagerInterface::class); + $this->logger = $this->createMock(LoggerInterface::class); + $this->serializer = $this->createMock(SerializerInterface::class); + $payload = '{"id":100}'; $snapshot = new TravelSnapshot(100, 200, $payload, hash('sha256', $payload)); @@ -377,13 +428,17 @@ class TravelSnapshotManagerTest extends TestCase ->expects($this->never()) ->method('flush'); - $result = $this->service->refreshExtendedSnapshots(500, false, 360, []); + $result = $this->service()->refreshExtendedSnapshots(500, false, 360, []); $this->assertSame(['processed' => 1, 'updated' => 0, 'failed' => 1], $result); } public function testRefreshSkipsAllCandidatesWhenXmlDateIdsIsNull(): void { + $this->snapshotRepository = $this->createMock(TravelSnapshotRepository::class); + $this->entityManager = $this->createMock(EntityManagerInterface::class); + $this->apiClient = $this->createMock(ApiClient::class); + $payload = '{"id":100}'; $snapshot = new TravelSnapshot(100, 200, $payload, hash('sha256', $payload)); @@ -400,13 +455,16 @@ class TravelSnapshotManagerTest extends TestCase ->expects($this->never()) ->method('flush'); - $result = $this->service->refreshExtendedSnapshots(500, false, 360, null); + $result = $this->service()->refreshExtendedSnapshots(500, false, 360, null); $this->assertSame(['processed' => 0, 'updated' => 0, 'failed' => 0], $result); } public function testRefreshSkipsSnapshotsWithXmlAvailable(): void { + $this->snapshotRepository = $this->createMock(TravelSnapshotRepository::class); + $this->apiClient = $this->createMock(ApiClient::class); + $payload = '{"id":100}'; $snapshot = new TravelSnapshot(100, 200, $payload, hash('sha256', $payload)); @@ -419,26 +477,30 @@ class TravelSnapshotManagerTest extends TestCase ->expects($this->never()) ->method('getAvailabilitiesExtended'); - $result = $this->service->refreshExtendedSnapshots(500, false, 360, [100]); + $result = $this->service()->refreshExtendedSnapshots(500, false, 360, [100]); $this->assertSame(['processed' => 0, 'updated' => 0, 'failed' => 0], $result); } public function testPurgeOrphanedFutureSnapshotsReturnsZeroForEmptyList(): void { + $this->snapshotRepository = $this->createMock(TravelSnapshotRepository::class); + $this->snapshotRepository ->expects($this->once()) ->method('deleteOrphanedFutureSnapshots') ->with([], $this->isInstanceOf(\DateTimeImmutable::class)) ->willReturn(0); - $result = $this->service->purgeOrphanedFutureSnapshots([]); + $result = $this->service()->purgeOrphanedFutureSnapshots([]); $this->assertSame(0, $result); } public function testPurgeOrphanedFutureSnapshotsDelegatesWithCorrectArguments(): void { + $this->snapshotRepository = $this->createMock(TravelSnapshotRepository::class); + $activeIds = [100, 200, 300]; $this->snapshotRepository @@ -454,13 +516,15 @@ class TravelSnapshotManagerTest extends TestCase ) ->willReturn(3); - $result = $this->service->purgeOrphanedFutureSnapshots($activeIds); + $result = $this->service()->purgeOrphanedFutureSnapshots($activeIds); $this->assertSame(3, $result); } public function testGenerateMappingBuildsCorrectStructure(): void { + $this->snapshotRepository = $this->createMock(TravelSnapshotRepository::class); + $hotel = new Hotel(); $hotel->code = 'HTL1'; $hotel->name = 'Hotel One'; @@ -498,7 +562,7 @@ class TravelSnapshotManagerTest extends TestCase ->method('findAllForMapping') ->willReturn([$snapshot1, $snapshot2]); - $mapping = $this->service->generateMapping(); + $mapping = $this->service()->generateMapping(); $this->assertArrayHasKey(10, $mapping); $this->assertSame('TRIP1', $mapping[10]['code']); diff --git a/tests/Validator/Constraints/MandatoryAdditionalServicesSelectedValidatorTest.php b/tests/Validator/Constraints/MandatoryAdditionalServicesSelectedValidatorTest.php index bd11e4c..b40d684 100644 --- a/tests/Validator/Constraints/MandatoryAdditionalServicesSelectedValidatorTest.php +++ b/tests/Validator/Constraints/MandatoryAdditionalServicesSelectedValidatorTest.php @@ -23,7 +23,7 @@ class MandatoryAdditionalServicesSelectedValidatorTest extends ConstraintValidat protected function createValidator(): MandatoryAdditionalServicesSelectedValidator { - $this->participantEligibilityService = $this->createMock(ParticipantEligibilityChecker::class); + $this->participantEligibilityService = $this->createStub(ParticipantEligibilityChecker::class); $this->participantEligibilityService ->method('isParticipantEligible') ->willReturnCallback(fn (): bool => $this->participantEligible);