From 474d0577eecc22f0869c360c29fc0a45d6188632 Mon Sep 17 00:00:00 2001 From: Konstantin Lapkovsky Date: Mon, 18 Dec 2023 21:40:59 +0400 Subject: [PATCH 01/20] test: add tests for factory generator. --- src/Generators/FactoryGenerator.php | 32 +-- tests/FactoryGeneratorTest.php | 149 ++++++++++++++ tests/Support/Factory/FactoryMockTrait.php | 204 +++++++++++++++++++ tests/Support/Factory/ModelFactory.php | 15 ++ tests/Support/Factory/ModelWithRelations.php | 11 + tests/TestCase.php | 8 + 6 files changed, 406 insertions(+), 13 deletions(-) create mode 100644 tests/FactoryGeneratorTest.php create mode 100644 tests/Support/Factory/FactoryMockTrait.php create mode 100644 tests/Support/Factory/ModelFactory.php create mode 100644 tests/Support/Factory/ModelWithRelations.php diff --git a/src/Generators/FactoryGenerator.php b/src/Generators/FactoryGenerator.php index dd64ada9..ad712186 100644 --- a/src/Generators/FactoryGenerator.php +++ b/src/Generators/FactoryGenerator.php @@ -2,6 +2,7 @@ namespace RonasIT\Support\Generators; +use Exception; use Faker\Generator as Faker; use Illuminate\Support\Arr; use Illuminate\Support\Str; @@ -10,7 +11,6 @@ use RonasIT\Support\Exceptions\ModelFactoryNotFoundedException; use RonasIT\Support\Exceptions\ClassAlreadyExistsException; use RonasIT\Support\Events\SuccessCreateMessage; -use Exception; class FactoryGenerator extends EntityGenerator { @@ -32,7 +32,7 @@ protected function generateSeparateClass(): string $this->throwFailureException( ClassNotExistsException::class, "Cannot create {$this->model}Factory cause {$this->model} Model does not exists.", - "Create a {$this->model} Model by himself or run command 'php artisan make:entity {$this->model} --only-model'." + "Create a {$this->model} Model by itself or run command 'php artisan make:entity {$this->model} --only-model'." ); } @@ -74,7 +74,7 @@ protected function generateToGenericClass(): string $createMessage = "Created a new Test factory for {$this->model} model in '{$this->paths['factory']}'"; - file_put_contents($this->paths['factory'], $content, FILE_APPEND); + file_put_contents(base_path($this->paths['factory']), $content, FILE_APPEND); $this->prepareRelatedFactories(); } else { @@ -86,13 +86,18 @@ protected function generateToGenericClass(): string public function generate(): void { - $createMessage = (version_compare(app()->version(), '8', '>=')) + $createMessage = ($this->allowedToCreateFactoryInSeparateClass()) ? $this->generateSeparateClass() : $this->generateToGenericClass(); event(new SuccessCreateMessage($createMessage)); } + protected function allowedToCreateFactoryInSeparateClass(): bool + { + return version_compare(app()->version(), '8', '>='); + } + protected function prepareEmptyFactory(): void { $stubPath = config('entity-generator.stubs.legacy_empty_factory'); @@ -111,7 +116,7 @@ protected function prepareEmptyFactory(): void protected function checkExistRelatedModelsFactories(): bool { - $modelFactoryContent = file_get_contents($this->paths['factory']); + $modelFactoryContent = file_get_contents(base_path($this->paths['factory'])); $relatedModels = $this->getRelatedModels($this->model); $modelNamespace = $this->getOrCreateNamespace('models'); @@ -122,8 +127,9 @@ protected function checkExistRelatedModelsFactories(): bool if (!$existModelFactory) { $this->throwFailureException( ModelFactoryNotFoundedException::class, - "Not found $relatedModel factory for $relatedModel model in '{$this->paths['factory']}", - "Please declare a factory for $relatedModel model on '{$this->paths['factory']}' path and run your command with option '--only-tests'." + "Not found {$relatedModel} factory for {$relatedModel} model in '{$this->paths['factory']}", + "Please declare a factory for {$relatedModel} model on '{$this->paths['factory']}' " + . "path and run your command with option '--only-tests'." ); } } @@ -158,12 +164,12 @@ protected function prepareRelatedFactories(): void ); foreach ($relations as $relation) { - $modelFactoryContent = file_get_contents($this->paths['factory']); + $modelFactoryContent = file_get_contents(base_path($this->paths['factory'])); if (!Str::contains($modelFactoryContent, $this->getModelClass($relation))) { $this->throwFailureException( ModelFactoryNotFound::class, - "Model factory for mode {$relation} not found.", + "Model factory for model {$relation} not found.", "Please create it and after thar you can run this command with flag '--only-tests'." ); } @@ -180,7 +186,7 @@ protected function prepareRelatedFactories(): void $modelFactoryContent = str_replace($match, $match . $newField, $modelFactoryContent); } - file_put_contents($this->paths['factory'], $modelFactoryContent); + file_put_contents(base_path($this->paths['factory']), $modelFactoryContent); } } @@ -206,7 +212,7 @@ public static function getFactoryFieldsContent($field): string protected function checkExistModelFactory(): int { - $modelFactoryContent = file_get_contents($this->paths['factory']); + $modelFactoryContent = file_get_contents(base_path($this->paths['factory'])); $modelNamespace = $this->getOrCreateNamespace('models'); $factoryClass = "{$modelNamespace}\\$this->model::class"; @@ -262,8 +268,8 @@ protected function getModelClassContent($model): string if (!$this->classExists('models', $model)) { $this->throwFailureException( ClassNotExistsException::class, - "Cannot create {$model} Model cause {$model} Model does not exists.", - "Create a {$model} Model by himself or run command 'php artisan make:entity {$model} --only-model'." + "Cannot get {$model} Model class content cause {$model} Model does not exists.", + "Create a {$model} Model by itself or run command 'php artisan make:entity {$model} --only-model'." ); } diff --git a/tests/FactoryGeneratorTest.php b/tests/FactoryGeneratorTest.php new file mode 100644 index 00000000..250005ce --- /dev/null +++ b/tests/FactoryGeneratorTest.php @@ -0,0 +1,149 @@ +generatedFileBasePath = vfsStream::url('root'); + + $this->app->setBasePath($this->generatedFileBasePath); + } + + public function testModelNotExists() + { + $this->getFiredEvents([SuccessCreateMessage::class]); + $this->expectException(ClassNotExistsException::class); + $this->expectErrorMessage("Cannot create PostFactory cause Post Model does not exists. " + . "Create a Post Model by itself or run command 'php artisan make:entity Post --only-model'."); + + $mock = $this->getFactoryGeneratorMockForMissingModel(); + $mock + ->setModel('Post') + ->generate(); + } + + public function testFactoryClassExists() + { + $this->getFiredEvents([SuccessCreateMessage::class]); + $this->expectException(ClassAlreadyExistsException::class); + $this->expectErrorMessage("Cannot create PostFactory cause PostFactory already exists. Remove PostFactory."); + + $mock = $this->getFactoryGeneratorMockForExistingFactory(); + $mock + ->setModel('Post') + ->generate(); + } + + public function testCannotGetContentForGenericFactory() + { + $this->getFiredEvents([SuccessCreateMessage::class]); + $this->expectException(ClassNotExistsException::class); + $this->expectErrorMessage("Cannot get Post Model class content cause Post Model does not exists. " + . "Create a Post Model by itself or run command 'php artisan make:entity Post --only-model'."); + + $funMock = $this->getMockForFileExists(); + + $this->mockConfigurations(); + $this->mockFilesystem(); + $this->mockFactoryGenerator(); + + try { + app(FactoryGenerator::class) + ->setModel('Post') + ->generate(); + } finally { + $funMock->disable(); + } + } + + public function testRelatedModelWithoutFactory() + { + $mock = $this->getMockForFileExists(); + + $this->getFiredEvents([SuccessCreateMessage::class]); + $this->expectException(ModelFactoryNotFoundedException::class); + $this->expectErrorMessage("Not found User factory for User model in 'database/factories/ModelFactory.php " + . "Please declare a factory for User model on 'database/factories/ModelFactory.php' path and run your command with option '--only-tests'."); + + $this->mockConfigurations(); + $this->mockFilesystemForNonExistingRelatedModelFactory(); + $this->mockFactoryGeneratorForMissingRelatedModelFactory(); + + try { + app(FactoryGenerator::class) + ->setModel('Post') + ->setFields([ + 'integer-required' => ['author_id'], + 'string' => ['title'] + ]) + ->generate(); + } finally { + $mock->disable(); + } + } + + public function testRevertedModelFactoryNotExists() + { + $this->expectException(ModelFactoryNotFound::class); + $this->expectErrorMessage("Model factory for model comment not found. " + . "Please create it and after thar you can run this command with flag '--only-tests'."); + + $mock = $this->getMockForFileExists(); + + $this->mockConfigurations(); + $this->mockViewsNamespace(); + $this->mockGeneratorForMissingRevertedRelationModelFactory(); + $this->mockFilesystemForMissingRevertedRelationModelFactory(); + + try { + app(FactoryGenerator::class) + ->setRelations([ + 'hasOne' => ['comment'], + 'hasMany' => ['comment'], + 'belongsTo' => ['user'] + ]) + ->setModel('Post') + ->generate(); + } finally { + $mock->disable(); + } + } + + public function testAlreadyExistsFactory() + { + $this->expectsEvents([SuccessCreateMessage::class]); + + $this->mockConfigurations(); + $this->mockFactoryGeneratorForAlreadyExistsFactory(); + + $mock = $this->getMockForFileExists(); + + try { + app(FactoryGenerator::class) + ->setModel('Post') + ->generate(); + } finally { + $mock->disable(); + } + } +} diff --git a/tests/Support/Factory/FactoryMockTrait.php b/tests/Support/Factory/FactoryMockTrait.php new file mode 100644 index 00000000..a14668f1 --- /dev/null +++ b/tests/Support/Factory/FactoryMockTrait.php @@ -0,0 +1,204 @@ +makePartial(); + + $mock + ->shouldAllowMockingProtectedMethods() + ->shouldReceive('classExists') + ->once() + ->with('models', 'Post') + ->andReturn(false); + + return $mock; + } + + public function getFactoryGeneratorMockForExistingFactory(): MockInterface + { + $mock = Mockery::mock(FactoryGenerator::class)->makePartial(); + + $mock + ->shouldAllowMockingProtectedMethods() + ->shouldReceive('classExists') + ->once() + ->with('models', 'Post') + ->andReturn(true); + + $mock + ->shouldReceive('classExists') + ->once() + ->with('factory', 'PostFactory') + ->andReturn(true); + + return $mock; + } + + public function mockGeneratorForMissingRevertedRelationModelFactory(): void + { + $this->mockClass(FactoryGenerator::class, [ + [ + 'method' => 'checkExistRelatedModelsFactories', + 'arguments' => [], + 'result' => true + ], + [ + 'method' => 'allowedToCreateFactoryInSeparateClass', + 'arguments' => [], + 'result' => false + ] + ]); + } + + public function mockFactoryGenerator(): void + { + $this->mockClass(FactoryGenerator::class, [ + [ + 'method' => 'classExists', + 'arguments' => ['models', 'Post'], + 'result' => false + ], + [ + 'method' => 'allowedToCreateFactoryInSeparateClass', + 'arguments' => [], + 'result' => false + ] + ]); + } + + public function mockFactoryGeneratorForAlreadyExistsFactory(): void + { + $this->mockClass(FactoryGenerator::class, [ + [ + 'method' => 'checkExistModelFactory', + 'arguments' => [], + 'result' => 1 + ], + [ + 'method' => 'allowedToCreateFactoryInSeparateClass', + 'arguments' => [], + 'result' => false + ] + ]); + } + + public function mockFactoryGeneratorForMissingRelatedModelFactory(): void + { + $this->mockClass(FactoryGenerator::class, [ + [ + 'method' => 'classExists', + 'arguments' => ['models', 'Post'], + 'result' => true + ], + [ + 'method' => 'allowedToCreateFactoryInSeparateClass', + 'arguments' => [], + 'result' => false + ] + ]); + } + + public function getMockForFileExists() + { + return $this->mockNativeFunction('\\RonasIT\\Support\\Generators', 'file_exists', true); + } + + public function mockConfigurations() + { + config([ + 'entity-generator.stubs.factory' => 'entity-generator::factory', + 'entity-generator.stubs.legacy_factory' => 'entity-generator::legacy_factory', + 'entity-generator.stubs.legacy_empty_factory' => 'entity-generator::legacy_empty_factory', + 'entity-generator.paths' => [ + 'models' => 'app/Models', + 'factory' => 'database/factories/ModelFactory.php', + ] + ]); + } + + public function mockFilesystem(): void + { + $structure = [ + 'app' => [ + 'Services' => [ + 'PostService.php' => ' [], + 'Models' => [] + ], + 'database' => [ + 'factories' => [ + 'ModelFactory.php' => 'getFileName(); + + $structure = [ + 'app' => [ + 'Services' => [ + 'PostService.php' => ' [], + 'Models' => [ + 'Post.php' => file_get_contents($postModelFileName), + 'User.php' => ' [ + 'factories' => [ + 'ModelFactory.php' => ' [ + 'Services' => [ + 'PostService.php' => ' [], + 'Models' => [ + 'Post.php' => ' ' [ + 'factories' => [ + 'ModelFactory.php' => file_get_contents(getcwd() . '/tests/Support/Factory/ModelFactory.php'), + ] + ] + ]; + + vfsStream::create($structure); + } +} \ No newline at end of file diff --git a/tests/Support/Factory/ModelFactory.php b/tests/Support/Factory/ModelFactory.php new file mode 100644 index 00000000..9c3b4012 --- /dev/null +++ b/tests/Support/Factory/ModelFactory.php @@ -0,0 +1,15 @@ +define(App\Models\User::class, function (Faker\Generator $faker) { + static $password; + + return [ + 'name' => $faker->name, + 'email' => $faker->unique()->safeEmail, + 'password' => $password ?: $password = bcrypt('secret'), + 'remember_token' => str_random(10), + ]; +}); \ No newline at end of file diff --git a/tests/Support/Factory/ModelWithRelations.php b/tests/Support/Factory/ModelWithRelations.php new file mode 100644 index 00000000..03e090be --- /dev/null +++ b/tests/Support/Factory/ModelWithRelations.php @@ -0,0 +1,11 @@ +belongsTo(User::class); + } +} \ No newline at end of file diff --git a/tests/TestCase.php b/tests/TestCase.php index 83917177..75530d12 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -6,6 +6,7 @@ use Illuminate\Foundation\Testing\Concerns\InteractsWithViews; use Illuminate\Support\Str; use Orchestra\Testbench\TestCase as BaseTestCase; +use phpmock\Mock; use RonasIT\Support\Traits\FixturesTrait; class TestCase extends BaseTestCase @@ -15,6 +16,13 @@ class TestCase extends BaseTestCase protected $globalExportMode = false; protected $generatedFileBasePath; + public function tearDown(): void + { + parent::tearDown(); + + Mock::disableAll(); + } + public function rollbackToDefaultBasePath(): void { $this->app->setBasePath(getcwd()); From a4d14e240e4243411def066a01d0a10064166041 Mon Sep 17 00:00:00 2001 From: Konstantin Lapkovsky Date: Wed, 20 Dec 2023 10:29:30 +0400 Subject: [PATCH 02/20] test: add factory generator tests. --- src/Generators/FactoryGenerator.php | 23 ++++++++-- tests/FactoryGeneratorTest.php | 27 ++++++++++++ tests/Support/Factory/FactoryMockTrait.php | 30 ++++++++++++- tests/Support/Factory/Post.php | 11 +++++ .../FactoryGeneratorTest/model_factory.php | 43 +++++++++++++++++++ 5 files changed, 129 insertions(+), 5 deletions(-) create mode 100644 tests/Support/Factory/Post.php create mode 100644 tests/fixtures/FactoryGeneratorTest/model_factory.php diff --git a/src/Generators/FactoryGenerator.php b/src/Generators/FactoryGenerator.php index ad712186..4f5503c9 100644 --- a/src/Generators/FactoryGenerator.php +++ b/src/Generators/FactoryGenerator.php @@ -6,6 +6,7 @@ use Faker\Generator as Faker; use Illuminate\Support\Arr; use Illuminate\Support\Str; +use InvalidArgumentException; use RonasIT\Support\Exceptions\ModelFactoryNotFound; use RonasIT\Support\Exceptions\ClassNotExistsException; use RonasIT\Support\Exceptions\ModelFactoryNotFoundedException; @@ -107,11 +108,13 @@ protected function prepareEmptyFactory(): void list($basePath, $databaseFactoryDir) = extract_last_part(config('entity-generator.paths.factory'), '/'); + $databaseFactoryDir = base_path($databaseFactoryDir); + if (!is_dir($databaseFactoryDir)) { mkdir($databaseFactoryDir); } - file_put_contents($this->paths['factory'], $content); + file_put_contents(base_path($this->paths['factory']), $content); } protected function checkExistRelatedModelsFactories(): bool @@ -199,11 +202,25 @@ public static function getFactoryFieldsContent($field): string return 1; } - if (property_exists($faker, $field['name'])) { + try { + $faker->{$field['name']}; + $hasFormatter = true; + } catch (InvalidArgumentException $e) { + $hasFormatter = false; + } + + if ($hasFormatter) { return "\$faker-\>{$field['name']}"; } - if (method_exists($faker, $field['name'])) { + try { + $faker->{$field['name']}(); + $hasFormatter = true; + } catch (InvalidArgumentException $e) { + $hasFormatter = false; + } + + if ($hasFormatter) { return "\$faker-\>{$field['name']}()"; } diff --git a/tests/FactoryGeneratorTest.php b/tests/FactoryGeneratorTest.php index 250005ce..aec221b7 100644 --- a/tests/FactoryGeneratorTest.php +++ b/tests/FactoryGeneratorTest.php @@ -146,4 +146,31 @@ public function testAlreadyExistsFactory() $mock->disable(); } } + + public function testCreate() + { + $this->expectsEvents([SuccessCreateMessage::class]); + + $this->mockConfigurations(); + $this->mockViewsNamespace(); + $this->mockFilesystemForCreation(); + $this->mockFactoryGeneratorForCreation(); + + app(FactoryGenerator::class) + ->setFields([ + 'integer-required' => ['author_id'], + 'string' => ['title', 'iban'] + ]) + ->setRelations([ + 'hasOne' => ['User'], + 'hasMany' => [], + 'belongsTo' => ['user'] + ]) + ->setModel('Post') + ->generate(); + + $this->rollbackToDefaultBasePath(); + + $this->assertGeneratedFileEquals('model_factory.php', '/database/factories/ModelFactory.php', true); + } } diff --git a/tests/Support/Factory/FactoryMockTrait.php b/tests/Support/Factory/FactoryMockTrait.php index a14668f1..88f6191f 100644 --- a/tests/Support/Factory/FactoryMockTrait.php +++ b/tests/Support/Factory/FactoryMockTrait.php @@ -99,6 +99,17 @@ public function mockFactoryGeneratorForAlreadyExistsFactory(): void ]); } + public function mockFactoryGeneratorForCreation(): void + { + $this->mockClass(FactoryGenerator::class, [ + [ + 'method' => 'allowedToCreateFactoryInSeparateClass', + 'arguments' => [], + 'result' => false + ] + ]); + } + public function mockFactoryGeneratorForMissingRelatedModelFactory(): void { $this->mockClass(FactoryGenerator::class, [ @@ -115,9 +126,9 @@ public function mockFactoryGeneratorForMissingRelatedModelFactory(): void ]); } - public function getMockForFileExists() + public function getMockForFileExists(bool $result = true) { - return $this->mockNativeFunction('\\RonasIT\\Support\\Generators', 'file_exists', true); + return $this->mockNativeFunction('\\RonasIT\\Support\\Generators', 'file_exists', $result); } public function mockConfigurations() @@ -201,4 +212,19 @@ public function mockFilesystemForMissingRevertedRelationModelFactory(): void vfsStream::create($structure); } + + public function mockFilesystemForCreation(): void + { + $structure = [ + 'app' => [ + 'Models' => [ + 'Post.php' => file_get_contents(getcwd() . '/tests/Support/Factory/Post.php'), + 'User.php' => ' [] + ]; + + vfsStream::create($structure); + } } \ No newline at end of file diff --git a/tests/Support/Factory/Post.php b/tests/Support/Factory/Post.php new file mode 100644 index 00000000..599ec8ab --- /dev/null +++ b/tests/Support/Factory/Post.php @@ -0,0 +1,11 @@ +belongsTo(User::class); + } +} \ No newline at end of file diff --git a/tests/fixtures/FactoryGeneratorTest/model_factory.php b/tests/fixtures/FactoryGeneratorTest/model_factory.php new file mode 100644 index 00000000..dfb2fa5c --- /dev/null +++ b/tests/fixtures/FactoryGeneratorTest/model_factory.php @@ -0,0 +1,43 @@ +define(App\Models\User::class, function (Faker\Generator $faker) { + static $password; + + return [ + "post_id" => 1, + 'name' => $faker->name, + 'email' => $faker->unique()->safeEmail, + 'password' => $password ?: $password = bcrypt('secret'), + 'remember_token' => Str::random(10), + ]; +}); + +$factory->define(App\Models\Role::class, function () { + return [ + 'name' => 'user' + ]; +}); + + +$factory->define(App\Models\Post::class, function (Faker\Generator $faker) { + return [ + 'author_id' => 1, + 'user_id' => 1, + 'title' => $faker-\>title, + 'iban' => $faker-\>iban, + ]; +}); \ No newline at end of file From 90e983c39804b4bd81e2de9bfee7f3772597a7a0 Mon Sep 17 00:00:00 2001 From: Konstantin Lapkovsky Date: Wed, 20 Dec 2023 17:39:19 +0400 Subject: [PATCH 03/20] test: add tests for factory generator. --- src/Exceptions/FakerMethodNotFound.php | 9 ++ src/Generators/FactoryGenerator.php | 21 ++-- tests/FactoryGeneratorTest.php | 75 +++++++++++-- tests/Support/Factory/FactoryMockTrait.php | 101 +++++++++++------- .../FactoryGeneratorTest/model_factory.php | 6 +- .../FactoryGeneratorTest/post_factory.php | 23 ++++ 6 files changed, 171 insertions(+), 64 deletions(-) create mode 100644 src/Exceptions/FakerMethodNotFound.php create mode 100644 tests/fixtures/FactoryGeneratorTest/post_factory.php diff --git a/src/Exceptions/FakerMethodNotFound.php b/src/Exceptions/FakerMethodNotFound.php new file mode 100644 index 00000000..3c069773 --- /dev/null +++ b/src/Exceptions/FakerMethodNotFound.php @@ -0,0 +1,9 @@ +{$field['name']}"; - } - - try { - $faker->{$field['name']}(); - $hasFormatter = true; - } catch (InvalidArgumentException $e) { - $hasFormatter = false; - } - - if ($hasFormatter) { - return "\$faker-\>{$field['name']}()"; + return "\$faker->{$field['name']}"; } return self::getFakerMethod($field); diff --git a/tests/FactoryGeneratorTest.php b/tests/FactoryGeneratorTest.php index aec221b7..bcc56b6c 100644 --- a/tests/FactoryGeneratorTest.php +++ b/tests/FactoryGeneratorTest.php @@ -2,15 +2,13 @@ namespace RonasIT\Support\Tests; -use Illuminate\Contracts\Filesystem\FileNotFoundException; +use Illuminate\View\ViewException; use org\bovigo\vfs\vfsStream; -use ReflectionClass; use RonasIT\Support\Events\SuccessCreateMessage; use RonasIT\Support\Exceptions\ClassAlreadyExistsException; use RonasIT\Support\Exceptions\ClassNotExistsException; use RonasIT\Support\Exceptions\ModelFactoryNotFound; use RonasIT\Support\Exceptions\ModelFactoryNotFoundedException; -use RonasIT\Support\Generators\ControllerGenerator; use RonasIT\Support\Generators\FactoryGenerator; use RonasIT\Support\Tests\Support\Factory\FactoryMockTrait; @@ -36,8 +34,9 @@ public function testModelNotExists() $this->expectErrorMessage("Cannot create PostFactory cause Post Model does not exists. " . "Create a Post Model by itself or run command 'php artisan make:entity Post --only-model'."); - $mock = $this->getFactoryGeneratorMockForMissingModel(); - $mock + $this->getFactoryGeneratorMockForMissingModel(); + + app(FactoryGenerator::class) ->setModel('Post') ->generate(); } @@ -48,8 +47,9 @@ public function testFactoryClassExists() $this->expectException(ClassAlreadyExistsException::class); $this->expectErrorMessage("Cannot create PostFactory cause PostFactory already exists. Remove PostFactory."); - $mock = $this->getFactoryGeneratorMockForExistingFactory(); - $mock + $this->getFactoryGeneratorMockForExistingFactory(); + + app(FactoryGenerator::class) ->setModel('Post') ->generate(); } @@ -147,19 +147,20 @@ public function testAlreadyExistsFactory() } } - public function testCreate() + public function testCreateGenericFactory() { $this->expectsEvents([SuccessCreateMessage::class]); $this->mockConfigurations(); $this->mockViewsNamespace(); - $this->mockFilesystemForCreation(); - $this->mockFactoryGeneratorForCreation(); + $this->mockFilesystemForGenericStyleCreation(); + $this->mockFactoryGeneratorForGenericTypeCreation(); app(FactoryGenerator::class) ->setFields([ 'integer-required' => ['author_id'], - 'string' => ['title', 'iban'] + 'string' => ['title', 'iban', 'something'], + 'json' => ['json_text'], ]) ->setRelations([ 'hasOne' => ['User'], @@ -173,4 +174,56 @@ public function testCreate() $this->assertGeneratedFileEquals('model_factory.php', '/database/factories/ModelFactory.php', true); } + + public function testProcessUnknownFieldType() + { + $this->mockConfigurations(); + $this->mockViewsNamespace(); + $this->mockFilesystemForGenericStyleCreation(); + $this->mockFactoryGeneratorForGenericTypeCreation(); + + $this->expectException(ViewException::class); + $this->expectErrorMessage("Cannot generate fake data for unsupported another_type field type. " + . "Supported custom field types are json"); + + app(FactoryGenerator::class) + ->setFields([ + 'another_type' => ['some_field'], + ]) + ->setRelations([ + 'hasOne' => [], + 'hasMany' => [], + 'belongsTo' => [] + ]) + ->setModel('Post') + ->generate(); + } + + public function testCreateClassStyleFactory() + { + $this->expectsEvents([SuccessCreateMessage::class]); + + $this->mockConfigurationsForClassStyleFactory(); + $this->mockViewsNamespace(); + $this->mockFilesystemForClassStyleFactoryCreation(); + $this->mockFactoryGeneratorForClassTypeCreation(); + + app(FactoryGenerator::class) + ->setFields([ + 'integer-required' => ['author_id'], + 'string' => ['title', 'iban', 'something'], + 'json' => ['json_text'], + ]) + ->setRelations([ + 'hasOne' => ['User'], + 'hasMany' => [], + 'belongsTo' => ['user'] + ]) + ->setModel('Post') + ->generate(); + + $this->rollbackToDefaultBasePath(); + + $this->assertGeneratedFileEquals('post_factory.php', '/database/factories/PostFactory.php', true); + } } diff --git a/tests/Support/Factory/FactoryMockTrait.php b/tests/Support/Factory/FactoryMockTrait.php index 88f6191f..32e170d7 100644 --- a/tests/Support/Factory/FactoryMockTrait.php +++ b/tests/Support/Factory/FactoryMockTrait.php @@ -2,12 +2,7 @@ namespace RonasIT\Support\Tests\Support\Factory; -use Illuminate\Foundation\Application; -use Mockery; -use Mockery\MockInterface; use org\bovigo\vfs\vfsStream; -use phpmock\functions\FixedValueFunction; -use phpmock\MockBuilder; use ReflectionClass; use RonasIT\Support\Generators\FactoryGenerator; use RonasIT\Support\Tests\Support\Shared\GeneratorMockTrait; @@ -17,38 +12,31 @@ trait FactoryMockTrait { use GeneratorMockTrait, MockClassTrait; - public function getFactoryGeneratorMockForMissingModel(): MockInterface + public function getFactoryGeneratorMockForMissingModel(): void { - $mock = Mockery::mock(FactoryGenerator::class)->makePartial(); - - $mock - ->shouldAllowMockingProtectedMethods() - ->shouldReceive('classExists') - ->once() - ->with('models', 'Post') - ->andReturn(false); - - return $mock; + $this->mockClass(FactoryGenerator::class, [ + [ + 'method' => 'classExists', + 'arguments' => ['models', 'Post'], + 'result' => false + ] + ]); } - public function getFactoryGeneratorMockForExistingFactory(): MockInterface + public function getFactoryGeneratorMockForExistingFactory(): void { - $mock = Mockery::mock(FactoryGenerator::class)->makePartial(); - - $mock - ->shouldAllowMockingProtectedMethods() - ->shouldReceive('classExists') - ->once() - ->with('models', 'Post') - ->andReturn(true); - - $mock - ->shouldReceive('classExists') - ->once() - ->with('factory', 'PostFactory') - ->andReturn(true); - - return $mock; + $this->mockClass(FactoryGenerator::class, [ + [ + 'method' => 'classExists', + 'arguments' => ['models', 'Post'], + 'result' => true + ], + [ + 'method' => 'classExists', + 'arguments' => ['factory', 'PostFactory'], + 'result' => true + ], + ]); } public function mockGeneratorForMissingRevertedRelationModelFactory(): void @@ -99,7 +87,7 @@ public function mockFactoryGeneratorForAlreadyExistsFactory(): void ]); } - public function mockFactoryGeneratorForCreation(): void + public function mockFactoryGeneratorForGenericTypeCreation(): void { $this->mockClass(FactoryGenerator::class, [ [ @@ -110,6 +98,17 @@ public function mockFactoryGeneratorForCreation(): void ]); } + public function mockFactoryGeneratorForClassTypeCreation(): void + { + $this->mockClass(FactoryGenerator::class, [ + [ + 'method' => 'allowedToCreateFactoryInSeparateClass', + 'arguments' => [], + 'result' => true + ] + ]); + } + public function mockFactoryGeneratorForMissingRelatedModelFactory(): void { $this->mockClass(FactoryGenerator::class, [ @@ -131,7 +130,7 @@ public function getMockForFileExists(bool $result = true) return $this->mockNativeFunction('\\RonasIT\\Support\\Generators', 'file_exists', $result); } - public function mockConfigurations() + public function mockConfigurations(): void { config([ 'entity-generator.stubs.factory' => 'entity-generator::factory', @@ -144,6 +143,19 @@ public function mockConfigurations() ]); } + public function mockConfigurationsForClassStyleFactory(): void + { + config([ + 'entity-generator.stubs.factory' => 'entity-generator::factory', + 'entity-generator.stubs.legacy_factory' => 'entity-generator::legacy_factory', + 'entity-generator.stubs.legacy_empty_factory' => 'entity-generator::legacy_empty_factory', + 'entity-generator.paths' => [ + 'models' => 'app/Models', + 'factory' => 'database/factories', + ] + ]); + } + public function mockFilesystem(): void { $structure = [ @@ -213,7 +225,7 @@ public function mockFilesystemForMissingRevertedRelationModelFactory(): void vfsStream::create($structure); } - public function mockFilesystemForCreation(): void + public function mockFilesystemForGenericStyleCreation(): void { $structure = [ 'app' => [ @@ -227,4 +239,21 @@ public function mockFilesystemForCreation(): void vfsStream::create($structure); } + + public function mockFilesystemForClassStyleFactoryCreation(): void + { + $structure = [ + 'app' => [ + 'Models' => [ + 'Post.php' => file_get_contents(getcwd() . '/tests/Support/Factory/Post.php'), + 'User.php' => ' [ + 'factories' => [] + ] + ]; + + vfsStream::create($structure); + } } \ No newline at end of file diff --git a/tests/fixtures/FactoryGeneratorTest/model_factory.php b/tests/fixtures/FactoryGeneratorTest/model_factory.php index dfb2fa5c..b1aa3d77 100644 --- a/tests/fixtures/FactoryGeneratorTest/model_factory.php +++ b/tests/fixtures/FactoryGeneratorTest/model_factory.php @@ -37,7 +37,9 @@ return [ 'author_id' => 1, 'user_id' => 1, - 'title' => $faker-\>title, - 'iban' => $faker-\>iban, + 'title' => $faker->title, + 'iban' => $faker->iban, + 'something' => $faker->word, + 'json_text' => [], ]; }); \ No newline at end of file diff --git a/tests/fixtures/FactoryGeneratorTest/post_factory.php b/tests/fixtures/FactoryGeneratorTest/post_factory.php new file mode 100644 index 00000000..9d5b91e4 --- /dev/null +++ b/tests/fixtures/FactoryGeneratorTest/post_factory.php @@ -0,0 +1,23 @@ + 1, + 'user_id' => 1, + 'title' => $faker->title, + 'iban' => $faker->iban, + 'something' => $faker->word, + 'json_text' => [], + ]; + } +} \ No newline at end of file From 485b59f023ab92592346ca0d4f29ffcc919f7995 Mon Sep 17 00:00:00 2001 From: Anton Zabolotnikov Date: Wed, 20 Nov 2024 12:50:06 +0500 Subject: [PATCH 04/20] chore: add factory tests --- src/Generators/FactoryGenerator.php | 28 ++-- tests/ControllerGeneratorTest.php | 6 +- tests/FactoryGeneratorTest.php | 126 +++++++++--------- tests/NovaResourceGeneratorTest.php | 4 +- tests/NovaTestGeneratorTest.php | 4 +- tests/Support/Factory/FactoryMockTrait.php | 90 +++++++------ tests/Support/Factory/ModelFactory.php | 2 +- tests/Support/Factory/ModelWithRelations.php | 6 +- tests/Support/Factory/Post.php | 2 +- tests/TestCase.php | 2 +- .../FactoryGeneratorTest/model_factory.php | 2 +- 11 files changed, 141 insertions(+), 131 deletions(-) diff --git a/src/Generators/FactoryGenerator.php b/src/Generators/FactoryGenerator.php index 0990d094..b6100a2e 100644 --- a/src/Generators/FactoryGenerator.php +++ b/src/Generators/FactoryGenerator.php @@ -27,6 +27,15 @@ class FactoryGenerator extends EntityGenerator 'json' => '[]', ]; + public function generate(): void + { + $createMessage = ($this->allowedToCreateFactoryInSeparateClass()) + ? $this->generateSeparateClass() + : $this->generateToGenericClass(); + + event(new SuccessCreateMessage($createMessage)); + } + protected function generateSeparateClass(): string { if (!$this->classExists('models', $this->model)) { @@ -85,15 +94,6 @@ protected function generateToGenericClass(): string return $createMessage; } - public function generate(): void - { - $createMessage = ($this->allowedToCreateFactoryInSeparateClass()) - ? $this->generateSeparateClass() - : $this->generateToGenericClass(); - - event(new SuccessCreateMessage($createMessage)); - } - protected function allowedToCreateFactoryInSeparateClass(): bool { return version_compare(app()->version(), '8', '>='); @@ -125,12 +125,12 @@ protected function checkExistRelatedModelsFactories(): bool foreach ($relatedModels as $relatedModel) { $relatedFactoryClass = "{$modelNamespace}\\$relatedModel::class"; - $existModelFactory = strpos($modelFactoryContent, $relatedFactoryClass); + $existModelFactory = (strpos($modelFactoryContent, $relatedFactoryClass) !== false); if (!$existModelFactory) { $this->throwFailureException( ModelFactoryNotFoundedException::class, - "Not found {$relatedModel} factory for {$relatedModel} model in '{$this->paths['factory']}", + "Not found {$relatedModel} factory for {$relatedModel} model in '{$this->paths['factory']}.", "Please declare a factory for {$relatedModel} model on '{$this->paths['factory']}' " . "path and run your command with option '--only-tests'." ); @@ -165,7 +165,7 @@ protected function prepareRelatedFactories(): void { $relations = array_merge( $this->relations['hasOne'], - $this->relations['hasMany'] + $this->relations['hasMany'], ); foreach ($relations as $relation) { @@ -218,13 +218,13 @@ public static function getFactoryFieldsContent($field): string return self::getFakerMethod($field); } - protected function checkExistModelFactory(): int + protected function checkExistModelFactory(): bool { $modelFactoryContent = file_get_contents(base_path($this->paths['factory'])); $modelNamespace = $this->getOrCreateNamespace('models'); $factoryClass = "{$modelNamespace}\\$this->model::class"; - return strpos($modelFactoryContent, $factoryClass); + return (strpos($modelFactoryContent, $factoryClass) !== false); } protected function prepareFields(): array diff --git a/tests/ControllerGeneratorTest.php b/tests/ControllerGeneratorTest.php index a551dcf5..fa5f257e 100644 --- a/tests/ControllerGeneratorTest.php +++ b/tests/ControllerGeneratorTest.php @@ -27,7 +27,7 @@ public function testControllerAlreadyExists() $this->classExistsMethodCall(['controllers', 'PostController']) ]); - $this->assertExceptionThrowed( + $this->assertExceptionThrew( className: ClassAlreadyExistsException::class, message: 'Cannot create PostController cause PostController already exists. Remove PostController.', ); @@ -44,7 +44,7 @@ public function testModelServiceNotExists() $this->classExistsMethodCall(['services', 'PostService'], false) ]); - $this->assertExceptionThrowed( + $this->assertExceptionThrew( className: ClassNotExistsException::class, message: 'Cannot create PostService cause PostService does not exists. Create a PostService by himself.', ); @@ -58,7 +58,7 @@ public function testRouteFileNotExists() { $this->mockFilesystemWithoutRoutesFile(); - $this->assertExceptionThrowed( + $this->assertExceptionThrew( className: FileNotFoundException::class, message: "Not found file with routes. Create a routes file on path: 'vfs://root/routes/api.php'", ); diff --git a/tests/FactoryGeneratorTest.php b/tests/FactoryGeneratorTest.php index bcc56b6c..b236cecc 100644 --- a/tests/FactoryGeneratorTest.php +++ b/tests/FactoryGeneratorTest.php @@ -2,6 +2,7 @@ namespace RonasIT\Support\Tests; +use Illuminate\Support\Facades\Event; use Illuminate\View\ViewException; use org\bovigo\vfs\vfsStream; use RonasIT\Support\Events\SuccessCreateMessage; @@ -29,9 +30,10 @@ public function setUp(): void public function testModelNotExists() { - $this->getFiredEvents([SuccessCreateMessage::class]); + Event::fake(); + $this->expectException(ClassNotExistsException::class); - $this->expectErrorMessage("Cannot create PostFactory cause Post Model does not exists. " + $this->expectExceptionMessage("Cannot create PostFactory cause Post Model does not exists. " . "Create a Post Model by itself or run command 'php artisan make:entity Post --only-model'."); $this->getFactoryGeneratorMockForMissingModel(); @@ -39,120 +41,117 @@ public function testModelNotExists() app(FactoryGenerator::class) ->setModel('Post') ->generate(); + + Event::assertDispatched(SuccessCreateMessage::class); } public function testFactoryClassExists() { - $this->getFiredEvents([SuccessCreateMessage::class]); + Event::fake(); + $this->expectException(ClassAlreadyExistsException::class); - $this->expectErrorMessage("Cannot create PostFactory cause PostFactory already exists. Remove PostFactory."); + $this->expectExceptionMessage("Cannot create PostFactory cause PostFactory already exists. Remove PostFactory."); $this->getFactoryGeneratorMockForExistingFactory(); app(FactoryGenerator::class) ->setModel('Post') ->generate(); + + Event::assertDispatched(SuccessCreateMessage::class); } public function testCannotGetContentForGenericFactory() { - $this->getFiredEvents([SuccessCreateMessage::class]); + Event::fake(); + $this->expectException(ClassNotExistsException::class); - $this->expectErrorMessage("Cannot get Post Model class content cause Post Model does not exists. " + $this->expectExceptionMessage("Cannot get Post Model class content cause Post Model does not exists. " . "Create a Post Model by itself or run command 'php artisan make:entity Post --only-model'."); - $funMock = $this->getMockForFileExists(); + $this->mockForFileExists([ + 'database/factories/ModelFactory.php', + 'vfs://root/app/Models', + ]); $this->mockConfigurations(); $this->mockFilesystem(); $this->mockFactoryGenerator(); - try { - app(FactoryGenerator::class) - ->setModel('Post') - ->generate(); - } finally { - $funMock->disable(); - } + app(FactoryGenerator::class) + ->setModel('Post') + ->generate(); + + Event::assertDispatched(SuccessCreateMessage::class); } public function testRelatedModelWithoutFactory() { - $mock = $this->getMockForFileExists(); + Event::fake(); - $this->getFiredEvents([SuccessCreateMessage::class]); $this->expectException(ModelFactoryNotFoundedException::class); - $this->expectErrorMessage("Not found User factory for User model in 'database/factories/ModelFactory.php " - . "Please declare a factory for User model on 'database/factories/ModelFactory.php' path and run your command with option '--only-tests'."); + $this->expectExceptionMessage("Not found Post factory for Post model in 'database/factories/ModelFactory.php. " + . "Please declare a factory for Post model on 'database/factories/ModelFactory.php' " + . "path and run your command with option '--only-tests'."); $this->mockConfigurations(); $this->mockFilesystemForNonExistingRelatedModelFactory(); $this->mockFactoryGeneratorForMissingRelatedModelFactory(); - try { - app(FactoryGenerator::class) - ->setModel('Post') - ->setFields([ - 'integer-required' => ['author_id'], - 'string' => ['title'] - ]) - ->generate(); - } finally { - $mock->disable(); - } + app(FactoryGenerator::class) + ->setModel('Post') + ->setFields([ + 'integer-required' => ['author_id'], + 'string' => ['title'], + ]) + ->generate(); + + Event::assertDispatched(SuccessCreateMessage::class); } public function testRevertedModelFactoryNotExists() { $this->expectException(ModelFactoryNotFound::class); - $this->expectErrorMessage("Model factory for model comment not found. " + $this->expectExceptionMessage("Model factory for model comment not found. " . "Please create it and after thar you can run this command with flag '--only-tests'."); - $mock = $this->getMockForFileExists(); - $this->mockConfigurations(); - $this->mockViewsNamespace(); $this->mockGeneratorForMissingRevertedRelationModelFactory(); $this->mockFilesystemForMissingRevertedRelationModelFactory(); - try { - app(FactoryGenerator::class) - ->setRelations([ - 'hasOne' => ['comment'], - 'hasMany' => ['comment'], - 'belongsTo' => ['user'] - ]) - ->setModel('Post') - ->generate(); - } finally { - $mock->disable(); - } + app(FactoryGenerator::class) + ->setRelations([ + 'hasOne' => ['comment'], + 'hasMany' => ['comment'], + 'belongsTo' => ['user'] + ]) + ->setModel('Post') + ->generate(); } public function testAlreadyExistsFactory() { - $this->expectsEvents([SuccessCreateMessage::class]); + Event::fake(); $this->mockConfigurations(); $this->mockFactoryGeneratorForAlreadyExistsFactory(); - $mock = $this->getMockForFileExists(); + $this->mockForFileExists([ + 'database/factories/ModelFactory.php', + ]); - try { - app(FactoryGenerator::class) - ->setModel('Post') - ->generate(); - } finally { - $mock->disable(); - } + app(FactoryGenerator::class) + ->setModel('Post') + ->generate(); + + Event::assertDispatched(SuccessCreateMessage::class); } public function testCreateGenericFactory() { - $this->expectsEvents([SuccessCreateMessage::class]); + Event::fake(); $this->mockConfigurations(); - $this->mockViewsNamespace(); $this->mockFilesystemForGenericStyleCreation(); $this->mockFactoryGeneratorForGenericTypeCreation(); @@ -172,18 +171,19 @@ public function testCreateGenericFactory() $this->rollbackToDefaultBasePath(); - $this->assertGeneratedFileEquals('model_factory.php', '/database/factories/ModelFactory.php', true); + $this->assertGeneratedFileEquals('model_factory.php', '/database/factories/ModelFactory.php'); + + Event::assertDispatched(SuccessCreateMessage::class); } public function testProcessUnknownFieldType() { $this->mockConfigurations(); - $this->mockViewsNamespace(); $this->mockFilesystemForGenericStyleCreation(); $this->mockFactoryGeneratorForGenericTypeCreation(); $this->expectException(ViewException::class); - $this->expectErrorMessage("Cannot generate fake data for unsupported another_type field type. " + $this->expectExceptionMessage("Cannot generate fake data for unsupported another_type field type. " . "Supported custom field types are json"); app(FactoryGenerator::class) @@ -197,14 +197,14 @@ public function testProcessUnknownFieldType() ]) ->setModel('Post') ->generate(); + } public function testCreateClassStyleFactory() { - $this->expectsEvents([SuccessCreateMessage::class]); + Event::fake(); $this->mockConfigurationsForClassStyleFactory(); - $this->mockViewsNamespace(); $this->mockFilesystemForClassStyleFactoryCreation(); $this->mockFactoryGeneratorForClassTypeCreation(); @@ -224,6 +224,8 @@ public function testCreateClassStyleFactory() $this->rollbackToDefaultBasePath(); - $this->assertGeneratedFileEquals('post_factory.php', '/database/factories/PostFactory.php', true); + $this->assertGeneratedFileEquals('post_factory.php', '/database/factories/PostFactory.php'); + + Event::assertDispatched(SuccessCreateMessage::class); } } diff --git a/tests/NovaResourceGeneratorTest.php b/tests/NovaResourceGeneratorTest.php index 95be8b76..292b0c69 100644 --- a/tests/NovaResourceGeneratorTest.php +++ b/tests/NovaResourceGeneratorTest.php @@ -38,7 +38,7 @@ public function testCreateNovaResourceWithMissingModel() { $this->mockNovaServiceProviderExists(); - $this->assertExceptionThrowed( + $this->assertExceptionThrew( className: ClassNotExistsException::class, message: 'Cannot create Post Nova resource cause Post Model does not exists. ' . "Create a Post Model by himself or run command 'php artisan make:entity Post --only-model'" @@ -58,7 +58,7 @@ public function testCreateNovaTestAlreadyExists() $this->classExistsMethodCall(['nova', 'PostResource']), ]); - $this->assertExceptionThrowed( + $this->assertExceptionThrew( className: ClassAlreadyExistsException::class, message: 'Cannot create PostResource cause PostResource already exists. Remove PostResource.', ); diff --git a/tests/NovaTestGeneratorTest.php b/tests/NovaTestGeneratorTest.php index 3159b47e..6ef0ce52 100644 --- a/tests/NovaTestGeneratorTest.php +++ b/tests/NovaTestGeneratorTest.php @@ -23,7 +23,7 @@ public function testGenerateResourceNotExists() $this->classExistsMethodCall(['nova', 'Post'], false), ]); - $this->assertExceptionThrowed( + $this->assertExceptionThrew( className: ClassNotExistsException::class, message: 'Cannot create NovaPostTest cause Post Nova resource does not exist. Create Post Nova resource.', ); @@ -42,7 +42,7 @@ public function testGenerateNovaTestAlreadyExists() $this->classExistsMethodCall(['nova', 'NovaPostTest']) ]); - $this->assertExceptionThrowed( + $this->assertExceptionThrew( className: ClassAlreadyExistsException::class, message: "Cannot create NovaPostTest cause it's already exist. Remove NovaPostTest.", ); diff --git a/tests/Support/Factory/FactoryMockTrait.php b/tests/Support/Factory/FactoryMockTrait.php index 32e170d7..af009c6e 100644 --- a/tests/Support/Factory/FactoryMockTrait.php +++ b/tests/Support/Factory/FactoryMockTrait.php @@ -2,24 +2,25 @@ namespace RonasIT\Support\Tests\Support\Factory; +use Illuminate\Support\Arr; use org\bovigo\vfs\vfsStream; use ReflectionClass; use RonasIT\Support\Generators\FactoryGenerator; -use RonasIT\Support\Tests\Support\Shared\GeneratorMockTrait; -use RonasIT\Support\Traits\MockClassTrait; +use RonasIT\Support\Tests\Support\GeneratorMockTrait; +use RonasIT\Support\Traits\MockTrait; trait FactoryMockTrait { - use GeneratorMockTrait, MockClassTrait; + use GeneratorMockTrait, MockTrait; public function getFactoryGeneratorMockForMissingModel(): void { $this->mockClass(FactoryGenerator::class, [ [ - 'method' => 'classExists', + 'function' => 'classExists', 'arguments' => ['models', 'Post'], - 'result' => false - ] + 'result' => false, + ], ]); } @@ -27,14 +28,14 @@ public function getFactoryGeneratorMockForExistingFactory(): void { $this->mockClass(FactoryGenerator::class, [ [ - 'method' => 'classExists', + 'function' => 'classExists', 'arguments' => ['models', 'Post'], - 'result' => true + 'result' => true, ], [ - 'method' => 'classExists', + 'function' => 'classExists', 'arguments' => ['factory', 'PostFactory'], - 'result' => true + 'result' => true, ], ]); } @@ -43,15 +44,15 @@ public function mockGeneratorForMissingRevertedRelationModelFactory(): void { $this->mockClass(FactoryGenerator::class, [ [ - 'method' => 'checkExistRelatedModelsFactories', + 'function' => 'checkExistRelatedModelsFactories', 'arguments' => [], - 'result' => true + 'result' => true, ], [ - 'method' => 'allowedToCreateFactoryInSeparateClass', + 'function' => 'allowedToCreateFactoryInSeparateClass', 'arguments' => [], - 'result' => false - ] + 'result' => false, + ], ]); } @@ -59,15 +60,15 @@ public function mockFactoryGenerator(): void { $this->mockClass(FactoryGenerator::class, [ [ - 'method' => 'classExists', + 'function' => 'classExists', 'arguments' => ['models', 'Post'], - 'result' => false + 'result' => false, ], [ - 'method' => 'allowedToCreateFactoryInSeparateClass', + 'function' => 'allowedToCreateFactoryInSeparateClass', 'arguments' => [], - 'result' => false - ] + 'result' => false, + ], ]); } @@ -75,15 +76,15 @@ public function mockFactoryGeneratorForAlreadyExistsFactory(): void { $this->mockClass(FactoryGenerator::class, [ [ - 'method' => 'checkExistModelFactory', + 'function' => 'checkExistModelFactory', 'arguments' => [], - 'result' => 1 + 'result' => true, ], [ - 'method' => 'allowedToCreateFactoryInSeparateClass', + 'function' => 'allowedToCreateFactoryInSeparateClass', 'arguments' => [], - 'result' => false - ] + 'result' => false, + ], ]); } @@ -91,10 +92,10 @@ public function mockFactoryGeneratorForGenericTypeCreation(): void { $this->mockClass(FactoryGenerator::class, [ [ - 'method' => 'allowedToCreateFactoryInSeparateClass', + 'function' => 'allowedToCreateFactoryInSeparateClass', 'arguments' => [], - 'result' => false - ] + 'result' => false, + ], ]); } @@ -102,10 +103,10 @@ public function mockFactoryGeneratorForClassTypeCreation(): void { $this->mockClass(FactoryGenerator::class, [ [ - 'method' => 'allowedToCreateFactoryInSeparateClass', + 'function' => 'allowedToCreateFactoryInSeparateClass', 'arguments' => [], - 'result' => true - ] + 'result' => true, + ], ]); } @@ -113,21 +114,28 @@ public function mockFactoryGeneratorForMissingRelatedModelFactory(): void { $this->mockClass(FactoryGenerator::class, [ [ - 'method' => 'classExists', + 'function' => 'classExists', 'arguments' => ['models', 'Post'], - 'result' => true + 'result' => true, ], [ - 'method' => 'allowedToCreateFactoryInSeparateClass', + 'function' => 'allowedToCreateFactoryInSeparateClass', 'arguments' => [], - 'result' => false - ] + 'result' => false, + ], ]); } - public function getMockForFileExists(bool $result = true) + public function mockForFileExists(array $arguments, bool $result = true): void { - return $this->mockNativeFunction('\\RonasIT\\Support\\Generators', 'file_exists', $result); + $this->mockNativeFunction( + namespace: '\\RonasIT\\Support\\Generators', + callChain: Arr::map($arguments, fn ($argument) => [ + 'function' => 'file_exists', + 'arguments' => Arr::wrap($argument), + 'result' => $result, + ]) + ); } public function mockConfigurations(): void @@ -217,7 +225,7 @@ public function mockFilesystemForMissingRevertedRelationModelFactory(): void ], 'database' => [ 'factories' => [ - 'ModelFactory.php' => file_get_contents(getcwd() . '/tests/Support/Factory/ModelFactory.php'), + 'ModelFactory.php' => file_get_contents(getcwd().'/tests/Support/Factory/ModelFactory.php'), ] ] ]; @@ -230,7 +238,7 @@ public function mockFilesystemForGenericStyleCreation(): void $structure = [ 'app' => [ 'Models' => [ - 'Post.php' => file_get_contents(getcwd() . '/tests/Support/Factory/Post.php'), + 'Post.php' => file_get_contents(getcwd().'/tests/Support/Factory/Post.php'), 'User.php' => ' [ 'Models' => [ - 'Post.php' => file_get_contents(getcwd() . '/tests/Support/Factory/Post.php'), + 'Post.php' => file_get_contents(getcwd().'/tests/Support/Factory/Post.php'), 'User.php' => ' $password ?: $password = bcrypt('secret'), 'remember_token' => str_random(10), ]; -}); \ No newline at end of file +}); diff --git a/tests/Support/Factory/ModelWithRelations.php b/tests/Support/Factory/ModelWithRelations.php index 03e090be..3fb1e4e4 100644 --- a/tests/Support/Factory/ModelWithRelations.php +++ b/tests/Support/Factory/ModelWithRelations.php @@ -4,8 +4,8 @@ class ModelWithRelations { - public function user() + public function Post() { - return $this->belongsTo(User::class); + return $this->belongsTo(Post::class); } -} \ No newline at end of file +} diff --git a/tests/Support/Factory/Post.php b/tests/Support/Factory/Post.php index 599ec8ab..1d493a8c 100644 --- a/tests/Support/Factory/Post.php +++ b/tests/Support/Factory/Post.php @@ -8,4 +8,4 @@ public function user() { return $this->belongsTo(User::class); } -} \ No newline at end of file +} diff --git a/tests/TestCase.php b/tests/TestCase.php index d9f154c1..2b1743d7 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -115,7 +115,7 @@ protected function assertEventPushedChain(array $events): void } } - protected function assertExceptionThrowed(string $className, string $message): void + protected function assertExceptionThrew(string $className, string $message): void { $this->expectException($className); $this->expectExceptionMessage($message); diff --git a/tests/fixtures/FactoryGeneratorTest/model_factory.php b/tests/fixtures/FactoryGeneratorTest/model_factory.php index b1aa3d77..858c0d27 100644 --- a/tests/fixtures/FactoryGeneratorTest/model_factory.php +++ b/tests/fixtures/FactoryGeneratorTest/model_factory.php @@ -13,7 +13,7 @@ | */ -/** @var \Illuminate\Database\Eloquent\Factory $factory */ +/** @var \Illuminate\Database\Eloquent\Factory $factory */ $factory->define(App\Models\User::class, function (Faker\Generator $faker) { static $password; From 91e584b31cb146157a56d7eea3477e55242be3b2 Mon Sep 17 00:00:00 2001 From: Anton Zabolotnikov Date: Wed, 20 Nov 2024 13:23:37 +0500 Subject: [PATCH 05/20] chore: add factory tests --- tests/FactoryGeneratorTest.php | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/FactoryGeneratorTest.php b/tests/FactoryGeneratorTest.php index b236cecc..cb919a89 100644 --- a/tests/FactoryGeneratorTest.php +++ b/tests/FactoryGeneratorTest.php @@ -71,7 +71,6 @@ public function testCannotGetContentForGenericFactory() $this->mockForFileExists([ 'database/factories/ModelFactory.php', - 'vfs://root/app/Models', ]); $this->mockConfigurations(); From ea6944058f8a47dfbc3d481f9e04a71b7b6f091f Mon Sep 17 00:00:00 2001 From: Anton Zabolotnikov Date: Wed, 20 Nov 2024 13:47:33 +0500 Subject: [PATCH 06/20] chore: add factory tests --- src/Generators/FactoryGenerator.php | 39 ++++++++++++++--------------- 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/src/Generators/FactoryGenerator.php b/src/Generators/FactoryGenerator.php index b6100a2e..3f993bb8 100644 --- a/src/Generators/FactoryGenerator.php +++ b/src/Generators/FactoryGenerator.php @@ -40,17 +40,17 @@ protected function generateSeparateClass(): string { if (!$this->classExists('models', $this->model)) { $this->throwFailureException( - ClassNotExistsException::class, - "Cannot create {$this->model}Factory cause {$this->model} Model does not exists.", - "Create a {$this->model} Model by itself or run command 'php artisan make:entity {$this->model} --only-model'." + exceptionClass: ClassNotExistsException::class, + failureMessage: "Cannot create {$this->model}Factory cause {$this->model} Model does not exists.", + recommendedMessage: "Create a {$this->model} Model by itself or run command 'php artisan make:entity {$this->model} --only-model'." ); } if ($this->classExists('factory', "{$this->model}Factory")) { $this->throwFailureException( - ClassAlreadyExistsException::class, - "Cannot create {$this->model}Factory cause {$this->model}Factory already exists.", - "Remove {$this->model}Factory." + exceptionClass: ClassAlreadyExistsException::class, + failureMessage: "Cannot create {$this->model}Factory cause {$this->model}Factory already exists.", + recommendedMessage: "Remove {$this->model}Factory." ); } @@ -125,13 +125,13 @@ protected function checkExistRelatedModelsFactories(): bool foreach ($relatedModels as $relatedModel) { $relatedFactoryClass = "{$modelNamespace}\\$relatedModel::class"; - $existModelFactory = (strpos($modelFactoryContent, $relatedFactoryClass) !== false); + $existModelFactory = Str::contains($modelFactoryContent, $relatedFactoryClass); if (!$existModelFactory) { $this->throwFailureException( - ModelFactoryNotFoundedException::class, - "Not found {$relatedModel} factory for {$relatedModel} model in '{$this->paths['factory']}.", - "Please declare a factory for {$relatedModel} model on '{$this->paths['factory']}' " + exceptionClass: ModelFactoryNotFoundedException::class, + failureMessage: "Not found {$relatedModel} factory for {$relatedModel} model in '{$this->paths['factory']}.", + recommendedMessage: "Please declare a factory for {$relatedModel} model on '{$this->paths['factory']}' " . "path and run your command with option '--only-tests'." ); } @@ -173,9 +173,9 @@ protected function prepareRelatedFactories(): void if (!Str::contains($modelFactoryContent, $this->getModelClass($relation))) { $this->throwFailureException( - ModelFactoryNotFound::class, - "Model factory for model {$relation} not found.", - "Please create it and after thar you can run this command with flag '--only-tests'." + exceptionClass: ModelFactoryNotFound::class, + failureMessage: "Model factory for model {$relation} not found.", + recommendedMessage: "Please create it and after thar you can run this command with flag '--only-tests'." ); } @@ -224,7 +224,7 @@ protected function checkExistModelFactory(): bool $modelNamespace = $this->getOrCreateNamespace('models'); $factoryClass = "{$modelNamespace}\\$this->model::class"; - return (strpos($modelFactoryContent, $factoryClass) !== false); + return Str::contains($modelFactoryContent, $factoryClass); } protected function prepareFields(): array @@ -233,11 +233,9 @@ protected function prepareFields(): array foreach ($this->fields as $type => $fields) { foreach ($fields as $field) { - $explodedType = explode('-', $type); - $result[] = [ 'name' => $field, - 'type' => head($explodedType) + 'type' => Str::before($type, '-'), ]; } } @@ -275,9 +273,10 @@ protected function getModelClassContent($model): string if (!$this->classExists('models', $model)) { $this->throwFailureException( - ClassNotExistsException::class, - "Cannot get {$model} Model class content cause {$model} Model does not exists.", - "Create a {$model} Model by itself or run command 'php artisan make:entity {$model} --only-model'." + exceptionClass: ClassNotExistsException::class, + failureMessage: "Cannot get {$model} Model class content cause {$model} Model does not exists.", + recommendedMessage: "Create a {$model} Model by itself or run command " + . "'php artisan make:entity {$model} --only-model'." ); } From 35d51f7338f8ef1b9e11291c15a92400069767a1 Mon Sep 17 00:00:00 2001 From: Anton Zabolotnikov Date: Wed, 20 Nov 2024 13:56:16 +0500 Subject: [PATCH 07/20] chore: add factory tests --- tests/FactoryGeneratorTest.php | 30 +++++----------------- tests/Support/Factory/FactoryMockTrait.php | 14 +++++----- 2 files changed, 15 insertions(+), 29 deletions(-) diff --git a/tests/FactoryGeneratorTest.php b/tests/FactoryGeneratorTest.php index cb919a89..3c8ed32e 100644 --- a/tests/FactoryGeneratorTest.php +++ b/tests/FactoryGeneratorTest.php @@ -4,7 +4,6 @@ use Illuminate\Support\Facades\Event; use Illuminate\View\ViewException; -use org\bovigo\vfs\vfsStream; use RonasIT\Support\Events\SuccessCreateMessage; use RonasIT\Support\Exceptions\ClassAlreadyExistsException; use RonasIT\Support\Exceptions\ClassNotExistsException; @@ -17,17 +16,6 @@ class FactoryGeneratorTest extends TestCase { use FactoryMockTrait; - public function setUp(): void - { - parent::setUp(); - - vfsStream::setup(); - - $this->generatedFileBasePath = vfsStream::url('root'); - - $this->app->setBasePath($this->generatedFileBasePath); - } - public function testModelNotExists() { Event::fake(); @@ -69,9 +57,7 @@ public function testCannotGetContentForGenericFactory() $this->expectExceptionMessage("Cannot get Post Model class content cause Post Model does not exists. " . "Create a Post Model by itself or run command 'php artisan make:entity Post --only-model'."); - $this->mockForFileExists([ - 'database/factories/ModelFactory.php', - ]); + $this->mockForFileExists('database/factories/ModelFactory.php'); $this->mockConfigurations(); $this->mockFilesystem(); @@ -122,7 +108,7 @@ public function testRevertedModelFactoryNotExists() ->setRelations([ 'hasOne' => ['comment'], 'hasMany' => ['comment'], - 'belongsTo' => ['user'] + 'belongsTo' => ['user'], ]) ->setModel('Post') ->generate(); @@ -135,9 +121,7 @@ public function testAlreadyExistsFactory() $this->mockConfigurations(); $this->mockFactoryGeneratorForAlreadyExistsFactory(); - $this->mockForFileExists([ - 'database/factories/ModelFactory.php', - ]); + $this->mockForFileExists('database/factories/ModelFactory.php'); app(FactoryGenerator::class) ->setModel('Post') @@ -163,7 +147,7 @@ public function testCreateGenericFactory() ->setRelations([ 'hasOne' => ['User'], 'hasMany' => [], - 'belongsTo' => ['user'] + 'belongsTo' => ['user'], ]) ->setModel('Post') ->generate(); @@ -192,7 +176,7 @@ public function testProcessUnknownFieldType() ->setRelations([ 'hasOne' => [], 'hasMany' => [], - 'belongsTo' => [] + 'belongsTo' => [], ]) ->setModel('Post') ->generate(); @@ -214,9 +198,9 @@ public function testCreateClassStyleFactory() 'json' => ['json_text'], ]) ->setRelations([ - 'hasOne' => ['User'], + 'hasOne' => ['user'], 'hasMany' => [], - 'belongsTo' => ['user'] + 'belongsTo' => ['user'], ]) ->setModel('Post') ->generate(); diff --git a/tests/Support/Factory/FactoryMockTrait.php b/tests/Support/Factory/FactoryMockTrait.php index af009c6e..30d674d9 100644 --- a/tests/Support/Factory/FactoryMockTrait.php +++ b/tests/Support/Factory/FactoryMockTrait.php @@ -126,15 +126,17 @@ public function mockFactoryGeneratorForMissingRelatedModelFactory(): void ]); } - public function mockForFileExists(array $arguments, bool $result = true): void + public function mockForFileExists(string $filePath, bool $result = true): void { $this->mockNativeFunction( namespace: '\\RonasIT\\Support\\Generators', - callChain: Arr::map($arguments, fn ($argument) => [ - 'function' => 'file_exists', - 'arguments' => Arr::wrap($argument), - 'result' => $result, - ]) + callChain: [ + [ + 'function' => 'file_exists', + 'arguments' => Arr::wrap($filePath), + 'result' => $result, + ], + ], ); } From 67fd5fbc9db3200aa891f1468f7107e281989fbc Mon Sep 17 00:00:00 2001 From: Anton Zabolotnikov Date: Wed, 20 Nov 2024 13:59:08 +0500 Subject: [PATCH 08/20] chore: add factory tests --- tests/FactoryGeneratorTest.php | 4 ---- tests/TestCase.php | 13 ------------- 2 files changed, 17 deletions(-) diff --git a/tests/FactoryGeneratorTest.php b/tests/FactoryGeneratorTest.php index 3c8ed32e..97641741 100644 --- a/tests/FactoryGeneratorTest.php +++ b/tests/FactoryGeneratorTest.php @@ -152,8 +152,6 @@ public function testCreateGenericFactory() ->setModel('Post') ->generate(); - $this->rollbackToDefaultBasePath(); - $this->assertGeneratedFileEquals('model_factory.php', '/database/factories/ModelFactory.php'); Event::assertDispatched(SuccessCreateMessage::class); @@ -205,8 +203,6 @@ public function testCreateClassStyleFactory() ->setModel('Post') ->generate(); - $this->rollbackToDefaultBasePath(); - $this->assertGeneratedFileEquals('post_factory.php', '/database/factories/PostFactory.php'); Event::assertDispatched(SuccessCreateMessage::class); diff --git a/tests/TestCase.php b/tests/TestCase.php index 2b1743d7..2c2144ca 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -8,7 +8,6 @@ use Illuminate\Support\Facades\Event; use Illuminate\Support\Str; use Orchestra\Testbench\TestCase as BaseTestCase; -use phpmock\Mock; use org\bovigo\vfs\vfsStream; use RonasIT\Support\EntityGeneratorServiceProvider; use RonasIT\Support\Traits\FixturesTrait; @@ -43,18 +42,6 @@ public function getFixturePath(string $fixtureName): string return getcwd() . "/tests/fixtures/{$className}/{$fixtureName}"; } - public function tearDown(): void - { - parent::tearDown(); - - Mock::disableAll(); - } - - public function rollbackToDefaultBasePath(): void - { - $this->app->setBasePath(getcwd()); - } - public function mockConfigurations(): void { config([ From a9f3ca232322a1af788e714b5f5e29e615fcfeb7 Mon Sep 17 00:00:00 2001 From: Anton Zabolotnikov Date: Wed, 20 Nov 2024 14:04:40 +0500 Subject: [PATCH 09/20] chore: add factory tests --- stubs/factory.blade.php | 2 +- tests/fixtures/FactoryGeneratorTest/post_factory.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/stubs/factory.blade.php b/stubs/factory.blade.php index 2511cd69..bedba559 100644 --- a/stubs/factory.blade.php +++ b/stubs/factory.blade.php @@ -17,4 +17,4 @@ public function definition(): array @endforeach ]; } -} \ No newline at end of file +} diff --git a/tests/fixtures/FactoryGeneratorTest/post_factory.php b/tests/fixtures/FactoryGeneratorTest/post_factory.php index 9d5b91e4..0b23874f 100644 --- a/tests/fixtures/FactoryGeneratorTest/post_factory.php +++ b/tests/fixtures/FactoryGeneratorTest/post_factory.php @@ -20,4 +20,4 @@ public function definition(): array 'json_text' => [], ]; } -} \ No newline at end of file +} From 672aaeffef4561ae94268e189bead2ba6cb9d9a5 Mon Sep 17 00:00:00 2001 From: Anton Zabolotnikov Date: Wed, 20 Nov 2024 14:10:20 +0500 Subject: [PATCH 10/20] chore: add factory tests --- tests/FactoryGeneratorTest.php | 2 +- tests/Support/Factory/FactoryMockTrait.php | 52 +++++++++++----------- 2 files changed, 27 insertions(+), 27 deletions(-) diff --git a/tests/FactoryGeneratorTest.php b/tests/FactoryGeneratorTest.php index 97641741..edb644ae 100644 --- a/tests/FactoryGeneratorTest.php +++ b/tests/FactoryGeneratorTest.php @@ -101,7 +101,7 @@ public function testRevertedModelFactoryNotExists() . "Please create it and after thar you can run this command with flag '--only-tests'."); $this->mockConfigurations(); - $this->mockGeneratorForMissingRevertedRelationModelFactory(); + $this->getMockGeneratorForMissingRevertedRelationModelFactory(); $this->mockFilesystemForMissingRevertedRelationModelFactory(); app(FactoryGenerator::class) diff --git a/tests/Support/Factory/FactoryMockTrait.php b/tests/Support/Factory/FactoryMockTrait.php index 30d674d9..ea4fcccd 100644 --- a/tests/Support/Factory/FactoryMockTrait.php +++ b/tests/Support/Factory/FactoryMockTrait.php @@ -40,7 +40,7 @@ public function getFactoryGeneratorMockForExistingFactory(): void ]); } - public function mockGeneratorForMissingRevertedRelationModelFactory(): void + public function getMockGeneratorForMissingRevertedRelationModelFactory(): void { $this->mockClass(FactoryGenerator::class, [ [ @@ -149,7 +149,7 @@ public function mockConfigurations(): void 'entity-generator.paths' => [ 'models' => 'app/Models', 'factory' => 'database/factories/ModelFactory.php', - ] + ], ]); } @@ -162,7 +162,7 @@ public function mockConfigurationsForClassStyleFactory(): void 'entity-generator.paths' => [ 'models' => 'app/Models', 'factory' => 'database/factories', - ] + ], ]); } @@ -174,13 +174,13 @@ public function mockFilesystem(): void 'PostService.php' => ' [], - 'Models' => [] + 'Models' => [], ], 'database' => [ 'factories' => [ - 'ModelFactory.php' => ' ' [], 'Models' => [ 'Post.php' => file_get_contents($postModelFileName), - 'User.php' => ' ' [ 'factories' => [ 'ModelFactory.php' => ' [ 'Services' => [ - 'PostService.php' => ' ' [], 'Models' => [ 'Post.php' => ' ' ' [ 'factories' => [ - 'ModelFactory.php' => file_get_contents(getcwd().'/tests/Support/Factory/ModelFactory.php'), - ] - ] + 'ModelFactory.php' => file_get_contents(getcwd() . '/tests/Support/Factory/ModelFactory.php'), + ], + ], ]; vfsStream::create($structure); @@ -240,11 +240,11 @@ public function mockFilesystemForGenericStyleCreation(): void $structure = [ 'app' => [ 'Models' => [ - 'Post.php' => file_get_contents(getcwd().'/tests/Support/Factory/Post.php'), - 'User.php' => ' file_get_contents(getcwd() . '/tests/Support/Factory/Post.php'), + 'User.php' => ' [] + 'database' => [], ]; vfsStream::create($structure); @@ -255,15 +255,15 @@ public function mockFilesystemForClassStyleFactoryCreation(): void $structure = [ 'app' => [ 'Models' => [ - 'Post.php' => file_get_contents(getcwd().'/tests/Support/Factory/Post.php'), - 'User.php' => ' file_get_contents(getcwd() . '/tests/Support/Factory/Post.php'), + 'User.php' => ' [ - 'factories' => [] - ] + 'factories' => [], + ], ]; vfsStream::create($structure); } -} \ No newline at end of file +} From 04dfc78def851f2cb8835437f07f894974e79881 Mon Sep 17 00:00:00 2001 From: Anton Zabolotnikov Date: Wed, 20 Nov 2024 14:19:01 +0500 Subject: [PATCH 11/20] chore: add factory tests --- tests/Support/Factory/FactoryMockTrait.php | 4 ++-- tests/Support/Factory/ModelWithRelations.php | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/Support/Factory/FactoryMockTrait.php b/tests/Support/Factory/FactoryMockTrait.php index ea4fcccd..107ca4b6 100644 --- a/tests/Support/Factory/FactoryMockTrait.php +++ b/tests/Support/Factory/FactoryMockTrait.php @@ -171,7 +171,7 @@ public function mockFilesystem(): void $structure = [ 'app' => [ 'Services' => [ - 'PostService.php' => ' ' [], 'Models' => [], @@ -194,7 +194,7 @@ public function mockFilesystemForNonExistingRelatedModelFactory(): void $structure = [ 'app' => [ 'Services' => [ - 'PostService.php' => ' ' [], 'Models' => [ diff --git a/tests/Support/Factory/ModelWithRelations.php b/tests/Support/Factory/ModelWithRelations.php index 3fb1e4e4..30f2f7b4 100644 --- a/tests/Support/Factory/ModelWithRelations.php +++ b/tests/Support/Factory/ModelWithRelations.php @@ -4,7 +4,7 @@ class ModelWithRelations { - public function Post() + public function post() { return $this->belongsTo(Post::class); } From 0e1496b56a2f8ca2650f4bae56684ed079acf3eb Mon Sep 17 00:00:00 2001 From: roman Date: Wed, 27 Nov 2024 14:53:59 +0600 Subject: [PATCH 12/20] feat: remove useless code refs: https://github.com/RonasIT/laravel-entity-generator/issues/49 --- config/entity-generator.php | 2 - src/Generators/FactoryGenerator.php | 177 +-------------- tests/FactoryGeneratorTest.php | 135 +---------- tests/Support/Factory/FactoryMockTrait.php | 213 ------------------ .../FactoryGeneratorTest/model_factory.php | 45 ---- 5 files changed, 12 insertions(+), 560 deletions(-) delete mode 100644 tests/fixtures/FactoryGeneratorTest/model_factory.php diff --git a/config/entity-generator.php b/config/entity-generator.php index bff879b1..8919cd20 100644 --- a/config/entity-generator.php +++ b/config/entity-generator.php @@ -32,8 +32,6 @@ 'routes' => 'entity-generator::routes', 'use_routes' => 'entity-generator::use_routes', 'factory' => 'entity-generator::factory', - 'legacy_factory' => 'entity-generator::legacy_factory', - 'legacy_empty_factory' => 'entity-generator::legacy_empty_factory', 'seeder' => 'entity-generator::seeder', 'legacy_seeder' => 'entity-generator::legacy_seeder', 'database_empty_seeder' => 'entity-generator::database_empty_seeder', diff --git a/src/Generators/FactoryGenerator.php b/src/Generators/FactoryGenerator.php index 3f993bb8..6e0aa0bd 100644 --- a/src/Generators/FactoryGenerator.php +++ b/src/Generators/FactoryGenerator.php @@ -7,9 +7,7 @@ use Illuminate\Support\Str; use InvalidArgumentException; use RonasIT\Support\Exceptions\FakerMethodNotFound; -use RonasIT\Support\Exceptions\ModelFactoryNotFound; use RonasIT\Support\Exceptions\ClassNotExistsException; -use RonasIT\Support\Exceptions\ModelFactoryNotFoundedException; use RonasIT\Support\Exceptions\ClassAlreadyExistsException; use RonasIT\Support\Events\SuccessCreateMessage; @@ -28,21 +26,12 @@ class FactoryGenerator extends EntityGenerator ]; public function generate(): void - { - $createMessage = ($this->allowedToCreateFactoryInSeparateClass()) - ? $this->generateSeparateClass() - : $this->generateToGenericClass(); - - event(new SuccessCreateMessage($createMessage)); - } - - protected function generateSeparateClass(): string { if (!$this->classExists('models', $this->model)) { $this->throwFailureException( exceptionClass: ClassNotExistsException::class, failureMessage: "Cannot create {$this->model}Factory cause {$this->model} Model does not exists.", - recommendedMessage: "Create a {$this->model} Model by itself or run command 'php artisan make:entity {$this->model} --only-model'." + recommendedMessage: "Create a {$this->model} Model by itself or run command 'php artisan make:entity {$this->model} --only-model'.", ); } @@ -50,94 +39,19 @@ protected function generateSeparateClass(): string $this->throwFailureException( exceptionClass: ClassAlreadyExistsException::class, failureMessage: "Cannot create {$this->model}Factory cause {$this->model}Factory already exists.", - recommendedMessage: "Remove {$this->model}Factory." + recommendedMessage: "Remove {$this->model}Factory.", ); } $factoryContent = $this->getStub('factory', [ 'namespace' => $this->getOrCreateNamespace('factory'), 'entity' => $this->model, - 'fields' => $this->prepareFields() + 'fields' => $this->prepareFields(), ]); $this->saveClass('factory', "{$this->model}Factory", $factoryContent); - return "Created a new Factory: {$this->model}Factory"; - } - - protected function generateToGenericClass(): string - { - if (!file_exists($this->paths['factory'])) { - $this->prepareEmptyFactory(); - } - - if (!$this->checkExistModelFactory() && $this->checkExistRelatedModelsFactories()) { - $stubPath = config("entity-generator.stubs.legacy_factory"); - - $content = view($stubPath)->with([ - 'entity' => $this->model, - 'fields' => $this->prepareFields(), - 'modelsNamespace' => $this->getOrCreateNamespace('models') - ])->render(); - - $content = "\n\n" . $content; - - $createMessage = "Created a new Test factory for {$this->model} model in '{$this->paths['factory']}'"; - - file_put_contents(base_path($this->paths['factory']), $content, FILE_APPEND); - - $this->prepareRelatedFactories(); - } else { - $createMessage = "Factory for {$this->model} model has already created, so new factory not necessary create."; - } - - return $createMessage; - } - - protected function allowedToCreateFactoryInSeparateClass(): bool - { - return version_compare(app()->version(), '8', '>='); - } - - protected function prepareEmptyFactory(): void - { - $stubPath = config('entity-generator.stubs.legacy_empty_factory'); - $content = " $this->getOrCreateNamespace('models') - ])->render(); - - list($basePath, $databaseFactoryDir) = extract_last_part(config('entity-generator.paths.factory'), '/'); - - $databaseFactoryDir = base_path($databaseFactoryDir); - - if (!is_dir($databaseFactoryDir)) { - mkdir($databaseFactoryDir); - } - - file_put_contents(base_path($this->paths['factory']), $content); - } - - protected function checkExistRelatedModelsFactories(): bool - { - $modelFactoryContent = file_get_contents(base_path($this->paths['factory'])); - $relatedModels = $this->getRelatedModels($this->model); - $modelNamespace = $this->getOrCreateNamespace('models'); - - foreach ($relatedModels as $relatedModel) { - $relatedFactoryClass = "{$modelNamespace}\\$relatedModel::class"; - $existModelFactory = Str::contains($modelFactoryContent, $relatedFactoryClass); - - if (!$existModelFactory) { - $this->throwFailureException( - exceptionClass: ModelFactoryNotFoundedException::class, - failureMessage: "Not found {$relatedModel} factory for {$relatedModel} model in '{$this->paths['factory']}.", - recommendedMessage: "Please declare a factory for {$relatedModel} model on '{$this->paths['factory']}' " - . "path and run your command with option '--only-tests'." - ); - } - } - - return true; + event(new SuccessCreateMessage("Created a new Factory: {$this->model}Factory")); } protected static function getFakerMethod($field): string @@ -161,40 +75,6 @@ protected static function getCustomMethod($field): string throw new FakerMethodNotFound($message); } - protected function prepareRelatedFactories(): void - { - $relations = array_merge( - $this->relations['hasOne'], - $this->relations['hasMany'], - ); - - foreach ($relations as $relation) { - $modelFactoryContent = file_get_contents(base_path($this->paths['factory'])); - - if (!Str::contains($modelFactoryContent, $this->getModelClass($relation))) { - $this->throwFailureException( - exceptionClass: ModelFactoryNotFound::class, - failureMessage: "Model factory for model {$relation} not found.", - recommendedMessage: "Please create it and after thar you can run this command with flag '--only-tests'." - ); - } - - $matches = []; - - preg_match($this->getFactoryPattern($relation), $modelFactoryContent, $matches); - - foreach ($matches as $match) { - $field = Str::snake($this->model) . '_id'; - - $newField = "\n \"{$field}\" => 1,"; - - $modelFactoryContent = str_replace($match, $match . $newField, $modelFactoryContent); - } - - file_put_contents(base_path($this->paths['factory']), $modelFactoryContent); - } - } - public static function getFactoryFieldsContent($field): string { /** @var Faker $faker */ @@ -218,15 +98,6 @@ public static function getFactoryFieldsContent($field): string return self::getFakerMethod($field); } - protected function checkExistModelFactory(): bool - { - $modelFactoryContent = file_get_contents(base_path($this->paths['factory'])); - $modelNamespace = $this->getOrCreateNamespace('models'); - $factoryClass = "{$modelNamespace}\\$this->model::class"; - - return Str::contains($modelFactoryContent, $factoryClass); - } - protected function prepareFields(): array { $result = []; @@ -242,44 +113,4 @@ protected function prepareFields(): array return $result; } - - protected function getFactoryPattern($model): string - { - $modelNamespace = "App\\\\Models\\\\" . $model; - $return = "return \\["; - - return "/{$modelNamespace}.*{$return}/sU"; - } - - protected function getModelClass($model): string - { - $modelNamespace = $this->getOrCreateNamespace('models'); - - return "{$modelNamespace}\\{$model}"; - } - - protected function getRelatedModels($model) - { - $content = $this->getModelClassContent($model); - - preg_match_all('/(?<=belongsTo\().*(?=::class)/', $content, $matches); - - return head($matches); - } - - protected function getModelClassContent($model): string - { - $path = base_path("{$this->paths['models']}/{$model}.php"); - - if (!$this->classExists('models', $model)) { - $this->throwFailureException( - exceptionClass: ClassNotExistsException::class, - failureMessage: "Cannot get {$model} Model class content cause {$model} Model does not exists.", - recommendedMessage: "Create a {$model} Model by itself or run command " - . "'php artisan make:entity {$model} --only-model'." - ); - } - - return file_get_contents($path); - } } diff --git a/tests/FactoryGeneratorTest.php b/tests/FactoryGeneratorTest.php index edb644ae..90ad5994 100644 --- a/tests/FactoryGeneratorTest.php +++ b/tests/FactoryGeneratorTest.php @@ -7,8 +7,6 @@ use RonasIT\Support\Events\SuccessCreateMessage; use RonasIT\Support\Exceptions\ClassAlreadyExistsException; use RonasIT\Support\Exceptions\ClassNotExistsException; -use RonasIT\Support\Exceptions\ModelFactoryNotFound; -use RonasIT\Support\Exceptions\ModelFactoryNotFoundedException; use RonasIT\Support\Generators\FactoryGenerator; use RonasIT\Support\Tests\Support\Factory\FactoryMockTrait; @@ -18,25 +16,17 @@ class FactoryGeneratorTest extends TestCase public function testModelNotExists() { - Event::fake(); - $this->expectException(ClassNotExistsException::class); $this->expectExceptionMessage("Cannot create PostFactory cause Post Model does not exists. " . "Create a Post Model by itself or run command 'php artisan make:entity Post --only-model'."); - $this->getFactoryGeneratorMockForMissingModel(); - app(FactoryGenerator::class) ->setModel('Post') ->generate(); - - Event::assertDispatched(SuccessCreateMessage::class); } public function testFactoryClassExists() { - Event::fake(); - $this->expectException(ClassAlreadyExistsException::class); $this->expectExceptionMessage("Cannot create PostFactory cause PostFactory already exists. Remove PostFactory."); @@ -45,123 +35,12 @@ public function testFactoryClassExists() app(FactoryGenerator::class) ->setModel('Post') ->generate(); - - Event::assertDispatched(SuccessCreateMessage::class); - } - - public function testCannotGetContentForGenericFactory() - { - Event::fake(); - - $this->expectException(ClassNotExistsException::class); - $this->expectExceptionMessage("Cannot get Post Model class content cause Post Model does not exists. " - . "Create a Post Model by itself or run command 'php artisan make:entity Post --only-model'."); - - $this->mockForFileExists('database/factories/ModelFactory.php'); - - $this->mockConfigurations(); - $this->mockFilesystem(); - $this->mockFactoryGenerator(); - - app(FactoryGenerator::class) - ->setModel('Post') - ->generate(); - - Event::assertDispatched(SuccessCreateMessage::class); - } - - public function testRelatedModelWithoutFactory() - { - Event::fake(); - - $this->expectException(ModelFactoryNotFoundedException::class); - $this->expectExceptionMessage("Not found Post factory for Post model in 'database/factories/ModelFactory.php. " - . "Please declare a factory for Post model on 'database/factories/ModelFactory.php' " - . "path and run your command with option '--only-tests'."); - - $this->mockConfigurations(); - $this->mockFilesystemForNonExistingRelatedModelFactory(); - $this->mockFactoryGeneratorForMissingRelatedModelFactory(); - - app(FactoryGenerator::class) - ->setModel('Post') - ->setFields([ - 'integer-required' => ['author_id'], - 'string' => ['title'], - ]) - ->generate(); - - Event::assertDispatched(SuccessCreateMessage::class); - } - - public function testRevertedModelFactoryNotExists() - { - $this->expectException(ModelFactoryNotFound::class); - $this->expectExceptionMessage("Model factory for model comment not found. " - . "Please create it and after thar you can run this command with flag '--only-tests'."); - - $this->mockConfigurations(); - $this->getMockGeneratorForMissingRevertedRelationModelFactory(); - $this->mockFilesystemForMissingRevertedRelationModelFactory(); - - app(FactoryGenerator::class) - ->setRelations([ - 'hasOne' => ['comment'], - 'hasMany' => ['comment'], - 'belongsTo' => ['user'], - ]) - ->setModel('Post') - ->generate(); - } - - public function testAlreadyExistsFactory() - { - Event::fake(); - - $this->mockConfigurations(); - $this->mockFactoryGeneratorForAlreadyExistsFactory(); - - $this->mockForFileExists('database/factories/ModelFactory.php'); - - app(FactoryGenerator::class) - ->setModel('Post') - ->generate(); - - Event::assertDispatched(SuccessCreateMessage::class); - } - - public function testCreateGenericFactory() - { - Event::fake(); - - $this->mockConfigurations(); - $this->mockFilesystemForGenericStyleCreation(); - $this->mockFactoryGeneratorForGenericTypeCreation(); - - app(FactoryGenerator::class) - ->setFields([ - 'integer-required' => ['author_id'], - 'string' => ['title', 'iban', 'something'], - 'json' => ['json_text'], - ]) - ->setRelations([ - 'hasOne' => ['User'], - 'hasMany' => [], - 'belongsTo' => ['user'], - ]) - ->setModel('Post') - ->generate(); - - $this->assertGeneratedFileEquals('model_factory.php', '/database/factories/ModelFactory.php'); - - Event::assertDispatched(SuccessCreateMessage::class); } public function testProcessUnknownFieldType() { $this->mockConfigurations(); - $this->mockFilesystemForGenericStyleCreation(); - $this->mockFactoryGeneratorForGenericTypeCreation(); + $this->mockFilesystem(); $this->expectException(ViewException::class); $this->expectExceptionMessage("Cannot generate fake data for unsupported another_type field type. " @@ -181,13 +60,12 @@ public function testProcessUnknownFieldType() } - public function testCreateClassStyleFactory() + public function testCreateSuccess() { Event::fake(); - $this->mockConfigurationsForClassStyleFactory(); - $this->mockFilesystemForClassStyleFactoryCreation(); - $this->mockFactoryGeneratorForClassTypeCreation(); + $this->mockConfigurations(); + $this->mockFilesystem(); app(FactoryGenerator::class) ->setFields([ @@ -205,6 +83,9 @@ public function testCreateClassStyleFactory() $this->assertGeneratedFileEquals('post_factory.php', '/database/factories/PostFactory.php'); - Event::assertDispatched(SuccessCreateMessage::class); + $this->assertEventPushed( + className: SuccessCreateMessage::class, + message: 'Created a new Factory: PostFactory', + ); } } diff --git a/tests/Support/Factory/FactoryMockTrait.php b/tests/Support/Factory/FactoryMockTrait.php index 107ca4b6..e6d498ca 100644 --- a/tests/Support/Factory/FactoryMockTrait.php +++ b/tests/Support/Factory/FactoryMockTrait.php @@ -2,9 +2,7 @@ namespace RonasIT\Support\Tests\Support\Factory; -use Illuminate\Support\Arr; use org\bovigo\vfs\vfsStream; -use ReflectionClass; use RonasIT\Support\Generators\FactoryGenerator; use RonasIT\Support\Tests\Support\GeneratorMockTrait; use RonasIT\Support\Traits\MockTrait; @@ -13,17 +11,6 @@ trait FactoryMockTrait { use GeneratorMockTrait, MockTrait; - public function getFactoryGeneratorMockForMissingModel(): void - { - $this->mockClass(FactoryGenerator::class, [ - [ - 'function' => 'classExists', - 'arguments' => ['models', 'Post'], - 'result' => false, - ], - ]); - } - public function getFactoryGeneratorMockForExistingFactory(): void { $this->mockClass(FactoryGenerator::class, [ @@ -40,125 +27,9 @@ public function getFactoryGeneratorMockForExistingFactory(): void ]); } - public function getMockGeneratorForMissingRevertedRelationModelFactory(): void - { - $this->mockClass(FactoryGenerator::class, [ - [ - 'function' => 'checkExistRelatedModelsFactories', - 'arguments' => [], - 'result' => true, - ], - [ - 'function' => 'allowedToCreateFactoryInSeparateClass', - 'arguments' => [], - 'result' => false, - ], - ]); - } - - public function mockFactoryGenerator(): void - { - $this->mockClass(FactoryGenerator::class, [ - [ - 'function' => 'classExists', - 'arguments' => ['models', 'Post'], - 'result' => false, - ], - [ - 'function' => 'allowedToCreateFactoryInSeparateClass', - 'arguments' => [], - 'result' => false, - ], - ]); - } - - public function mockFactoryGeneratorForAlreadyExistsFactory(): void - { - $this->mockClass(FactoryGenerator::class, [ - [ - 'function' => 'checkExistModelFactory', - 'arguments' => [], - 'result' => true, - ], - [ - 'function' => 'allowedToCreateFactoryInSeparateClass', - 'arguments' => [], - 'result' => false, - ], - ]); - } - - public function mockFactoryGeneratorForGenericTypeCreation(): void - { - $this->mockClass(FactoryGenerator::class, [ - [ - 'function' => 'allowedToCreateFactoryInSeparateClass', - 'arguments' => [], - 'result' => false, - ], - ]); - } - - public function mockFactoryGeneratorForClassTypeCreation(): void - { - $this->mockClass(FactoryGenerator::class, [ - [ - 'function' => 'allowedToCreateFactoryInSeparateClass', - 'arguments' => [], - 'result' => true, - ], - ]); - } - - public function mockFactoryGeneratorForMissingRelatedModelFactory(): void - { - $this->mockClass(FactoryGenerator::class, [ - [ - 'function' => 'classExists', - 'arguments' => ['models', 'Post'], - 'result' => true, - ], - [ - 'function' => 'allowedToCreateFactoryInSeparateClass', - 'arguments' => [], - 'result' => false, - ], - ]); - } - - public function mockForFileExists(string $filePath, bool $result = true): void - { - $this->mockNativeFunction( - namespace: '\\RonasIT\\Support\\Generators', - callChain: [ - [ - 'function' => 'file_exists', - 'arguments' => Arr::wrap($filePath), - 'result' => $result, - ], - ], - ); - } - public function mockConfigurations(): void { config([ - 'entity-generator.stubs.factory' => 'entity-generator::factory', - 'entity-generator.stubs.legacy_factory' => 'entity-generator::legacy_factory', - 'entity-generator.stubs.legacy_empty_factory' => 'entity-generator::legacy_empty_factory', - 'entity-generator.paths' => [ - 'models' => 'app/Models', - 'factory' => 'database/factories/ModelFactory.php', - ], - ]); - } - - public function mockConfigurationsForClassStyleFactory(): void - { - config([ - 'entity-generator.stubs.factory' => 'entity-generator::factory', - 'entity-generator.stubs.legacy_factory' => 'entity-generator::legacy_factory', - 'entity-generator.stubs.legacy_empty_factory' => 'entity-generator::legacy_empty_factory', 'entity-generator.paths' => [ 'models' => 'app/Models', 'factory' => 'database/factories', @@ -167,90 +38,6 @@ public function mockConfigurationsForClassStyleFactory(): void } public function mockFilesystem(): void - { - $structure = [ - 'app' => [ - 'Services' => [ - 'PostService.php' => ' [], - 'Models' => [], - ], - 'database' => [ - 'factories' => [ - 'ModelFactory.php' => 'getFileName(); - - $structure = [ - 'app' => [ - 'Services' => [ - 'PostService.php' => ' [], - 'Models' => [ - 'Post.php' => file_get_contents($postModelFileName), - 'User.php' => ' [ - 'factories' => [ - 'ModelFactory.php' => ' [ - 'Services' => [ - 'PostService.php' => ' [], - 'Models' => [ - 'Post.php' => ' ' [ - 'factories' => [ - 'ModelFactory.php' => file_get_contents(getcwd() . '/tests/Support/Factory/ModelFactory.php'), - ], - ], - ]; - - vfsStream::create($structure); - } - - public function mockFilesystemForGenericStyleCreation(): void - { - $structure = [ - 'app' => [ - 'Models' => [ - 'Post.php' => file_get_contents(getcwd() . '/tests/Support/Factory/Post.php'), - 'User.php' => ' [], - ]; - - vfsStream::create($structure); - } - - public function mockFilesystemForClassStyleFactoryCreation(): void { $structure = [ 'app' => [ diff --git a/tests/fixtures/FactoryGeneratorTest/model_factory.php b/tests/fixtures/FactoryGeneratorTest/model_factory.php deleted file mode 100644 index 858c0d27..00000000 --- a/tests/fixtures/FactoryGeneratorTest/model_factory.php +++ /dev/null @@ -1,45 +0,0 @@ -define(App\Models\User::class, function (Faker\Generator $faker) { - static $password; - - return [ - "post_id" => 1, - 'name' => $faker->name, - 'email' => $faker->unique()->safeEmail, - 'password' => $password ?: $password = bcrypt('secret'), - 'remember_token' => Str::random(10), - ]; -}); - -$factory->define(App\Models\Role::class, function () { - return [ - 'name' => 'user' - ]; -}); - - -$factory->define(App\Models\Post::class, function (Faker\Generator $faker) { - return [ - 'author_id' => 1, - 'user_id' => 1, - 'title' => $faker->title, - 'iban' => $faker->iban, - 'something' => $faker->word, - 'json_text' => [], - ]; -}); \ No newline at end of file From 7aa73ba6266ff4bb2d24d752dd6180041b69c77f Mon Sep 17 00:00:00 2001 From: roman Date: Wed, 27 Nov 2024 15:01:51 +0600 Subject: [PATCH 13/20] feat: remove useless code refs: https://github.com/RonasIT/laravel-entity-generator/issues/49 --- tests/FactoryGeneratorTest.php | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/tests/FactoryGeneratorTest.php b/tests/FactoryGeneratorTest.php index 90ad5994..9c2011cb 100644 --- a/tests/FactoryGeneratorTest.php +++ b/tests/FactoryGeneratorTest.php @@ -16,25 +16,37 @@ class FactoryGeneratorTest extends TestCase public function testModelNotExists() { - $this->expectException(ClassNotExistsException::class); - $this->expectExceptionMessage("Cannot create PostFactory cause Post Model does not exists. " - . "Create a Post Model by itself or run command 'php artisan make:entity Post --only-model'."); + Event::fake(); + + $this->assertExceptionThrew( + className: ClassNotExistsException::class, + message: "Cannot create PostFactory cause Post Model does not exists. " + . "Create a Post Model by itself or run command 'php artisan make:entity Post --only-model'." + ); app(FactoryGenerator::class) ->setModel('Post') ->generate(); + + Event::assertNothingDispatched(); } public function testFactoryClassExists() { - $this->expectException(ClassAlreadyExistsException::class); - $this->expectExceptionMessage("Cannot create PostFactory cause PostFactory already exists. Remove PostFactory."); + Event::fake(); + + $this->assertExceptionThrew( + className: ClassAlreadyExistsException::class, + message: "Cannot create PostFactory cause PostFactory already exists. Remove PostFactory.", + ); $this->getFactoryGeneratorMockForExistingFactory(); app(FactoryGenerator::class) ->setModel('Post') ->generate(); + + Event::assertNothingDispatched(); } public function testProcessUnknownFieldType() From bbce08b9c7972b1b36ac6490d96f6f2020fa8b37 Mon Sep 17 00:00:00 2001 From: roman Date: Wed, 27 Nov 2024 16:05:53 +0600 Subject: [PATCH 14/20] refactor: remove useless classes refs: https://github.com/RonasIT/laravel-entity-generator/issues/49 --- tests/Support/Factory/ModelFactory.php | 15 --------------- tests/Support/Factory/ModelWithRelations.php | 11 ----------- tests/Support/Factory/Post.php | 4 ---- 3 files changed, 30 deletions(-) delete mode 100644 tests/Support/Factory/ModelFactory.php delete mode 100644 tests/Support/Factory/ModelWithRelations.php diff --git a/tests/Support/Factory/ModelFactory.php b/tests/Support/Factory/ModelFactory.php deleted file mode 100644 index 69417bd4..00000000 --- a/tests/Support/Factory/ModelFactory.php +++ /dev/null @@ -1,15 +0,0 @@ -define(App\Models\User::class, function (Faker\Generator $faker) { - static $password; - - return [ - 'name' => $faker->name, - 'email' => $faker->unique()->safeEmail, - 'password' => $password ?: $password = bcrypt('secret'), - 'remember_token' => str_random(10), - ]; -}); diff --git a/tests/Support/Factory/ModelWithRelations.php b/tests/Support/Factory/ModelWithRelations.php deleted file mode 100644 index 30f2f7b4..00000000 --- a/tests/Support/Factory/ModelWithRelations.php +++ /dev/null @@ -1,11 +0,0 @@ -belongsTo(Post::class); - } -} diff --git a/tests/Support/Factory/Post.php b/tests/Support/Factory/Post.php index 1d493a8c..162b17d8 100644 --- a/tests/Support/Factory/Post.php +++ b/tests/Support/Factory/Post.php @@ -4,8 +4,4 @@ class Post { - public function user() - { - return $this->belongsTo(User::class); - } } From 0718d41b9e83cd7e6fd75c88909bfeb255b5b9f7 Mon Sep 17 00:00:00 2001 From: roman Date: Thu, 28 Nov 2024 11:49:47 +0600 Subject: [PATCH 15/20] refactor: code refs: https://github.com/RonasIT/laravel-entity-generator/issues/49 --- ...d.php => FakerMethodNotFoundException.php} | 2 +- src/Generators/FactoryGenerator.php | 4 ++-- tests/FactoryGeneratorTest.php | 24 ++++++++++++------- tests/Support/Factory/FactoryMockTrait.php | 19 ++++----------- tests/Support/Factory/Post.php | 7 ------ 5 files changed, 22 insertions(+), 34 deletions(-) rename src/Exceptions/{FakerMethodNotFound.php => FakerMethodNotFoundException.php} (55%) delete mode 100644 tests/Support/Factory/Post.php diff --git a/src/Exceptions/FakerMethodNotFound.php b/src/Exceptions/FakerMethodNotFoundException.php similarity index 55% rename from src/Exceptions/FakerMethodNotFound.php rename to src/Exceptions/FakerMethodNotFoundException.php index 3c069773..c652e8a3 100644 --- a/src/Exceptions/FakerMethodNotFound.php +++ b/src/Exceptions/FakerMethodNotFoundException.php @@ -4,6 +4,6 @@ use Exception; -class FakerMethodNotFound extends Exception +class FakerMethodNotFoundException extends Exception { } diff --git a/src/Generators/FactoryGenerator.php b/src/Generators/FactoryGenerator.php index 6e0aa0bd..fd747a7a 100644 --- a/src/Generators/FactoryGenerator.php +++ b/src/Generators/FactoryGenerator.php @@ -6,7 +6,7 @@ use Illuminate\Support\Arr; use Illuminate\Support\Str; use InvalidArgumentException; -use RonasIT\Support\Exceptions\FakerMethodNotFound; +use RonasIT\Support\Exceptions\FakerMethodNotFoundException; use RonasIT\Support\Exceptions\ClassNotExistsException; use RonasIT\Support\Exceptions\ClassAlreadyExistsException; use RonasIT\Support\Events\SuccessCreateMessage; @@ -72,7 +72,7 @@ protected static function getCustomMethod($field): string $message = "Cannot generate fake data for unsupported {$field['type']} field type. " . "Supported custom field types are " . implode(', ', array_keys(self::CUSTOM_METHODS)); - throw new FakerMethodNotFound($message); + throw new FakerMethodNotFoundException($message); } public static function getFactoryFieldsContent($field): string diff --git a/tests/FactoryGeneratorTest.php b/tests/FactoryGeneratorTest.php index 9c2011cb..8976ef98 100644 --- a/tests/FactoryGeneratorTest.php +++ b/tests/FactoryGeneratorTest.php @@ -14,10 +14,15 @@ class FactoryGeneratorTest extends TestCase { use FactoryMockTrait; - public function testModelNotExists() + public function setUp(): void { + parent::setUp(); + Event::fake(); + } + public function testModelNotExists() + { $this->assertExceptionThrew( className: ClassNotExistsException::class, message: "Cannot create PostFactory cause Post Model does not exists. " @@ -33,14 +38,15 @@ className: ClassNotExistsException::class, public function testFactoryClassExists() { - Event::fake(); - $this->assertExceptionThrew( className: ClassAlreadyExistsException::class, message: "Cannot create PostFactory cause PostFactory already exists. Remove PostFactory.", ); - $this->getFactoryGeneratorMockForExistingFactory(); + $this->mockFactoryGenerator( + $this->classExistsMethodCall(['models', 'Post']), + $this->classExistsMethodCall(['factory', 'PostFactory']), + ); app(FactoryGenerator::class) ->setModel('Post') @@ -54,9 +60,11 @@ public function testProcessUnknownFieldType() $this->mockConfigurations(); $this->mockFilesystem(); - $this->expectException(ViewException::class); - $this->expectExceptionMessage("Cannot generate fake data for unsupported another_type field type. " - . "Supported custom field types are json"); + $this->assertExceptionThrew( + className: ViewException::class, + message: "Cannot generate fake data for unsupported another_type field type. " + . "Supported custom field types are json", + ); app(FactoryGenerator::class) ->setFields([ @@ -74,8 +82,6 @@ public function testProcessUnknownFieldType() public function testCreateSuccess() { - Event::fake(); - $this->mockConfigurations(); $this->mockFilesystem(); diff --git a/tests/Support/Factory/FactoryMockTrait.php b/tests/Support/Factory/FactoryMockTrait.php index e6d498ca..e9c08a61 100644 --- a/tests/Support/Factory/FactoryMockTrait.php +++ b/tests/Support/Factory/FactoryMockTrait.php @@ -11,20 +11,9 @@ trait FactoryMockTrait { use GeneratorMockTrait, MockTrait; - public function getFactoryGeneratorMockForExistingFactory(): void + public function mockFactoryGenerator(...$functionCalls): void { - $this->mockClass(FactoryGenerator::class, [ - [ - 'function' => 'classExists', - 'arguments' => ['models', 'Post'], - 'result' => true, - ], - [ - 'function' => 'classExists', - 'arguments' => ['factory', 'PostFactory'], - 'result' => true, - ], - ]); + $this->mockClass(FactoryGenerator::class, $functionCalls); } public function mockConfigurations(): void @@ -42,8 +31,8 @@ public function mockFilesystem(): void $structure = [ 'app' => [ 'Models' => [ - 'Post.php' => file_get_contents(getcwd() . '/tests/Support/Factory/Post.php'), - 'User.php' => ' $this->mockPhpFileContent(), + 'User.php' => $this->mockPhpFileContent(), ], ], 'database' => [ diff --git a/tests/Support/Factory/Post.php b/tests/Support/Factory/Post.php deleted file mode 100644 index 162b17d8..00000000 --- a/tests/Support/Factory/Post.php +++ /dev/null @@ -1,7 +0,0 @@ - Date: Thu, 28 Nov 2024 12:07:20 +0600 Subject: [PATCH 16/20] refactor: code refs: https://github.com/RonasIT/laravel-entity-generator/issues/49 --- tests/ControllerGeneratorTest.php | 4 ++-- tests/FactoryGeneratorTest.php | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/ControllerGeneratorTest.php b/tests/ControllerGeneratorTest.php index fa5f257e..6b887ad1 100644 --- a/tests/ControllerGeneratorTest.php +++ b/tests/ControllerGeneratorTest.php @@ -24,7 +24,7 @@ public function setUp(): void public function testControllerAlreadyExists() { $this->mockClass(ControllerGenerator::class, [ - $this->classExistsMethodCall(['controllers', 'PostController']) + $this->classExistsMethodCall(['controllers', 'PostController']), ]); $this->assertExceptionThrew( @@ -41,7 +41,7 @@ public function testModelServiceNotExists() { $this->mockClass(ControllerGenerator::class, [ $this->classExistsMethodCall(['controllers', 'PostController'], false), - $this->classExistsMethodCall(['services', 'PostService'], false) + $this->classExistsMethodCall(['services', 'PostService'], false), ]); $this->assertExceptionThrew( diff --git a/tests/FactoryGeneratorTest.php b/tests/FactoryGeneratorTest.php index 8976ef98..a02bfdf9 100644 --- a/tests/FactoryGeneratorTest.php +++ b/tests/FactoryGeneratorTest.php @@ -26,7 +26,7 @@ public function testModelNotExists() $this->assertExceptionThrew( className: ClassNotExistsException::class, message: "Cannot create PostFactory cause Post Model does not exists. " - . "Create a Post Model by itself or run command 'php artisan make:entity Post --only-model'." + . "Create a Post Model by itself or run command 'php artisan make:entity Post --only-model'.", ); app(FactoryGenerator::class) From fac9425ffec9f451d888d6805f4248ed7bf0ef8a Mon Sep 17 00:00:00 2001 From: roman Date: Thu, 28 Nov 2024 19:50:06 +0600 Subject: [PATCH 17/20] refactor: code refs: https://github.com/RonasIT/laravel-entity-generator/issues/49 --- config/entity-generator.php | 2 +- src/Commands/MakeEntityCommand.php | 6 ++---- src/Generators/AbstractTestsGenerator.php | 14 ++++++-------- src/Generators/FactoryGenerator.php | 6 +++--- tests/FactoryGeneratorTest.php | 2 +- tests/Support/Factory/FactoryMockTrait.php | 2 +- 6 files changed, 14 insertions(+), 18 deletions(-) diff --git a/config/entity-generator.php b/config/entity-generator.php index 8919cd20..6d498c76 100644 --- a/config/entity-generator.php +++ b/config/entity-generator.php @@ -16,7 +16,7 @@ 'repositories' => 'app/Repositories', 'tests' => 'tests', 'routes' => 'routes/api.php', - 'factory' => 'database/factories/ModelFactory.php', + 'factories' => 'database/factories', 'translations' => 'resources/lang/en/validation.php', 'resources' => 'app/Http/Resources', 'nova' => 'app/Nova', diff --git a/src/Commands/MakeEntityCommand.php b/src/Commands/MakeEntityCommand.php index 7790c263..f300ff5a 100644 --- a/src/Commands/MakeEntityCommand.php +++ b/src/Commands/MakeEntityCommand.php @@ -2,7 +2,6 @@ namespace RonasIT\Support\Commands; -use Closure; use Illuminate\Console\Command; use Illuminate\Support\Arr; use Illuminate\Support\Facades\Config; @@ -217,10 +216,9 @@ protected function outputNewConfig($packageConfigs, $projectConfigs) } $factories = 'database/factories'; - $factories = (version_compare(app()->version(), '8', '>=')) ? $factories : "{$factories}/ModelFactory.php"; - if ($newConfig['paths.factory'] !== $factories) { - $newConfig['paths.factory'] = $factories; + if ($newConfig['paths.factories'] !== $factories) { + $newConfig['paths.factories'] = $factories; } $differences = array_diff_key($newConfig, $flattenedProjectConfigs); diff --git a/src/Generators/AbstractTestsGenerator.php b/src/Generators/AbstractTestsGenerator.php index 780f889d..f56a1b8b 100644 --- a/src/Generators/AbstractTestsGenerator.php +++ b/src/Generators/AbstractTestsGenerator.php @@ -90,14 +90,11 @@ protected function getInserts(): array }, $this->buildRelationsTree($arrayModels)); } - protected function isFactoryExists($modelName): bool + protected function isFactoryExists(string $modelName): bool { - $factory = app(LegacyFactories::class); $modelClass = $this->getModelClass($modelName); - $isNewStyleFactoryExists = $this->classExists('factory', "{$modelName}Factory") && method_exists($modelClass, 'factory'); - - return $isNewStyleFactoryExists || !empty($factory[$this->getModelClass($modelName)]); + return $this->classExists('factories', "{$modelName}Factory") && method_exists($modelClass, 'factory'); } protected function isMethodExists($modelName, $method): bool @@ -176,13 +173,14 @@ protected function getModelFields($model): array protected function getMockModel($model): array { - if (!$this->isFactoryExists($model)) { + $hasFactory = $this->isFactoryExists($model); + + if (!$hasFactory) { return []; } $modelClass = $this->getModelClass($model); - $hasFactory = method_exists($modelClass, 'factory') && $this->classExists('factory', "{$model}Factory"); - $factory = ($hasFactory) ? $modelClass::factory() : factory($modelClass); + $factory = $modelClass::factory(); return $factory ->make() diff --git a/src/Generators/FactoryGenerator.php b/src/Generators/FactoryGenerator.php index fd747a7a..59ec4c3d 100644 --- a/src/Generators/FactoryGenerator.php +++ b/src/Generators/FactoryGenerator.php @@ -35,7 +35,7 @@ public function generate(): void ); } - if ($this->classExists('factory', "{$this->model}Factory")) { + if ($this->classExists('factories', "{$this->model}Factory")) { $this->throwFailureException( exceptionClass: ClassAlreadyExistsException::class, failureMessage: "Cannot create {$this->model}Factory cause {$this->model}Factory already exists.", @@ -44,12 +44,12 @@ public function generate(): void } $factoryContent = $this->getStub('factory', [ - 'namespace' => $this->getOrCreateNamespace('factory'), + 'namespace' => $this->getOrCreateNamespace('factories'), 'entity' => $this->model, 'fields' => $this->prepareFields(), ]); - $this->saveClass('factory', "{$this->model}Factory", $factoryContent); + $this->saveClass('factories', "{$this->model}Factory", $factoryContent); event(new SuccessCreateMessage("Created a new Factory: {$this->model}Factory")); } diff --git a/tests/FactoryGeneratorTest.php b/tests/FactoryGeneratorTest.php index a02bfdf9..0d103dd9 100644 --- a/tests/FactoryGeneratorTest.php +++ b/tests/FactoryGeneratorTest.php @@ -45,7 +45,7 @@ className: ClassAlreadyExistsException::class, $this->mockFactoryGenerator( $this->classExistsMethodCall(['models', 'Post']), - $this->classExistsMethodCall(['factory', 'PostFactory']), + $this->classExistsMethodCall(['factories', 'PostFactory']), ); app(FactoryGenerator::class) diff --git a/tests/Support/Factory/FactoryMockTrait.php b/tests/Support/Factory/FactoryMockTrait.php index e9c08a61..420b6cb1 100644 --- a/tests/Support/Factory/FactoryMockTrait.php +++ b/tests/Support/Factory/FactoryMockTrait.php @@ -21,7 +21,7 @@ public function mockConfigurations(): void config([ 'entity-generator.paths' => [ 'models' => 'app/Models', - 'factory' => 'database/factories', + 'factories' => 'database/factories', ], ]); } From fdb25c83e98f610e6fe89f95ad002dc55c5d1677 Mon Sep 17 00:00:00 2001 From: roman Date: Fri, 29 Nov 2024 14:41:33 +0600 Subject: [PATCH 18/20] refactor: remove useless stubs refs: https://github.com/RonasIT/laravel-entity-generator/issues/49 --- stubs/legacy_empty_factory.blade.php | 30 ---------------------------- stubs/legacy_factory.blade.php | 7 ------- 2 files changed, 37 deletions(-) delete mode 100644 stubs/legacy_empty_factory.blade.php delete mode 100644 stubs/legacy_factory.blade.php diff --git a/stubs/legacy_empty_factory.blade.php b/stubs/legacy_empty_factory.blade.php deleted file mode 100644 index af39da4e..00000000 --- a/stubs/legacy_empty_factory.blade.php +++ /dev/null @@ -1,30 +0,0 @@ -use Illuminate\Support\Str; - -/* -|-------------------------------------------------------------------------- -| Model Factories -|-------------------------------------------------------------------------- -| -| Here you may define all of your model factories. Model factories give -| you a convenient way to create models for testing and seeding your -| database. Just tell the factory how a default model should look. -| -*/ - -/** @var \Illuminate\Database\Eloquent\Factory $factory */ -$factory->define({{$modelsNamespace}}\User::class, function (Faker\Generator $faker) { - static $password; - - return [ - 'name' => $faker->name, - 'email' => $faker->unique()->safeEmail, - 'password' => $password ?: $password = bcrypt('secret'), - 'remember_token' => Str::random(10), - ]; -}); - -$factory->define({{$modelsNamespace}}\Role::class, function () { - return [ - 'name' => 'user' - ]; -}); diff --git a/stubs/legacy_factory.blade.php b/stubs/legacy_factory.blade.php deleted file mode 100644 index 7756e2e0..00000000 --- a/stubs/legacy_factory.blade.php +++ /dev/null @@ -1,7 +0,0 @@ -$factory->define({{$modelsNamespace}}\{{$entity}}::class, function (Faker\Generator $faker) { - return [ -@foreach($fields as $field) - '{{$field['name']}}' => {!! \RonasIT\Support\Generators\FactoryGenerator::getFactoryFieldsContent($field) !!}, -@endforeach - ]; -}); \ No newline at end of file From f6fa94cd1264201bab0c3b53ba425a63d70966ac Mon Sep 17 00:00:00 2001 From: DenTray Date: Mon, 2 Dec 2024 14:32:51 +0600 Subject: [PATCH 19/20] Update tests/Support/Factory/FactoryMockTrait.php --- tests/Support/Factory/FactoryMockTrait.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Support/Factory/FactoryMockTrait.php b/tests/Support/Factory/FactoryMockTrait.php index 420b6cb1..60a4b920 100644 --- a/tests/Support/Factory/FactoryMockTrait.php +++ b/tests/Support/Factory/FactoryMockTrait.php @@ -11,7 +11,7 @@ trait FactoryMockTrait { use GeneratorMockTrait, MockTrait; - public function mockFactoryGenerator(...$functionCalls): void + public function mockFactoryGenerator(array ...$functionCalls): void { $this->mockClass(FactoryGenerator::class, $functionCalls); } From 53f9fce7ea2632b990df18c85f4f927708adb234 Mon Sep 17 00:00:00 2001 From: roman Date: Mon, 2 Dec 2024 14:50:50 +0600 Subject: [PATCH 20/20] fix: conflicts refs: https://github.com/RonasIT/laravel-entity-generator/issues/49 --- src/Generators/FactoryGenerator.php | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/Generators/FactoryGenerator.php b/src/Generators/FactoryGenerator.php index 172e9e7e..59ec4c3d 100644 --- a/src/Generators/FactoryGenerator.php +++ b/src/Generators/FactoryGenerator.php @@ -113,12 +113,4 @@ protected function prepareFields(): array return $result; } - - protected function getFactoryPattern($model): string - { - $modelNamespace = "App\\\\Models\\\\" . $model; - $return = "return \\["; - - return "/{$modelNamespace}.*{$return}/sU"; - } }