Files
netslim-core/tests/Architecture/ModuleBoundaryGovernanceTest.php
2026-03-20 22:13:41 +01:00

113 lines
3.7 KiB
PHP

<?php
declare(strict_types=1);
namespace Tests\Architecture;
use Tests\Architecture\Support\ArchitectureTestCase;
final class ModuleBoundaryGovernanceTest extends ArchitectureTestCase
{
public function testKernelDoesNotImportFeatureModules(): void
{
$violations = [];
$featurePrefixes = [
'Netig\\Netslim\\Identity\\',
'Netig\\Netslim\\Settings\\',
'Netig\\Netslim\\AuditLog\\',
'Netig\\Netslim\\Notifications\\',
'Netig\\Netslim\\Taxonomy\\',
'Netig\\Netslim\\Media\\',
];
foreach ($this->phpFilesUnder('src/Kernel') as $file) {
foreach ($this->importedClasses($file) as $import) {
$importsFeatureModule = false;
foreach ($featurePrefixes as $prefix) {
if (str_starts_with($import, $prefix)) {
$importsFeatureModule = true;
break;
}
}
if (!$importsFeatureModule) {
continue;
}
$violations[] = $this->relativePath($file) . ' -> ' . $import;
}
}
$this->assertNoArchitectureViolations(
$violations,
'Kernel must not import feature modules directly',
);
}
public function testApplicationDomainAndInfrastructureUseOnlyApprovedCrossModuleContracts(): void
{
$violations = [];
$allowedExternalImports = [
'Identity' => [],
'Settings' => [],
'AuditLog' => [],
'Notifications' => [],
'Taxonomy' => [],
'Media' => [],
];
foreach (self::FEATURE_MODULES as $module) {
$directories = [
$this->projectPath('src/' . $module . '/Application'),
$this->projectPath('src/' . $module . '/Domain'),
$this->projectPath('src/' . $module . '/Infrastructure'),
];
foreach ($directories as $directory) {
if (!is_dir($directory)) {
continue;
}
$iterator = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($directory));
foreach ($iterator as $fileInfo) {
if (!$fileInfo->isFile() || $fileInfo->getExtension() !== 'php') {
continue;
}
$file = $fileInfo->getPathname();
$imports = $this->importedClasses($file);
foreach ($imports as $import) {
if (!str_starts_with($import, 'Netig\\Netslim\\')) {
continue;
}
if (str_starts_with($import, 'Netig\\Netslim\\Kernel\\') || str_starts_with($import, 'Netig\\Netslim\\' . $module . '\\')) {
continue;
}
$isAllowed = false;
foreach ($allowedExternalImports[$module] as $allowedPrefix) {
if (str_starts_with($import, $allowedPrefix)) {
$isAllowed = true;
break;
}
}
if ($isAllowed) {
continue;
}
$violations[] = $this->relativePath($file) . ' -> ' . $import;
}
}
}
}
$this->assertNoArchitectureViolations(
$violations,
'Application, Domain and Infrastructure layers must only cross module boundaries through approved public contracts',
);
}
}