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

1<?php
2
3declare(strict_types=1);
4
5namespace Tests\Unit\SqlFaker\MySql\Generation\Rewrite;
6
7use PHPUnit\Framework\Attributes\CoversClass;
8use PHPUnit\Framework\Attributes\UsesClass;
9use PHPUnit\Framework\TestCase;
10use SqlFaker\Generation\Derivation\DerivationTrace;
11use SqlFaker\Grammar\Model\NonTerminal;
12use SqlFaker\Grammar\Model\Production;
13use SqlFaker\Grammar\Model\Terminal;
14use SqlFaker\MySql\Generation\Rewrite\SetNamesRule;
15
16#[CoversClass(SetNamesRule::class)]
17#[UsesClass(DerivationTrace::class)]
18#[UsesClass(NonTerminal::class)]
19#[UsesClass(Production::class)]
20#[UsesClass(Terminal::class)]
21#[UsesClass(\SqlFaker\Generation\Token\ProductionOccurrence::class)]
22#[UsesClass(\SqlFaker\Generation\Token\TerminalOccurrence::class)]
23#[UsesClass(\SqlFaker\Generation\Token\TerminalSequence::class)]
24final class SetNamesRuleTest extends TestCase
25{
26    public function testRewriteRepairsColonEqualsWithoutChangingOtherAssignments(): void
27    {
28        $trace = new DerivationTrace('option_value_no_option_type');
29        $trace->expand(0, new Production([new Terminal('NAMES_SYM'), new Terminal('SET_VAR'), new Terminal('NUM')]), 0);
30        $input = $trace->terminals();
31        $result = (new SetNamesRule())->rewrite($input);
32        self::assertSame(['NAMES_SYM', 'DEFAULT_SYM'], $result->names());
33        self::assertSame($input->original, $result->original);
34        self::assertSame($input->productions, $result->productions);
35        self::assertSame($result, (new SetNamesRule())->rewrite($result));
36
37        $ordinary = new DerivationTrace('option_value_no_option_type');
38        $ordinary->expand(0, new Production([new Terminal('IDENT'), new Terminal('SET_VAR'), new Terminal('NUM')]), 0);
39        $assignment = $ordinary->terminals();
40        self::assertSame($assignment, (new SetNamesRule())->rewrite($assignment));
41    }
42
43    public function testRewriteUsesTheConfiguredDefaultToken(): void
44    {
45        $trace = new DerivationTrace('option_value_no_option_type');
46        $trace->expand(0, new Production([new Terminal('NAMES_SYM'), new Terminal('EQ'), new Terminal('NUM')]), 0);
47        self::assertSame(['NAMES_SYM', 'DEFAULT'], (new SetNamesRule('DEFAULT'))->rewrite($trace->terminals())->names());
48    }
49
50    public function testRewriteReplacesTheEntireErrorProductionWithoutTouchingAdjacentOptions(): void
51    {
52        $trace = new DerivationTrace('root');
53        $trace->expand(0, new Production([new NonTerminal('option_value_no_option_type'), new Terminal(','), new Terminal('IDENT'), new Terminal('EQ'), new Terminal('NUM')]), 0);
54        $trace->expand(0, new Production([new Terminal('NAMES_SYM'), new Terminal('EQ'), new Terminal('COMPLEX'), new Terminal('EXPR')]), 0);
55        $input = $trace->terminals();
56        $result = (new SetNamesRule())->rewrite($input);
57        self::assertSame(['NAMES_SYM', 'DEFAULT_SYM', ',', 'IDENT', 'EQ', 'NUM'], $result->names());
58        self::assertSame($input->original, $result->original);
59        self::assertCount(count($result->terminals), array_unique(array_map(static fn ($terminal): int => $terminal->id, $result->terminals)));
60        self::assertSame($result, (new SetNamesRule())->rewrite($result));
61    }
62}
63