packages/sql-parser/tests/Unit/Grammar/SymbolTableTest.php

1<?php
2
3declare(strict_types=1);
4
5namespace Tests\Unit\Grammar;
6
7use PHPUnit\Framework\Attributes\CoversClass;
8use PHPUnit\Framework\Attributes\Small;
9use PHPUnit\Framework\Attributes\UsesClass;
10use PHPUnit\Framework\TestCase;
11use SqlParser\Grammar\GrammarException;
12use SqlParser\Grammar\SymbolTable;
13
14#[CoversClass(SymbolTable::class)]
15#[UsesClass(GrammarException::class)]
16#[Small]
17final class SymbolTableTest extends TestCase
18{
19    public function testId(): void
20    {
21        $table = new SymbolTable(['$end', 'NUM', '+'], ['$accept', 'expr']);
22
23        self::assertSame(0, $table->id('$end'));
24        self::assertSame(2, $table->id('+'));
25        self::assertSame(4, $table->id('expr'));
26        self::assertNull($table->id('missing'));
27    }
28
29    public function testName(): void
30    {
31        $table = new SymbolTable(['$end', 'NUM'], ['$accept', 'expr']);
32
33        self::assertSame('NUM', $table->name(1));
34        self::assertSame('expr', $table->name(3));
35    }
36
37    public function testNameRejectsAnUnknownNumber(): void
38    {
39        $this->expectException(GrammarException::class);
40
41        (new SymbolTable(['$end'], ['$accept']))->name(2);
42    }
43
44    public function testNameRejectsANegativeNumber(): void
45    {
46        $this->expectException(GrammarException::class);
47
48        (new SymbolTable(['$end'], ['$accept']))->name(-1);
49    }
50
51    public function testIsTerminal(): void
52    {
53        $table = new SymbolTable(['$end', 'NUM'], ['$accept', 'expr']);
54
55        self::assertTrue($table->isTerminal(1));
56        self::assertFalse($table->isTerminal(2));
57    }
58
59    public function testTerminalCount(): void
60    {
61        self::assertSame(2, (new SymbolTable(['$end', 'NUM'], ['$accept']))->terminalCount());
62    }
63
64    public function testCount(): void
65    {
66        self::assertSame(4, (new SymbolTable(['$end', 'NUM'], ['$accept', 'expr']))->count());
67    }
68
69    public function testTerminals(): void
70    {
71        self::assertSame(['$end', 'NUM'], (new SymbolTable(['$end', 'NUM'], ['$accept']))->terminals());
72    }
73
74    public function testNonterminals(): void
75    {
76        self::assertSame(['$accept', 'expr'], (new SymbolTable(['$end'], ['$accept', 'expr']))->nonterminals());
77    }
78
79    public function testTerminalsMustStartWithTheEndMarker(): void
80    {
81        $this->expectException(GrammarException::class);
82
83        new SymbolTable(['NUM'], ['$accept']);
84    }
85
86    public function testNamesMustBeUnique(): void
87    {
88        $this->expectException(GrammarException::class);
89
90        new SymbolTable(['$end', 'x'], ['x']);
91    }
92}
93