From ebdca743aaec116942ed258718d8c823cffb49f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=20G=C3=B3mez?= Date: Tue, 3 Oct 2023 18:38:36 +0200 Subject: [PATCH] chore(phpat): test shared infrastructure architecture --- phpstan.neon | 6 ++ src/Shared/Domain/Utils.php | 9 --- .../Symfony/ApiExceptionListener.php | 10 +++- tests/Mooc/MoocArchitectureTest.php | 56 +++++++++++++++++++ .../Infrastructure/ArchitectureTest.php | 40 +++++++++++++ tests/Shared/SharedArchitectureTest.php | 35 +----------- 6 files changed, 113 insertions(+), 43 deletions(-) create mode 100644 tests/Mooc/MoocArchitectureTest.php create mode 100644 tests/Shared/Infrastructure/ArchitectureTest.php diff --git a/phpstan.neon b/phpstan.neon index e0cc48dcd..4404d69b2 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -12,8 +12,14 @@ parameters: - ./apps/backoffice/frontend/var - ./apps/mooc/backend/var - ./apps/mooc/frontend/var + services: - class: CodelyTv\Tests\Shared\SharedArchitectureTest tags: - phpat.test + + - + class: CodelyTv\Tests\Mooc\MoocArchitectureTest + tags: + - phpat.test diff --git a/src/Shared/Domain/Utils.php b/src/Shared/Domain/Utils.php index c7825a25b..df64bfb87 100644 --- a/src/Shared/Domain/Utils.php +++ b/src/Shared/Domain/Utils.php @@ -6,9 +6,7 @@ use DateTimeImmutable; use DateTimeInterface; -use ReflectionClass; use RuntimeException; - use function Lambdish\Phunctional\filter; final class Utils @@ -81,13 +79,6 @@ public static function filesIn(string $path, string $fileType): array ); } - public static function extractClassName(object $object): string - { - $reflect = new ReflectionClass($object); - - return $reflect->getShortName(); - } - public static function iterableToArray(iterable $iterable): array { if (is_array($iterable)) { diff --git a/src/Shared/Infrastructure/Symfony/ApiExceptionListener.php b/src/Shared/Infrastructure/Symfony/ApiExceptionListener.php index a18ea1e20..80ef312df 100644 --- a/src/Shared/Infrastructure/Symfony/ApiExceptionListener.php +++ b/src/Shared/Infrastructure/Symfony/ApiExceptionListener.php @@ -6,6 +6,7 @@ use CodelyTv\Shared\Domain\DomainError; use CodelyTv\Shared\Domain\Utils; +use ReflectionClass; use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpKernel\Event\ExceptionEvent; use Throwable; @@ -35,6 +36,13 @@ private function exceptionCodeFor(Throwable $error): string return $error instanceof $domainErrorClass ? $error->errorCode() - : Utils::toSnakeCase(Utils::extractClassName($error)); + : Utils::toSnakeCase($this->extractClassName($error)); + } + + private function extractClassName(object $object): string + { + $reflect = new ReflectionClass($object); + + return $reflect->getShortName(); } } diff --git a/tests/Mooc/MoocArchitectureTest.php b/tests/Mooc/MoocArchitectureTest.php new file mode 100644 index 000000000..a1cf75f57 --- /dev/null +++ b/tests/Mooc/MoocArchitectureTest.php @@ -0,0 +1,56 @@ +classes(Selector::inNamespace('/^CodelyTv\\\\Mooc\\\\.+\\\\Domain/', true)) + ->canOnlyDependOn() + ->classes(...array_merge(ArchitectureTest::languageClasses(), [ + // Itself + Selector::inNamespace('/^CodelyTv\\\\Mooc\\\\.+\\\\Domain/', true), + // Shared + Selector::inNamespace('CodelyTv\Shared\Domain'), + ])) + ->because('mooc domain can only import itself and shared domain'); + } + + public function test_mooc_application_should_only_import_itself_and_domain(): Rule + { + return PHPat::rule() + ->classes(Selector::inNamespace('/^CodelyTv\\\\Mooc\\\\.+\\\\Application/', true)) + ->canOnlyDependOn() + ->classes(...array_merge(ArchitectureTest::languageClasses(), [ + // Itself + Selector::inNamespace('/^CodelyTv\\\\Mooc\\\\.+\\\\Application/', true), + Selector::inNamespace('/^CodelyTv\\\\Mooc\\\\.+\\\\Domain/', true), + // Shared + Selector::inNamespace('CodelyTv\Shared'), + ])) + ->because('mooc application can only import itself and shared'); + } + + public function test_mooc_infrastructure_should_not_import_other_contexts_beside_shared(): Rule + { + return PHPat::rule() + ->classes(Selector::inNamespace('CodelyTv\Mooc')) + ->shouldNotDependOn() + ->classes(Selector::inNamespace('CodelyTv')) + ->excluding( + // Itself + Selector::inNamespace('CodelyTv\Mooc'), + // Shared + Selector::inNamespace('CodelyTv\Shared'), + ); + } +} diff --git a/tests/Shared/Infrastructure/ArchitectureTest.php b/tests/Shared/Infrastructure/ArchitectureTest.php new file mode 100644 index 000000000..17d97198b --- /dev/null +++ b/tests/Shared/Infrastructure/ArchitectureTest.php @@ -0,0 +1,40 @@ +classes(Selector::inNamespace('CodelyTv\Shared\Domain')) ->canOnlyDependOn() - ->classes(...array_merge($this->languageClasses(), [ + ->classes(...array_merge(ArchitectureTest::languageClasses(), [ // Itself Selector::inNamespace('CodelyTv\Shared\Domain'), // Dependencies treated as domain @@ -54,23 +42,4 @@ public function test_shared_infrastructure_should_not_import_from_other_contexts Selector::classname(AuthenticateUserCommand::class), ); } - - private function languageClasses(): array - { - return [ - Selector::classname(Throwable::class), - Selector::classname(InvalidArgumentException::class), - Selector::classname(RuntimeException::class), - Selector::classname(DateTimeImmutable::class), - Selector::classname(DateTimeInterface::class), - Selector::classname(DomainException::class), - Selector::classname(Stringable::class), - Selector::classname(BackedEnum::class), - Selector::classname(Countable::class), - Selector::classname(IteratorAggregate::class), - Selector::classname(Traversable::class), - Selector::classname(ArrayIterator::class), - Selector::classname(ReflectionClass::class), - ]; - } }