packages/sql-faker/tests/Unit/Generation/Derivation/Completion/PatternProductionsTest.php

1<?php
2
3declare(strict_types=1);
4
5namespace Tests\Unit\Generation\Derivation\Completion;
6
7use PHPUnit\Framework\Attributes\CoversClass;
8use PHPUnit\Framework\Attributes\UsesClass;
9use PHPUnit\Framework\TestCase;
10use SqlFaker\Generation\Derivation\Completion\PatternProductions;
11use SqlFaker\Generation\Plan\ProductionPattern;
12use SqlFaker\Grammar\Model\Grammar;
13use SqlFaker\Grammar\Model\NonTerminal;
14use SqlFaker\Grammar\Model\Production;
15use SqlFaker\Grammar\Model\ProductionRule;
16use SqlFaker\Grammar\Model\Terminal;
17
18#[CoversClass(PatternProductions::class)]
19#[UsesClass(ProductionPattern::class)]
20#[UsesClass(Grammar::class)]
21#[UsesClass(Production::class)]
22#[UsesClass(ProductionRule::class)]
23#[UsesClass(Terminal::class)]
24#[UsesClass(NonTerminal::class)]
25final class PatternProductionsTest extends TestCase
26{
27    public function testMatchingSeparatesPatternsAndRuleScopesWhenReusingItsCache(): void
28    {
29        $empty = new Production([]);
30        $output = new Production([new Terminal('T')]);
31        $grammar = new Grammar('root', ['root' => new ProductionRule('root', [$empty, $output]), 'other' => new ProductionRule('other', [$output])]);
32        $choices = new PatternProductions($grammar);
33        self::assertSame([$output], $choices->matching('root', ProductionPattern::at(1)));
34        self::assertSame([$output], $choices->matching('root', ProductionPattern::at(1)));
35        self::assertSame([$empty], $choices->matching('root', ProductionPattern::exactly()));
36        self::assertSame([$empty, $output], $choices->matching('root', null));
37        self::assertSame([], $choices->matching('other', ProductionPattern::at(1)));
38        self::assertSame([], $choices->matching('missing', null));
39    }
40
41    public function testSourceRuleAndMatchingUseOriginalNamesAndOrdinals(): void
42    {
43        $production = new Production([new Terminal('T')], 4);
44        $grammar = new Grammar('@plan0', ['@plan0' => new ProductionRule('@plan0', [$production])], ['@plan0' => 'root']);
45        $choices = new PatternProductions($grammar);
46        self::assertSame('root', $choices->sourceRule('@plan0'));
47        self::assertSame([$production], $choices->matching('@plan0', ProductionPattern::at(4)));
48        self::assertSame([], $choices->matching('@plan0', ProductionPattern::at(0)));
49    }
50
51
52    public function testMatchingUsesSourceSymbolNamesInSpecializedProductions(): void
53    {
54        $production = new Production([new Terminal('SELECT'), new NonTerminal('special')], 3);
55        $grammar = new Grammar('root', [
56            'root' => new ProductionRule('root', [$production]),
57            'special' => new ProductionRule('special', [new Production([new Terminal('ID')])]),
58        ], ['special' => 'name']);
59        $choices = new PatternProductions($grammar);
60        self::assertSame([$production], $choices->matching('root', ProductionPattern::exactly('SELECT', 'name')));
61        self::assertSame([], $choices->matching('root', ProductionPattern::exactly('SELECT', 'special')));
62    }
63
64}
65