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