diff --git a/tests/Unit/Console/Commands/InstallToolkitCommandTest.php b/tests/Unit/Console/Commands/InstallToolkitCommandTest.php index 6f94c754a..08fdbb755 100644 --- a/tests/Unit/Console/Commands/InstallToolkitCommandTest.php +++ b/tests/Unit/Console/Commands/InstallToolkitCommandTest.php @@ -3,16 +3,26 @@ namespace Quantum\Tests\Unit\Console\Commands; use Quantum\Console\Commands\InstallToolkitCommand; +use Symfony\Component\Console\Tester\CommandTester; +use Quantum\App\App; use Quantum\Tests\Unit\AppTestCase; class InstallToolkitCommandTest extends AppTestCase { private InstallToolkitCommand $command; + private string $envFilePath; + private string $originalFileContent; + /** @var array */ + private array $originalEnvData; public function setUp(): void { parent::setUp(); + $this->envFilePath = App::getBaseDir() . DS . '.env.testing'; + $this->originalFileContent = (string) $this->fs->get($this->envFilePath); + $this->originalEnvData = $this->getPrivateProperty(environment(), 'envContent'); + $this->command = new InstallToolkitCommand(); } @@ -32,4 +42,45 @@ public function testCommandArgumentsAreRegistered(): void $this->assertTrue($definition->getArgument('username')->isRequired()); $this->assertTrue($definition->getArgument('password')->isRequired()); } + + public function testExecUpdatesEnvAndRunsModuleGeneration(): void + { + $command = new class () extends InstallToolkitCommand { + public string $calledCommand = ''; + + /** @var array */ + public array $calledArguments = []; + + protected function runExternalCommand(string $commandName, array $arguments): void + { + $this->calledCommand = $commandName; + $this->calledArguments = $arguments; + } + }; + + $tester = new CommandTester($command); + $tester->execute([ + 'username' => 'test-user', + 'password' => 'test-pass', + ]); + + $this->assertSame('test-user', env('BASIC_AUTH_NAME')); + $this->assertSame('test-pass', env('BASIC_AUTH_PWD')); + $this->assertSame(InstallToolkitCommand::COMMAND_CREATE_MODULE, $command->calledCommand); + $this->assertSame([ + 'module' => 'Toolkit', + '--yes' => true, + '--template' => 'Toolkit', + '--with-assets' => true, + ], $command->calledArguments); + $this->assertStringContainsString('Toolkit installed successfully', $tester->getDisplay()); + } + + public function tearDown(): void + { + $this->fs->put($this->envFilePath, $this->originalFileContent); + $this->setPrivateProperty(environment(), 'envContent', $this->originalEnvData); + + parent::tearDown(); + } } diff --git a/tests/Unit/Console/Commands/MigrationGenerateCommandTest.php b/tests/Unit/Console/Commands/MigrationGenerateCommandTest.php index 09166e0d5..8a5dfee2e 100644 --- a/tests/Unit/Console/Commands/MigrationGenerateCommandTest.php +++ b/tests/Unit/Console/Commands/MigrationGenerateCommandTest.php @@ -3,17 +3,28 @@ namespace Quantum\Tests\Unit\Console\Commands; use Quantum\Console\Commands\MigrationGenerateCommand; +use Symfony\Component\Console\Tester\CommandTester; use Quantum\Tests\Unit\AppTestCase; class MigrationGenerateCommandTest extends AppTestCase { private MigrationGenerateCommand $command; + /** @var array */ + private array $existingMigrationFiles = []; public function setUp(): void { parent::setUp(); $this->command = new MigrationGenerateCommand(); + + $migrationsPath = base_dir() . DS . 'migrations'; + if (!is_dir($migrationsPath)) { + mkdir($migrationsPath, 0777, true); + } + + $files = glob($migrationsPath . DS . '*.php'); + $this->existingMigrationFiles = is_array($files) ? $files : []; } public function testCommandMetadata(): void @@ -31,4 +42,35 @@ public function testCommandArgumentsAreRegistered(): void $this->assertTrue($definition->getArgument('action')->isRequired()); $this->assertTrue($definition->getArgument('table')->isRequired()); } + + public function testExecCreatesMigrationFile(): void + { + $tester = new CommandTester($this->command); + + $tester->execute([ + 'action' => 'create', + 'table' => 'tickets', + ]); + + $output = $tester->getDisplay(); + $this->assertStringContainsString('Migration file', $output); + $this->assertStringContainsString('successfully created', $output); + } + + public function tearDown(): void + { + $migrationsPath = base_dir() . DS . 'migrations'; + $files = glob($migrationsPath . DS . '*.php'); + $currentFiles = is_array($files) ? $files : []; + + $createdByTest = array_diff($currentFiles, $this->existingMigrationFiles); + + foreach ($createdByTest as $file) { + if (is_file($file)) { + @unlink($file); + } + } + + parent::tearDown(); + } } diff --git a/tests/Unit/Console/Commands/MigrationMigrateCommandTest.php b/tests/Unit/Console/Commands/MigrationMigrateCommandTest.php index bf943bf09..bfc8b1352 100644 --- a/tests/Unit/Console/Commands/MigrationMigrateCommandTest.php +++ b/tests/Unit/Console/Commands/MigrationMigrateCommandTest.php @@ -3,6 +3,9 @@ namespace Quantum\Tests\Unit\Console\Commands; use Quantum\Console\Commands\MigrationMigrateCommand; +use Symfony\Component\Console\Helper\QuestionHelper; +use Symfony\Component\Console\Tester\CommandTester; +use Symfony\Component\Console\Helper\HelperSet; use Quantum\Tests\Unit\AppTestCase; class MigrationMigrateCommandTest extends AppTestCase @@ -14,6 +17,7 @@ public function setUp(): void parent::setUp(); $this->command = new MigrationMigrateCommand(); + $this->command->setHelperSet(new HelperSet(['question' => new QuestionHelper()])); } public function testCommandMetadata(): void @@ -31,4 +35,17 @@ public function testCommandArgumentsAndOptionsAreRegistered(): void $this->assertTrue($definition->hasOption('step')); } + + public function testExecCancelsDownDirectionWhenNotConfirmed(): void + { + $tester = new CommandTester($this->command); + + $tester->setInputs(['n']); + $tester->execute([ + 'direction' => 'down', + ]); + + $output = $tester->getDisplay(); + $this->assertStringContainsString('Operation was canceled!', $output); + } } diff --git a/tests/Unit/Console/Commands/ModuleGenerateCommandTest.php b/tests/Unit/Console/Commands/ModuleGenerateCommandTest.php index 0aace0256..39b9c0f1b 100644 --- a/tests/Unit/Console/Commands/ModuleGenerateCommandTest.php +++ b/tests/Unit/Console/Commands/ModuleGenerateCommandTest.php @@ -3,17 +3,27 @@ namespace Quantum\Tests\Unit\Console\Commands; use Quantum\Console\Commands\ModuleGenerateCommand; +use Symfony\Component\Console\Tester\CommandTester; use Quantum\Tests\Unit\AppTestCase; +use Quantum\App\App; class ModuleGenerateCommandTest extends AppTestCase { private ModuleGenerateCommand $command; + private string $moduleName; + private string $modulesConfigPath; + private string $modulePath; + private bool $moduleCreatedByTest = false; + private bool $moduleConfigCreatedByTest = false; public function setUp(): void { parent::setUp(); $this->command = new ModuleGenerateCommand(); + $this->moduleName = str_replace('.', '_', uniqid('Issue479Module_', true)); + $this->modulesConfigPath = App::getBaseDir() . DS . 'shared' . DS . 'config' . DS . 'modules.php'; + $this->modulePath = App::getBaseDir() . DS . 'modules' . DS . $this->moduleName; } public function testCommandMetadata(): void @@ -34,4 +44,56 @@ public function testCommandArgumentsAndOptionsAreRegistered(): void $this->assertTrue($definition->hasOption('template')); $this->assertTrue($definition->hasOption('with-assets')); } + + public function testExecCreatesModule(): void + { + $tester = new CommandTester($this->command); + + $tester->execute([ + 'module' => $this->moduleName, + '--yes' => true, + '--template' => 'DefaultApi', + '--with-assets' => false, + ]); + + $this->assertTrue($this->fs->isDirectory($this->modulePath)); + $this->moduleCreatedByTest = true; + + $moduleConfigs = $this->fs->require($this->modulesConfigPath); + if (is_array($moduleConfigs) && isset($moduleConfigs[$this->moduleName])) { + $this->moduleConfigCreatedByTest = true; + } + + $this->assertStringContainsString($this->moduleName . ' module successfully created', $tester->getDisplay()); + } + + public function tearDown(): void + { + if ($this->fs->exists($this->modulesConfigPath)) { + $moduleConfigs = $this->fs->require($this->modulesConfigPath); + if ( + $this->moduleConfigCreatedByTest + && is_array($moduleConfigs) + && isset($moduleConfigs[$this->moduleName]) + ) { + unset($moduleConfigs[$this->moduleName]); + + $this->fs->put( + $this->modulesConfigPath, + "moduleCreatedByTest + && $this->fs->isDirectory($this->modulePath) + && basename($this->modulePath) === $this->moduleName + && strpos($this->moduleName, 'Issue479Module_') === 0 + ) { + deleteDirectoryWithFiles($this->modulePath); + } + + parent::tearDown(); + } } diff --git a/tests/Unit/Console/Commands/OpenApiCommandTest.php b/tests/Unit/Console/Commands/OpenApiCommandTest.php index a3327166e..32756a2a4 100644 --- a/tests/Unit/Console/Commands/OpenApiCommandTest.php +++ b/tests/Unit/Console/Commands/OpenApiCommandTest.php @@ -2,9 +2,10 @@ namespace Quantum\Tests\Unit\Console\Commands; +use Symfony\Component\Console\Tester\CommandTester; use Quantum\Console\Commands\OpenApiCommand; -use Quantum\Storage\FileSystem; use Quantum\Tests\Unit\AppTestCase; +use Quantum\Storage\FileSystem; class OpenApiCommandTest extends AppTestCase { @@ -37,4 +38,44 @@ public function testConstructorInitializesFileSystem(): void $fs = $this->getPrivateProperty($this->command, 'fs'); $this->assertInstanceOf(FileSystem::class, $fs); } + + public function testExecShowsErrorWhenModuleIsMissing(): void + { + $openApiAssets = assets_dir() . DS . 'OpenApiUi'; + $indexCssPath = $openApiAssets . DS . 'index.css'; + $assetsDirCreatedByTest = false; + $indexCssExisted = false; + $indexCssBackup = ''; + + if (!$this->fs->isDirectory($openApiAssets)) { + mkdir($openApiAssets, 0777, true); + $assetsDirCreatedByTest = true; + } + + if ($this->fs->exists($indexCssPath)) { + $indexCssExisted = true; + $indexCssBackup = (string) $this->fs->get($indexCssPath); + } + + $this->fs->put($indexCssPath, '/* stub */'); + + try { + $tester = new CommandTester($this->command); + $tester->execute([ + 'module' => 'MissingModule', + ]); + + $this->assertStringContainsString('The module `MissingModule` not found', $tester->getDisplay()); + } finally { + if ($indexCssExisted) { + $this->fs->put($indexCssPath, $indexCssBackup); + } elseif ($this->fs->exists($indexCssPath)) { + $this->fs->remove($indexCssPath); + } + + if ($assetsDirCreatedByTest && $this->fs->isDirectory($openApiAssets)) { + @rmdir($openApiAssets); + } + } + } } diff --git a/tests/Unit/Console/Commands/RouteListCommandTest.php b/tests/Unit/Console/Commands/RouteListCommandTest.php index 58102ea46..0286c94e6 100644 --- a/tests/Unit/Console/Commands/RouteListCommandTest.php +++ b/tests/Unit/Console/Commands/RouteListCommandTest.php @@ -2,6 +2,7 @@ namespace Quantum\Tests\Unit\Console\Commands; +use Symfony\Component\Console\Tester\CommandTester; use Quantum\Console\Commands\RouteListCommand; use Quantum\Tests\Unit\AppTestCase; @@ -29,4 +30,25 @@ public function testCommandOptionsAreRegistered(): void $this->assertTrue($definition->hasOption('module')); $this->assertFalse($definition->getOption('module')->isValueRequired()); } + + public function testExecRendersRoutesTable(): void + { + $tester = new CommandTester($this->command); + $tester->execute([]); + + $output = $tester->getDisplay(); + $this->assertStringContainsString('Routes', $output); + $this->assertStringContainsString('MODULE', $output); + $this->assertStringContainsString('URI', $output); + } + + public function testExecShowsErrorForUnknownModuleFilter(): void + { + $tester = new CommandTester($this->command); + $tester->execute([ + '--module' => 'Nope', + ]); + + $this->assertStringContainsString('The module is not found', $tester->getDisplay()); + } } diff --git a/tests/Unit/Console/Commands/ServeCommandTest.php b/tests/Unit/Console/Commands/ServeCommandTest.php index 7b7079a5c..2820248be 100644 --- a/tests/Unit/Console/Commands/ServeCommandTest.php +++ b/tests/Unit/Console/Commands/ServeCommandTest.php @@ -2,6 +2,7 @@ namespace Quantum\Tests\Unit\Console\Commands; +use Symfony\Component\Console\Tester\CommandTester; use Quantum\Console\Commands\ServeCommand; use Quantum\Tests\Unit\AppTestCase; @@ -46,4 +47,42 @@ public function testBrowserCommandReturnsArrayForKnownPlatform(): void $this->assertNull($result); } } + + public function testExecUsesResolvedHostAndPortFlow(): void + { + $command = new class () extends ServeCommand { + public string $receivedHost = ''; + public int $receivedPort = 0; + + /** @var array */ + public array $receivedServerData = []; + + protected function startServerOnAvailablePort(string $host, int $startPort): array + { + $this->receivedHost = $host; + $this->receivedPort = $startPort; + + return [ + 'process' => fopen('php://memory', 'r'), + 'port' => $startPort, + 'url' => "http://{$host}:{$startPort}", + ]; + } + + protected function handleServerExecution(array $serverData): void + { + $this->receivedServerData = $serverData; + } + }; + + $tester = new CommandTester($command); + $tester->execute([ + '--host' => '127.0.0.1', + '--port' => '8011', + ]); + + $this->assertSame('127.0.0.1', $command->receivedHost); + $this->assertSame(8011, $command->receivedPort); + $this->assertSame('http://127.0.0.1:8011', $command->receivedServerData['url']); + } } diff --git a/tests/Unit/Console/Commands/VersionCommandTest.php b/tests/Unit/Console/Commands/VersionCommandTest.php index e533d4637..4aab89f81 100644 --- a/tests/Unit/Console/Commands/VersionCommandTest.php +++ b/tests/Unit/Console/Commands/VersionCommandTest.php @@ -2,6 +2,7 @@ namespace Quantum\Tests\Unit\Console\Commands; +use Symfony\Component\Console\Tester\CommandTester; use Quantum\Console\Commands\VersionCommand; use Quantum\Tests\Unit\AppTestCase; @@ -22,4 +23,21 @@ public function testCommandMetadata(): void $this->assertSame('Core version', $this->command->getDescription()); $this->assertSame('Printing the current version of the framework into the terminal', $this->command->getHelp()); } + + public function testExecPrintsFrameworkVersion(): void + { + config()->set('app', ['version' => '3.0.0']); + + $tester = new CommandTester($this->command); + $fontPath = assets_dir() . DS . 'shared' . DS . 'fonts' . DS . 'figlet' . DS . 'slant.flf'; + + if (!is_file($fontPath)) { + $this->expectException(\Exception::class); + $this->expectExceptionMessage('slant.flf'); + } + + $tester->execute([]); + $output = $tester->getDisplay(); + $this->assertStringContainsString('3.0.0', $output); + } }