packages/sql-faker/tests/Unit/MySql/Generation/Rewrite/Partition/ListValueRuleTest.php

1<?php
2
3declare(strict_types=1);
4
5namespace Tests\Unit\MySql\Generation\Rewrite\Partition;
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\MySql\Generation\Rewrite\Partition\ListValueRule;
15
16#[CoversClass(ListValueRule::class)]
17#[UsesClass(ProductionOccurrence::class)]
18#[UsesClass(TerminalOccurrence::class)]
19#[UsesClass(TerminalSequence::class)]
20final class ListValueRuleTest extends TestCase
21{
22    #[DataProvider('providerValues')]
23    public function testRewriteDisambiguatesListExpressionsAndPreservesRangeBounds(string $scope, string $first, string $expected): void
24    {
25        $item = new TerminalOccurrence($first, 10, [0, 1], [$scope, 'part_value_item']);
26        $input = new TerminalSequence([$item], productions: [new ProductionOccurrence(0, null, $scope, 0), new ProductionOccurrence(1, 0, 'part_value_item', 0)]);
27        $result = (new ListValueRule())->rewrite($input);
28        self::assertSame($expected === '+' ? ['+', '('] : [$expected], $result->names());
29        self::assertSame($input->original, $result->original);
30        self::assertSame($input->productions, $result->productions);
31        self::assertSame($item->id, $result->terminals[count($result->terminals) - 1]->id);
32        self::assertSame($result, (new ListValueRule())->rewrite($result));
33    }
34
35    /**
36     * @return list<array{string, string, string}>
37     */
38    public static function providerValues(): array
39    {
40        return [['part_values_in', 'MAX_VALUE_SYM', 'NUM'], ['part_func_max', 'MAX_VALUE_SYM', 'MAX_VALUE_SYM'], ['part_values_in', '(', '+'], ['part_func_max', '(', '('], ['part_values_in', 'NUM', 'NUM']];
41    }
42
43    public function testRewritePreservesAnEmptyListItem(): void
44    {
45        $input = new TerminalSequence([], productions: [new ProductionOccurrence(0, null, 'part_value_item', 0)]);
46        self::assertSame($input, (new ListValueRule())->rewrite($input));
47    }
48
49    public function testRewriteDisambiguatesLegacyScalarsWithoutChangingTheirTuple(): void
50    {
51        $tupleOpen = new TerminalOccurrence('(', 10, [0, 1], ['part_values_in', 'part_value_item']);
52        $scalarOpen = new TerminalOccurrence('(', 11, [0, 1, 2], ['part_values_in', 'part_value_item', 'part_value_expr_item']);
53        $value = new TerminalOccurrence('NUM', 12, [0, 1, 2], ['part_values_in', 'part_value_item', 'part_value_expr_item']);
54        $scalarClose = new TerminalOccurrence(')', 13, [0, 1, 2], ['part_values_in', 'part_value_item', 'part_value_expr_item']);
55        $tupleClose = new TerminalOccurrence(')', 14, [0, 1], ['part_values_in', 'part_value_item']);
56        $input = new TerminalSequence([$tupleOpen, $scalarOpen, $value, $scalarClose, $tupleClose], productions: [new ProductionOccurrence(0, null, 'part_values_in', 0), new ProductionOccurrence(1, 0, 'part_value_item', 0), new ProductionOccurrence(2, 1, 'part_value_expr_item', 0)]);
57        $rule = new ListValueRule('part_value_expr_item');
58        $result = $rule->rewrite($input);
59        self::assertSame(['(', '+', '(', 'NUM', ')', ')'], $result->names());
60        self::assertSame($tupleOpen, $result->terminals[0]);
61        self::assertSame($tupleClose, $result->terminals[5]);
62        self::assertSame($result, $rule->rewrite($result));
63    }
64}
65