packages/sql-faker/tests/Unit/MySql/Generation/Rewrite/GeneratedColumnRuleTest.php
1<?php
2
3declare(strict_types=1);
4
5namespace Tests\Unit\SqlFaker\MySql\Generation\Rewrite;
6
7use PHPUnit\Framework\Attributes\CoversClass;
8use PHPUnit\Framework\Attributes\DataProvider;
9use PHPUnit\Framework\Attributes\UsesClass;
10use PHPUnit\Framework\TestCase;
11use SqlFaker\Generation\Derivation\DerivationTrace;
12use SqlFaker\Generation\Token\ProductionOccurrence;
13use SqlFaker\Generation\Token\TerminalOccurrence;
14use SqlFaker\Generation\Token\TerminalSequence;
15use SqlFaker\Grammar\Model\NonTerminal;
16use SqlFaker\Grammar\Model\Production;
17use SqlFaker\Grammar\Model\Terminal;
18use SqlFaker\MySql\Generation\Rewrite\GeneratedColumnRule;
19
20#[CoversClass(GeneratedColumnRule::class)]
21#[UsesClass(DerivationTrace::class)]
22#[UsesClass(TerminalSequence::class)]
23#[UsesClass(TerminalOccurrence::class)]
24#[UsesClass(ProductionOccurrence::class)]
25#[UsesClass(NonTerminal::class)]
26#[UsesClass(Production::class)]
27#[UsesClass(Terminal::class)]
28final class GeneratedColumnRuleTest extends TestCase
29{
30 public function testRewriteConvertsSerialOnlyOnGeneratedFields(): void
31 {
32 $trace = new DerivationTrace('field_def');
33 $trace->expand(0, new Production([new NonTerminal('type'), new Terminal('AS'), new NonTerminal('expr')]), 1);
34 $trace->expand(0, new Production([new Terminal('SERIAL_SYM')]), 0);
35 $trace->expand(2, new Production([new Terminal('NUM')]), 0);
36 $input = $trace->terminals();
37 $rule = new GeneratedColumnRule();
38 $result = $rule->rewrite($input);
39 self::assertSame(['BIGINT_SYM', 'UNSIGNED_SYM', 'AS', 'NUM'], $result->names());
40 self::assertSame($input->terminals[2], $result->terminals[3]);
41 self::assertSame($input->terminals[0]->id, $result->terminals[0]->id);
42 self::assertSame($input->original, $result->original);
43 self::assertCount(count($result->terminals), array_unique(array_map(static fn ($terminal): int => $terminal->id, $result->terminals)));
44 self::assertSame($result, $rule->rewrite($result));
45 }
46
47 /**
48 * @param list<string> $attribute
49 * @param list<string> $expected
50 */
51 #[DataProvider('providerAttributes')]
52 public function testRewriteRemovesOnlyAttributesForbiddenOnGeneratedFields(array $attribute, array $expected): void
53 {
54 $trace = new DerivationTrace('field_def');
55 $trace->expand(0, new Production([new NonTerminal('type'), new Terminal('AS'), new NonTerminal('expr'), new NonTerminal('column_attribute')]), 1);
56 $trace->expand(0, new Production([new Terminal('INT_SYM')]), 0);
57 $trace->expand(2, new Production([new Terminal('NUM')]), 0);
58 $trace->expand(3, new Production(array_map(static fn (string $name): Terminal => new Terminal($name), $attribute)), 0);
59 $input = $trace->terminals();
60 $rule = new GeneratedColumnRule();
61 $result = $rule->rewrite($input);
62 self::assertSame(['INT_SYM', 'AS', 'NUM', ...$expected], $result->names());
63 self::assertSame($input->original, $result->original);
64 self::assertCount(count($result->terminals), array_unique(array_map(static fn ($terminal): int => $terminal->id, $result->terminals)));
65 self::assertSame($input->productions, $result->productions);
66 self::assertSame($result, $rule->rewrite($result));
67 }
68
69 /**
70 * @return iterable<string, array{list<string>, list<string>}>
71 */
72 public static function providerAttributes(): iterable
73 {
74 yield 'default' => [['DEFAULT_SYM', 'NUM'], []];
75 yield 'on update' => [['ON_SYM', 'UPDATE_SYM', 'NOW_SYM'], []];
76 yield 'auto increment' => [['AUTO_INC'], []];
77 yield 'serial default' => [['SERIAL_SYM', 'DEFAULT_SYM', 'VALUE_SYM'], []];
78 yield 'format' => [['COLUMN_FORMAT_SYM', 'DEFAULT_SYM'], []];
79 yield 'storage' => [['STORAGE_SYM', 'DISK_SYM'], []];
80 yield 'not null' => [['NOT_SYM', 'NULL_SYM'], ['NOT_SYM', 'NULL_SYM']];
81 yield 'comment' => [['COMMENT_SYM', 'TEXT_STRING'], ['COMMENT_SYM', 'TEXT_STRING']];
82 yield 'removed attribute' => [[], []];
83 }
84
85 public function testRewritePreservesOrdinarySerialFieldsAndTheirDefaults(): void
86 {
87 $trace = new DerivationTrace('field_def');
88 $trace->expand(0, new Production([new NonTerminal('type'), new NonTerminal('column_attribute')]), 0);
89 $trace->expand(0, new Production([new Terminal('SERIAL_SYM')]), 0);
90 $trace->expand(1, new Production([new Terminal('DEFAULT_SYM'), new Terminal('NUM')]), 0);
91 $input = $trace->terminals();
92 self::assertSame($input, (new GeneratedColumnRule())->rewrite($input));
93 }
94}
95