diff --git a/.roave-backward-compatibility-check.xml b/.roave-backward-compatibility-check.xml index 40073f8..4d0de5c 100644 --- a/.roave-backward-compatibility-check.xml +++ b/.roave-backward-compatibility-check.xml @@ -3,7 +3,7 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="vendor/roave/backward-compatibility-check/resources/schema.xsd"> - #\[BC\] SKIPPED: An enum expression Dot\Maker\\VisibilityEnum\:\:Public is not supported in class Dot\\Maker\\Component\\Method in file /src/Component/Method.php# - #\[BC\] SKIPPED: An enum expression Dot\Maker\\VisibilityEnum\:\:Protected is not supported in class Dot\\Maker\\Component\\Property in file /src/Component/Property.php# + #\[BC\] SKIPPED: An enum expression Dot\\Maker\\VisibilityEnum::Public is not supported in class Dot\\Maker\\Component\\Method in file \/src\/Component\/Method\.php \(line 20\)# + #\[BC\] SKIPPED: An enum expression Dot\\Maker\\VisibilityEnum::Protected is not supported in class Dot\\Maker\\Component\\Property in file \/src\/Component\/Property\.php \(line 15\)# diff --git a/src/Component/InterfaceFile.php b/src/Component/InterfaceFile.php index e6758a4..6848049 100644 --- a/src/Component/InterfaceFile.php +++ b/src/Component/InterfaceFile.php @@ -153,7 +153,7 @@ public function render(): string } if ($this->comment !== '') { - $interface .= PHP_EOL . $this->comment . PHP_EOL; + $interface .= PHP_EOL . $this->comment; } $interface .= PHP_EOL; diff --git a/src/Type/InputFilter/DeleteResourceInputFilter.php b/src/Type/InputFilter/DeleteResourceInputFilter.php index 37966d6..800320b 100644 --- a/src/Type/InputFilter/DeleteResourceInputFilter.php +++ b/src/Type/InputFilter/DeleteResourceInputFilter.php @@ -31,18 +31,11 @@ public function create(string $name): File throw DuplicateFileException::create($inputFilter); } - if ($this->context->isApi()) { - $content = $this->renderApi( - $name, - $inputFilter->getComponent(), - ); - } else { - $content = $this->render( - $name, - $inputFilter->getComponent(), - $this->fileSystem->confirmDeleteInput($name)->getComponent(), - ); - } + $content = $this->render( + $name, + $inputFilter->getComponent(), + $this->fileSystem->confirmDeleteInput($name)->getComponent(), + ); $inputFilter->create($content); @@ -77,25 +70,4 @@ public function render(string $name, Component $inputFilter, Component $input): return $class->render(); } - - public function renderApi(string $name, Component $inputFilter): string - { - $class = (new ClassFile($inputFilter->getNamespace(), $inputFilter->getClassName())) - ->setExtends('AbstractInputFilter') - ->useClass($this->import->getAbstractInputFilterFqcn()) - ->setComment(<< - */ -COMM); - - $init = (new Constructor()) - ->setBody(<<addMethod($init); - - return $class->render(); - } } diff --git a/test/ColorEnumTest.php b/test/ColorEnumTest.php new file mode 100644 index 0000000..87f94d5 --- /dev/null +++ b/test/ColorEnumTest.php @@ -0,0 +1,65 @@ +outputStream = fopen('php://memory', 'w+'); + Output::setOutputStream($this->outputStream); + } + + protected function tearDown(): void + { + fclose($this->outputStream); + } + + public function testWillRenderMessageWithBackgroundColor(): void + { + Output::write( + ColorEnum::colorize('Test Message', ColorEnum::BackgroundBlack) + ); + + rewind($this->outputStream); + $this->assertSame("\033[40mTest Message\033[0m", stream_get_contents($this->outputStream)); + } + + public function testWillRenderMessageWithForegroundColor(): void + { + Output::write( + ColorEnum::colorize('Test Message', ColorEnum::ForegroundBrightGreen) + ); + + rewind($this->outputStream); + $this->assertSame("\033[92mTest Message\033[0m", stream_get_contents($this->outputStream)); + } + + public function testWillRenderMessageWithBackgroundAndForegroundColor(): void + { + Output::write( + ColorEnum::colorize( + 'Test Message', + ColorEnum::ForegroundBrightGreen, + ColorEnum::BackgroundBlack + ) + ); + + rewind($this->outputStream); + $this->assertSame("\033[92;40mTest Message\033[0m", stream_get_contents($this->outputStream)); + } +} diff --git a/test/Component/ClassFileTest.php b/test/Component/ClassFileTest.php index f422030..f4bbaee 100644 --- a/test/Component/ClassFileTest.php +++ b/test/Component/ClassFileTest.php @@ -111,6 +111,9 @@ public function testWillRenderClass(): void ->addInject( (new Inject('CustomInjector'))->addArgument('true', 'param') ) + ->setAbstract(true) + ->setFinal(true) + ->setReadonly(true) ->useClass('App\\Module\\OtherClassName') ->useClass('App\\Module\\InterfaceName') ->useFunction('sprintf') @@ -158,7 +161,7 @@ public function testWillRenderClass(): void ->appendBody('// add logic') ); - $this->assertSame($this->dataProviderRenderedClass(), $actual->render()); + $this->assertSame($this->dataProviderRenderedClass(), (string) $actual); } private function dataProviderRenderedClass(): string @@ -178,7 +181,7 @@ private function dataProviderRenderedClass(): string use const PHP_EOL; #[CustomInjector(param: true)] -class ClassName extends OtherClassName implements InterfaceName +final readonly abstract class ClassName extends OtherClassName implements InterfaceName { protected bool \$propertyName = true; diff --git a/test/Component/DeclarationTest.php b/test/Component/DeclarationTest.php index 3806fab..c6fd406 100644 --- a/test/Component/DeclarationTest.php +++ b/test/Component/DeclarationTest.php @@ -59,6 +59,41 @@ public function testWillSetReturnType(): void $this->assertSame('self', $declaration->getReturnType()); } + public function testWillRenderParameters(): void + { + $declaration = new Declaration($this->declarationName); + $this->assertSame('', $declaration->renderParameters()); + + $declaration->addParameter( + new Parameter('param', 'string') + ); + $this->assertSame(' string $param,', $declaration->renderParameters()); + + $declaration->addParameter( + new Parameter('other', 'string') + ); + $this->assertSame(<<renderParameters()); + } + + public function testWillRenderSignature(): void + { + $declaration = new Declaration($this->declarationName); + $this->assertSame(': void', $declaration->renderSignature()); + + $declaration->setReturnType(''); + $this->assertSame('', $declaration->renderSignature()); + + $declaration->setReturnType('self'); + $this->assertSame(': self', $declaration->renderSignature()); + + $declaration->setReturnType('string'); + $declaration->setNullable(true); + $this->assertSame(': ?string', $declaration->renderSignature()); + } + public function testWillRender(): void { $comment = <<addParameter( new Parameter('param', 'string') ); - $this->assertSame($this->dataProviderRenderedDeclaration(), $declaration->render()); + $this->assertSame($this->dataProviderRenderedDeclaration(), (string) $declaration); } private function dataProviderRenderedDeclaration(): string diff --git a/test/Component/InterfaceFileTest.php b/test/Component/InterfaceFileTest.php index e835214..ee9c859 100644 --- a/test/Component/InterfaceFileTest.php +++ b/test/Component/InterfaceFileTest.php @@ -73,9 +73,14 @@ public function testWillRenderInterface(): void ->useClass('App\\Module\\OtherInterface') ->useFunction('sprintf') ->useConstant('PHP_EOL') + ->setComment(<<addDeclaration((new Declaration('getResource'))->setReturnType('Resource')); - $this->assertSame($this->dataProviderRenderedClass(), $actual->render()); + $this->assertSame($this->dataProviderRenderedClass(), (string) $actual); } private function dataProviderRenderedClass(): string @@ -93,6 +98,9 @@ private function dataProviderRenderedClass(): string use const PHP_EOL; +/** + * Comment + */ interface ClassName extends OtherInterface { public function getResource(): Resource; diff --git a/test/Component/MethodTest.php b/test/Component/MethodTest.php index 6ceb154..86b5c7a 100644 --- a/test/Component/MethodTest.php +++ b/test/Component/MethodTest.php @@ -108,7 +108,15 @@ public function testWillSetVisibility(): void $this->assertSame(VisibilityEnum::Private, $method->getVisibility()); } - public function testWillRender(): void + public function testWillRenderMethodWithoutBody(): void + { + $method = (new Method($this->methodName)) + ->setVisibility(VisibilityEnum::Private) + ->setNullable(false); + $this->assertSame($this->dataProviderRenderedMethodWithoutBody(), (string) $method); + } + + public function testWillRenderMethod(): void { $method = (new Method($this->methodName)) ->setVisibility(VisibilityEnum::Private) @@ -121,7 +129,16 @@ public function testWillRender(): void COMM) ->addParameter(new Parameter('param', 'string', true, 'null')) ->setBody(' return $this;'); - $this->assertSame($this->dataProviderRenderedMethod(), $method->render()); + $this->assertSame($this->dataProviderRenderedMethod(), (string) $method); + } + + private function dataProviderRenderedMethodWithoutBody(): string + { + return <<assertSame('?string $param = "test"', $parameter->render()); + $this->assertSame('?string $param = "test"', (string) $parameter); } } diff --git a/test/ComponentTest.php b/test/ComponentTest.php index 4295f3c..db52108 100644 --- a/test/ComponentTest.php +++ b/test/ComponentTest.php @@ -269,4 +269,15 @@ public function testWillRenderInputServiceInterface(): void $this->assertSame('BOOK_STORE_SERVICE_INTERFACE', $component->toUpperCase(false)); $this->assertSame('BOOK_STORE_SERVICE', $component->toUpperCase()); } + + public function testWillPluralize(): void + { + $this->assertSame('buses', Component::pluralize('bus')); + $this->assertSame('boxes', Component::pluralize('box')); + $this->assertSame('jazzes', Component::pluralize('jazz')); + $this->assertSame('fishes', Component::pluralize('fish')); + $this->assertSame('watches', Component::pluralize('watch')); + $this->assertSame('candies', Component::pluralize('candy')); + $this->assertSame('books', Component::pluralize('book')); + } } diff --git a/test/IO/InputTest.php b/test/IO/InputTest.php index 80daa3a..dbe83e7 100644 --- a/test/IO/InputTest.php +++ b/test/IO/InputTest.php @@ -111,4 +111,16 @@ public function testConfirmWillOutputMessageAndReadNegativeAnswer(string $input) fclose($inputStream); fclose($outputStream); } + + public function testWillAlwaysGetInputStream(): void + { + Input::setStream(fopen('php://memory', 'w+')); + + $stream = Input::getStream(); + $this->assertIsResource($stream); + fclose($stream); + + $stream = Input::getStream(); + $this->assertIsResource($stream); + } } diff --git a/test/IO/OutputTest.php b/test/IO/OutputTest.php index 28922e0..67f9b80 100644 --- a/test/IO/OutputTest.php +++ b/test/IO/OutputTest.php @@ -169,4 +169,28 @@ public function testWillWriteLine(): void fclose($stream); } + + public function testWillAlwaysGetErrorStream(): void + { + Output::setErrorStream(fopen('php://memory', 'w+')); + + $stream = Output::getErrorStream(); + $this->assertIsResource($stream); + fclose($stream); + + $stream = Output::getErrorStream(); + $this->assertIsResource($stream); + } + + public function testWillAlwaysGetOutputStream(): void + { + Output::setOutputStream(fopen('php://memory', 'w+')); + + $stream = Output::getOutputStream(); + $this->assertIsResource($stream); + fclose($stream); + + $stream = Output::getOutputStream(); + $this->assertIsResource($stream); + } } diff --git a/test/MakerTest.php b/test/MakerTest.php index 4e10cd7..194df4f 100644 --- a/test/MakerTest.php +++ b/test/MakerTest.php @@ -5,6 +5,7 @@ namespace DotTest\Maker; use Dot\Maker\ColorEnum; +use Dot\Maker\IO\Input; use Dot\Maker\IO\Output; use Dot\Maker\Maker; use org\bovigo\vfs\vfsStream; @@ -12,6 +13,7 @@ use function fclose; use function fopen; +use function fwrite; use function rewind; use function stream_get_contents; @@ -19,17 +21,41 @@ class MakerTest extends TestCase { + /** @var resource $outputStream */ + private $outputStream; + /** @var resource $inputStream */ + private $inputStream; + /** @var resource $errorStream */ + private $errorStream; + + protected function setUp(): void + { + $this->errorStream = fopen('php://memory', 'w+'); + Output::setErrorStream($this->errorStream); + + $this->inputStream = fopen('php://memory', 'w+'); + Input::setStream($this->inputStream); + + $this->outputStream = fopen('php://memory', 'w+'); + Output::setOutputStream($this->outputStream); + } + + protected function tearDown(): void + { + fclose($this->outputStream); + fclose($this->inputStream); + fclose($this->errorStream); + } + public function testWillInstantiate(): void { $maker = new Maker(''); $this->assertContainsOnlyInstancesOf(Maker::class, [$maker]); + $this->assertTrue($maker->isCli()); } - public function testInvokeWillOutputErrorWhenNotInCliMode(): void + public function testCallingInvokeWillOutputErrorWhenNotInCliMode(): void { - $errorStream = fopen('php://memory', 'w+'); - Output::setErrorStream($errorStream); - $maker = $this->getMockBuilder(Maker::class) ->onlyMethods(['isCli']) ->setConstructorArgs(['']) @@ -37,16 +63,14 @@ public function testInvokeWillOutputErrorWhenNotInCliMode(): void $maker->method('isCli')->willReturn(false); $maker([]); - rewind($errorStream); + rewind($this->errorStream); $this->assertSame( ColorEnum::colorize('dot-maker must be run in CLI only', ColorEnum::ForegroundBrightRed) . PHP_EOL, - stream_get_contents($errorStream) + stream_get_contents($this->errorStream) ); - - fclose($errorStream); } - public function testInvokeWillOutputErrorWhenInvalidComponent(): void + public function testCallingInvokeWillOutputErrorWhenInvalidComponent(): void { $root = vfsStream::setup('root', 0644, [ 'composer.json' => '{ @@ -59,12 +83,6 @@ public function testInvokeWillOutputErrorWhenInvalidComponent(): void }', ]); - $errorStream = fopen('php://memory', 'w+'); - Output::setErrorStream($errorStream); - - $outputStream = fopen('php://memory', 'w+'); - Output::setOutputStream($outputStream); - $maker = $this->getMockBuilder(Maker::class) ->onlyMethods(['isCli']) ->setConstructorArgs([$root->url()]) @@ -72,19 +90,16 @@ public function testInvokeWillOutputErrorWhenInvalidComponent(): void $maker->method('isCli')->willReturn(true); $maker(['', 'invalid-component']); - rewind($errorStream); - rewind($outputStream); + rewind($this->errorStream); + rewind($this->outputStream); $this->assertSame( ColorEnum::colorize('Unknown component: "invalid-component"', ColorEnum::ForegroundBrightRed) . PHP_EOL, - stream_get_contents($errorStream) + stream_get_contents($this->errorStream) ); - $this->assertEmpty(stream_get_contents($outputStream)); - - fclose($errorStream); - fclose($outputStream); + $this->assertEmpty(stream_get_contents($this->outputStream)); } - public function testInvokeWithoutArgsWillOutputHelpText(): void + public function testCallingInvokeWithoutArgsWillOutputHelpText(): void { $root = vfsStream::setup('root', 0644, [ 'composer.json' => '{ @@ -97,12 +112,6 @@ public function testInvokeWithoutArgsWillOutputHelpText(): void }', ]); - $errorStream = fopen('php://memory', 'w+'); - Output::setErrorStream($errorStream); - - $outputStream = fopen('php://memory', 'w+'); - Output::setOutputStream($outputStream); - $maker = $this->getMockBuilder(Maker::class) ->onlyMethods(['isCli']) ->setConstructorArgs([$root->url()]) @@ -110,15 +119,78 @@ public function testInvokeWithoutArgsWillOutputHelpText(): void $maker->method('isCli')->willReturn(true); $maker(['', '']); - rewind($errorStream); - rewind($outputStream); + rewind($this->errorStream); + rewind($this->outputStream); $this->assertSame( Helper::getHelpText(), - stream_get_contents($outputStream) + stream_get_contents($this->outputStream) ); - $this->assertEmpty(stream_get_contents($errorStream)); + $this->assertEmpty(stream_get_contents($this->errorStream)); + } + + public function testCallingInvokeWithArgsModuleWillOutputDebugInfo(): void + { + $root = vfsStream::setup('root', 0644, [ + 'composer.json' => '{ + "autoload": { + "psr-4": { + "Api\\\\App\\\\": "src/App/src/" + } + } + }', + ]); + + fwrite($this->inputStream, PHP_EOL); + rewind($this->inputStream); + + $maker = $this->getMockBuilder(Maker::class) + ->onlyMethods(['isCli']) + ->setConstructorArgs([$root->url()]) + ->getMock(); + $maker->method('isCli')->willReturn(true); + $maker(['', 'module']); + + rewind($this->outputStream); + $this->assertSame( + <<outputStream) + ); + $this->assertEmpty(stream_get_contents($this->errorStream)); + } + + public function testCallingInvokeWithValidComponentIdentifierWillSucceed(): void + { + $root = vfsStream::setup('root', 0644, [ + 'composer.json' => '{ + "autoload": { + "psr-4": { + "Api\\\\App\\\\": "src/App/src/" + } + } + }', + 'src' => [ + 'App' => [], + ], + ]); + + fwrite($this->inputStream, 'App' . PHP_EOL); + fwrite($this->inputStream, 'Test' . PHP_EOL); + fwrite($this->inputStream, PHP_EOL); + rewind($this->inputStream); + + $maker = $this->getMockBuilder(Maker::class) + ->onlyMethods(['isCli']) + ->setConstructorArgs([$root->url()]) + ->getMock(); + $maker->method('isCli')->willReturn(true); + $maker(['', 'command']); - fclose($errorStream); - fclose($outputStream); + rewind($this->errorStream); + $this->assertEmpty(stream_get_contents($this->errorStream)); } } diff --git a/test/Type/ModuleTest.php b/test/Type/ModuleTest.php index 03495ca..7462378 100644 --- a/test/Type/ModuleTest.php +++ b/test/Type/ModuleTest.php @@ -57,6 +57,45 @@ protected function tearDown(): void fclose($this->outputStream); } + public function testWillCallAccessors(): void + { + $root = vfsStream::setup('root', 0644, [ + 'composer.json' => '{ + "autoload": { + "psr-4": { + "Api\\\\App\\\\": "src/App/src/" + } + } + }', + ]); + + $config = new Config($root->url()); + $context = new Context($root->url()); + $fileSystem = (new FileSystem($context))->setModuleName($this->moduleName); + + fwrite($this->inputStream, PHP_EOL); + rewind($this->inputStream); + + $module = new Module($fileSystem, $context, $config); + $this->assertContainsOnlyInstancesOf(Config::class, [$module->getConfig()]); + $this->assertContainsOnlyInstancesOf(Context::class, [$module->getContext()]); + $this->assertContainsOnlyInstancesOf(FileSystem::class, [$module->getFileSystem()]); + + $this->assertTrue($module->isModule()); + $this->assertNull($module->getModule()); + $this->assertFalse($module->hasModule()); + $module->setModule($module); + $this->assertContainsOnlyInstancesOf(Module::class, [$module->getModule()]); + $this->assertTrue($module->hasModule()); + + $module->setConfig(new Config($root->url())); + $module->setContext(new Context($root->url())); + $module->setFileSystem((new FileSystem($context))->setModuleName($this->moduleName)); + $this->assertContainsOnlyInstancesOf(Config::class, [$module->getConfig()]); + $this->assertContainsOnlyInstancesOf(Context::class, [$module->getContext()]); + $this->assertContainsOnlyInstancesOf(FileSystem::class, [$module->getFileSystem()]); + } + public function testCallToInvokeWillEarlyReturnOnEmptyInput(): void { $root = vfsStream::setup('root', 0644, [ diff --git a/test/Type/TypeEnumTest.php b/test/Type/TypeEnumTest.php new file mode 100644 index 0000000..1cb676e --- /dev/null +++ b/test/Type/TypeEnumTest.php @@ -0,0 +1,42 @@ +assertSame(Help::class, TypeEnum::getClass('')); + $this->assertSame(Collection::class, TypeEnum::getClass('collection')); + $this->assertSame(Command::class, TypeEnum::getClass('command')); + $this->assertSame(Entity::class, TypeEnum::getClass('entity')); + $this->assertSame(Form::class, TypeEnum::getClass('form')); + $this->assertSame(Handler::class, TypeEnum::getClass('handler')); + $this->assertSame(Input::class, TypeEnum::getClass('input')); + $this->assertSame(InputFilter::class, TypeEnum::getClass('input-filter')); + $this->assertSame(Middleware::class, TypeEnum::getClass('middleware')); + $this->assertSame(Module::class, TypeEnum::getClass('module')); + $this->assertSame(Repository::class, TypeEnum::getClass('repository')); + $this->assertSame(Service::class, TypeEnum::getClass('service')); + $this->assertSame(ServiceInterface::class, TypeEnum::getClass('service-interface')); + $this->assertNull(TypeEnum::getClass('test')); + } +}