ldc-boutique-cnc-sable/tests/Architecture/ApplicationTest.php

82 lines
3.3 KiB
PHP

<?php
declare(strict_types=1);
use App\Contracts\Action;
use App\Contracts\ActionInput;
use App\Contracts\Query;
use App\Contracts\QueryInput;
use Symfony\Component\Finder\Finder;
describe('application coding rules', function (): void {
arch('No Domain Entities are used in Controllers')
->expect('App\Http\Controllers')
->not->toUse('Domain\Entities');
arch('No Domain Entities are used in Policies')
->expect('App\Policies')
->not->toUse('Domain\Entities');
arch('App Repositories implement App\Contracts\Repository')
->expect('App\Repositories')
->toImplement('App\Contracts\Repository');
arch('App Directories implement App\Contracts\Directory')
->expect('App\Directories')
->toImplement('App\Contracts\Directory');
arch('App DTOs are final readonly classes')
->expect('App\Dto')
->classes()
->toBeFinal()
->toBeReadonly();
arch('App Actions implement App\Contracts\Action and Inputs implement ActionInput', function (): void {
$path = __DIR__ . '/../../app/Actions';
$files = (new Finder())->files()->in($path)->name('*.php');
foreach ($files as $file) {
$subPath = $file->getRelativePathname();
$className = 'App\\Actions\\' . str_replace(['/', '.php'], ['\\', ''], $subPath);
$reflection = new \ReflectionClass($className);
if (str_ends_with($className, 'Input')) {
expect($reflection->implementsInterface(ActionInput::class))
->toBeTrue("{$className} must implement App\Contracts\ActionInput");
} elseif (str_ends_with($className, 'Output')) {
if ($reflection->isEnum()) {
expect($reflection->isEnum())->toBeTrue();
} else {
expect($reflection->isFinal())
->toBeTrue("{$className} must be final");
expect($reflection->isReadOnly())
->toBeTrue("{$className} must be readonly");
}
} else {
expect($reflection->implementsInterface(Action::class))
->toBeTrue("{$className} must implement App\Contracts\Action");
}
}
});
arch('App Queries implement App\Contracts\Query and Inputs implement QueryInput', function (): void {
$path = __DIR__ . '/../../app/Queries';
$files = (new Finder())->files()->in($path)->name('*.php');
foreach ($files as $file) {
$subPath = $file->getRelativePathname();
$className = 'App\\Queries\\' . str_replace(['/', '.php'], ['\\', ''], $subPath);
$reflection = new \ReflectionClass($className);
if (str_ends_with($className, 'Input')) {
expect($reflection->implementsInterface(QueryInput::class))
->toBeTrue("{$className} must implement App\Contracts\QueryInput");
} elseif (str_ends_with($className, 'Output')) {
expect($reflection->isFinal() && $reflection->isReadOnly())
->toBeTrue("{$className} must be final readonly");
} else {
expect($reflection->implementsInterface(Query::class))
->toBeTrue("{$className} must implement App\Contracts\Query");
}
}
});
});