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