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