Refactor core test runtime and simplify project documentation
This commit is contained in:
163
tests/Support/TestRuntimeFactory.php
Normal file
163
tests/Support/TestRuntimeFactory.php
Normal file
@@ -0,0 +1,163 @@
|
||||
<?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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user