packages/sql-faker/tests/Unit/PostgreSql/Generation/Rewrite/Routine/TableFunctionRuleTest.php

1<?php
2
3declare(strict_types=1);
4
5namespace Tests\Unit\SqlFaker\PostgreSql\Generation\Rewrite\Routine;
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\Grammar\Model\NonTerminal;
13use SqlFaker\Grammar\Model\Production;
14use SqlFaker\Grammar\Model\Terminal;
15use SqlFaker\PostgreSql\Generation\Rewrite\Routine\TableFunctionRule;
16
17#[CoversClass(TableFunctionRule::class)]
18#[UsesClass(DerivationTrace::class)]
19#[UsesClass(NonTerminal::class)]
20#[UsesClass(Production::class)]
21#[UsesClass(Terminal::class)]
22#[UsesClass(\SqlFaker\Generation\Token\ProductionOccurrence::class)]
23#[UsesClass(\SqlFaker\Generation\Token\TerminalOccurrence::class)]
24#[UsesClass(\SqlFaker\Generation\Token\TerminalSequence::class)]
25final class TableFunctionRuleTest extends TestCase
26{
27    /**
28     * @param list<string> $mode
29     * @param list<string> $expected
30     */
31    #[DataProvider('providerModes')]
32    public function testRewriteRestrictsOnlyInputArgumentsOfTableFunctions(array $mode, array $expected, bool $table, string $parameters): void
33    {
34        $trace = new DerivationTrace('CreateFunctionStmt');
35        $trace->expand(0, new Production([new NonTerminal($parameters), new NonTerminal($table ? 'table_func_column_list' : 'func_return')]), 0);
36        $trace->expand(0, new Production([new Terminal('('), new NonTerminal('func_arg'), new Terminal(')')]), 0);
37        $trace->expand(1, new Production([new NonTerminal('arg_class'), new Terminal('IDENT'), new Terminal('INT_P')]), 0);
38        $trace->expand(1, new Production(array_map(static fn (string $name): Terminal => new Terminal($name), $mode)), 0);
39        $trace->expand(count($mode) + 4, new Production([new Terminal('INT_P')]), 0);
40        $input = $trace->terminals();
41        $rule = new TableFunctionRule();
42        $result = $rule->rewrite($input);
43        self::assertSame(['(', ...$expected, 'IDENT', 'INT_P', ')', 'INT_P'], $result->names());
44        self::assertSame($input->original, $result->original);
45        self::assertCount(count($result->terminals), array_unique(array_map(static fn ($terminal): int => $terminal->id, $result->terminals)));
46        self::assertSame($result, $rule->rewrite($result));
47    }
48
49    /**
50     * @return iterable<array{list<string>, list<string>, bool, string}>
51     */
52    public static function providerModes(): iterable
53    {
54        foreach ([['OUT_P'], ['INOUT'], ['IN_P', 'OUT_P']] as $mode) {
55            yield [$mode, ['IN_P'], true, 'func_args_with_defaults'];
56            yield [$mode, $mode, false, 'func_args_with_defaults'];
57            yield [$mode, $mode, true, 'func_args'];
58        }
59        foreach ([[], ['IN_P'], ['VARIADIC']] as $mode) {
60            yield [$mode, $mode, true, 'func_args_with_defaults'];
61        }
62    }
63}
64