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

185 lines
6.8 KiB
PHP

<?php
declare(strict_types=1);
namespace Tests\Kernel;
use DI\Container;
use DI\ContainerBuilder;
use Netig\Netslim\AuditLog\Application\AuditLogServiceInterface;
use Netig\Netslim\Identity\Application\AuthorizationServiceInterface;
use Netig\Netslim\Identity\Application\AuthServiceInterface;
use Netig\Netslim\Identity\Application\PasswordResetServiceInterface;
use Netig\Netslim\Identity\Application\UserServiceInterface;
use Netig\Netslim\Identity\UI\Http\AccountController;
use Netig\Netslim\Identity\UI\Http\AuthController;
use Netig\Netslim\Identity\UI\Http\PasswordResetController;
use Netig\Netslim\Identity\UI\Http\UserController;
use Netig\Netslim\Kernel\Http\Infrastructure\Twig\AppExtension;
use Netig\Netslim\Kernel\Runtime\Http\MiddlewareRegistrar;
use Netig\Netslim\Kernel\Runtime\Module\ModuleRegistry;
use Netig\Netslim\Kernel\Runtime\RuntimePaths;
use Netig\Netslim\Media\Application\MediaServiceInterface;
use Netig\Netslim\Media\UI\Http\MediaController;
use Netig\Netslim\Notifications\Application\NotificationServiceInterface;
use Netig\Netslim\Settings\Application\SettingsServiceInterface;
use Netig\Netslim\Taxonomy\Application\TaxonomyServiceInterface;
use Netig\Netslim\Taxonomy\Contracts\TaxonomyReaderInterface;
use Netig\Netslim\Taxonomy\UI\Http\TaxonomyController;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\TestCase;
use Slim\Factory\AppFactory;
use Slim\Views\Twig;
use Twig\Loader\FilesystemLoader;
final class ContainerWiringIntegrationTest extends TestCase
{
private const ENV_DEFAULTS = [
'APP_ENV' => '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<string, string|null> */
private array $envBackup = [];
protected function setUp(): void
{
RuntimePaths::setApplicationRoot(dirname(__DIR__, 2) . '/tests/Fixtures/Application');
ModuleRegistry::reset();
foreach (self::ENV_DEFAULTS as $key => $value) {
$this->envBackup[$key] = $_ENV[$key] ?? null;
$_ENV[$key] = $value;
}
}
protected function tearDown(): void
{
RuntimePaths::resetApplicationRoot();
RuntimePaths::resetProjectRoot();
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<string, array{class-string}> */
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();
}
}