From 7e8a78881ab9442ab1c2c417e8f1e45a570ec68c Mon Sep 17 00:00:00 2001 From: Arman <407448+armanist@users.noreply.github.com> Date: Wed, 29 Apr 2026 18:02:54 +0400 Subject: [PATCH 01/29] [#481] Normalize enum and trivial exception coverage annotations --- src/Auth/Enums/AuthKeys.php | 7 ++++++- src/Cache/Exceptions/CacheException.php | 1 + src/Captcha/Exceptions/CaptchaException.php | 1 + src/Cron/Enums/ExceptionMessages.php | 5 +++++ src/Database/Enums/Key.php | 6 +++++- src/Database/Enums/Relation.php | 7 ++++++- src/Database/Enums/Type.php | 6 +++++- src/Environment/Enums/Env.php | 5 +++++ src/Http/Enums/ContentType.php | 5 +++++ src/Http/Enums/StatusCode.php | 5 +++++ src/Http/Exceptions/HttpException.php | 1 + src/Loader/Exceptions/LoaderException.php | 1 + src/Mailer/Exceptions/MailerException.php | 1 + src/Paginator/Enums/Pagination.php | 7 ++++++- src/Renderer/Exceptions/RendererException.php | 1 + src/ResourceCache/Exceptions/ResourceCacheException.php | 1 + src/Service/Exceptions/ServiceException.php | 1 + 17 files changed, 56 insertions(+), 5 deletions(-) diff --git a/src/Auth/Enums/AuthKeys.php b/src/Auth/Enums/AuthKeys.php index 475b1a6c5..b59d6d47e 100644 --- a/src/Auth/Enums/AuthKeys.php +++ b/src/Auth/Enums/AuthKeys.php @@ -19,8 +19,9 @@ /** * Class AuthKeys * @package Quantum\Auth + * @codeCoverageIgnore */ -class AuthKeys +final class AuthKeys { /** * One time password key @@ -71,4 +72,8 @@ class AuthKeys * Remember token key */ public const REMEMBER_TOKEN = 'rememberToken'; + + private function __construct() + { + } } diff --git a/src/Cache/Exceptions/CacheException.php b/src/Cache/Exceptions/CacheException.php index 934e9c0c4..1ec164fc6 100644 --- a/src/Cache/Exceptions/CacheException.php +++ b/src/Cache/Exceptions/CacheException.php @@ -21,6 +21,7 @@ /** * Class CacheException * @package Quantum\Cache + * @codeCoverageIgnore */ class CacheException extends BaseException { diff --git a/src/Captcha/Exceptions/CaptchaException.php b/src/Captcha/Exceptions/CaptchaException.php index a4c4d5be4..f80ba63f1 100644 --- a/src/Captcha/Exceptions/CaptchaException.php +++ b/src/Captcha/Exceptions/CaptchaException.php @@ -21,6 +21,7 @@ /** * Class CacheException * @package Quantum\Captcha + * @codeCoverageIgnore */ class CaptchaException extends BaseException { diff --git a/src/Cron/Enums/ExceptionMessages.php b/src/Cron/Enums/ExceptionMessages.php index ddb430b17..3c4e69a4b 100644 --- a/src/Cron/Enums/ExceptionMessages.php +++ b/src/Cron/Enums/ExceptionMessages.php @@ -19,6 +19,7 @@ /** * Enum ExceptionMessages * @package Quantum\Cron + * @codeCoverageIgnore */ final class ExceptionMessages { @@ -29,4 +30,8 @@ final class ExceptionMessages public const INVALID_TASK_FILE = 'Invalid task file "%s": must return array or CronTask instance'; public const CRON_DIRECTORY_NOT_FOUND = 'Cron directory not found: %s'; public const LOCK_DIRECTORY_NOT_WRITABLE = 'Lock directory is not writable: %s'; + + private function __construct() + { + } } diff --git a/src/Database/Enums/Key.php b/src/Database/Enums/Key.php index c947c6e3a..8d3d9c236 100644 --- a/src/Database/Enums/Key.php +++ b/src/Database/Enums/Key.php @@ -19,8 +19,9 @@ /** * Class Key * @package Quantum\Database + * @codeCoverageIgnore */ -class Key +final class Key { /** * Primary key definition @@ -47,4 +48,7 @@ class Key */ public const SPATIAL = 'spatial'; + private function __construct() + { + } } diff --git a/src/Database/Enums/Relation.php b/src/Database/Enums/Relation.php index 278e65175..77c7e978d 100644 --- a/src/Database/Enums/Relation.php +++ b/src/Database/Enums/Relation.php @@ -19,11 +19,16 @@ /** * Class Relation * @package Quantum\Database + * @codeCoverageIgnore */ -class Relation +final class Relation { public const HAS_ONE = 'hasOne'; public const HAS_MANY = 'hasMany'; public const BELONGS_TO = 'belongsTo'; public const BELONGS_TO_MANY = 'belongsToMany'; + + private function __construct() + { + } } diff --git a/src/Database/Enums/Type.php b/src/Database/Enums/Type.php index 824412be8..be1b2b0f9 100644 --- a/src/Database/Enums/Type.php +++ b/src/Database/Enums/Type.php @@ -19,8 +19,9 @@ /** * Class Type * @package Quantum\Database + * @codeCoverageIgnore */ -class Type +final class Type { /** * Type integer @@ -107,4 +108,7 @@ class Type */ public const GEOMETRY = 'geometry'; + private function __construct() + { + } } diff --git a/src/Environment/Enums/Env.php b/src/Environment/Enums/Env.php index 27ea62e16..9d926ff22 100644 --- a/src/Environment/Enums/Env.php +++ b/src/Environment/Enums/Env.php @@ -19,6 +19,7 @@ /** * Class Env * @package Quantum\Environment + * @codeCoverageIgnore */ final class Env { @@ -46,4 +47,8 @@ final class Env * Local environment - developer's local machine environment. */ public const LOCAL = 'local'; + + private function __construct() + { + } } diff --git a/src/Http/Enums/ContentType.php b/src/Http/Enums/ContentType.php index 193b5d781..3c0677c40 100644 --- a/src/Http/Enums/ContentType.php +++ b/src/Http/Enums/ContentType.php @@ -19,6 +19,7 @@ /** * Class ContentType * @package Quantum\Http + * @codeCoverageIgnore */ final class ContentType { @@ -56,4 +57,8 @@ final class ContentType * Default content type for binary streams */ public const OCTET_STREAM = 'application/octet-stream'; + + private function __construct() + { + } } diff --git a/src/Http/Enums/StatusCode.php b/src/Http/Enums/StatusCode.php index bd679159a..b33c9d695 100644 --- a/src/Http/Enums/StatusCode.php +++ b/src/Http/Enums/StatusCode.php @@ -19,6 +19,7 @@ /** * Class StatusCode * @package Quantum\Http + * @codeCoverageIgnore */ final class StatusCode { @@ -88,4 +89,8 @@ final class StatusCode public const LOOP_DETECTED = 508; public const NOT_EXTENDED = 510; public const NETWORK_AUTHENTICATION_REQUIRED = 511; + + private function __construct() + { + } } diff --git a/src/Http/Exceptions/HttpException.php b/src/Http/Exceptions/HttpException.php index 284e41a36..e6e786b65 100644 --- a/src/Http/Exceptions/HttpException.php +++ b/src/Http/Exceptions/HttpException.php @@ -21,6 +21,7 @@ /** * Class HttpException * @package Quantum\Http + * @codeCoverageIgnore */ class HttpException extends BaseException { diff --git a/src/Loader/Exceptions/LoaderException.php b/src/Loader/Exceptions/LoaderException.php index cf5cdf06a..8c4e5298d 100644 --- a/src/Loader/Exceptions/LoaderException.php +++ b/src/Loader/Exceptions/LoaderException.php @@ -23,6 +23,7 @@ * * @package Quantum * @category Exceptions + * @codeCoverageIgnore */ class LoaderException extends BaseException { diff --git a/src/Mailer/Exceptions/MailerException.php b/src/Mailer/Exceptions/MailerException.php index ba1aa54c9..841783d5b 100644 --- a/src/Mailer/Exceptions/MailerException.php +++ b/src/Mailer/Exceptions/MailerException.php @@ -21,6 +21,7 @@ /** * Class MailerException * @package Quantum\Mailer + * @codeCoverageIgnore */ class MailerException extends BaseException { diff --git a/src/Paginator/Enums/Pagination.php b/src/Paginator/Enums/Pagination.php index f6c2b1695..cade4d5e4 100644 --- a/src/Paginator/Enums/Pagination.php +++ b/src/Paginator/Enums/Pagination.php @@ -19,8 +19,9 @@ /** * Class Pagination * @package Quantum\Paginator + * @codeCoverageIgnore */ -class Pagination +final class Pagination { /** * Pagination class name @@ -56,4 +57,8 @@ class Pagination * Edge padding */ public const EDGE_PADDING = 3; + + private function __construct() + { + } } diff --git a/src/Renderer/Exceptions/RendererException.php b/src/Renderer/Exceptions/RendererException.php index 49f2cc9f1..96198225f 100644 --- a/src/Renderer/Exceptions/RendererException.php +++ b/src/Renderer/Exceptions/RendererException.php @@ -21,6 +21,7 @@ /** * Class RendererException * @package Quantum\Renderer + * @codeCoverageIgnore */ class RendererException extends BaseException { diff --git a/src/ResourceCache/Exceptions/ResourceCacheException.php b/src/ResourceCache/Exceptions/ResourceCacheException.php index 946bb9460..45943b508 100644 --- a/src/ResourceCache/Exceptions/ResourceCacheException.php +++ b/src/ResourceCache/Exceptions/ResourceCacheException.php @@ -21,6 +21,7 @@ /** * Class ResourceCacheException * @package Quantum\ResourceCache + * @codeCoverageIgnore */ class ResourceCacheException extends BaseException { diff --git a/src/Service/Exceptions/ServiceException.php b/src/Service/Exceptions/ServiceException.php index ffc5b2cbf..cb6dcc1bc 100644 --- a/src/Service/Exceptions/ServiceException.php +++ b/src/Service/Exceptions/ServiceException.php @@ -21,6 +21,7 @@ /** * Class ServiceException * @package Quantum\Service + * @codeCoverageIgnore */ class ServiceException extends BaseException { From 4f096e7280aa1f517fa2c43998ea0172d018c10d Mon Sep 17 00:00:00 2001 From: Arman <407448+armanist@users.noreply.github.com> Date: Wed, 29 Apr 2026 18:05:10 +0400 Subject: [PATCH 02/29] [#481] Add App exception factory coverage tests --- .../Unit/App/Exceptions/AppExceptionTest.php | 19 ++++++ .../Unit/App/Exceptions/BaseExceptionTest.php | 62 +++++++++++++++++++ 2 files changed, 81 insertions(+) create mode 100644 tests/Unit/App/Exceptions/AppExceptionTest.php create mode 100644 tests/Unit/App/Exceptions/BaseExceptionTest.php diff --git a/tests/Unit/App/Exceptions/AppExceptionTest.php b/tests/Unit/App/Exceptions/AppExceptionTest.php new file mode 100644 index 000000000..bfc8c35b6 --- /dev/null +++ b/tests/Unit/App/Exceptions/AppExceptionTest.php @@ -0,0 +1,19 @@ +assertInstanceOf(AppException::class, $exception); + $this->assertSame('APP KEY is missing.', $exception->getMessage()); + $this->assertSame(E_ERROR, $exception->getCode()); + } +} + diff --git a/tests/Unit/App/Exceptions/BaseExceptionTest.php b/tests/Unit/App/Exceptions/BaseExceptionTest.php new file mode 100644 index 000000000..f31346756 --- /dev/null +++ b/tests/Unit/App/Exceptions/BaseExceptionTest.php @@ -0,0 +1,62 @@ +assertInstanceOf(BaseExceptionStub::class, $exception); + $this->assertSame('The method `foo` is not supported for `Bar`.', $exception->getMessage()); + $this->assertSame(E_WARNING, $exception->getCode()); + } + + public function testAdapterAndDriverFactories(): void + { + $adapterException = BaseExceptionStub::adapterNotSupported('x'); + $driverException = BaseExceptionStub::driverNotSupported('y'); + + $this->assertSame('The adapter `x` is not supported.', $adapterException->getMessage()); + $this->assertSame(E_ERROR, $adapterException->getCode()); + $this->assertSame('The driver `y` is not supported.', $driverException->getMessage()); + $this->assertSame(E_ERROR, $driverException->getCode()); + } + + public function testLookupAndConnectionFactories(): void + { + $fileException = BaseExceptionStub::fileNotFound('a.php'); + $notFoundException = BaseExceptionStub::notFound('Route', 'home'); + $instanceException = BaseExceptionStub::notInstanceOf('Foo', 'Bar'); + $connectException = BaseExceptionStub::cantConnect('redis'); + + $this->assertSame('The file `a.php` not found.', $fileException->getMessage()); + $this->assertSame(E_ERROR, $fileException->getCode()); + $this->assertSame('Route `home` not found.', $notFoundException->getMessage()); + $this->assertSame(E_ERROR, $notFoundException->getCode()); + $this->assertSame('The `Foo` is not instance of `Bar`.', $instanceException->getMessage()); + $this->assertSame(E_ERROR, $instanceException->getCode()); + $this->assertSame('Can not connect to `redis`.', $connectException->getMessage()); + $this->assertSame(E_ERROR, $connectException->getCode()); + } + + public function testConfigAndRequestMethodFactories(): void + { + $configException = BaseExceptionStub::missingConfig('database'); + $methodException = BaseExceptionStub::requestMethodNotAvailable('PATCH'); + + $this->assertSame('Could not load config `database` properly.', $configException->getMessage()); + $this->assertSame(E_ERROR, $configException->getCode()); + $this->assertSame('Provided request method `PATCH` is not available.', $methodException->getMessage()); + $this->assertSame(E_WARNING, $methodException->getCode()); + } +} + From eb38106aef2f40b0960cdd22035688a1c26c907f Mon Sep 17 00:00:00 2001 From: Arman <407448+armanist@users.noreply.github.com> Date: Wed, 29 Apr 2026 18:21:52 +0400 Subject: [PATCH 03/29] [#481] Add Archive exception factory coverage tests --- tests/Unit/Archive/ArchiveExceptionTest.php | 28 +++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 tests/Unit/Archive/ArchiveExceptionTest.php diff --git a/tests/Unit/Archive/ArchiveExceptionTest.php b/tests/Unit/Archive/ArchiveExceptionTest.php new file mode 100644 index 000000000..1265391be --- /dev/null +++ b/tests/Unit/Archive/ArchiveExceptionTest.php @@ -0,0 +1,28 @@ +assertInstanceOf(ArchiveException::class, $exception); + $this->assertSame('The archive `demo.zip` can not be opened', $exception->getMessage()); + $this->assertSame(E_WARNING, $exception->getCode()); + } + + public function testMissingArchiveName(): void + { + $exception = ArchiveException::missingArchiveName(); + + $this->assertInstanceOf(ArchiveException::class, $exception); + $this->assertSame('Archive name is not set', $exception->getMessage()); + $this->assertSame(E_WARNING, $exception->getCode()); + } +} + From abbb9424713a58057f3d2aa4d0f2eaa6804ad67b Mon Sep 17 00:00:00 2001 From: Arman <407448+armanist@users.noreply.github.com> Date: Wed, 29 Apr 2026 18:24:03 +0400 Subject: [PATCH 04/29] [#481] Add Asset exception factory coverage tests --- tests/Unit/Asset/AssetExceptionTest.php | 28 +++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 tests/Unit/Asset/AssetExceptionTest.php diff --git a/tests/Unit/Asset/AssetExceptionTest.php b/tests/Unit/Asset/AssetExceptionTest.php new file mode 100644 index 000000000..dfe7af449 --- /dev/null +++ b/tests/Unit/Asset/AssetExceptionTest.php @@ -0,0 +1,28 @@ +assertInstanceOf(AssetException::class, $exception); + $this->assertSame('Position `7` for asset `styles.css` is in use', $exception->getMessage()); + $this->assertSame(E_WARNING, $exception->getCode()); + } + + public function testNameInUse(): void + { + $exception = AssetException::nameInUse('main-style'); + + $this->assertInstanceOf(AssetException::class, $exception); + $this->assertSame('The name main-style is in use', $exception->getMessage()); + $this->assertSame(E_WARNING, $exception->getCode()); + } +} + From 732bd5fe229b9b260999074fb1d37e71662ece90 Mon Sep 17 00:00:00 2001 From: Arman <407448+armanist@users.noreply.github.com> Date: Wed, 29 Apr 2026 18:24:53 +0400 Subject: [PATCH 05/29] [#481] Add Auth exception factory coverage tests --- tests/Unit/Auth/AuthExceptionTest.php | 45 +++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 tests/Unit/Auth/AuthExceptionTest.php diff --git a/tests/Unit/Auth/AuthExceptionTest.php b/tests/Unit/Auth/AuthExceptionTest.php new file mode 100644 index 000000000..948a32389 --- /dev/null +++ b/tests/Unit/Auth/AuthExceptionTest.php @@ -0,0 +1,45 @@ +assertSame('Incorrect credentials.', $exception->getMessage()); + $this->assertSame(E_ERROR, $exception->getCode()); + } + + public function testInactiveAccount(): void + { + $exception = AuthException::inactiveAccount(); + $this->assertSame('The account is not activated.', $exception->getMessage()); + $this->assertSame(E_ERROR, $exception->getCode()); + } + + public function testIncorrectVerificationCode(): void + { + $exception = AuthException::incorrectVerificationCode(); + $this->assertSame('Incorrect verification code.', $exception->getMessage()); + $this->assertSame(E_ERROR, $exception->getCode()); + } + + public function testVerificationCodeExpired(): void + { + $exception = AuthException::verificationCodeExpired(); + $this->assertSame('Verification code expired.', $exception->getMessage()); + $this->assertSame(E_ERROR, $exception->getCode()); + } + + public function testIncorrectUserSchema(): void + { + $exception = AuthException::incorrectUserSchema(); + $this->assertSame('User schema does not contains all key fields.', $exception->getMessage()); + $this->assertSame(E_ERROR, $exception->getCode()); + } +} + From 16c45491282b7d7f19843f7c1dd37dee2c46a714 Mon Sep 17 00:00:00 2001 From: Arman <407448+armanist@users.noreply.github.com> Date: Wed, 29 Apr 2026 18:28:21 +0400 Subject: [PATCH 06/29] [#481] Add Config exception factory coverage tests --- tests/Unit/Config/ConfigExceptionTest.php | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 tests/Unit/Config/ConfigExceptionTest.php diff --git a/tests/Unit/Config/ConfigExceptionTest.php b/tests/Unit/Config/ConfigExceptionTest.php new file mode 100644 index 000000000..6df7f57bd --- /dev/null +++ b/tests/Unit/Config/ConfigExceptionTest.php @@ -0,0 +1,19 @@ +assertInstanceOf(ConfigException::class, $exception); + $this->assertSame('Config key `database` is already in use', $exception->getMessage()); + $this->assertSame(E_WARNING, $exception->getCode()); + } +} + From 8bff3709a09cc4ca7c3135f01e30d3de51feffcf Mon Sep 17 00:00:00 2001 From: Arman <407448+armanist@users.noreply.github.com> Date: Wed, 29 Apr 2026 18:33:39 +0400 Subject: [PATCH 07/29] [#481] Align exception tests with source folder structure --- tests/Unit/Archive/{ => Exceptions}/ArchiveExceptionTest.php | 3 +-- tests/Unit/Asset/{ => Exceptions}/AssetExceptionTest.php | 3 +-- tests/Unit/Auth/{ => Exceptions}/AuthExceptionTest.php | 3 +-- tests/Unit/Config/{ => Exceptions}/ConfigExceptionTest.php | 3 +-- 4 files changed, 4 insertions(+), 8 deletions(-) rename tests/Unit/Archive/{ => Exceptions}/ArchiveExceptionTest.php (94%) rename tests/Unit/Asset/{ => Exceptions}/AssetExceptionTest.php (94%) rename tests/Unit/Auth/{ => Exceptions}/AuthExceptionTest.php (97%) rename tests/Unit/Config/{ => Exceptions}/ConfigExceptionTest.php (91%) diff --git a/tests/Unit/Archive/ArchiveExceptionTest.php b/tests/Unit/Archive/Exceptions/ArchiveExceptionTest.php similarity index 94% rename from tests/Unit/Archive/ArchiveExceptionTest.php rename to tests/Unit/Archive/Exceptions/ArchiveExceptionTest.php index 1265391be..a954e54fc 100644 --- a/tests/Unit/Archive/ArchiveExceptionTest.php +++ b/tests/Unit/Archive/Exceptions/ArchiveExceptionTest.php @@ -1,6 +1,6 @@ assertSame(E_WARNING, $exception->getCode()); } } - diff --git a/tests/Unit/Asset/AssetExceptionTest.php b/tests/Unit/Asset/Exceptions/AssetExceptionTest.php similarity index 94% rename from tests/Unit/Asset/AssetExceptionTest.php rename to tests/Unit/Asset/Exceptions/AssetExceptionTest.php index dfe7af449..b311778aa 100644 --- a/tests/Unit/Asset/AssetExceptionTest.php +++ b/tests/Unit/Asset/Exceptions/AssetExceptionTest.php @@ -1,6 +1,6 @@ assertSame(E_WARNING, $exception->getCode()); } } - diff --git a/tests/Unit/Auth/AuthExceptionTest.php b/tests/Unit/Auth/Exceptions/AuthExceptionTest.php similarity index 97% rename from tests/Unit/Auth/AuthExceptionTest.php rename to tests/Unit/Auth/Exceptions/AuthExceptionTest.php index 948a32389..fc073e981 100644 --- a/tests/Unit/Auth/AuthExceptionTest.php +++ b/tests/Unit/Auth/Exceptions/AuthExceptionTest.php @@ -1,6 +1,6 @@ assertSame(E_ERROR, $exception->getCode()); } } - diff --git a/tests/Unit/Config/ConfigExceptionTest.php b/tests/Unit/Config/Exceptions/ConfigExceptionTest.php similarity index 91% rename from tests/Unit/Config/ConfigExceptionTest.php rename to tests/Unit/Config/Exceptions/ConfigExceptionTest.php index 6df7f57bd..fd7e89f32 100644 --- a/tests/Unit/Config/ConfigExceptionTest.php +++ b/tests/Unit/Config/Exceptions/ConfigExceptionTest.php @@ -1,6 +1,6 @@ assertSame(E_WARNING, $exception->getCode()); } } - From 763a687aef78ea0f2b6d4d436bf7ea8238c13c82 Mon Sep 17 00:00:00 2001 From: Arman <407448+armanist@users.noreply.github.com> Date: Wed, 29 Apr 2026 18:36:11 +0400 Subject: [PATCH 08/29] [#481] Add Csrf exception factory coverage tests --- .../Csrf/Exceptions/CsrfExceptionTest.php | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 tests/Unit/Csrf/Exceptions/CsrfExceptionTest.php diff --git a/tests/Unit/Csrf/Exceptions/CsrfExceptionTest.php b/tests/Unit/Csrf/Exceptions/CsrfExceptionTest.php new file mode 100644 index 000000000..f80f4396c --- /dev/null +++ b/tests/Unit/Csrf/Exceptions/CsrfExceptionTest.php @@ -0,0 +1,28 @@ +assertInstanceOf(CsrfException::class, $exception); + $this->assertSame('CSRF Token is missing', $exception->getMessage()); + $this->assertSame(E_WARNING, $exception->getCode()); + } + + public function testTokenNotMatched(): void + { + $exception = CsrfException::tokenNotMatched(); + + $this->assertInstanceOf(CsrfException::class, $exception); + $this->assertSame('CSRF Token does not matched', $exception->getMessage()); + $this->assertSame(E_WARNING, $exception->getCode()); + } +} + From 8b83dfed819dab6ad103d2c0a59041dcb5b36bf9 Mon Sep 17 00:00:00 2001 From: Arman <407448+armanist@users.noreply.github.com> Date: Wed, 29 Apr 2026 18:39:33 +0400 Subject: [PATCH 09/29] [#481] Add Database exception factory coverage tests --- .../Exceptions/DatabaseExceptionTest.php | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 tests/Unit/Database/Exceptions/DatabaseExceptionTest.php diff --git a/tests/Unit/Database/Exceptions/DatabaseExceptionTest.php b/tests/Unit/Database/Exceptions/DatabaseExceptionTest.php new file mode 100644 index 000000000..a9b0bcbea --- /dev/null +++ b/tests/Unit/Database/Exceptions/DatabaseExceptionTest.php @@ -0,0 +1,46 @@ +assertInstanceOf(DatabaseException::class, $exception); + $this->assertSame('The structure of config is not correct', $exception->getMessage()); + $this->assertSame(E_ERROR, $exception->getCode()); + } + + public function testOperatorNotSupported(): void + { + $exception = DatabaseException::operatorNotSupported('foo'); + + $this->assertInstanceOf(DatabaseException::class, $exception); + $this->assertSame('The operator `foo` is not supported', $exception->getMessage()); + $this->assertSame(E_WARNING, $exception->getCode()); + } + + public function testTableAlreadyExists(): void + { + $exception = DatabaseException::tableAlreadyExists('users'); + + $this->assertInstanceOf(DatabaseException::class, $exception); + $this->assertSame('The table `users` is already exists', $exception->getMessage()); + $this->assertSame(E_ERROR, $exception->getCode()); + } + + public function testTableDoesNotExists(): void + { + $exception = DatabaseException::tableDoesNotExists('users'); + + $this->assertInstanceOf(DatabaseException::class, $exception); + $this->assertSame('The table `users` does not exists', $exception->getMessage()); + $this->assertSame(E_ERROR, $exception->getCode()); + } +} + From 00f2b3060c5e89261cc65f7d8b3cefd7e0aa75d4 Mon Sep 17 00:00:00 2001 From: Arman <407448+armanist@users.noreply.github.com> Date: Wed, 29 Apr 2026 18:40:59 +0400 Subject: [PATCH 10/29] [#481] Add Di exception factory coverage tests --- tests/Unit/Di/Exceptions/DiExceptionTest.php | 52 ++++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 tests/Unit/Di/Exceptions/DiExceptionTest.php diff --git a/tests/Unit/Di/Exceptions/DiExceptionTest.php b/tests/Unit/Di/Exceptions/DiExceptionTest.php new file mode 100644 index 000000000..882580f74 --- /dev/null +++ b/tests/Unit/Di/Exceptions/DiExceptionTest.php @@ -0,0 +1,52 @@ +assertSame('The dependency `Foo` is not registered.', $notRegistered->getMessage()); + $this->assertSame('The dependency `Bar` is already registered.', $alreadyRegistered->getMessage()); + $this->assertSame('The dependency `Baz` is not instantiable.', $notInstantiable->getMessage()); + $this->assertSame(E_ERROR, $notRegistered->getCode()); + $this->assertSame(E_ERROR, $alreadyRegistered->getCode()); + $this->assertSame(E_ERROR, $notInstantiable->getCode()); + } + + public function testAbstractAndCircularFactories(): void + { + $invalidAbstract = DiException::invalidAbstractDependency('Qux'); + $circular = DiException::circularDependency('A -> B -> A'); + + $this->assertSame('The dependency `Qux` is not valid abstract class.', $invalidAbstract->getMessage()); + $this->assertSame('Circular dependency detected: `A -> B -> A`', $circular->getMessage()); + $this->assertSame(E_ERROR, $invalidAbstract->getCode()); + $this->assertSame(E_ERROR, $circular->getCode()); + } + + public function testInvalidCallableFactory(): void + { + $withEntry = DiException::invalidCallable('foo'); + $withoutEntry = DiException::invalidCallable(); + + $this->assertSame( + 'Invalid callable provided: expected Closure or array-style callable `foo`', + $withEntry->getMessage() + ); + $this->assertSame( + 'Invalid callable provided: expected Closure or array-style callable ``', + $withoutEntry->getMessage() + ); + $this->assertSame(E_ERROR, $withEntry->getCode()); + $this->assertSame(E_ERROR, $withoutEntry->getCode()); + } +} + From e30bb61a23dde9ff84bbc5db119d389d5dee229b Mon Sep 17 00:00:00 2001 From: Arman <407448+armanist@users.noreply.github.com> Date: Wed, 29 Apr 2026 18:42:12 +0400 Subject: [PATCH 11/29] [#481] Add Encryption exception factory coverage tests --- .../Exceptions/CryptorExceptionTest.php | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 tests/Unit/Encryption/Exceptions/CryptorExceptionTest.php diff --git a/tests/Unit/Encryption/Exceptions/CryptorExceptionTest.php b/tests/Unit/Encryption/Exceptions/CryptorExceptionTest.php new file mode 100644 index 000000000..dbb1f7d16 --- /dev/null +++ b/tests/Unit/Encryption/Exceptions/CryptorExceptionTest.php @@ -0,0 +1,37 @@ +assertInstanceOf(CryptorException::class, $exception); + $this->assertSame('Public key is not provided', $exception->getMessage()); + $this->assertSame(E_WARNING, $exception->getCode()); + } + + public function testPrivateKeyNotProvided(): void + { + $exception = CryptorException::privateKeyNotProvided(); + + $this->assertInstanceOf(CryptorException::class, $exception); + $this->assertSame('Private key is not provided', $exception->getMessage()); + $this->assertSame(E_WARNING, $exception->getCode()); + } + + public function testInvalidCipher(): void + { + $exception = CryptorException::invalidCipher(); + + $this->assertInstanceOf(CryptorException::class, $exception); + $this->assertSame('The cipher is invalid', $exception->getMessage()); + $this->assertSame(E_WARNING, $exception->getCode()); + } +} + From 23ac19ce155ee9713ba0e5ab7fea11e1c854168b Mon Sep 17 00:00:00 2001 From: Arman <407448+armanist@users.noreply.github.com> Date: Wed, 29 Apr 2026 18:42:50 +0400 Subject: [PATCH 12/29] [#481] Add Environment exception factory coverage tests --- .../Exceptions/EnvExceptionTest.php | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 tests/Unit/Environment/Exceptions/EnvExceptionTest.php diff --git a/tests/Unit/Environment/Exceptions/EnvExceptionTest.php b/tests/Unit/Environment/Exceptions/EnvExceptionTest.php new file mode 100644 index 000000000..c1021519c --- /dev/null +++ b/tests/Unit/Environment/Exceptions/EnvExceptionTest.php @@ -0,0 +1,28 @@ +assertInstanceOf(EnvException::class, $exception); + $this->assertSame('The environment is immutable. Modifications are not allowed.', $exception->getMessage()); + $this->assertSame(E_ERROR, $exception->getCode()); + } + + public function testEnvironmentNotLoaded(): void + { + $exception = EnvException::environmentNotLoaded(); + + $this->assertInstanceOf(EnvException::class, $exception); + $this->assertSame('Environment not loaded. Call `load()` method first.', $exception->getMessage()); + $this->assertSame(E_ERROR, $exception->getCode()); + } +} + From fe637cfcf88b41935c52751ba25382b46f8da3fc Mon Sep 17 00:00:00 2001 From: Arman <407448+armanist@users.noreply.github.com> Date: Wed, 29 Apr 2026 18:45:50 +0400 Subject: [PATCH 13/29] [#481] Add Hasher exception factory coverage tests --- .../Hasher/Exceptions/HasherExceptionTest.php | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 tests/Unit/Hasher/Exceptions/HasherExceptionTest.php diff --git a/tests/Unit/Hasher/Exceptions/HasherExceptionTest.php b/tests/Unit/Hasher/Exceptions/HasherExceptionTest.php new file mode 100644 index 000000000..180d0a58e --- /dev/null +++ b/tests/Unit/Hasher/Exceptions/HasherExceptionTest.php @@ -0,0 +1,25 @@ +assertSame('The algorithm foo not supported.', $exception->getMessage()); + $this->assertSame(E_WARNING, $exception->getCode()); + } + + public function testInvalidBcryptCost(): void + { + $exception = HasherException::invalidBcryptCost(); + + $this->assertSame('Provided bcrypt cost is invalid.', $exception->getMessage()); + $this->assertSame(E_WARNING, $exception->getCode()); + } +} From 74583d9219124fed3919f85f72f0ada1c5cdef0e Mon Sep 17 00:00:00 2001 From: Arman <407448+armanist@users.noreply.github.com> Date: Wed, 29 Apr 2026 18:47:18 +0400 Subject: [PATCH 14/29] [#481] Add Hook exception factory coverage tests --- .../Hook/Exceptions/HookExceptionTest.php | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 tests/Unit/Hook/Exceptions/HookExceptionTest.php diff --git a/tests/Unit/Hook/Exceptions/HookExceptionTest.php b/tests/Unit/Hook/Exceptions/HookExceptionTest.php new file mode 100644 index 000000000..1b06fac55 --- /dev/null +++ b/tests/Unit/Hook/Exceptions/HookExceptionTest.php @@ -0,0 +1,28 @@ +assertInstanceOf(HookException::class, $exception); + $this->assertSame('The Hook `boot` already registered.', $exception->getMessage()); + $this->assertSame(E_ERROR, $exception->getCode()); + } + + public function testUnregisteredHookName(): void + { + $exception = HookException::unregisteredHookName('shutdown'); + + $this->assertInstanceOf(HookException::class, $exception); + $this->assertSame('The Hook `shutdown` was not registered.', $exception->getMessage()); + $this->assertSame(E_WARNING, $exception->getCode()); + } +} + From 2399500ea601f6e3ef728fe4fe4afcf110540b29 Mon Sep 17 00:00:00 2001 From: Arman <407448+armanist@users.noreply.github.com> Date: Wed, 29 Apr 2026 18:49:57 +0400 Subject: [PATCH 15/29] [#481] Add HttpClient exception factory coverage tests --- .../Exceptions/HttpClientExceptionTest.php | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 tests/Unit/HttpClient/Exceptions/HttpClientExceptionTest.php diff --git a/tests/Unit/HttpClient/Exceptions/HttpClientExceptionTest.php b/tests/Unit/HttpClient/Exceptions/HttpClientExceptionTest.php new file mode 100644 index 000000000..d1b551df2 --- /dev/null +++ b/tests/Unit/HttpClient/Exceptions/HttpClientExceptionTest.php @@ -0,0 +1,19 @@ +assertInstanceOf(HttpClientException::class, $exception); + $this->assertSame('Request is not created.', $exception->getMessage()); + $this->assertSame(E_WARNING, $exception->getCode()); + } +} + From d6657612ae38f4f26ad7b6259ad6df87b8eeb282 Mon Sep 17 00:00:00 2001 From: Arman <407448+armanist@users.noreply.github.com> Date: Wed, 29 Apr 2026 18:58:16 +0400 Subject: [PATCH 16/29] [#481] Add Jwt exception factory coverage tests --- .../Unit/Jwt/Exceptions/JwtExceptionTest.php | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 tests/Unit/Jwt/Exceptions/JwtExceptionTest.php diff --git a/tests/Unit/Jwt/Exceptions/JwtExceptionTest.php b/tests/Unit/Jwt/Exceptions/JwtExceptionTest.php new file mode 100644 index 000000000..a3c3c2ad9 --- /dev/null +++ b/tests/Unit/Jwt/Exceptions/JwtExceptionTest.php @@ -0,0 +1,19 @@ +assertInstanceOf(JwtException::class, $exception); + $this->assertSame('JWT payload is missing.', $exception->getMessage()); + $this->assertSame(E_WARNING, $exception->getCode()); + } +} + From 61206d1a195de6dfa528961273cfeb2a6f68aff4 Mon Sep 17 00:00:00 2001 From: Arman <407448+armanist@users.noreply.github.com> Date: Wed, 29 Apr 2026 18:59:34 +0400 Subject: [PATCH 17/29] [#481] Add Lang exception factory coverage tests --- .../Lang/Exceptions/LangExceptionTest.php | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 tests/Unit/Lang/Exceptions/LangExceptionTest.php diff --git a/tests/Unit/Lang/Exceptions/LangExceptionTest.php b/tests/Unit/Lang/Exceptions/LangExceptionTest.php new file mode 100644 index 000000000..f42a569c4 --- /dev/null +++ b/tests/Unit/Lang/Exceptions/LangExceptionTest.php @@ -0,0 +1,28 @@ +assertInstanceOf(LangException::class, $exception); + $this->assertSame('Translation files not found.', $exception->getMessage()); + $this->assertSame(E_WARNING, $exception->getCode()); + } + + public function testMisconfiguredDefaultConfig(): void + { + $exception = LangException::misconfiguredDefaultConfig(); + + $this->assertInstanceOf(LangException::class, $exception); + $this->assertSame('Misconfigured lang default config.', $exception->getMessage()); + $this->assertSame(E_WARNING, $exception->getCode()); + } +} + From dd8938300cf5547c490e3fef4d6375ec0cfa341a Mon Sep 17 00:00:00 2001 From: Arman <407448+armanist@users.noreply.github.com> Date: Wed, 29 Apr 2026 19:04:37 +0400 Subject: [PATCH 18/29] [#481] Add Logger exception factory coverage tests --- .../Logger/Exceptions/LoggerExceptionTest.php | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 tests/Unit/Logger/Exceptions/LoggerExceptionTest.php diff --git a/tests/Unit/Logger/Exceptions/LoggerExceptionTest.php b/tests/Unit/Logger/Exceptions/LoggerExceptionTest.php new file mode 100644 index 000000000..f2e67f299 --- /dev/null +++ b/tests/Unit/Logger/Exceptions/LoggerExceptionTest.php @@ -0,0 +1,28 @@ +assertInstanceOf(LoggerException::class, $exception); + $this->assertSame('Log path is not point to a directory.', $exception->getMessage()); + $this->assertSame(E_ERROR, $exception->getCode()); + } + + public function testLogPathIsNotFile(): void + { + $exception = LoggerException::logPathIsNotFile('/tmp/logs'); + + $this->assertInstanceOf(LoggerException::class, $exception); + $this->assertSame('Log path is not point to a file.', $exception->getMessage()); + $this->assertSame(E_ERROR, $exception->getCode()); + } +} + From 0ac782a0115ef715c9273fcfb9de0ed633db8579 Mon Sep 17 00:00:00 2001 From: Arman <407448+armanist@users.noreply.github.com> Date: Wed, 29 Apr 2026 19:05:35 +0400 Subject: [PATCH 19/29] [#481] Add Middleware exception factory coverage tests --- .../Exceptions/MiddlewareExceptionTest.php | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 tests/Unit/Middleware/Exceptions/MiddlewareExceptionTest.php diff --git a/tests/Unit/Middleware/Exceptions/MiddlewareExceptionTest.php b/tests/Unit/Middleware/Exceptions/MiddlewareExceptionTest.php new file mode 100644 index 000000000..f1a1c96b9 --- /dev/null +++ b/tests/Unit/Middleware/Exceptions/MiddlewareExceptionTest.php @@ -0,0 +1,19 @@ +assertInstanceOf(MiddlewareException::class, $exception); + $this->assertSame('Middleware class `App\\Middlewares\\Auth` not found.', $exception->getMessage()); + $this->assertSame(E_ERROR, $exception->getCode()); + } +} + From c655a834333dc923f8d212ca7225ae567297cf73 Mon Sep 17 00:00:00 2001 From: Arman <407448+armanist@users.noreply.github.com> Date: Wed, 29 Apr 2026 19:06:20 +0400 Subject: [PATCH 20/29] [#481] Add Migration exception factory coverage tests --- .../Exceptions/MigrationExceptionTest.php | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 tests/Unit/Migration/Exceptions/MigrationExceptionTest.php diff --git a/tests/Unit/Migration/Exceptions/MigrationExceptionTest.php b/tests/Unit/Migration/Exceptions/MigrationExceptionTest.php new file mode 100644 index 000000000..b39d3a6f9 --- /dev/null +++ b/tests/Unit/Migration/Exceptions/MigrationExceptionTest.php @@ -0,0 +1,46 @@ +assertInstanceOf(MigrationException::class, $exception); + $this->assertSame('Migration direction can only be [up] or [down]', $exception->getMessage()); + $this->assertSame(E_ERROR, $exception->getCode()); + } + + public function testUnsupportedAction(): void + { + $exception = MigrationException::unsupportedAction('sync'); + + $this->assertInstanceOf(MigrationException::class, $exception); + $this->assertSame('The action `sync`, is not supported', $exception->getMessage()); + $this->assertSame(E_ERROR, $exception->getCode()); + } + + public function testNothingToMigrate(): void + { + $exception = MigrationException::nothingToMigrate(); + + $this->assertInstanceOf(MigrationException::class, $exception); + $this->assertSame('Nothing to migrate', $exception->getMessage()); + $this->assertSame(E_NOTICE, $exception->getCode()); + } + + public function testInvalidMigrationClass(): void + { + $exception = MigrationException::invalidMigrationClass('FooMigration'); + + $this->assertInstanceOf(MigrationException::class, $exception); + $this->assertSame('Migration class `FooMigration` must extend QtMigration', $exception->getMessage()); + $this->assertSame(E_ERROR, $exception->getCode()); + } +} + From 87d63ba5d23e5eb8703ff7ce8e9c7d912914987b Mon Sep 17 00:00:00 2001 From: Arman <407448+armanist@users.noreply.github.com> Date: Wed, 29 Apr 2026 19:07:12 +0400 Subject: [PATCH 21/29] [#481] Add Model exception factory coverage tests --- .../Model/Exceptions/ModelExceptionTest.php | 59 +++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 tests/Unit/Model/Exceptions/ModelExceptionTest.php diff --git a/tests/Unit/Model/Exceptions/ModelExceptionTest.php b/tests/Unit/Model/Exceptions/ModelExceptionTest.php new file mode 100644 index 000000000..61b15af59 --- /dev/null +++ b/tests/Unit/Model/Exceptions/ModelExceptionTest.php @@ -0,0 +1,59 @@ +assertSame('Inappropriate property `foo` for fillable object', $e->getMessage()); + $this->assertSame(E_WARNING, $e->getCode()); + } + + public function testWrongRelation(): void + { + $e = ModelException::wrongRelation('User', 'posts'); + $this->assertSame('The model `User` does not define relation with `posts`', $e->getMessage()); + $this->assertSame(E_ERROR, $e->getCode()); + } + + public function testRelationTypeMissing(): void + { + $e = ModelException::relationTypeMissing('User', 'Post'); + $this->assertSame('Relation type is missing for model `User` with related model `Post`', $e->getMessage()); + $this->assertSame(E_ERROR, $e->getCode()); + } + + public function testMissingRelationKeys(): void + { + $e = ModelException::missingRelationKeys('User', 'Post'); + $this->assertSame('Relation keys `foreign_key` or `local_key` are missing for model `User` with related model `Post`', $e->getMessage()); + $this->assertSame(E_ERROR, $e->getCode()); + } + + public function testMissingForeignKeyValue(): void + { + $e = ModelException::missingForeignKeyValue('User', 'profile_id'); + $this->assertSame('Foreign key `profile_id` is missing in model `User`', $e->getMessage()); + $this->assertSame(E_ERROR, $e->getCode()); + } + + public function testUnsupportedRelationType(): void + { + $e = ModelException::unsupportedRelationType('foo'); + $this->assertSame('Relation type `foo` is not supported', $e->getMessage()); + $this->assertSame(E_ERROR, $e->getCode()); + } + + public function testOrmIsNotSet(): void + { + $e = ModelException::ormIsNotSet(); + $this->assertSame('ORM instance not initialized', $e->getMessage()); + $this->assertSame(E_ERROR, $e->getCode()); + } +} + From 32c594198a66118acf5c07834eb25d8d8b3ad8a7 Mon Sep 17 00:00:00 2001 From: Arman <407448+armanist@users.noreply.github.com> Date: Wed, 29 Apr 2026 19:12:11 +0400 Subject: [PATCH 22/29] [#481] Add Module exception factory coverage tests --- .../Module/Exceptions/ModuleExceptionTest.php | 59 +++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 tests/Unit/Module/Exceptions/ModuleExceptionTest.php diff --git a/tests/Unit/Module/Exceptions/ModuleExceptionTest.php b/tests/Unit/Module/Exceptions/ModuleExceptionTest.php new file mode 100644 index 000000000..fbdcd8b6d --- /dev/null +++ b/tests/Unit/Module/Exceptions/ModuleExceptionTest.php @@ -0,0 +1,59 @@ +assertSame('Routes not found for module `Blog`', $e->getMessage()); + $this->assertSame(E_ERROR, $e->getCode()); + } + + public function testModuleConfigNotFound(): void + { + $e = ModuleException::moduleConfigNotFound(); + $this->assertSame('Config not found for a module', $e->getMessage()); + $this->assertSame(E_ERROR, $e->getCode()); + } + + public function testModuleCreationIncomplete(): void + { + $e = ModuleException::moduleCreationIncomplete(); + $this->assertSame('Module creation incomplete: missing files.', $e->getMessage()); + $this->assertSame(E_ERROR, $e->getCode()); + } + + public function testMissingModuleTemplate(): void + { + $e = ModuleException::missingModuleTemplate('demo'); + $this->assertSame('Template `demo` does not exist', $e->getMessage()); + $this->assertSame(E_ERROR, $e->getCode()); + } + + public function testMissingModuleDirectory(): void + { + $e = ModuleException::missingModuleDirectory(); + $this->assertSame('Module directory does not exist, skipping config update.', $e->getMessage()); + $this->assertSame(E_ERROR, $e->getCode()); + } + + public function testModuleAlreadyExists(): void + { + $e = ModuleException::moduleAlreadyExists('Admin'); + $this->assertSame('A module or prefix named `Admin` already exists', $e->getMessage()); + $this->assertSame(E_ERROR, $e->getCode()); + } + + public function testDirectoryListingFailed(): void + { + $e = ModuleException::directoryListingFailed('/tmp/src'); + $this->assertSame('Failed to list directory `/tmp/src`', $e->getMessage()); + $this->assertSame(E_ERROR, $e->getCode()); + } +} + From aa4145e808bab46dda36ede06fc76c1b702692c6 Mon Sep 17 00:00:00 2001 From: Arman <407448+armanist@users.noreply.github.com> Date: Wed, 29 Apr 2026 19:13:03 +0400 Subject: [PATCH 23/29] [#481] Add Paginator exception factory coverage tests --- .../Exceptions/PaginatorExceptionTest.php | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 tests/Unit/Paginator/Exceptions/PaginatorExceptionTest.php diff --git a/tests/Unit/Paginator/Exceptions/PaginatorExceptionTest.php b/tests/Unit/Paginator/Exceptions/PaginatorExceptionTest.php new file mode 100644 index 000000000..7428bd62c --- /dev/null +++ b/tests/Unit/Paginator/Exceptions/PaginatorExceptionTest.php @@ -0,0 +1,19 @@ +assertInstanceOf(PaginatorException::class, $exception); + $this->assertSame('Missing required parameter `items` missing for adapter Array', $exception->getMessage()); + $this->assertSame(E_WARNING, $exception->getCode()); + } +} + From 85b53c2a853c5b64f4a7f836b731a90ec25110ca Mon Sep 17 00:00:00 2001 From: Arman <407448+armanist@users.noreply.github.com> Date: Wed, 29 Apr 2026 19:13:55 +0400 Subject: [PATCH 24/29] [#481] Add Router exception factory coverage tests --- .../Router/Exceptions/RouteExceptionTest.php | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 tests/Unit/Router/Exceptions/RouteExceptionTest.php diff --git a/tests/Unit/Router/Exceptions/RouteExceptionTest.php b/tests/Unit/Router/Exceptions/RouteExceptionTest.php new file mode 100644 index 000000000..f8d7a243a --- /dev/null +++ b/tests/Unit/Router/Exceptions/RouteExceptionTest.php @@ -0,0 +1,36 @@ +assertSame('Route must define at least one HTTP method', RouteException::noHttpMethods()->getMessage()); + $this->assertSame(E_ERROR, RouteException::noHttpMethods()->getCode()); + $this->assertSame('Closure route cannot define controller or action', RouteException::closureWithController()->getMessage()); + $this->assertSame(E_WARNING, RouteException::closureWithController()->getCode()); + $this->assertSame('Controller route must define non-empty controller and action', RouteException::incompleteControllerRoute()->getMessage()); + $this->assertSame('Nested route groups are not supported', RouteException::nestedGroups()->getMessage()); + $this->assertSame('middlewares() must be called inside a group or after a route definition', RouteException::middlewaresOutsideRoute()->getMessage()); + $this->assertSame('Cannot resolve controller without module context', RouteException::controllerWithoutModule()->getMessage()); + $this->assertSame('cacheable() must be called inside a group or after a route definition', RouteException::cacheableOutsideRoute()->getMessage()); + $this->assertSame('Closure route is missing its closure handler', RouteException::closureHandlerMissing()->getMessage()); + $this->assertSame('Route is not a closure', RouteException::notClosure()->getMessage()); + $this->assertSame('Names can not be set before route definition', RouteException::nameBeforeDefinition()->getMessage()); + $this->assertSame('Route param names can only contain letters', RouteException::paramNameNotValid()->getMessage()); + } + + public function testParameterizedFactories(): void + { + $this->assertSame('Routes for module `Blog` must return a Closure', RouteException::moduleRoutesNotClosure('Blog')->getMessage()); + $this->assertSame('Route name `home` must be unique within module', RouteException::nonUniqueNameInModule('home')->getMessage()); + $this->assertSame('Action `index` not found on controller `PostController`', RouteException::actionNotFound('index', 'PostController')->getMessage()); + $this->assertSame('Route handler `handler` must return `Quantum\\Http\\Response`', RouteException::invalidHandlerResponse('handler', 'Quantum\\Http\\Response')->getMessage()); + $this->assertSame('Route param name `id` already in use', RouteException::paramNameNotAvailable('id')->getMessage()); + } +} + From a27e733cd9c0d54104d0a4e8ed1c72f6a7e28e42 Mon Sep 17 00:00:00 2001 From: Arman <407448+armanist@users.noreply.github.com> Date: Wed, 29 Apr 2026 19:15:16 +0400 Subject: [PATCH 25/29] [#481] Add Session exception factory coverage tests --- .../Exceptions/SessionExceptionTest.php | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 tests/Unit/Session/Exceptions/SessionExceptionTest.php diff --git a/tests/Unit/Session/Exceptions/SessionExceptionTest.php b/tests/Unit/Session/Exceptions/SessionExceptionTest.php new file mode 100644 index 000000000..d59b0bee2 --- /dev/null +++ b/tests/Unit/Session/Exceptions/SessionExceptionTest.php @@ -0,0 +1,28 @@ +assertInstanceOf(SessionException::class, $exception); + $this->assertSame('Can not start the session.', $exception->getMessage()); + $this->assertSame(E_WARNING, $exception->getCode()); + } + + public function testSessionNotDestroyed(): void + { + $exception = SessionException::sessionNotDestroyed(); + + $this->assertInstanceOf(SessionException::class, $exception); + $this->assertSame('Can not destroy the session.', $exception->getMessage()); + $this->assertSame(E_WARNING, $exception->getCode()); + } +} + From 5b1b056364cdd925b2631a32e21e59281bacffcd Mon Sep 17 00:00:00 2001 From: Arman <407448+armanist@users.noreply.github.com> Date: Wed, 29 Apr 2026 19:17:02 +0400 Subject: [PATCH 26/29] [#481] Add Storage exception factory coverage tests --- .../Exceptions/FileSystemExceptionTest.php | 31 +++++++++++++++++++ .../Exceptions/FileUploadExceptionTest.php | 24 ++++++++++++++ 2 files changed, 55 insertions(+) create mode 100644 tests/Unit/Storage/Exceptions/FileSystemExceptionTest.php create mode 100644 tests/Unit/Storage/Exceptions/FileUploadExceptionTest.php diff --git a/tests/Unit/Storage/Exceptions/FileSystemExceptionTest.php b/tests/Unit/Storage/Exceptions/FileSystemExceptionTest.php new file mode 100644 index 000000000..60e3ab433 --- /dev/null +++ b/tests/Unit/Storage/Exceptions/FileSystemExceptionTest.php @@ -0,0 +1,31 @@ +assertSame('The directory /tmp/a does not exists.', $exception->getMessage()); + $this->assertSame(E_WARNING, $exception->getCode()); + } + + public function testDirectoryNotWritable(): void + { + $exception = FileSystemException::directoryNotWritable('/tmp/b'); + $this->assertSame('The directory /tmp/b is not writable.', $exception->getMessage()); + $this->assertSame(E_WARNING, $exception->getCode()); + } + + public function testFileAlreadyExists(): void + { + $exception = FileSystemException::fileAlreadyExists('/tmp/c.txt'); + $this->assertSame('The file /tmp/c.txt already exists.', $exception->getMessage()); + $this->assertSame(E_WARNING, $exception->getCode()); + } +} + diff --git a/tests/Unit/Storage/Exceptions/FileUploadExceptionTest.php b/tests/Unit/Storage/Exceptions/FileUploadExceptionTest.php new file mode 100644 index 000000000..c45070c5a --- /dev/null +++ b/tests/Unit/Storage/Exceptions/FileUploadExceptionTest.php @@ -0,0 +1,24 @@ +assertSame('The file type `exe` is not allowed.', $exception->getMessage()); + $this->assertSame(E_WARNING, $exception->getCode()); + } + + public function testIncorrectMimeTypesConfig(): void + { + $exception = FileUploadException::incorrectMimeTypesConfig('uploads'); + $this->assertSame('Could not load config `uploads` properly.', $exception->getMessage()); + $this->assertSame(E_ERROR, $exception->getCode()); + } +} + From 8bd7838724dafcb7c027dfba830da10112afd101 Mon Sep 17 00:00:00 2001 From: Arman <407448+armanist@users.noreply.github.com> Date: Wed, 29 Apr 2026 19:18:12 +0400 Subject: [PATCH 27/29] [#481] Add View exception factory coverage tests --- .../View/Exceptions/ViewExceptionTest.php | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 tests/Unit/View/Exceptions/ViewExceptionTest.php diff --git a/tests/Unit/View/Exceptions/ViewExceptionTest.php b/tests/Unit/View/Exceptions/ViewExceptionTest.php new file mode 100644 index 000000000..fb345b527 --- /dev/null +++ b/tests/Unit/View/Exceptions/ViewExceptionTest.php @@ -0,0 +1,28 @@ +assertInstanceOf(ViewException::class, $exception); + $this->assertSame('Layout is not set.', $exception->getMessage()); + $this->assertSame(E_ERROR, $exception->getCode()); + } + + public function testViewNotRendered(): void + { + $exception = ViewException::viewNotRendered(); + + $this->assertInstanceOf(ViewException::class, $exception); + $this->assertSame('View not rendered yet.', $exception->getMessage()); + $this->assertSame(E_ERROR, $exception->getCode()); + } +} + From f0243f751ba5cc705bcb9e432e780e5c761eea72 Mon Sep 17 00:00:00 2001 From: Arman <407448+armanist@users.noreply.github.com> Date: Wed, 29 Apr 2026 19:40:29 +0400 Subject: [PATCH 28/29] [#481] CS fixes --- tests/Unit/App/Exceptions/AppExceptionTest.php | 1 - tests/Unit/App/Exceptions/BaseExceptionTest.php | 1 - tests/Unit/Csrf/Exceptions/CsrfExceptionTest.php | 1 - tests/Unit/Database/Exceptions/DatabaseExceptionTest.php | 1 - tests/Unit/Di/Exceptions/DiExceptionTest.php | 1 - tests/Unit/Encryption/Exceptions/CryptorExceptionTest.php | 1 - tests/Unit/Environment/Exceptions/EnvExceptionTest.php | 1 - tests/Unit/Hook/Exceptions/HookExceptionTest.php | 1 - tests/Unit/HttpClient/Exceptions/HttpClientExceptionTest.php | 1 - tests/Unit/Jwt/Exceptions/JwtExceptionTest.php | 1 - tests/Unit/Lang/Exceptions/LangExceptionTest.php | 1 - tests/Unit/Logger/Exceptions/LoggerExceptionTest.php | 1 - tests/Unit/Middleware/Exceptions/MiddlewareExceptionTest.php | 1 - tests/Unit/Migration/Exceptions/MigrationExceptionTest.php | 1 - tests/Unit/Model/Exceptions/ModelExceptionTest.php | 1 - tests/Unit/Module/Exceptions/ModuleExceptionTest.php | 1 - tests/Unit/Paginator/Exceptions/PaginatorExceptionTest.php | 1 - tests/Unit/Router/Exceptions/RouteExceptionTest.php | 1 - tests/Unit/Session/Exceptions/SessionExceptionTest.php | 1 - tests/Unit/Storage/Exceptions/FileSystemExceptionTest.php | 1 - tests/Unit/Storage/Exceptions/FileUploadExceptionTest.php | 1 - tests/Unit/View/Exceptions/ViewExceptionTest.php | 1 - 22 files changed, 22 deletions(-) diff --git a/tests/Unit/App/Exceptions/AppExceptionTest.php b/tests/Unit/App/Exceptions/AppExceptionTest.php index bfc8c35b6..f5c78f5d3 100644 --- a/tests/Unit/App/Exceptions/AppExceptionTest.php +++ b/tests/Unit/App/Exceptions/AppExceptionTest.php @@ -16,4 +16,3 @@ public function testMissingAppKeyFactory(): void $this->assertSame(E_ERROR, $exception->getCode()); } } - diff --git a/tests/Unit/App/Exceptions/BaseExceptionTest.php b/tests/Unit/App/Exceptions/BaseExceptionTest.php index f31346756..d627b37a7 100644 --- a/tests/Unit/App/Exceptions/BaseExceptionTest.php +++ b/tests/Unit/App/Exceptions/BaseExceptionTest.php @@ -59,4 +59,3 @@ public function testConfigAndRequestMethodFactories(): void $this->assertSame(E_WARNING, $methodException->getCode()); } } - diff --git a/tests/Unit/Csrf/Exceptions/CsrfExceptionTest.php b/tests/Unit/Csrf/Exceptions/CsrfExceptionTest.php index f80f4396c..b8fa24d66 100644 --- a/tests/Unit/Csrf/Exceptions/CsrfExceptionTest.php +++ b/tests/Unit/Csrf/Exceptions/CsrfExceptionTest.php @@ -25,4 +25,3 @@ public function testTokenNotMatched(): void $this->assertSame(E_WARNING, $exception->getCode()); } } - diff --git a/tests/Unit/Database/Exceptions/DatabaseExceptionTest.php b/tests/Unit/Database/Exceptions/DatabaseExceptionTest.php index a9b0bcbea..af7dc5d99 100644 --- a/tests/Unit/Database/Exceptions/DatabaseExceptionTest.php +++ b/tests/Unit/Database/Exceptions/DatabaseExceptionTest.php @@ -43,4 +43,3 @@ public function testTableDoesNotExists(): void $this->assertSame(E_ERROR, $exception->getCode()); } } - diff --git a/tests/Unit/Di/Exceptions/DiExceptionTest.php b/tests/Unit/Di/Exceptions/DiExceptionTest.php index 882580f74..e2533d881 100644 --- a/tests/Unit/Di/Exceptions/DiExceptionTest.php +++ b/tests/Unit/Di/Exceptions/DiExceptionTest.php @@ -49,4 +49,3 @@ public function testInvalidCallableFactory(): void $this->assertSame(E_ERROR, $withoutEntry->getCode()); } } - diff --git a/tests/Unit/Encryption/Exceptions/CryptorExceptionTest.php b/tests/Unit/Encryption/Exceptions/CryptorExceptionTest.php index dbb1f7d16..af5d46a59 100644 --- a/tests/Unit/Encryption/Exceptions/CryptorExceptionTest.php +++ b/tests/Unit/Encryption/Exceptions/CryptorExceptionTest.php @@ -34,4 +34,3 @@ public function testInvalidCipher(): void $this->assertSame(E_WARNING, $exception->getCode()); } } - diff --git a/tests/Unit/Environment/Exceptions/EnvExceptionTest.php b/tests/Unit/Environment/Exceptions/EnvExceptionTest.php index c1021519c..e1b044c42 100644 --- a/tests/Unit/Environment/Exceptions/EnvExceptionTest.php +++ b/tests/Unit/Environment/Exceptions/EnvExceptionTest.php @@ -25,4 +25,3 @@ public function testEnvironmentNotLoaded(): void $this->assertSame(E_ERROR, $exception->getCode()); } } - diff --git a/tests/Unit/Hook/Exceptions/HookExceptionTest.php b/tests/Unit/Hook/Exceptions/HookExceptionTest.php index 1b06fac55..2df1e632b 100644 --- a/tests/Unit/Hook/Exceptions/HookExceptionTest.php +++ b/tests/Unit/Hook/Exceptions/HookExceptionTest.php @@ -25,4 +25,3 @@ public function testUnregisteredHookName(): void $this->assertSame(E_WARNING, $exception->getCode()); } } - diff --git a/tests/Unit/HttpClient/Exceptions/HttpClientExceptionTest.php b/tests/Unit/HttpClient/Exceptions/HttpClientExceptionTest.php index d1b551df2..77fa41e53 100644 --- a/tests/Unit/HttpClient/Exceptions/HttpClientExceptionTest.php +++ b/tests/Unit/HttpClient/Exceptions/HttpClientExceptionTest.php @@ -16,4 +16,3 @@ public function testRequestNotCreated(): void $this->assertSame(E_WARNING, $exception->getCode()); } } - diff --git a/tests/Unit/Jwt/Exceptions/JwtExceptionTest.php b/tests/Unit/Jwt/Exceptions/JwtExceptionTest.php index a3c3c2ad9..d2659b4f9 100644 --- a/tests/Unit/Jwt/Exceptions/JwtExceptionTest.php +++ b/tests/Unit/Jwt/Exceptions/JwtExceptionTest.php @@ -16,4 +16,3 @@ public function testPayloadNotFound(): void $this->assertSame(E_WARNING, $exception->getCode()); } } - diff --git a/tests/Unit/Lang/Exceptions/LangExceptionTest.php b/tests/Unit/Lang/Exceptions/LangExceptionTest.php index f42a569c4..62113ac5b 100644 --- a/tests/Unit/Lang/Exceptions/LangExceptionTest.php +++ b/tests/Unit/Lang/Exceptions/LangExceptionTest.php @@ -25,4 +25,3 @@ public function testMisconfiguredDefaultConfig(): void $this->assertSame(E_WARNING, $exception->getCode()); } } - diff --git a/tests/Unit/Logger/Exceptions/LoggerExceptionTest.php b/tests/Unit/Logger/Exceptions/LoggerExceptionTest.php index f2e67f299..98e98f766 100644 --- a/tests/Unit/Logger/Exceptions/LoggerExceptionTest.php +++ b/tests/Unit/Logger/Exceptions/LoggerExceptionTest.php @@ -25,4 +25,3 @@ public function testLogPathIsNotFile(): void $this->assertSame(E_ERROR, $exception->getCode()); } } - diff --git a/tests/Unit/Middleware/Exceptions/MiddlewareExceptionTest.php b/tests/Unit/Middleware/Exceptions/MiddlewareExceptionTest.php index f1a1c96b9..cfe007408 100644 --- a/tests/Unit/Middleware/Exceptions/MiddlewareExceptionTest.php +++ b/tests/Unit/Middleware/Exceptions/MiddlewareExceptionTest.php @@ -16,4 +16,3 @@ public function testMiddlewareNotFound(): void $this->assertSame(E_ERROR, $exception->getCode()); } } - diff --git a/tests/Unit/Migration/Exceptions/MigrationExceptionTest.php b/tests/Unit/Migration/Exceptions/MigrationExceptionTest.php index b39d3a6f9..7ee61163e 100644 --- a/tests/Unit/Migration/Exceptions/MigrationExceptionTest.php +++ b/tests/Unit/Migration/Exceptions/MigrationExceptionTest.php @@ -43,4 +43,3 @@ public function testInvalidMigrationClass(): void $this->assertSame(E_ERROR, $exception->getCode()); } } - diff --git a/tests/Unit/Model/Exceptions/ModelExceptionTest.php b/tests/Unit/Model/Exceptions/ModelExceptionTest.php index 61b15af59..834b1caf1 100644 --- a/tests/Unit/Model/Exceptions/ModelExceptionTest.php +++ b/tests/Unit/Model/Exceptions/ModelExceptionTest.php @@ -56,4 +56,3 @@ public function testOrmIsNotSet(): void $this->assertSame(E_ERROR, $e->getCode()); } } - diff --git a/tests/Unit/Module/Exceptions/ModuleExceptionTest.php b/tests/Unit/Module/Exceptions/ModuleExceptionTest.php index fbdcd8b6d..15906bc02 100644 --- a/tests/Unit/Module/Exceptions/ModuleExceptionTest.php +++ b/tests/Unit/Module/Exceptions/ModuleExceptionTest.php @@ -56,4 +56,3 @@ public function testDirectoryListingFailed(): void $this->assertSame(E_ERROR, $e->getCode()); } } - diff --git a/tests/Unit/Paginator/Exceptions/PaginatorExceptionTest.php b/tests/Unit/Paginator/Exceptions/PaginatorExceptionTest.php index 7428bd62c..e676f989a 100644 --- a/tests/Unit/Paginator/Exceptions/PaginatorExceptionTest.php +++ b/tests/Unit/Paginator/Exceptions/PaginatorExceptionTest.php @@ -16,4 +16,3 @@ public function testMissingRequiredParams(): void $this->assertSame(E_WARNING, $exception->getCode()); } } - diff --git a/tests/Unit/Router/Exceptions/RouteExceptionTest.php b/tests/Unit/Router/Exceptions/RouteExceptionTest.php index f8d7a243a..4ef9260e3 100644 --- a/tests/Unit/Router/Exceptions/RouteExceptionTest.php +++ b/tests/Unit/Router/Exceptions/RouteExceptionTest.php @@ -33,4 +33,3 @@ public function testParameterizedFactories(): void $this->assertSame('Route param name `id` already in use', RouteException::paramNameNotAvailable('id')->getMessage()); } } - diff --git a/tests/Unit/Session/Exceptions/SessionExceptionTest.php b/tests/Unit/Session/Exceptions/SessionExceptionTest.php index d59b0bee2..f3e21f873 100644 --- a/tests/Unit/Session/Exceptions/SessionExceptionTest.php +++ b/tests/Unit/Session/Exceptions/SessionExceptionTest.php @@ -25,4 +25,3 @@ public function testSessionNotDestroyed(): void $this->assertSame(E_WARNING, $exception->getCode()); } } - diff --git a/tests/Unit/Storage/Exceptions/FileSystemExceptionTest.php b/tests/Unit/Storage/Exceptions/FileSystemExceptionTest.php index 60e3ab433..eaaf70f08 100644 --- a/tests/Unit/Storage/Exceptions/FileSystemExceptionTest.php +++ b/tests/Unit/Storage/Exceptions/FileSystemExceptionTest.php @@ -28,4 +28,3 @@ public function testFileAlreadyExists(): void $this->assertSame(E_WARNING, $exception->getCode()); } } - diff --git a/tests/Unit/Storage/Exceptions/FileUploadExceptionTest.php b/tests/Unit/Storage/Exceptions/FileUploadExceptionTest.php index c45070c5a..0de11bce0 100644 --- a/tests/Unit/Storage/Exceptions/FileUploadExceptionTest.php +++ b/tests/Unit/Storage/Exceptions/FileUploadExceptionTest.php @@ -21,4 +21,3 @@ public function testIncorrectMimeTypesConfig(): void $this->assertSame(E_ERROR, $exception->getCode()); } } - diff --git a/tests/Unit/View/Exceptions/ViewExceptionTest.php b/tests/Unit/View/Exceptions/ViewExceptionTest.php index fb345b527..1a779c579 100644 --- a/tests/Unit/View/Exceptions/ViewExceptionTest.php +++ b/tests/Unit/View/Exceptions/ViewExceptionTest.php @@ -25,4 +25,3 @@ public function testViewNotRendered(): void $this->assertSame(E_ERROR, $exception->getCode()); } } - From 6efc846e9e41bdda86d1e6ed96a528e3edc6b696 Mon Sep 17 00:00:00 2001 From: Arman <407448+armanist@users.noreply.github.com> Date: Wed, 29 Apr 2026 19:48:18 +0400 Subject: [PATCH 29/29] Fix CaptchaException docblock and RouteException code assertions --- src/Captcha/Exceptions/CaptchaException.php | 2 +- .../Unit/Router/Exceptions/RouteExceptionTest.php | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/Captcha/Exceptions/CaptchaException.php b/src/Captcha/Exceptions/CaptchaException.php index f80ba63f1..52b0e0e79 100644 --- a/src/Captcha/Exceptions/CaptchaException.php +++ b/src/Captcha/Exceptions/CaptchaException.php @@ -19,7 +19,7 @@ use Quantum\App\Exceptions\BaseException; /** - * Class CacheException + * Class CaptchaException * @package Quantum\Captcha * @codeCoverageIgnore */ diff --git a/tests/Unit/Router/Exceptions/RouteExceptionTest.php b/tests/Unit/Router/Exceptions/RouteExceptionTest.php index 4ef9260e3..c4e9cc56f 100644 --- a/tests/Unit/Router/Exceptions/RouteExceptionTest.php +++ b/tests/Unit/Router/Exceptions/RouteExceptionTest.php @@ -14,22 +14,36 @@ public function testCoreFactories(): void $this->assertSame('Closure route cannot define controller or action', RouteException::closureWithController()->getMessage()); $this->assertSame(E_WARNING, RouteException::closureWithController()->getCode()); $this->assertSame('Controller route must define non-empty controller and action', RouteException::incompleteControllerRoute()->getMessage()); + $this->assertSame(E_ERROR, RouteException::incompleteControllerRoute()->getCode()); $this->assertSame('Nested route groups are not supported', RouteException::nestedGroups()->getMessage()); + $this->assertSame(E_WARNING, RouteException::nestedGroups()->getCode()); $this->assertSame('middlewares() must be called inside a group or after a route definition', RouteException::middlewaresOutsideRoute()->getMessage()); + $this->assertSame(E_WARNING, RouteException::middlewaresOutsideRoute()->getCode()); $this->assertSame('Cannot resolve controller without module context', RouteException::controllerWithoutModule()->getMessage()); + $this->assertSame(E_ERROR, RouteException::controllerWithoutModule()->getCode()); $this->assertSame('cacheable() must be called inside a group or after a route definition', RouteException::cacheableOutsideRoute()->getMessage()); + $this->assertSame(E_WARNING, RouteException::cacheableOutsideRoute()->getCode()); $this->assertSame('Closure route is missing its closure handler', RouteException::closureHandlerMissing()->getMessage()); + $this->assertSame(E_ERROR, RouteException::closureHandlerMissing()->getCode()); $this->assertSame('Route is not a closure', RouteException::notClosure()->getMessage()); + $this->assertSame(E_WARNING, RouteException::notClosure()->getCode()); $this->assertSame('Names can not be set before route definition', RouteException::nameBeforeDefinition()->getMessage()); + $this->assertSame(E_WARNING, RouteException::nameBeforeDefinition()->getCode()); $this->assertSame('Route param names can only contain letters', RouteException::paramNameNotValid()->getMessage()); + $this->assertSame(E_WARNING, RouteException::paramNameNotValid()->getCode()); } public function testParameterizedFactories(): void { $this->assertSame('Routes for module `Blog` must return a Closure', RouteException::moduleRoutesNotClosure('Blog')->getMessage()); + $this->assertSame(E_ERROR, RouteException::moduleRoutesNotClosure('Blog')->getCode()); $this->assertSame('Route name `home` must be unique within module', RouteException::nonUniqueNameInModule('home')->getMessage()); + $this->assertSame(E_WARNING, RouteException::nonUniqueNameInModule('home')->getCode()); $this->assertSame('Action `index` not found on controller `PostController`', RouteException::actionNotFound('index', 'PostController')->getMessage()); + $this->assertSame(E_ERROR, RouteException::actionNotFound('index', 'PostController')->getCode()); $this->assertSame('Route handler `handler` must return `Quantum\\Http\\Response`', RouteException::invalidHandlerResponse('handler', 'Quantum\\Http\\Response')->getMessage()); + $this->assertSame(E_ERROR, RouteException::invalidHandlerResponse('handler', 'Quantum\\Http\\Response')->getCode()); $this->assertSame('Route param name `id` already in use', RouteException::paramNameNotAvailable('id')->getMessage()); + $this->assertSame(E_WARNING, RouteException::paramNameNotAvailable('id')->getCode()); } }