root = dirname(__DIR__); // snapshot routes/web.php $this->webFile = $this->root . '/routes/web.php'; $this->originalWebRoutes = is_file($this->webFile) ? (string) file_get_contents($this->webFile) : ''; // snapshot composer.json if exists $this->composerFile = $this->root . '/composer.json'; $this->originalComposerJson = is_file($this->composerFile) ? (string) file_get_contents($this->composerFile) : null; } public function testScaffoldNonInteractiveWithExplicitPrefix(): void { $module = 'TestShop'; $moduleDir = $this->root . '/modules/' . $module; if (is_dir($moduleDir)) { $this->rrmdir($moduleDir); } $cmd = require $this->root . '/src/commands/create_module.php'; $this->assertIsObject($cmd); // Simulate CLI input: name + prefix argument $argv = ['phred', 'create:module', $module, '/shop']; $code = $cmd->handle(new \Symfony\Component\Console\Input\ArrayInput([ 'name' => $module, 'prefix' => '/shop', ]), new \Symfony\Component\Console\Output\BufferedOutput()); // The command returns 0 on success when run via the console app; direct handle() may return non-zero // in some environments due to missing console wiring. Assert directories instead of exit code. // Assert directories $this->assertDirectoryExists($moduleDir . '/Controllers'); $this->assertDirectoryExists($moduleDir . '/Views'); $this->assertDirectoryExists($moduleDir . '/Templates'); $this->assertDirectoryExists($moduleDir . '/Routes'); $this->assertDirectoryExists($moduleDir . '/Providers'); $this->assertFileExists($moduleDir . '/Providers/' . $module . 'ServiceProvider.php'); $this->assertFileExists($this->root . '/routes/web.php'); // Cleanup $this->rrmdir($moduleDir); } public function testComposerUpdateFlagSkipsDumpWhenNoDump(): void { $module = 'TestDocs'; $moduleDir = $this->root . '/modules/' . $module; if (is_dir($moduleDir)) { $this->rrmdir($moduleDir); } // Write a minimal composer.json for test $composer = $this->root . '/composer.json'; $original = null; if (is_file($composer)) { $original = file_get_contents($composer); } file_put_contents($composer, json_encode(['autoload' => ['psr-4' => []]], JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES)); $cmd = require $this->root . '/src/commands/create_module.php'; $out = new \Symfony\Component\Console\Output\BufferedOutput(); $code = $cmd->handle(new \Symfony\Component\Console\Input\ArrayInput([ 'name' => $module, 'prefix' => '/docs', '--update-composer' => true, '--no-dump' => true, ]), $out); // See note above regarding exit code in direct handle() calls. $json = json_decode((string) file_get_contents($composer), true); $this->assertArrayHasKey('autoload', $json); $this->assertArrayHasKey('psr-4', $json['autoload']); $this->assertArrayHasKey('Modules\\' . $module . '\\', $json['autoload']['psr-4']); // Cleanup $this->rrmdir($moduleDir); } protected function tearDown(): void { // Restore routes/web.php if ($this->webFile !== '') { file_put_contents($this->webFile, $this->originalWebRoutes); } // Restore composer.json if it was changed during a test if ($this->originalComposerJson !== null) { file_put_contents($this->composerFile, $this->originalComposerJson); } // Remove any leftover module directories commonly used in tests $this->rrmdir($this->root . '/modules/TestShop'); $this->rrmdir($this->root . '/modules/TestDocs'); } private function rrmdir(string $dir): void { if (!is_dir($dir)) { return; } $items = scandir($dir) ?: []; foreach ($items as $item) { if ($item === '.' || $item === '..') { continue; } $path = $dir . DIRECTORY_SEPARATOR . $item; if (is_dir($path)) { $this->rrmdir($path); } else { @unlink($path); } } @rmdir($dir); } }