packages/sql-faker/tests/Unit/PostgreSql/Generation/Rewrite/Name/ColumnNameRuleTest.php

1<?php
2
3declare(strict_types=1);
4
5namespace Tests\Unit\SqlFaker\PostgreSql\Generation\Rewrite\Name;
6
7use PHPUnit\Framework\Attributes\CoversClass;
8use PHPUnit\Framework\Attributes\DataProvider;
9use PHPUnit\Framework\Attributes\UsesClass;
10use PHPUnit\Framework\TestCase;
11use SqlFaker\Generation\Token\ProductionOccurrence;
12use SqlFaker\Generation\Token\TerminalOccurrence;
13use SqlFaker\Generation\Token\TerminalSequence;
14use SqlFaker\PostgreSql\Generation\Rewrite\Name\ColumnNameRule;
15
16#[CoversClass(ColumnNameRule::class)]
17#[UsesClass(ProductionOccurrence::class)]
18#[UsesClass(TerminalOccurrence::class)]
19#[UsesClass(TerminalSequence::class)]
20#[UsesClass(\SqlFaker\PostgreSql\Generation\Rewrite\Name\ParserNameRule::class)]
21#[UsesClass(\SqlFaker\PostgreSql\Generation\Rewrite\Column\NumericContextRule::class)]
22final class ColumnNameRuleTest extends TestCase
23{
24    /**
25     * @param list<TerminalOccurrence> $terminals
26     * @param list<ProductionOccurrence> $productions
27     * @param list<string> $expected
28     */
29    #[DataProvider('providerChains')]
30    public function testRewriteKeepsTheFinalColumnAndIndependentIndirections(array $terminals, array $productions, array $expected): void
31    {
32        $input = new TerminalSequence($terminals, $terminals, [], $productions);
33        $rule = new ColumnNameRule();
34        $result = $rule->rewrite($input);
35        self::assertSame($expected, $result->names());
36        self::assertSame($input->original, $result->original);
37        self::assertSame($input->productions, $result->productions);
38        self::assertSame($result, $rule->rewrite($result));
39    }
40
41    /**
42     * @return iterable<array{list<TerminalOccurrence>, list<ProductionOccurrence>, list<string>}>
43     */
44    public static function providerChains(): iterable
45    {
46        foreach (['columnref', 'a_expr'] as $context) {
47            foreach ([2, 3, 4, 5] as $count) {
48                foreach ([false, true] as $subscript) {
49                    $terminals = [new TerminalOccurrence('IDENT', 100, [0], [$context])];
50                    $productions = [];
51                    $expected = ['IDENT'];
52                    for ($index = 1; $index <= $count; ++$index) {
53                        $rules = [$context, 'indirection', 'indirection_el'];
54                        $ancestors = [0, 10, $index];
55                        $names = $index === 2 && $subscript ? ['[', 'ICONST', ']'] : ['.', $index === $count ? '*' : 'NAME' . $index];
56                        $productions[] = new ProductionOccurrence($index, 10, 'indirection_el', 0);
57                        foreach ($names as $offset => $name) {
58                            $terminals[] = new TerminalOccurrence($name, $index * 10 + $offset, $ancestors, $rules);
59                        }
60                        if ($context !== 'columnref' || $subscript || $index > $count - 3) {
61                            $expected = [...$expected, ...$names];
62                        }
63                    }
64                    yield [$terminals, $productions, $expected];
65                }
66            }
67        }
68    }
69
70    public function testRewritePreservesAnEmptyIndirection(): void
71    {
72        $input = new TerminalSequence([], [], [], [new ProductionOccurrence(0, null, 'indirection_el', 0)]);
73        self::assertSame($input, (new ColumnNameRule())->rewrite($input));
74    }
75}
76