'development', 'APP_URL' => 'http://localhost', 'APP_NAME' => 'NETslim Test', 'ADMIN_USERNAME' => 'admin', 'ADMIN_EMAIL' => 'admin@example.test', 'ADMIN_PASSWORD' => 'secret123456', 'MAIL_HOST' => 'localhost', 'MAIL_PORT' => '1025', 'MAIL_USERNAME' => '', 'MAIL_PASSWORD' => '', 'MAIL_ENCRYPTION' => 'tls', 'MAIL_FROM' => 'noreply@example.test', 'MAIL_FROM_NAME' => 'NETslim Test', 'TIMEZONE' => 'UTC', ]; /** @var array */ private array $envBackup = []; protected function setUp(): void { TestRuntimeFactory::resetRuntime(); foreach (self::ENV_DEFAULTS as $key => $value) { $this->envBackup[$key] = $_ENV[$key] ?? null; $_ENV[$key] = $value; } } protected function tearDown(): void { ModuleRegistry::reset(); foreach (self::ENV_DEFAULTS as $key => $_) { $previous = $this->envBackup[$key] ?? null; if ($previous === null) { unset($_ENV[$key]); continue; } $_ENV[$key] = $previous; } parent::tearDown(); } /** @return iterable */ public static function containerServicesProvider(): iterable { yield 'auth service' => [AuthServiceInterface::class]; yield 'password reset service' => [PasswordResetServiceInterface::class]; yield 'authorization service' => [AuthorizationServiceInterface::class]; yield 'settings service' => [SettingsServiceInterface::class]; yield 'audit log service' => [AuditLogServiceInterface::class]; yield 'notification service' => [NotificationServiceInterface::class]; yield 'taxonomy service' => [TaxonomyServiceInterface::class]; yield 'media service' => [MediaServiceInterface::class]; yield 'taxonomy reader' => [TaxonomyReaderInterface::class]; yield 'user service' => [UserServiceInterface::class]; yield 'auth controller' => [AuthController::class]; yield 'account controller' => [AccountController::class]; yield 'password reset controller' => [PasswordResetController::class]; yield 'taxonomy controller' => [TaxonomyController::class]; yield 'media controller' => [MediaController::class]; yield 'user controller' => [UserController::class]; yield 'twig' => [Twig::class]; yield 'app extension' => [AppExtension::class]; } #[DataProvider('containerServicesProvider')] public function testContainerResolvesExpectedServices(string $id): void { $container = $this->buildContainer(); $resolved = $container->get($id); self::assertInstanceOf($id, $resolved); } public function testTwigFactoryRegistersModuleTemplateNamespaces(): void { $container = $this->buildContainer(); $twig = $container->get(Twig::class); $loader = $twig->getEnvironment()->getLoader(); self::assertInstanceOf(FilesystemLoader::class, $loader); foreach (ModuleRegistry::modules() as $module) { foreach ($module->templateNamespaces() as $namespace => $templatePath) { self::assertContains( $templatePath, $loader->getPaths($namespace), sprintf('Le namespace Twig "%s" doit pointer vers "%s".', $namespace, $templatePath), ); } } } public function testMiddlewareRegistrationLoadsModuleTwigExtensions(): void { if (session_status() === PHP_SESSION_ACTIVE) { session_write_close(); } session_id('netslim-container-wiring-test'); session_start(); try { $container = $this->buildContainer(); AppFactory::setContainer($container); $app = AppFactory::create(); $registrar = new MiddlewareRegistrar(); $registrar->register($app, $container); $extensions = $container->get(Twig::class)->getEnvironment()->getExtensions(); $assertions = 0; foreach (ModuleRegistry::modules() as $module) { foreach ($module->twigExtensions() as $twigExtensionClass) { self::assertArrayHasKey( $twigExtensionClass, $extensions, sprintf("L'extension Twig \"%s\" doit être chargée par MiddlewareRegistrar.", $twigExtensionClass), ); self::assertInstanceOf($twigExtensionClass, $extensions[$twigExtensionClass]); ++$assertions; } } self::assertGreaterThanOrEqual(0, $assertions); } finally { session_write_close(); } } private function buildContainer(): Container { $builder = new ContainerBuilder(); $builder->useAutowiring(true); $builder->addDefinitions(dirname(__DIR__, 2) . '/src/Kernel/Runtime/DI/container.php'); return $builder->build(); } }