packages/sql-faker/tests/Unit/Sqlite/Generation/Rewrite/GeneratedColumnRuleTest.php

1<?php
2
3declare(strict_types=1);
4
5namespace Tests\Unit\SqlFaker\Sqlite\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\Sqlite\Generation\Rewrite\GeneratedColumnRule;
19
20#[CoversClass(GeneratedColumnRule::class)]
21#[UsesClass(DerivationTrace::class)]
22#[UsesClass(ProductionOccurrence::class)]
23#[UsesClass(TerminalOccurrence::class)]
24#[UsesClass(TerminalSequence::class)]
25#[UsesClass(NonTerminal::class)]
26#[UsesClass(Production::class)]
27#[UsesClass(Terminal::class)]
28final class GeneratedColumnRuleTest extends TestCase
29{
30    /**
31     * @param list<string> $expected
32     */
33    #[DataProvider('providerConstraints')]
34    public function testRewriteKeepsOneGeneratedExpressionWithoutDefaults(TerminalSequence $input, array $expected): void
35    {
36        $rule = new GeneratedColumnRule();
37        $result = $rule->rewrite($input);
38        self::assertSame($expected, $result->names());
39        self::assertSame($input->original, $result->original);
40        self::assertSame($input->productions, $result->productions);
41        self::assertSame($result, $rule->rewrite($result));
42    }
43
44    /**
45     * @return iterable<array{TerminalSequence, list<string>}>
46     */
47    public static function providerConstraints(): iterable
48    {
49        foreach (['column', 'carglist'] as $scope) {
50            foreach ([['AS', 'AS'], ['DEFAULT', 'AS'], ['AS', 'DEFAULT'], ['DEFAULT', 'DEFAULT'], ['AS', 'NULL', 'AS', 'DEFAULT']] as $clauses) {
51                $trace = new DerivationTrace($scope);
52                $trace->expand(0, new Production(array_fill(0, count($clauses), new NonTerminal('ccons'))), 0);
53                $position = 0;
54                $expected = [];
55                $seen = false;
56                foreach ($clauses as $index => $clause) {
57                    if ($clause === 'AS') {
58                        $trace->expand($position, new Production([new Terminal('AS'), new NonTerminal('generated')]), 0);
59                        $trace->expand($position + 1, new Production([new Terminal('LP'), new Terminal('VALUE_' . $index), new Terminal('RP')]), 0);
60                        if (!$seen) {
61                            array_push($expected, 'AS', 'LP', 'VALUE_' . $index, 'RP');
62                        }
63                        $seen = true;
64                        $position += 4;
65                    } else {
66                        $trace->expand($position, new Production([new Terminal($clause)]), 0);
67                        if ($clause !== 'DEFAULT' || !in_array('AS', $clauses, true)) {
68                            $expected[] = $clause;
69                        }
70                        ++$position;
71                    }
72                }
73                yield [$trace->terminals(), $expected];
74            }
75        }
76    }
77
78    public function testRewriteKeepsGeneratedExpressionsOnSeparateColumns(): void
79    {
80        $trace = new DerivationTrace('table');
81        $trace->expand(0, new Production([new NonTerminal('column'), new Terminal('COMMA'), new NonTerminal('column')]), 0);
82        $trace->expand(0, new Production([new NonTerminal('ccons')]), 0);
83        $trace->expand(0, new Production([new Terminal('AS'), new NonTerminal('generated')]), 0);
84        $trace->expand(1, new Production([new Terminal('FIRST')]), 0);
85        $trace->expand(3, new Production([new NonTerminal('ccons')]), 0);
86        $trace->expand(3, new Production([new Terminal('AS'), new NonTerminal('generated')]), 0);
87        $trace->expand(4, new Production([new Terminal('SECOND')]), 0);
88        $input = $trace->terminals();
89        self::assertSame($input, (new GeneratedColumnRule())->rewrite($input));
90    }
91}
92