packages/sql-faker/tests/Unit/PostgreSql/Generation/Rewrite/Routine/SubstringRuleTest.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\Token\ProductionOccurrence;
12use SqlFaker\Generation\Token\TerminalOccurrence;
13use SqlFaker\Generation\Token\TerminalSequence;
14use SqlFaker\PostgreSql\Generation\Rewrite\Routine\SubstringRule;
15
16#[CoversClass(SubstringRule::class)]
17#[UsesClass(ProductionOccurrence::class)]
18#[UsesClass(TerminalOccurrence::class)]
19#[UsesClass(TerminalSequence::class)]
20final class SubstringRuleTest extends TestCase
21{
22    #[DataProvider('providerArguments')]
23    public function testRewriteKeepsSubstringSeparatorsOutsideCompoundArguments(TerminalSequence $input, string $expected): void
24    {
25        $rule = new SubstringRule();
26        $result = $rule->rewrite($input);
27        self::assertSame(explode(' ', $expected), $result->names());
28        self::assertSame($input->original, $result->original);
29        self::assertSame($input->productions, $result->productions);
30        self::assertSame($input->terminals, array_values(array_filter($result->terminals, static fn (TerminalOccurrence $token): bool => $token->id >= 0)));
31        self::assertCount(count($result->terminals), array_unique(array_column($result->terminals, 'id')));
32        self::assertSame($result, $rule->rewrite($result));
33    }
34
35    /**
36     * @return iterable<array{TerminalSequence, string}>
37     */
38    public static function providerArguments(): iterable
39    {
40        foreach (['substr_list', 'func_arg_list'] as $scope) {
41            $tokens = [];
42            foreach ([1 => 'DEFAULT IS NOT DISTINCT FROM DEFAULT', 0 => 'SIMILAR', 2 => 'DEFAULT LIKE DEFAULT', 4 => 'ESCAPE', 3 => 'DEFAULT'] as $id => $text) {
43                foreach (explode(' ', $text) as $name) {
44                    $tokens[] = new TerminalOccurrence($name, count($tokens), $id === 0 || $id === 4 ? [0] : [0, $id], $id === 0 || $id === 4 ? [$scope] : [$scope, 'a_expr']);
45                }
46            }
47            $productions = [new ProductionOccurrence(0, null, $scope, 0), new ProductionOccurrence(1, 0, 'a_expr', 0), new ProductionOccurrence(2, 0, 'a_expr', 0), new ProductionOccurrence(3, 0, 'a_expr', 0)];
48            yield [new TerminalSequence($tokens, $tokens, productions: $productions), $scope === 'substr_list' ? '( DEFAULT IS NOT DISTINCT FROM DEFAULT ) SIMILAR ( DEFAULT LIKE DEFAULT ) ESCAPE DEFAULT' : 'DEFAULT IS NOT DISTINCT FROM DEFAULT SIMILAR DEFAULT LIKE DEFAULT ESCAPE DEFAULT'];
49        }
50    }
51
52    public function testRewritePreservesAnEmptyArgument(): void
53    {
54        $input = new TerminalSequence([], productions: [new ProductionOccurrence(0, null, 'substr_list', 0), new ProductionOccurrence(1, 0, 'a_expr', 0)]);
55        self::assertSame($input, (new SubstringRule())->rewrite($input));
56    }
57}
58