packages/sql-fixture/tests/Unit/Provider/FixtureGeneratorTest.php

1<?php
2
3declare(strict_types=1);
4
5namespace Tests\Unit\Provider;
6
7use Faker\Factory;
8use PHPUnit\Framework\Attributes\CoversClass;
9use PHPUnit\Framework\Attributes\Test;
10use PHPUnit\Framework\Attributes\UsesClass;
11use PHPUnit\Framework\TestCase;
12use SqlFixture\Fixture\Exception\InvalidOverrideException;
13use SqlFixture\Hydrator\ReflectionHydrator;
14use SqlFixture\Platform\MySql\MySqlSchemaParser;
15use SqlFixture\Platform\MySql\MySqlTypeMapper;
16use SqlFixture\Provider\FixtureGenerator;
17use SqlFixture\Schema\ColumnDefinition;
18use SqlFixture\Schema\TableSchema;
19
20#[CoversClass(FixtureGenerator::class)]
21#[UsesClass(InvalidOverrideException::class)]
22#[UsesClass(MySqlTypeMapper::class)]
23#[UsesClass(ColumnDefinition::class)]
24#[UsesClass(TableSchema::class)]
25#[UsesClass(ReflectionHydrator::class)]
26#[CoversClass(\SqlFixture\Fixture\Validation\OverrideValidator::class)]
27#[UsesClass(\SqlFixture\Hydrator\HydrationException::class)]
28#[UsesClass(\SqlFixture\Hydrator\HydratorInterface::class)]
29#[UsesClass(MySqlSchemaParser::class)]
30#[UsesClass(\SqlFixture\Schema\SchemaParseException::class)]
31#[UsesClass(\SqlFixture\Schema\SchemaParserInterface::class)]
32#[UsesClass(\SqlFixture\TypeMapper\TypeMapperInterface::class)]
33#[UsesClass(\SqlFixture\Fixture\RowGeneration::class)]
34#[UsesClass(\SqlFixture\Hydrator\Reflection\ConstructorHydration::class)]
35#[UsesClass(\SqlFixture\Hydrator\Reflection\PropertyHydration::class)]
36#[UsesClass(\SqlFixture\Hydrator\Reflection\PropertyNames::class)]
37#[UsesClass(\SqlFixture\Hydrator\Reflection\ValueConversion::class)]
38#[UsesClass(\SqlFixture\Platform\MySql\Schema\ColumnParser::class)]
39#[UsesClass(\SqlFixture\Platform\MySql\Schema\DefaultExpression::class)]
40#[UsesClass(\SqlFixture\Platform\MySql\Schema\DefinitionIntegrity::class)]
41#[UsesClass(\SqlFixture\Platform\MySql\Schema\TableDefinition::class)]
42#[UsesClass(\SqlFixture\Platform\MySql\Schema\TypeParameters::class)]
43#[UsesClass(\SqlFixture\Platform\MySql\Value\ColumnGenerator::class)]
44#[UsesClass(\SqlFixture\Platform\MySql\Value\DecimalGenerator::class)]
45#[UsesClass(\SqlFixture\Platform\MySql\Value\GeometryGenerator::class)]
46#[UsesClass(\SqlFixture\Platform\MySql\Value\IntegerGenerator::class)]
47#[UsesClass(\SqlFixture\Platform\MySql\Value\NumericGenerator::class)]
48#[UsesClass(\SqlFixture\Platform\MySql\Value\SpatialGenerator::class)]
49#[UsesClass(\SqlFixture\Platform\MySql\Value\StringGenerator::class)]
50#[UsesClass(\SqlFixture\Platform\MySql\Value\TextGenerator::class)]
51#[UsesClass(\SqlFixture\Schema\TypeShape::class)]
52#[UsesClass(\SqlFixture\TypeMapper\ParagraphGenerator::class)]
53#[UsesClass(\SqlFixture\Platform\MySql\Schema\TableDefinitionInput::class)]
54#[UsesClass(\SqlFixture\Hydrator\Exception\ClassNotFoundException::class)]
55#[UsesClass(\SqlFixture\Hydrator\Exception\MissingConstructorArgumentException::class)]
56#[UsesClass(\SqlFixture\Fixture\Exception\UnknownOverrideColumnException::class)]
57#[UsesClass(\SqlFixture\Fixture\Exception\NullOverrideException::class)]
58#[UsesClass(\SqlFixture\Fixture\Exception\GeneratedColumnOverrideException::class)]
59#[UsesClass(\SqlFixture\Schema\Exception\InvalidSqlException::class)]
60#[UsesClass(\SqlFixture\Schema\Exception\ExpectedCreateTableException::class)]
61#[UsesClass(\SqlFixture\Schema\Exception\MissingColumnDefinitionsException::class)]
62#[UsesClass(\SqlFixture\TypeMapper\IntegerRange::class)]
63#[UsesClass(\SqlFixture\TypeMapper\IntegerWidth::class)]
64#[UsesClass(\SqlFixture\TypeMapper\DecimalRange::class)]
65#[UsesClass(\SqlFixture\Hydrator\Reflection\ConversionTarget::class)]
66#[UsesClass(\SqlFixture\Fixture\RowGenerator::class)]
67final class FixtureGeneratorTest extends TestCase
68{
69    #[Test]
70    public function testGenerateWithSchema(): void
71    {
72        $schema = new TableSchema('users', [
73            'id' => new ColumnDefinition('id', 'INT'),
74            'name' => new ColumnDefinition('name', 'VARCHAR', length: 255),
75        ], ['id']);
76
77        $faker = Factory::create();
78        $faker->seed(12345);
79        $data = (new FixtureGenerator($faker))->generate($schema);
80
81        self::assertArrayHasKey('id', $data);
82        self::assertArrayHasKey('name', $data);
83    }
84
85    #[Test]
86    public function testGenerateWithOverrides(): void
87    {
88        $schema = new TableSchema('users', [
89            'id' => new ColumnDefinition('id', 'INT'),
90            'name' => new ColumnDefinition('name', 'VARCHAR', length: 255),
91        ], ['id']);
92
93        $faker = Factory::create();
94        $faker->seed(12345);
95        $data = (new FixtureGenerator($faker))->generate($schema, ['name' => 'Override']);
96
97        self::assertSame('Override', $data['name']);
98    }
99
100    #[Test]
101    public function testGenerateSkipsAutoIncrement(): void
102    {
103        $schema = new TableSchema('users', [
104            'id' => new ColumnDefinition('id', 'INT', autoIncrement: true),
105            'name' => new ColumnDefinition('name', 'VARCHAR', length: 255),
106        ], ['id']);
107
108        $faker = Factory::create();
109        $faker->seed(12345);
110        $data = (new FixtureGenerator($faker))->generate($schema);
111
112        self::assertArrayNotHasKey('id', $data);
113        self::assertArrayHasKey('name', $data);
114        self::assertIsString($data['name']);
115    }
116
117    #[Test]
118    public function testGenerateSkipsGeneratedColumns(): void
119    {
120        $schema = new TableSchema('users', [
121            'id' => new ColumnDefinition('id', 'INT'),
122            'computed' => new ColumnDefinition('computed', 'INT', generated: true),
123            'name' => new ColumnDefinition('name', 'VARCHAR', length: 255),
124        ], ['id']);
125
126        $faker = Factory::create();
127        $faker->seed(12345);
128        $data = (new FixtureGenerator($faker))->generate($schema);
129
130        self::assertArrayNotHasKey('computed', $data);
131        self::assertArrayHasKey('id', $data);
132        self::assertArrayHasKey('name', $data);
133    }
134
135    #[Test]
136    public function testGenerateWithHydration(): void
137    {
138        $target = new class (0, '') {
139            public function __construct(
140                public readonly int $id,
141                public readonly string $name,
142            ) {
143            }
144        };
145        $schema = new TableSchema('users', [
146            'id' => new ColumnDefinition('id', 'INT'),
147            'name' => new ColumnDefinition('name', 'VARCHAR', length: 255),
148        ], ['id']);
149
150        $faker = Factory::create();
151        $faker->seed(12345);
152        $user = (new FixtureGenerator($faker))->generate($schema, ['id' => 1, 'name' => 'Test'], $target::class);
153
154        self::assertSame(1, $user->id);
155        self::assertSame('Test', $user->name);
156    }
157
158    #[Test]
159    public function testGetSchemaParser(): void
160    {
161        $faker = Factory::create();
162        $faker->seed(12345);
163        $parser = (new FixtureGenerator($faker))->getSchemaParser();
164        self::assertInstanceOf(MySqlSchemaParser::class, $parser);
165    }
166
167    #[Test]
168    public function testGetTypeMapper(): void
169    {
170        $faker = Factory::create();
171        $faker->seed(12345);
172        $mapper = (new FixtureGenerator($faker))->getTypeMapper();
173        self::assertInstanceOf(MySqlTypeMapper::class, $mapper);
174    }
175
176    #[Test]
177    public function testGetHydrator(): void
178    {
179        $faker = Factory::create();
180        $faker->seed(12345);
181        $hydrator = (new FixtureGenerator($faker))->getHydrator();
182        self::assertInstanceOf(ReflectionHydrator::class, $hydrator);
183    }
184
185    #[Test]
186    public function testConfigureWithCustomDependencies(): void
187    {
188        $faker = Factory::create();
189        $customMapper = new MySqlTypeMapper();
190        $customHydrator = new ReflectionHydrator();
191        $customParser = new MySqlSchemaParser();
192
193        $generator = new FixtureGenerator(
194            $faker,
195            $customMapper,
196            $customHydrator,
197            $customParser
198        );
199
200        self::assertSame($customMapper, $generator->getTypeMapper());
201        self::assertSame($customHydrator, $generator->getHydrator());
202        self::assertSame($customParser, $generator->getSchemaParser());
203    }
204
205    #[Test]
206    public function testNullIsAcceptedForANullableColumn(): void
207    {
208        $schema = new TableSchema('users', [
209            'note' => new ColumnDefinition('note', 'VARCHAR', length: 255, nullable: true),
210        ]);
211
212        $data = (new FixtureGenerator(Factory::create()))->generate($schema, ['note' => null]);
213
214        self::assertNull($data['note']);
215    }
216
217    #[Test]
218    public function testAnOverrideForAnAutoIncrementColumnIsStillAllowed(): void
219    {
220        $schema = new TableSchema('users', [
221            'id' => new ColumnDefinition('id', 'INT', autoIncrement: true),
222        ], ['id']);
223
224        $data = (new FixtureGenerator(Factory::create()))->generate($schema, ['id' => 100]);
225
226        self::assertSame(100, $data['id']);
227    }
228}
229