diff --git a/src/Traits/InteractsWithScaffolder.php b/src/Traits/InteractsWithScaffolder.php new file mode 100644 index 0000000..2d3607d --- /dev/null +++ b/src/Traits/InteractsWithScaffolder.php @@ -0,0 +1,94 @@ +mockScaffolder($command, $args, function ( + string $filename, + string $data, + ) use ($expected, $expectedFilename): bool { + $this->assertSame($expected, $data, 'Generated code is not the same with expected.'); + + if ($expectedFilename) { + $root = $this->getDirectoryByAlias('root'); + $this->assertSame( + \str_replace($root, '', $expectedFilename), + \str_replace($root, '', $filename), + 'Generated filename is not the same with expected.', + ); + } + + return true; + }); + + foreach ($expectedOutputStrings as $expected) { + $this->assertStringContainsString($expected, $output, 'Output does not contain expected string.'); + } + } + + public function assertScaffolderCommandContains( + string $command, + array $args, + array $expectedStrings, + ?string $expectedFilename = null, + array $expectedOutputStrings = [], + ): void { + $output = $this->mockScaffolder($command, $args, function ( + string $filename, + string $data, + ) use ($expectedStrings, $expectedFilename): bool { + foreach ($expectedStrings as $expected) { + $this->assertStringContainsString($expected, $data, 'Generated code does not contain expected string.'); + } + + if ($expectedFilename) { + $root = $this->getDirectoryByAlias('root'); + $this->assertSame( + \str_replace($root, '', $expectedFilename), + \str_replace($root, '', $filename), + 'Generated filename is not the same with expected.', + ); + } + + return true; + }); + + foreach ($expectedOutputStrings as $expected) { + $this->assertStringContainsString($expected, $output, 'Output does not contain expected string.'); + } + } + + public function mockScaffolder(string $command, array $args, \Closure $expected): string + { + $originalFiles = $this->getContainer()->has(FilesInterface::class) + ? $this->getContainer()->get(FilesInterface::class) + : null; + + $files = $this->mockContainer(FilesInterface::class); + $files->shouldReceive('exists')->andReturnFalse(); + $files->shouldReceive('write')->withArgs($expected); + + $this->getConsole()->run($command, new ArrayInput($args), $output = new BufferedOutput()); + + $this->getContainer()->removeBinding(FilesInterface::class); + if ($originalFiles !== null) { + $this->getContainer()->bind(FilesInterface::class, $originalFiles); + } + + return $output->fetch(); + } +} diff --git a/tests/src/Scaffolder/ScaffolderTest.php b/tests/src/Scaffolder/ScaffolderTest.php new file mode 100644 index 0000000..1acbb4f --- /dev/null +++ b/tests/src/Scaffolder/ScaffolderTest.php @@ -0,0 +1,109 @@ +assertScaffolderCommandSame( + 'create:command', + [ + 'name' => 'TestCommand', + ], + expected: <<<'PHP' +info('Command logic is not implemented yet'); + + return self::SUCCESS; + } +} + +PHP, + expectedFilename: 'app/src/Command/TestCommand.php', + expectedOutputStrings: [ + "Declaration of 'TestCommand' has been successfully written into 'app/src/Command/TestCommand.php", + ], + ); + } + + public function testCreateCommandContainsNamespace(): void + { + $this->assertScaffolderCommandContains( + 'create:command', + [ + 'name' => 'TestCommand', + '--namespace' => 'App\Command', + ], + expectedStrings: [ + 'namespace App\Command;', + ], + expectedFilename: 'app/src/TestCommand.php', + ); + } + + public function testCommandNameIsRequired(): void + { + $this->expectException(RuntimeException::class); + $this->expectExceptionMessage('Not enough arguments (missing: "name").'); + + $this->assertScaffolderCommandSame( + 'create:command', + ['-n' => false], + '', + ); + } + + public function testCreateCommandWithAdditionalOptions(): void + { + $this->assertScaffolderCommandContains( + 'create:command', + [ + 'name' => 'TestCommand', + '-o' => 'foo', + ], + expectedStrings: [ + "#[Option(description: 'Argument description')]", + 'private bool $foo;', + ], + ); + } + + public function testAfterTestFilesShoulBeRestored(): void + { + $files = $this->mockContainer(FilesInterface::class); + + $this->assertScaffolderCommandContains( + 'create:command', + [ + 'name' => 'TestCommand', + ], + expectedStrings: ['final class TestCommand extends Command'], + ); + + $this->assertSame($files, $this->getContainer()->get(FilesInterface::class)); + } +}