diff --git a/src/Validation/Console/MakeRule.php b/src/Validation/Console/MakeRule.php new file mode 100644 index 00000000..d6186c91 --- /dev/null +++ b/src/Validation/Console/MakeRule.php @@ -0,0 +1,49 @@ +setHelp('This command allows you to create a new validation rule.'); + + $this->addArgument('name', InputArgument::REQUIRED, 'The rule class name'); + $this->addOption('force', 'f', InputOption::VALUE_NONE, 'Force to create rule'); + } + + protected function outputDirectory(): string + { + return 'app' . DIRECTORY_SEPARATOR . 'Validation' . DIRECTORY_SEPARATOR . 'Rules'; + } + + protected function stub(): string + { + return 'rule.stub'; + } + + protected function commonName(): string + { + return 'Rule'; + } +} diff --git a/src/Validation/Console/MakeType.php b/src/Validation/Console/MakeType.php new file mode 100644 index 00000000..a7dec5c8 --- /dev/null +++ b/src/Validation/Console/MakeType.php @@ -0,0 +1,49 @@ +addArgument('name', InputArgument::REQUIRED, 'The type class name'); + $this->addOption('force', 'f', InputOption::VALUE_NONE, 'Force to create type'); + + $this->setHelp('This command allows you to create a new data type for validation.'); + } + + protected function commonName(): string + { + return 'Type'; + } + + protected function stub(): string + { + return 'type.stub'; + } + + protected function outputDirectory(): string + { + return 'app' . DIRECTORY_SEPARATOR . 'Validation' . DIRECTORY_SEPARATOR . 'Types'; + } +} diff --git a/src/Validation/ValidationServiceProvider.php b/src/Validation/ValidationServiceProvider.php new file mode 100644 index 00000000..412f42f8 --- /dev/null +++ b/src/Validation/ValidationServiceProvider.php @@ -0,0 +1,20 @@ +commands([ + MakeRule::class, + MakeType::class, + ]); + } +} diff --git a/src/stubs/rule.stub b/src/stubs/rule.stub new file mode 100644 index 00000000..d054192f --- /dev/null +++ b/src/stubs/rule.stub @@ -0,0 +1,20 @@ + $this->getFieldForHumans()]); + } +} diff --git a/src/stubs/type.stub b/src/stubs/type.stub new file mode 100644 index 00000000..3ccb0506 --- /dev/null +++ b/src/stubs/type.stub @@ -0,0 +1,17 @@ +expect( + exists: fn (string $path) => false, + get: fn (string $path) => '', + put: function (string $path) { + expect($path)->toBe(base_path('app/Validation/Rules/AwesomeRule.php')); + + return true; + }, + createDirectory: function (string $path): void { + // .. + } + ); + + $this->app->swap(File::class, $mock); + + /** @var \Symfony\Component\Console\Tester\CommandTester $command */ + $command = $this->phenix('make:rule', [ + 'name' => 'AwesomeRule', + ]); + + $command->assertCommandIsSuccessful(); + + expect($command->getDisplay())->toContain('Rule [app/Validation/Rules/AwesomeRule.php] successfully generated!'); +}); + +it('does not create the rule because it already exists', function () { + $mock = Mock::of(File::class)->expect( + exists: fn (string $path) => true, + ); + + $this->app->swap(File::class, $mock); + + $this->phenix('make:rule', [ + 'name' => 'TestRule', + ]); + + /** @var \Symfony\Component\Console\Tester\CommandTester $command */ + $command = $this->phenix('make:rule', [ + 'name' => 'TestRule', + ]); + + $command->assertCommandIsSuccessful(); + + expect($command->getDisplay())->toContain('Rule already exists!'); +}); + +it('creates rule successfully with force option', function () { + $tempDir = sys_get_temp_dir(); + $tempPath = $tempDir . DIRECTORY_SEPARATOR . 'TestRule.php'; + + file_put_contents($tempPath, 'old content'); + + $this->assertEquals('old content', file_get_contents($tempPath)); + + $mock = Mock::of(File::class)->expect( + exists: fn (string $path) => false, + get: fn (string $path) => 'new content', + put: fn (string $path, string $content) => file_put_contents($tempPath, $content), + createDirectory: function (string $path): void { + // .. + } + ); + + $this->app->swap(File::class, $mock); + + /** @var \Symfony\Component\Console\Tester\CommandTester $command */ + $command = $this->phenix('make:rule', [ + 'name' => 'TestRule', + '--force' => true, + ]); + + $command->assertCommandIsSuccessful(); + + expect($command->getDisplay())->toContain('Rule [app/Validation/Rules/TestRule.php] successfully generated!'); + expect('new content')->toBe(file_get_contents($tempPath)); +}); + +it('creates rule successfully in nested namespace', function () { + $mock = Mock::of(File::class)->expect( + exists: fn (string $path) => false, + get: fn (string $path) => '', + put: function (string $path) { + expect($path)->toBe(base_path('app/Validation/Rules/Admin/TestRule.php')); + + return true; + }, + createDirectory: function (string $path): void { + // .. + } + ); + + $this->app->swap(File::class, $mock); + + /** @var \Symfony\Component\Console\Tester\CommandTester $command */ + $command = $this->phenix('make:rule', [ + 'name' => 'Admin/TestRule', + ]); + + $command->assertCommandIsSuccessful(); + + expect($command->getDisplay())->toContain('Rule [app/Validation/Rules/Admin/TestRule.php] successfully generated!'); +}); diff --git a/tests/Unit/Validation/Console/MakeTypeCommandTest.php b/tests/Unit/Validation/Console/MakeTypeCommandTest.php new file mode 100644 index 00000000..d9845dd9 --- /dev/null +++ b/tests/Unit/Validation/Console/MakeTypeCommandTest.php @@ -0,0 +1,110 @@ +expect( + exists: fn (string $path) => false, + get: fn (string $path) => '', + put: function (string $path) { + expect($path)->toBe(base_path('app/Validation/Types/AwesomeType.php')); + + return true; + }, + createDirectory: function (string $path): void { + // .. + } + ); + + $this->app->swap(File::class, $mock); + + /** @var \Symfony\Component\Console\Tester\CommandTester $command */ + $command = $this->phenix('make:type', [ + 'name' => 'AwesomeType', + ]); + + $command->assertCommandIsSuccessful(); + + expect($command->getDisplay())->toContain('Type [app/Validation/Types/AwesomeType.php] successfully generated!'); +}); + +it('does not create the type because it already exists', function () { + $mock = Mock::of(File::class)->expect( + exists: fn (string $path) => true, + ); + + $this->app->swap(File::class, $mock); + + $this->phenix('make:type', [ + 'name' => 'TestType', + ]); + + /** @var \Symfony\Component\Console\Tester\CommandTester $command */ + $command = $this->phenix('make:type', [ + 'name' => 'TestType', + ]); + + $command->assertCommandIsSuccessful(); + + expect($command->getDisplay())->toContain('Type already exists!'); +}); + +it('creates type successfully with force option', function () { + $tempDir = sys_get_temp_dir(); + $tempPath = $tempDir . DIRECTORY_SEPARATOR . 'TestType.php'; + + file_put_contents($tempPath, 'old content'); + + $this->assertEquals('old content', file_get_contents($tempPath)); + + $mock = Mock::of(File::class)->expect( + exists: fn (string $path) => false, + get: fn (string $path) => 'new content', + put: fn (string $path, string $content) => file_put_contents($tempPath, $content), + createDirectory: function (string $path): void { + // .. + } + ); + + $this->app->swap(File::class, $mock); + + /** @var \Symfony\Component\Console\Tester\CommandTester $command */ + $command = $this->phenix('make:type', [ + 'name' => 'TestType', + '--force' => true, + ]); + + $command->assertCommandIsSuccessful(); + + expect($command->getDisplay())->toContain('Type [app/Validation/Types/TestType.php] successfully generated!'); + expect('new content')->toBe(file_get_contents($tempPath)); +}); + +it('creates type successfully in nested namespace', function () { + $mock = Mock::of(File::class)->expect( + exists: fn (string $path) => false, + get: fn (string $path) => '', + put: function (string $path) { + expect($path)->toBe(base_path('app/Validation/Types/Admin/TestType.php')); + + return true; + }, + createDirectory: function (string $path): void { + // .. + } + ); + + $this->app->swap(File::class, $mock); + + /** @var \Symfony\Component\Console\Tester\CommandTester $command */ + $command = $this->phenix('make:type', [ + 'name' => 'Admin/TestType', + ]); + + $command->assertCommandIsSuccessful(); + + expect($command->getDisplay())->toContain('Type [app/Validation/Types/Admin/TestType.php] successfully generated!'); +}); diff --git a/tests/fixtures/application/config/app.php b/tests/fixtures/application/config/app.php index d0b5a581..732528da 100644 --- a/tests/fixtures/application/config/app.php +++ b/tests/fixtures/application/config/app.php @@ -31,5 +31,6 @@ \Phenix\Queue\QueueServiceProvider::class, \Phenix\Events\EventServiceProvider::class, \Phenix\Translation\TranslationServiceProvider::class, + \Phenix\Validation\ValidationServiceProvider::class, ], ];