str_ends_with($f, '.php') )); $allowed = [ 'ApiAuditServiceInterface.php', 'ApiSystemAuditReporterInterface.php', 'AuditMetadataEnricherInterface.php', 'AuditRecorderInterface.php', 'ImportAuditInterface.php', 'NullApiAuditService.php', 'NullApiSystemAuditReporter.php', 'NullAuditMetadataEnricher.php', 'NullAuditRecorder.php', 'NullImportAudit.php', 'NullUserLifecycleAudit.php', 'UserLifecycleAuditInterface.php', ]; sort($files); sort($allowed); self::assertSame( $allowed, $files, 'core/Service/Audit/ should contain only interfaces and null implementations, found: ' . implode(', ', $files) ); } public function testCoreRepositoryAuditDirectoryDoesNotExist(): void { $root = dirname(__DIR__, 2); self::assertDirectoryDoesNotExist( $root . '/core/Repository/Audit', 'Audit repository classes should live in modules/audit/lib, not in Core core/Repository/Audit' ); } public function testCoreDomainTaxonomyHasNoAuditEnums(): void { $dir = dirname(__DIR__, 2) . '/core/Domain/Taxonomy'; if (!is_dir($dir)) { self::addToAssertionCount(1); return; } $entries = scandir($dir) ?: []; $auditFiles = array_filter($entries, static fn (string $f): bool => str_contains($f, 'Audit') || str_contains($f, 'Lifecycle')); self::assertSame( [], array_values($auditFiles), 'Core lib/Domain/Taxonomy/ still contains audit enum files: ' . implode(', ', $auditFiles) ); } public function testCoreAuditPagesRemoved(): void { $root = dirname(__DIR__, 2); self::assertDirectoryDoesNotExist($root . '/pages/admin/api-audit'); self::assertDirectoryDoesNotExist($root . '/pages/admin/system-audit'); self::assertDirectoryDoesNotExist($root . '/pages/admin/import-audit'); self::assertDirectoryDoesNotExist($root . '/pages/admin/user-lifecycle-audit'); self::assertDirectoryDoesNotExist($root . '/pages/admin/frontend-telemetry'); } public function testCoreJsHasNoAuditPageScripts(): void { $root = dirname(__DIR__, 2); self::assertFileDoesNotExist($root . '/web/js/pages/admin-api-audit-index.js'); self::assertFileDoesNotExist($root . '/web/js/pages/admin-system-audit-index.js'); self::assertFileDoesNotExist($root . '/web/js/pages/admin-import-audit-index.js'); self::assertFileDoesNotExist($root . '/web/js/pages/admin-user-lifecycle-audit-index.js'); } public function testCoreHttpHasNoConcreteAuditReporter(): void { $root = dirname(__DIR__, 2); self::assertFileDoesNotExist( $root . '/core/Http/ApiSystemAuditReporter.php', 'ApiSystemAuditReporter should live in modules/audit/lib, not in Core lib/Http' ); } public function testCoreSidebarHasNoHardcodedAuditNavigation(): void { $file = dirname(__DIR__, 2) . '/templates/partials/app-main-aside.phtml'; $content = file_get_contents($file); self::assertIsString($content); self::assertStringNotContainsString('can_view_api_audit', $content); self::assertStringNotContainsString('can_view_system_audit', $content); self::assertStringNotContainsString('can_view_imports_audit', $content); self::assertStringNotContainsString('can_view_user_lifecycle_audit', $content); self::assertStringNotContainsString('admin/api-audit', $content); self::assertStringNotContainsString('admin/system-audit', $content); self::assertStringNotContainsString('admin/import-audit', $content); self::assertStringNotContainsString('admin/user-lifecycle-audit', $content); } public function testCoreSchedulerHandlerRemoved(): void { $root = dirname(__DIR__, 2); self::assertFileDoesNotExist( $root . '/core/Service/Scheduler/Handler/SystemAuditPurgeJobHandler.php', 'SystemAuditPurgeJobHandler should live in modules/audit, not in Core' ); } }