164 lines
4.5 KiB
PHP
164 lines
4.5 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace Tests\Support;
|
|
|
|
use Netig\Netslim\Kernel\Runtime\Module\ModuleRegistry;
|
|
use Netig\Netslim\Kernel\Runtime\RuntimePaths;
|
|
|
|
/**
|
|
* Prépare une mini application consommatrice éphémère pour les tests du core.
|
|
*
|
|
* Tous les chemins runtime persistants (database/, var/, public/media) sont
|
|
* créés sous un répertoire temporaire isolé afin que la suite de tests ne
|
|
* touche ni le dépôt courant ni un projet client réel.
|
|
*/
|
|
final class TestRuntimeFactory
|
|
{
|
|
private static ?string $projectRoot = null;
|
|
|
|
public static function boot(): void
|
|
{
|
|
if (self::$projectRoot !== null) {
|
|
self::applyRuntimeRoots();
|
|
|
|
return;
|
|
}
|
|
|
|
$baseRoot = rtrim(sys_get_temp_dir(), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'netslim-core-tests';
|
|
if (!is_dir($baseRoot)) {
|
|
mkdir($baseRoot, 0777, true);
|
|
}
|
|
|
|
$projectRoot = $baseRoot . DIRECTORY_SEPARATOR . 'run-' . bin2hex(random_bytes(6));
|
|
mkdir($projectRoot, 0777, true);
|
|
|
|
self::copyDirectory(self::fixtureRoot() . '/config', $projectRoot . '/config');
|
|
self::copyDirectory(self::fixtureRoot() . '/templates', $projectRoot . '/templates');
|
|
|
|
foreach (['database', 'var/cache/twig', 'var/cache/htmlpurifier', 'var/logs', 'public/media'] as $directory) {
|
|
$path = $projectRoot . DIRECTORY_SEPARATOR . str_replace('/', DIRECTORY_SEPARATOR, $directory);
|
|
if (!is_dir($path)) {
|
|
mkdir($path, 0777, true);
|
|
}
|
|
}
|
|
|
|
self::$projectRoot = $projectRoot;
|
|
self::applyRuntimeRoots();
|
|
|
|
register_shutdown_function(static function (): void {
|
|
TestRuntimeFactory::cleanup();
|
|
});
|
|
}
|
|
|
|
public static function projectRoot(): string
|
|
{
|
|
self::boot();
|
|
|
|
return self::$projectRoot;
|
|
}
|
|
|
|
public static function applicationRoot(): string
|
|
{
|
|
return self::projectRoot();
|
|
}
|
|
|
|
public static function path(string $relativePath = ''): string
|
|
{
|
|
$root = self::projectRoot();
|
|
|
|
return $relativePath === ''
|
|
? $root
|
|
: $root . DIRECTORY_SEPARATOR . ltrim(str_replace('/', DIRECTORY_SEPARATOR, $relativePath), DIRECTORY_SEPARATOR);
|
|
}
|
|
|
|
public static function resetRuntime(): void
|
|
{
|
|
self::boot();
|
|
self::applyRuntimeRoots();
|
|
}
|
|
|
|
private static function applyRuntimeRoots(): void
|
|
{
|
|
if (self::$projectRoot === null) {
|
|
throw new \LogicException('Test runtime project root is not initialized.');
|
|
}
|
|
|
|
RuntimePaths::setProjectRoot(self::$projectRoot);
|
|
RuntimePaths::setApplicationRoot(self::$projectRoot);
|
|
ModuleRegistry::reset();
|
|
}
|
|
|
|
public static function cleanup(): void
|
|
{
|
|
if (self::$projectRoot === null || !is_dir(self::$projectRoot)) {
|
|
return;
|
|
}
|
|
|
|
self::deleteDirectory(self::$projectRoot);
|
|
self::$projectRoot = null;
|
|
RuntimePaths::resetProjectRoot();
|
|
RuntimePaths::resetApplicationRoot();
|
|
ModuleRegistry::reset();
|
|
}
|
|
|
|
private static function fixtureRoot(): string
|
|
{
|
|
return dirname(__DIR__) . '/Fixtures/Application';
|
|
}
|
|
|
|
private static function copyDirectory(string $source, string $destination): void
|
|
{
|
|
if (!is_dir($destination)) {
|
|
mkdir($destination, 0777, true);
|
|
}
|
|
|
|
$items = scandir($source);
|
|
if ($items === false) {
|
|
throw new \RuntimeException(sprintf('Unable to read fixture directory: %s', $source));
|
|
}
|
|
|
|
foreach ($items as $item) {
|
|
if ($item === '.' || $item === '..') {
|
|
continue;
|
|
}
|
|
|
|
$from = $source . DIRECTORY_SEPARATOR . $item;
|
|
$to = $destination . DIRECTORY_SEPARATOR . $item;
|
|
|
|
if (is_dir($from)) {
|
|
self::copyDirectory($from, $to);
|
|
continue;
|
|
}
|
|
|
|
copy($from, $to);
|
|
}
|
|
}
|
|
|
|
private static function deleteDirectory(string $path): void
|
|
{
|
|
$items = scandir($path);
|
|
if ($items === false) {
|
|
return;
|
|
}
|
|
|
|
foreach ($items as $item) {
|
|
if ($item === '.' || $item === '..') {
|
|
continue;
|
|
}
|
|
|
|
$current = $path . DIRECTORY_SEPARATOR . $item;
|
|
|
|
if (is_dir($current)) {
|
|
self::deleteDirectory($current);
|
|
continue;
|
|
}
|
|
|
|
@unlink($current);
|
|
}
|
|
|
|
@rmdir($path);
|
|
}
|
|
}
|