packages/sql-faker/tests/Unit/MySql/Generation/Rewrite/Expression/QuantifiedComparisonRuleTest.php

1<?php
2
3declare(strict_types=1);
4
5namespace Tests\Unit\SqlFaker\MySql\Generation\Rewrite\Expression;
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\MySql\Generation\Rewrite\Expression\QuantifiedComparisonRule;
19
20#[CoversClass(QuantifiedComparisonRule::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 QuantifiedComparisonRuleTest extends TestCase
29{
30    #[DataProvider('providerComparisons')]
31    public function testRewriteRestrictsNullSafeEqualityToScalarComparisons(string $scope, string $context, string $operator, string $quantifier, string $expected): void
32    {
33        $trace = new DerivationTrace($scope);
34        $trace->expand(0, new Production([new Terminal('LEFT'), new NonTerminal('comp_op'), new NonTerminal($context), new Terminal('RIGHT')]), 0);
35        $trace->expand(1, new Production([new Terminal($operator)]), 0);
36        $trace->expand(2, new Production([new Terminal($quantifier)]), 0);
37        $input = $trace->terminals();
38        $rule = new QuantifiedComparisonRule();
39        $result = $rule->rewrite($input);
40        self::assertSame(['LEFT', $expected, $quantifier, 'RIGHT'], $result->names());
41        self::assertSame($input->terminals[1]->id, $result->terminals[1]->id);
42        self::assertSame($input->terminals[1]->ancestors, $result->terminals[1]->ancestors);
43        self::assertSame($input->original, $result->original);
44        self::assertSame($input->productions, $result->productions);
45        self::assertSame($result, $rule->rewrite($result));
46    }
47
48    /**
49     * @return iterable<array{string, string, string, string, string}>
50     */
51    public static function providerComparisons(): iterable
52    {
53        foreach (['ALL', 'ANY_SYM'] as $quantifier) {
54            yield ['bool_pri', 'all_or_any', 'EQUAL_SYM', $quantifier, 'EQ'];
55            yield ['bool_pri', 'predicate', 'EQUAL_SYM', $quantifier, 'EQUAL_SYM'];
56            yield ['ordinary', 'all_or_any', 'EQUAL_SYM', $quantifier, 'EQUAL_SYM'];
57            foreach (['EQ', 'GE', 'GT_SYM', 'LE', 'LT', 'NE'] as $operator) {
58                yield ['bool_pri', 'all_or_any', $operator, $quantifier, $operator];
59            }
60        }
61    }
62
63    public function testRewritePreservesAnEmptyOrAbsentOperator(): void
64    {
65        $input = new TerminalSequence([], [], [], [
66            new ProductionOccurrence(0, null, 'bool_pri', 0),
67            new ProductionOccurrence(1, 0, 'all_or_any', 0),
68            new ProductionOccurrence(2, 0, 'comp_op', 0),
69            new ProductionOccurrence(3, null, 'bool_pri', 0),
70            new ProductionOccurrence(4, 3, 'all_or_any', 0),
71        ]);
72        self::assertSame($input, (new QuantifiedComparisonRule())->rewrite($input));
73    }
74}
75