packages/sql-fixture/tests/Unit/TypeMapper/MySqlTypeMapperTest.php

1<?php
2
3declare(strict_types=1);
4
5namespace Tests\Unit\TypeMapper;
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\Platform\MySql\MySqlTypeMapper as PlatformMySqlTypeMapper;
13use SqlFixture\Schema\ColumnDefinition;
14use SqlFixture\TypeMapper\MySqlTypeMapper;
15
16#[CoversClass(MySqlTypeMapper::class)]
17#[UsesClass(ColumnDefinition::class)]
18#[UsesClass(PlatformMySqlTypeMapper::class)]
19#[UsesClass(\SqlFixture\TypeMapper\TypeMapperInterface::class)]
20#[UsesClass(\SqlFixture\Platform\MySql\Value\ColumnGenerator::class)]
21#[UsesClass(\SqlFixture\Platform\MySql\Value\DecimalGenerator::class)]
22#[UsesClass(\SqlFixture\Platform\MySql\Value\GeometryGenerator::class)]
23#[UsesClass(\SqlFixture\Platform\MySql\Value\IntegerGenerator::class)]
24#[UsesClass(\SqlFixture\Platform\MySql\Value\NumericGenerator::class)]
25#[UsesClass(\SqlFixture\Platform\MySql\Value\SpatialGenerator::class)]
26#[UsesClass(\SqlFixture\Platform\MySql\Value\StringGenerator::class)]
27#[UsesClass(\SqlFixture\Platform\MySql\Value\TextGenerator::class)]
28#[UsesClass(\SqlFixture\TypeMapper\ParagraphGenerator::class)]
29#[UsesClass(\SqlFixture\TypeMapper\IntegerRange::class)]
30#[UsesClass(\SqlFixture\TypeMapper\IntegerWidth::class)]
31#[UsesClass(\SqlFixture\TypeMapper\DecimalRange::class)]
32final class MySqlTypeMapperTest extends TestCase
33{
34    #[Test]
35    public function testGenerateTinyInt(): void
36    {
37        $faker = Factory::create();
38        $faker->seed(12345);
39        $mapper = new MySqlTypeMapper();
40
41        $column = new ColumnDefinition('col', 'TINYINT', nullable: false);
42        $value = $mapper->generate($faker, $column);
43
44        self::assertIsInt($value);
45        self::assertGreaterThanOrEqual(-128, $value);
46        self::assertLessThanOrEqual(127, $value);
47    }
48
49    #[Test]
50    public function testGenerateTinyIntUnsigned(): void
51    {
52        $faker = Factory::create();
53        $faker->seed(12345);
54        $mapper = new MySqlTypeMapper();
55
56        $column = new ColumnDefinition('col', 'TINYINT', unsigned: true, nullable: false);
57        $value = $mapper->generate($faker, $column);
58
59        self::assertIsInt($value);
60        self::assertGreaterThanOrEqual(0, $value);
61        self::assertLessThanOrEqual(255, $value);
62    }
63
64    #[Test]
65    public function testGenerateTinyIntOneAsBoolean(): void
66    {
67        $faker = Factory::create();
68        $faker->seed(12345);
69        $mapper = new MySqlTypeMapper();
70
71        $column = new ColumnDefinition('col', 'TINYINT', length: 1, nullable: false);
72        $value = $mapper->generate($faker, $column);
73
74        self::assertIsBool($value);
75    }
76
77    #[Test]
78    public function testGenerateInt(): void
79    {
80        $faker = Factory::create();
81        $faker->seed(12345);
82        $mapper = new MySqlTypeMapper();
83
84        $column = new ColumnDefinition('col', 'INT', nullable: false);
85        $value = $mapper->generate($faker, $column);
86
87        self::assertIsInt($value);
88    }
89
90    #[Test]
91    public function testGenerateDecimal(): void
92    {
93        $faker = Factory::create();
94        $faker->seed(12345);
95        $mapper = new MySqlTypeMapper();
96
97        $column = new ColumnDefinition('col', 'DECIMAL', precision: 10, scale: 2, nullable: false);
98        $value = $mapper->generate($faker, $column);
99
100        self::assertIsFloat($value);
101    }
102
103    #[Test]
104    public function testGenerateVarchar(): void
105    {
106        $faker = Factory::create();
107        $faker->seed(12345);
108        $mapper = new MySqlTypeMapper();
109
110        $column = new ColumnDefinition('col', 'VARCHAR', length: 100, nullable: false);
111        $value = $mapper->generate($faker, $column);
112
113        self::assertIsString($value);
114        self::assertLessThanOrEqual(100, strlen($value));
115    }
116
117    #[Test]
118    public function testGenerateChar(): void
119    {
120        $faker = Factory::create();
121        $faker->seed(12345);
122        $mapper = new MySqlTypeMapper();
123
124        $column = new ColumnDefinition('col', 'CHAR', length: 5, nullable: false);
125        $value = $mapper->generate($faker, $column);
126
127        self::assertIsString($value);
128        self::assertSame(5, strlen($value));
129    }
130
131    #[Test]
132    public function testGenerateDate(): void
133    {
134        $faker = Factory::create();
135        $faker->seed(12345);
136        $mapper = new MySqlTypeMapper();
137
138        $column = new ColumnDefinition('col', 'DATE', nullable: false);
139        $value = $mapper->generate($faker, $column);
140
141        self::assertIsString($value);
142        self::assertMatchesRegularExpression('/^\d{4}-\d{2}-\d{2}$/', $value);
143    }
144
145    #[Test]
146    public function testGenerateTime(): void
147    {
148        $faker = Factory::create();
149        $faker->seed(12345);
150        $mapper = new MySqlTypeMapper();
151
152        $column = new ColumnDefinition('col', 'TIME', nullable: false);
153        $value = $mapper->generate($faker, $column);
154
155        self::assertIsString($value);
156        self::assertMatchesRegularExpression('/^\d{2}:\d{2}:\d{2}$/', $value);
157    }
158
159    #[Test]
160    public function testGenerateDatetime(): void
161    {
162        $faker = Factory::create();
163        $faker->seed(12345);
164        $mapper = new MySqlTypeMapper();
165
166        $column = new ColumnDefinition('col', 'DATETIME', nullable: false);
167        $value = $mapper->generate($faker, $column);
168
169        self::assertIsString($value);
170        self::assertMatchesRegularExpression('/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$/', $value);
171    }
172
173    #[Test]
174    public function testGenerateTimestamp(): void
175    {
176        $faker = Factory::create();
177        $faker->seed(12345);
178        $mapper = new MySqlTypeMapper();
179
180        $column = new ColumnDefinition('col', 'TIMESTAMP', nullable: false);
181        $value = $mapper->generate($faker, $column);
182
183        self::assertIsString($value);
184        $timestamp = strtotime($value);
185        self::assertGreaterThanOrEqual(strtotime('1970-01-01'), $timestamp);
186        self::assertLessThanOrEqual(strtotime('2038-01-19'), $timestamp);
187    }
188
189    #[Test]
190    public function testGenerateYear(): void
191    {
192        $faker = Factory::create();
193        $faker->seed(12345);
194        $mapper = new MySqlTypeMapper();
195
196        $column = new ColumnDefinition('col', 'YEAR', nullable: false);
197        $value = $mapper->generate($faker, $column);
198
199        self::assertIsInt($value);
200        self::assertGreaterThanOrEqual(1901, $value);
201        self::assertLessThanOrEqual(2155, $value);
202    }
203
204    #[Test]
205    public function testGenerateEnum(): void
206    {
207        $faker = Factory::create();
208        $faker->seed(12345);
209        $mapper = new MySqlTypeMapper();
210
211        $column = new ColumnDefinition('col', 'ENUM', enumValues: ['a', 'b', 'c'], nullable: false);
212        $value = $mapper->generate($faker, $column);
213
214        self::assertIsString($value);
215        self::assertContains($value, ['a', 'b', 'c']);
216    }
217
218    #[Test]
219    public function testGenerateSet(): void
220    {
221        $faker = Factory::create();
222        $faker->seed(12345);
223        $mapper = new MySqlTypeMapper();
224
225        $column = new ColumnDefinition('col', 'SET', enumValues: ['x', 'y', 'z'], nullable: false);
226        $value = $mapper->generate($faker, $column);
227
228        self::assertIsString($value);
229        $parts = explode(',', $value);
230        array_walk($parts, static function (string $part): void {
231            self::assertContains($part, ['x', 'y', 'z']);
232        });
233    }
234
235    #[Test]
236    public function testGenerateJson(): void
237    {
238        $faker = Factory::create();
239        $faker->seed(12345);
240        $mapper = new MySqlTypeMapper();
241
242        $column = new ColumnDefinition('col', 'JSON', nullable: false);
243        $value = $mapper->generate($faker, $column);
244
245        self::assertIsString($value);
246        $decoded = json_decode($value, true);
247        self::assertIsArray($decoded);
248        self::assertArrayHasKey('key', $decoded);
249        self::assertArrayHasKey('value', $decoded);
250    }
251
252    #[Test]
253    public function testGeneratePoint(): void
254    {
255        $faker = Factory::create();
256        $faker->seed(12345);
257        $mapper = new MySqlTypeMapper();
258
259        $column = new ColumnDefinition('col', 'POINT', nullable: false);
260        $value = $mapper->generate($faker, $column);
261
262        self::assertIsString($value);
263        self::assertStringStartsWith('POINT(', $value);
264    }
265
266    #[Test]
267    public function testGenerateAutoIncrementReturnsNull(): void
268    {
269        $faker = Factory::create();
270        $faker->seed(12345);
271        $mapper = new MySqlTypeMapper();
272
273        $column = new ColumnDefinition('id', 'INT', autoIncrement: true, nullable: false);
274        $value = $mapper->generate($faker, $column);
275
276        self::assertNull($value);
277    }
278
279    #[Test]
280    public function testGenerateGeneratedColumnReturnsNull(): void
281    {
282        $faker = Factory::create();
283        $faker->seed(12345);
284        $mapper = new MySqlTypeMapper();
285
286        $column = new ColumnDefinition('computed', 'INT', generated: true, nullable: false);
287        $value = $mapper->generate($faker, $column);
288
289        self::assertNull($value);
290    }
291
292    #[Test]
293    public function testGenerateBit(): void
294    {
295        $faker = Factory::create();
296        $faker->seed(12345);
297        $mapper = new MySqlTypeMapper();
298
299        $column = new ColumnDefinition('col', 'BIT', length: 8, nullable: false);
300        $value = $mapper->generate($faker, $column);
301
302        self::assertIsInt($value);
303        self::assertGreaterThanOrEqual(0, $value);
304        self::assertLessThanOrEqual(255, $value);
305    }
306
307    #[Test]
308    public function testGenerateBinary(): void
309    {
310        $faker = Factory::create();
311        $faker->seed(12345);
312        $mapper = new MySqlTypeMapper();
313
314        $column = new ColumnDefinition('col', 'BINARY', length: 16, nullable: false);
315        $value = $mapper->generate($faker, $column);
316
317        self::assertIsString($value);
318        self::assertSame(16, strlen($value));
319    }
320
321    #[Test]
322    public function testGenerateBlob(): void
323    {
324        $faker = Factory::create();
325        $faker->seed(12345);
326        $mapper = new MySqlTypeMapper();
327
328        $column = new ColumnDefinition('col', 'BLOB', nullable: false);
329        $value = $mapper->generate($faker, $column);
330
331        self::assertIsString($value);
332        self::assertGreaterThan(0, strlen($value));
333    }
334
335    #[Test]
336    public function testGenerateText(): void
337    {
338        $faker = Factory::create();
339        $faker->seed(12345);
340        $mapper = new MySqlTypeMapper();
341
342        $column = new ColumnDefinition('col', 'TEXT', nullable: false);
343        $value = $mapper->generate($faker, $column);
344
345        self::assertIsString($value);
346        self::assertGreaterThan(0, strlen($value));
347    }
348
349    #[Test]
350    public function testGenerateSmallInt(): void
351    {
352        $faker = Factory::create();
353        $faker->seed(12345);
354        $mapper = new MySqlTypeMapper();
355
356        $column = new ColumnDefinition('col', 'SMALLINT', nullable: false);
357        $value = $mapper->generate($faker, $column);
358
359        self::assertIsInt($value);
360        self::assertGreaterThanOrEqual(-32768, $value);
361        self::assertLessThanOrEqual(32767, $value);
362    }
363
364    #[Test]
365    public function testGenerateSmallIntUnsigned(): void
366    {
367        $faker = Factory::create();
368        $faker->seed(12345);
369        $mapper = new MySqlTypeMapper();
370
371        $column = new ColumnDefinition('col', 'SMALLINT', unsigned: true, nullable: false);
372        $value = $mapper->generate($faker, $column);
373
374        self::assertIsInt($value);
375        self::assertGreaterThanOrEqual(0, $value);
376        self::assertLessThanOrEqual(65535, $value);
377    }
378
379    #[Test]
380    public function testGenerateMediumInt(): void
381    {
382        $faker = Factory::create();
383        $faker->seed(12345);
384        $mapper = new MySqlTypeMapper();
385
386        $column = new ColumnDefinition('col', 'MEDIUMINT', nullable: false);
387        $value = $mapper->generate($faker, $column);
388
389        self::assertIsInt($value);
390        self::assertGreaterThanOrEqual(-8388608, $value);
391        self::assertLessThanOrEqual(8388607, $value);
392    }
393
394    #[Test]
395    public function testGenerateMediumIntUnsigned(): void
396    {
397        $faker = Factory::create();
398        $faker->seed(12345);
399        $mapper = new MySqlTypeMapper();
400
401        $column = new ColumnDefinition('col', 'MEDIUMINT', unsigned: true, nullable: false);
402        $value = $mapper->generate($faker, $column);
403
404        self::assertIsInt($value);
405        self::assertGreaterThanOrEqual(0, $value);
406        self::assertLessThanOrEqual(16777215, $value);
407    }
408
409    #[Test]
410    public function testGenerateIntUnsigned(): void
411    {
412        $faker = Factory::create();
413        $faker->seed(12345);
414        $mapper = new MySqlTypeMapper();
415
416        $column = new ColumnDefinition('col', 'INT', unsigned: true, nullable: false);
417        $value = $mapper->generate($faker, $column);
418
419        self::assertIsInt($value);
420        self::assertGreaterThanOrEqual(0, $value);
421    }
422
423    #[Test]
424    public function testGenerateBigInt(): void
425    {
426        $faker = Factory::create();
427        $faker->seed(12345);
428        $mapper = new MySqlTypeMapper();
429
430        $column = new ColumnDefinition('col', 'BIGINT', nullable: false);
431        $value = $mapper->generate($faker, $column);
432
433        self::assertIsInt($value);
434    }
435
436    #[Test]
437    public function testGenerateBigIntUnsigned(): void
438    {
439        $faker = Factory::create();
440        $faker->seed(12345);
441        $mapper = new MySqlTypeMapper();
442
443        $column = new ColumnDefinition('col', 'BIGINT', unsigned: true, nullable: false);
444        $value = $mapper->generate($faker, $column);
445
446        self::assertIsInt($value);
447        self::assertGreaterThanOrEqual(0, $value);
448    }
449
450    #[Test]
451    public function testGenerateFloat(): void
452    {
453        $faker = Factory::create();
454        $faker->seed(12345);
455        $mapper = new MySqlTypeMapper();
456
457        $column = new ColumnDefinition('col', 'FLOAT', nullable: false);
458        $value = $mapper->generate($faker, $column);
459
460        self::assertIsFloat($value);
461    }
462
463    #[Test]
464    public function testGenerateDouble(): void
465    {
466        $faker = Factory::create();
467        $faker->seed(12345);
468        $mapper = new MySqlTypeMapper();
469
470        $column = new ColumnDefinition('col', 'DOUBLE', nullable: false);
471        $value = $mapper->generate($faker, $column);
472
473        self::assertIsFloat($value);
474    }
475
476    #[Test]
477    public function testGenerateDecimalUnsigned(): void
478    {
479        $faker = Factory::create();
480        $faker->seed(12345);
481        $mapper = new MySqlTypeMapper();
482
483        $column = new ColumnDefinition('col', 'DECIMAL', precision: 10, scale: 2, unsigned: true, nullable: false);
484        $value = $mapper->generate($faker, $column);
485
486        self::assertIsFloat($value);
487        self::assertGreaterThanOrEqual(0, $value);
488    }
489
490    #[Test]
491    public function testGenerateTinyText(): void
492    {
493        $faker = Factory::create();
494        $faker->seed(12345);
495        $mapper = new MySqlTypeMapper();
496
497        $column = new ColumnDefinition('col', 'TINYTEXT', nullable: false);
498        $value = $mapper->generate($faker, $column);
499
500        self::assertIsString($value);
501        self::assertLessThanOrEqual(255, strlen($value));
502    }
503
504    #[Test]
505    public function testGenerateMediumText(): void
506    {
507        $faker = Factory::create();
508        $faker->seed(12345);
509        $mapper = new MySqlTypeMapper();
510
511        $column = new ColumnDefinition('col', 'MEDIUMTEXT', nullable: false);
512        $value = $mapper->generate($faker, $column);
513
514        self::assertIsString($value);
515    }
516
517    #[Test]
518    public function testGenerateLongText(): void
519    {
520        $faker = Factory::create();
521        $faker->seed(12345);
522        $mapper = new MySqlTypeMapper();
523
524        $column = new ColumnDefinition('col', 'LONGTEXT', nullable: false);
525        $value = $mapper->generate($faker, $column);
526
527        self::assertIsString($value);
528    }
529
530    #[Test]
531    public function testGenerateVarbinary(): void
532    {
533        $faker = Factory::create();
534        $faker->seed(12345);
535        $mapper = new MySqlTypeMapper();
536
537        $column = new ColumnDefinition('col', 'VARBINARY', length: 100, nullable: false);
538        $value = $mapper->generate($faker, $column);
539
540        self::assertIsString($value);
541        self::assertLessThanOrEqual(100, strlen($value));
542    }
543
544    #[Test]
545    public function testGenerateTinyBlob(): void
546    {
547        $faker = Factory::create();
548        $faker->seed(12345);
549        $mapper = new MySqlTypeMapper();
550
551        $column = new ColumnDefinition('col', 'TINYBLOB', nullable: false);
552        $value = $mapper->generate($faker, $column);
553
554        self::assertIsString($value);
555    }
556
557    #[Test]
558    public function testGenerateMediumBlob(): void
559    {
560        $faker = Factory::create();
561        $faker->seed(12345);
562        $mapper = new MySqlTypeMapper();
563
564        $column = new ColumnDefinition('col', 'MEDIUMBLOB', nullable: false);
565        $value = $mapper->generate($faker, $column);
566
567        self::assertIsString($value);
568    }
569
570    #[Test]
571    public function testGenerateLongBlob(): void
572    {
573        $faker = Factory::create();
574        $faker->seed(12345);
575        $mapper = new MySqlTypeMapper();
576
577        $column = new ColumnDefinition('col', 'LONGBLOB', nullable: false);
578        $value = $mapper->generate($faker, $column);
579
580        self::assertIsString($value);
581    }
582
583    #[Test]
584    public function testGenerateEnumEmpty(): void
585    {
586        $faker = Factory::create();
587        $faker->seed(12345);
588        $mapper = new MySqlTypeMapper();
589
590        $column = new ColumnDefinition('col', 'ENUM', enumValues: [], nullable: false);
591        $value = $mapper->generate($faker, $column);
592
593        self::assertNull($value);
594    }
595
596    #[Test]
597    public function testGenerateSetEmpty(): void
598    {
599        $faker = Factory::create();
600        $faker->seed(12345);
601        $mapper = new MySqlTypeMapper();
602
603        $column = new ColumnDefinition('col', 'SET', enumValues: [], nullable: false);
604        $value = $mapper->generate($faker, $column);
605
606        self::assertNull($value);
607    }
608
609    #[Test]
610    public function testGenerateLineString(): void
611    {
612        $faker = Factory::create();
613        $faker->seed(12345);
614        $mapper = new MySqlTypeMapper();
615
616        $column = new ColumnDefinition('col', 'LINESTRING', nullable: false);
617        $value = $mapper->generate($faker, $column);
618
619        self::assertIsString($value);
620        self::assertStringStartsWith('LINESTRING(', $value);
621    }
622
623    #[Test]
624    public function testGeneratePolygon(): void
625    {
626        $faker = Factory::create();
627        $faker->seed(12345);
628        $mapper = new MySqlTypeMapper();
629
630        $column = new ColumnDefinition('col', 'POLYGON', nullable: false);
631        $value = $mapper->generate($faker, $column);
632
633        self::assertIsString($value);
634        self::assertStringStartsWith('POLYGON((', $value);
635    }
636
637    #[Test]
638    public function testGenerateMultiPoint(): void
639    {
640        $faker = Factory::create();
641        $faker->seed(12345);
642        $mapper = new MySqlTypeMapper();
643
644        $column = new ColumnDefinition('col', 'MULTIPOINT', nullable: false);
645        $value = $mapper->generate($faker, $column);
646
647        self::assertIsString($value);
648        self::assertStringStartsWith('MULTIPOINT(', $value);
649    }
650
651    #[Test]
652    public function testGenerateMultiLineString(): void
653    {
654        $faker = Factory::create();
655        $faker->seed(12345);
656        $mapper = new MySqlTypeMapper();
657
658        $column = new ColumnDefinition('col', 'MULTILINESTRING', nullable: false);
659        $value = $mapper->generate($faker, $column);
660
661        self::assertIsString($value);
662        self::assertStringStartsWith('MULTILINESTRING(', $value);
663    }
664
665    #[Test]
666    public function testGenerateMultiPolygon(): void
667    {
668        $faker = Factory::create();
669        $faker->seed(12345);
670        $mapper = new MySqlTypeMapper();
671
672        $column = new ColumnDefinition('col', 'MULTIPOLYGON', nullable: false);
673        $value = $mapper->generate($faker, $column);
674
675        self::assertIsString($value);
676        self::assertStringStartsWith('MULTIPOLYGON(', $value);
677    }
678
679    #[Test]
680    public function testGenerateGeometry(): void
681    {
682        $faker = Factory::create();
683        $faker->seed(12345);
684        $mapper = new MySqlTypeMapper();
685
686        $column = new ColumnDefinition('col', 'GEOMETRY', nullable: false);
687        $value = $mapper->generate($faker, $column);
688
689        self::assertIsString($value);
690        self::assertStringStartsWith('POINT(', $value);
691    }
692
693    #[Test]
694    public function testGenerateGeometryCollection(): void
695    {
696        $faker = Factory::create();
697        $faker->seed(12345);
698        $mapper = new MySqlTypeMapper();
699
700        $column = new ColumnDefinition('col', 'GEOMETRYCOLLECTION', nullable: false);
701        $value = $mapper->generate($faker, $column);
702
703        self::assertIsString($value);
704        self::assertStringStartsWith('GEOMETRYCOLLECTION(', $value);
705    }
706
707    #[Test]
708    public function testGenerateBoolean(): void
709    {
710        $faker = Factory::create();
711        $faker->seed(12345);
712        $mapper = new MySqlTypeMapper();
713
714        $column = new ColumnDefinition('col', 'BOOLEAN', nullable: false);
715        $value = $mapper->generate($faker, $column);
716
717        self::assertIsBool($value);
718    }
719
720    #[Test]
721    public function testGenerateBool(): void
722    {
723        $faker = Factory::create();
724        $faker->seed(12345);
725        $mapper = new MySqlTypeMapper();
726
727        $column = new ColumnDefinition('col', 'BOOL', nullable: false);
728        $value = $mapper->generate($faker, $column);
729
730        self::assertIsBool($value);
731    }
732
733    #[Test]
734    public function testGenerateReal(): void
735    {
736        $faker = Factory::create();
737        $faker->seed(12345);
738        $mapper = new MySqlTypeMapper();
739
740        $column = new ColumnDefinition('col', 'REAL', nullable: false);
741        $value = $mapper->generate($faker, $column);
742
743        self::assertIsFloat($value);
744    }
745
746    #[Test]
747    public function testGenerateNumeric(): void
748    {
749        $faker = Factory::create();
750        $faker->seed(12345);
751        $mapper = new MySqlTypeMapper();
752
753        $column = new ColumnDefinition('col', 'NUMERIC', precision: 8, scale: 2, nullable: false);
754        $value = $mapper->generate($faker, $column);
755
756        self::assertIsFloat($value);
757    }
758
759    #[Test]
760    public function testGenerateInteger(): void
761    {
762        $faker = Factory::create();
763        $faker->seed(12345);
764        $mapper = new MySqlTypeMapper();
765
766        $column = new ColumnDefinition('col', 'INTEGER', nullable: false);
767        $value = $mapper->generate($faker, $column);
768
769        self::assertIsInt($value);
770    }
771
772    #[Test]
773    public function testGenerateUnknownType(): void
774    {
775        $faker = Factory::create();
776        $faker->seed(12345);
777        $mapper = new MySqlTypeMapper();
778
779        $column = new ColumnDefinition('col', 'UNKNOWN_TYPE', nullable: false);
780        $value = $mapper->generate($faker, $column);
781
782        self::assertIsString($value);
783    }
784
785    #[Test]
786    public function testGenerateNullableWithDefaultNull(): void
787    {
788        $faker = Factory::create();
789        $faker->seed(12345);
790        $mapper = new MySqlTypeMapper();
791
792        $column = new ColumnDefinition('col', 'INT', nullable: true, default: null);
793
794        [$hasNull, $hasValue] = (static function () use ($faker, $mapper, $column): array {
795            $hasNull = false;
796            $hasValue = false;
797            for ($i = 0; $i < 100; $i++) {
798                $value = $mapper->generate($faker, $column);
799                if ($value === null) {
800                    $hasNull = true;
801                } else {
802                    $hasValue = true;
803                    self::assertIsInt($value);
804                }
805                if ($hasNull && $hasValue) {
806                    break;
807                }
808            }
809
810            return [$hasNull, $hasValue];
811        })();
812
813        self::assertTrue($hasNull, 'Expected at least one null value in 100 iterations');
814        self::assertTrue($hasValue, 'Expected at least one non-null value in 100 iterations');
815    }
816
817    #[Test]
818    public function testGenerateNonNullableNeverReturnsNull(): void
819    {
820        $faker = Factory::create();
821        $faker->seed(12345);
822        $mapper = new MySqlTypeMapper();
823
824        $column = new ColumnDefinition('col', 'INT', nullable: false);
825
826        (static function () use ($faker, $mapper, $column): void {
827            for ($i = 0; $i < 50; $i++) {
828                $value = $mapper->generate($faker, $column);
829                self::assertNotNull($value, 'Non-nullable column should never return null');
830                self::assertIsInt($value);
831            }
832        })();
833    }
834
835    #[Test]
836    public function testGenerateDecimalBoundaryValues(): void
837    {
838        $faker = Factory::create();
839        $faker->seed(12345);
840        $mapper = new MySqlTypeMapper();
841
842        $column = new ColumnDefinition('col', 'DECIMAL', precision: 5, scale: 2, nullable: false);
843
844        (static function () use ($faker, $mapper, $column): void {
845            for ($i = 0; $i < 50; $i++) {
846                $value = $mapper->generate($faker, $column);
847                self::assertIsFloat($value);
848                self::assertGreaterThanOrEqual(-999.99, $value);
849                self::assertLessThanOrEqual(999.99, $value);
850            }
851        })();
852    }
853
854    #[Test]
855    public function testGenerateIntBoundaryValues(): void
856    {
857        $faker = Factory::create();
858        $faker->seed(12345);
859        $mapper = new MySqlTypeMapper();
860
861        $column = new ColumnDefinition('col', 'INT', nullable: false);
862
863        (static function () use ($faker, $mapper, $column): void {
864            for ($i = 0; $i < 50; $i++) {
865                $value = $mapper->generate($faker, $column);
866                self::assertIsInt($value);
867                self::assertGreaterThanOrEqual(-2147483648, $value);
868                self::assertLessThanOrEqual(2147483647, $value);
869            }
870        })();
871    }
872
873    #[Test]
874    public function testGenerateIntUnsignedBoundaryValues(): void
875    {
876        $faker = Factory::create();
877        $faker->seed(12345);
878        $mapper = new MySqlTypeMapper();
879
880        $column = new ColumnDefinition('col', 'INT', unsigned: true, nullable: false);
881
882        (static function () use ($faker, $mapper, $column): void {
883            for ($i = 0; $i < 50; $i++) {
884                $value = $mapper->generate($faker, $column);
885                self::assertIsInt($value);
886                self::assertGreaterThanOrEqual(0, $value);
887                self::assertLessThanOrEqual(4294967295, $value);
888            }
889        })();
890    }
891
892    #[Test]
893    public function testGenerateVarcharRespectsLength(): void
894    {
895        $faker = Factory::create();
896        $faker->seed(12345);
897        $mapper = new MySqlTypeMapper();
898
899        $column = new ColumnDefinition('col', 'VARCHAR', length: 10, nullable: false);
900
901        (static function () use ($faker, $mapper, $column): void {
902            for ($i = 0; $i < 20; $i++) {
903                $value = $mapper->generate($faker, $column);
904                self::assertIsString($value);
905                self::assertLessThanOrEqual(10, strlen($value));
906                self::assertGreaterThan(0, strlen($value));
907            }
908        })();
909    }
910
911    #[Test]
912    public function testGenerateBitBoundaryValues(): void
913    {
914        $faker = Factory::create();
915        $faker->seed(12345);
916        $mapper = new MySqlTypeMapper();
917
918        $column1 = new ColumnDefinition('col', 'BIT', length: 1, nullable: false);
919        $value = $mapper->generate($faker, $column1);
920        self::assertIsInt($value);
921        self::assertGreaterThanOrEqual(0, $value);
922        self::assertLessThanOrEqual(1, $value);
923
924        $column16 = new ColumnDefinition('col', 'BIT', length: 16, nullable: false);
925        (static function () use ($faker, $mapper, $column16): void {
926            for ($i = 0; $i < 20; $i++) {
927                $value = $mapper->generate($faker, $column16);
928                self::assertIsInt($value);
929                self::assertGreaterThanOrEqual(0, $value);
930                self::assertLessThanOrEqual(65535, $value);
931            }
932        })();
933    }
934
935    #[Test]
936    public function testGenerateYearBoundary(): void
937    {
938        $faker = Factory::create();
939        $faker->seed(12345);
940        $mapper = new MySqlTypeMapper();
941
942        $column = new ColumnDefinition('col', 'YEAR', nullable: false);
943
944        (static function () use ($faker, $mapper, $column): void {
945            for ($i = 0; $i < 50; $i++) {
946                $value = $mapper->generate($faker, $column);
947                self::assertIsInt($value);
948                self::assertGreaterThanOrEqual(1901, $value);
949                self::assertLessThanOrEqual(2155, $value);
950            }
951        })();
952    }
953}
954