packages/sql-faker/tests/Unit/PostgreSql/Generation/Rewrite/GeneratedColumnRuleTest.php
1<?php
2
3declare(strict_types=1);
4
5namespace Tests\Unit\SqlFaker\PostgreSql\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\PostgreSql\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 /**
31 * @param list<string> $when
32 * @param list<string> $expected
33 */
34 #[DataProvider('providerGenerationModes')]
35 public function testRewriteRequiresAlwaysForExpressionsAndPreservesIdentityModes(array $when, string $valueRule, array $expected): void
36 {
37 $trace = new DerivationTrace('ColConstraintElem');
38 $trace->expand(0, new Production([new Terminal('GENERATED'), new NonTerminal('generated_when'), new Terminal('AS'), new NonTerminal($valueRule)]), 0);
39 $trace->expand(1, new Production(array_map(static fn (string $name): Terminal => new Terminal($name), $when)), 0);
40 $trace->expand(2 + count($when), new Production([new Terminal('VALUE')]), 0);
41 $input = $trace->terminals();
42 $rule = new GeneratedColumnRule();
43 $result = $rule->rewrite($input);
44 self::assertSame($expected, $result->names());
45 self::assertSame($input->terminals[count($input->terminals) - 1], $result->terminals[count($result->terminals) - 1]);
46 self::assertSame($input->original, $result->original);
47 self::assertCount(count($result->terminals), array_unique(array_map(static fn ($terminal): int => $terminal->id, $result->terminals)));
48 self::assertSame($input->productions, $result->productions);
49 self::assertSame($result, $rule->rewrite($result));
50 }
51
52 /**
53 * @return iterable<string, array{list<string>, string, list<string>}>
54 */
55 public static function providerGenerationModes(): iterable
56 {
57 yield 'expression by default' => [['BY', 'DEFAULT'], 'a_expr', ['GENERATED', 'ALWAYS', 'AS', 'VALUE']];
58 yield 'expression always' => [['ALWAYS'], 'a_expr', ['GENERATED', 'ALWAYS', 'AS', 'VALUE']];
59 yield 'identity by default' => [['BY', 'DEFAULT'], 'OptParenthesizedSeqOptList', ['GENERATED', 'BY', 'DEFAULT', 'AS', 'VALUE']];
60 yield 'identity always' => [['ALWAYS'], 'OptParenthesizedSeqOptList', ['GENERATED', 'ALWAYS', 'AS', 'VALUE']];
61 yield 'removed timing' => [[], 'a_expr', ['GENERATED', 'AS', 'VALUE']];
62 }
63
64 public function testRewritePreservesOtherColumnConstraints(): void
65 {
66 $trace = new DerivationTrace('ColConstraintElem');
67 $trace->expand(0, new Production([new Terminal('CHECK'), new NonTerminal('a_expr')]), 0);
68 $trace->expand(1, new Production([new Terminal('VALUE')]), 0);
69 $input = $trace->terminals();
70 self::assertSame($input, (new GeneratedColumnRule())->rewrite($input));
71 }
72}
73