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

1<?php
2
3declare(strict_types=1);
4
5namespace Tests\Unit;
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\FixtureGenerator;
13use SqlFixture\Hydrator\ReflectionHydrator;
14use SqlFixture\InvalidOverrideException;
15use SqlFixture\Platform\MySql\MySqlSchemaParser;
16use SqlFixture\Platform\MySql\MySqlTypeMapper;
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)]
66final class FixtureGeneratorTest extends TestCase
67{
68    #[Test]
69    public function testGenerateWithSchema(): void
70    {
71        $schema = new TableSchema('users', [
72            'id' => new ColumnDefinition('id', 'INT'),
73            'name' => new ColumnDefinition('name', 'VARCHAR', length: 255),
74        ], ['id']);
75
76        $faker = Factory::create();
77        $faker->seed(12345);
78        $data = (new FixtureGenerator($faker))->generate($schema);
79
80        self::assertArrayHasKey('id', $data);
81        self::assertArrayHasKey('name', $data);
82    }
83
84    #[Test]
85    public function testGenerateWithOverrides(): void
86    {
87        $schema = new TableSchema('users', [
88            'id' => new ColumnDefinition('id', 'INT'),
89            'name' => new ColumnDefinition('name', 'VARCHAR', length: 255),
90        ], ['id']);
91
92        $faker = Factory::create();
93        $faker->seed(12345);
94        $data = (new FixtureGenerator($faker))->generate($schema, ['name' => 'Override']);
95
96        self::assertSame('Override', $data['name']);
97    }
98
99    #[Test]
100    public function testGenerateSkipsAutoIncrement(): void
101    {
102        $schema = new TableSchema('users', [
103            'id' => new ColumnDefinition('id', 'INT', autoIncrement: true),
104            'name' => new ColumnDefinition('name', 'VARCHAR', length: 255),
105        ], ['id']);
106
107        $faker = Factory::create();
108        $faker->seed(12345);
109        $data = (new FixtureGenerator($faker))->generate($schema);
110
111        self::assertArrayNotHasKey('id', $data);
112        self::assertArrayHasKey('name', $data);
113        self::assertIsString($data['name']);
114    }
115
116    #[Test]
117    public function testGenerateSkipsGeneratedColumns(): void
118    {
119        $schema = new TableSchema('users', [
120            'id' => new ColumnDefinition('id', 'INT'),
121            'computed' => new ColumnDefinition('computed', 'INT', generated: true),
122            'name' => new ColumnDefinition('name', 'VARCHAR', length: 255),
123        ], ['id']);
124
125        $faker = Factory::create();
126        $faker->seed(12345);
127        $data = (new FixtureGenerator($faker))->generate($schema);
128
129        self::assertArrayNotHasKey('computed', $data);
130        self::assertArrayHasKey('id', $data);
131        self::assertArrayHasKey('name', $data);
132    }
133
134    #[Test]
135    public function testGenerateWithHydration(): void
136    {
137        $target = new class (0, '') {
138            public function __construct(
139                public readonly int $id,
140                public readonly string $name,
141            ) {
142            }
143        };
144        $schema = new TableSchema('users', [
145            'id' => new ColumnDefinition('id', 'INT'),
146            'name' => new ColumnDefinition('name', 'VARCHAR', length: 255),
147        ], ['id']);
148
149        $faker = Factory::create();
150        $faker->seed(12345);
151        $user = (new FixtureGenerator($faker))->generate($schema, ['id' => 1, 'name' => 'Test'], $target::class);
152
153        self::assertSame(1, $user->id);
154        self::assertSame('Test', $user->name);
155    }
156
157    #[Test]
158    public function testGetSchemaParser(): void
159    {
160        $faker = Factory::create();
161        $faker->seed(12345);
162        $parser = (new FixtureGenerator($faker))->getSchemaParser();
163        self::assertInstanceOf(MySqlSchemaParser::class, $parser);
164    }
165
166    #[Test]
167    public function testGetTypeMapper(): void
168    {
169        $faker = Factory::create();
170        $faker->seed(12345);
171        $mapper = (new FixtureGenerator($faker))->getTypeMapper();
172        self::assertInstanceOf(MySqlTypeMapper::class, $mapper);
173    }
174
175    #[Test]
176    public function testGetHydrator(): void
177    {
178        $faker = Factory::create();
179        $faker->seed(12345);
180        $hydrator = (new FixtureGenerator($faker))->getHydrator();
181        self::assertInstanceOf(ReflectionHydrator::class, $hydrator);
182    }
183
184    #[Test]
185    public function testConfigureWithCustomDependencies(): void
186    {
187        $faker = Factory::create();
188        $customMapper = new MySqlTypeMapper();
189        $customHydrator = new ReflectionHydrator();
190        $customParser = new MySqlSchemaParser();
191
192        $generator = new FixtureGenerator(
193            $faker,
194            $customMapper,
195            $customHydrator,
196            $customParser
197        );
198
199        self::assertSame($customMapper, $generator->getTypeMapper());
200        self::assertSame($customHydrator, $generator->getHydrator());
201        self::assertSame($customParser, $generator->getSchemaParser());
202    }
203
204    #[Test]
205    public function testNullIsAcceptedForANullableColumn(): void
206    {
207        $schema = new TableSchema('users', [
208            'note' => new ColumnDefinition('note', 'VARCHAR', length: 255, nullable: true),
209        ]);
210
211        $data = (new FixtureGenerator(Factory::create()))->generate($schema, ['note' => null]);
212
213        self::assertNull($data['note']);
214    }
215
216    #[Test]
217    public function testAnOverrideForAnAutoIncrementColumnIsStillAllowed(): void
218    {
219        $schema = new TableSchema('users', [
220            'id' => new ColumnDefinition('id', 'INT', autoIncrement: true),
221        ], ['id']);
222
223        $data = (new FixtureGenerator(Factory::create()))->generate($schema, ['id' => 100]);
224
225        self::assertSame(100, $data['id']);
226    }
227}
228