packages/sql-parser/tests/Unit/Table/TableCodecTest.php
1<?php
2
3declare(strict_types=1);
4
5namespace Tests\Unit\Table;
6
7use PHPUnit\Framework\Attributes\CoversClass;
8use PHPUnit\Framework\Attributes\Small;
9use PHPUnit\Framework\Attributes\UsesClass;
10use PHPUnit\Framework\TestCase;
11use RuntimeException;
12use SqlParser\Grammar\SymbolTable;
13use SqlParser\Table\ActionCode;
14use SqlParser\Table\ArrayRows;
15use SqlParser\Table\PackedRows;
16use SqlParser\Table\ParseTable;
17use SqlParser\Table\TableCodec;
18use SqlParser\Table\TableRule;
19
20#[CoversClass(TableCodec::class)]
21#[UsesClass(ActionCode::class)]
22#[UsesClass(ArrayRows::class)]
23#[UsesClass(PackedRows::class)]
24#[UsesClass(ParseTable::class)]
25#[UsesClass(SymbolTable::class)]
26#[UsesClass(TableRule::class)]
27#[Small]
28final class TableCodecTest extends TestCase
29{
30 public function testEncodeAndDecodeRoundTrip(): void
31 {
32 $symbols = new SymbolTable(['$end', 'ID', 'ABORT', 'ANY'], ['$accept', 's']);
33 $table = new ParseTable($symbols, [new TableRule(4, 2, 0), new TableRule(5, 1, 3, true)], [ActionCode::reduce(0), ActionCode::ERROR], new ArrayRows([[1 => 2, 5 => -3], []]), [2 => 1], 3);
34 $codec = new TableCodec();
35 $decoded = $codec->decode($codec->encode($table));
36
37 self::assertSame(['$end', 'ID', 'ABORT', 'ANY'], $decoded->symbols->terminals());
38 self::assertSame(['$accept', 's'], $decoded->symbols->nonterminals());
39 self::assertSame(2, $decoded->rules[0]->length);
40 self::assertTrue($decoded->rules[1]->hidden);
41 self::assertSame(3, $decoded->rules[1]->ordinal);
42 self::assertSame([ActionCode::reduce(0), ActionCode::ERROR], $decoded->defaults);
43 self::assertSame([1 => 2, 5 => -3], $decoded->rows->row(0));
44 self::assertSame([], $decoded->rows->row(1));
45 self::assertSame([2 => 1], $decoded->fallbacks);
46 self::assertSame(3, $decoded->wildcard);
47 }
48
49 public function testDecodeKeepsAMissingWildcard(): void
50 {
51 $codec = new TableCodec();
52 $table = new ParseTable(new SymbolTable(['$end'], ['$accept']), [], [], new ArrayRows([]));
53
54 self::assertNull($codec->decode($codec->encode($table))->wildcard);
55 self::assertSame(0, $codec->decode($codec->encode($table))->stateCount());
56 }
57
58 public function testDecodeRejectsForeignBytes(): void
59 {
60 $this->expectException(RuntimeException::class);
61
62 (new TableCodec())->decode('not a table');
63 }
64
65 public function testEncodeRowSortsBySymbol(): void
66 {
67 $codec = new TableCodec();
68
69 self::assertSame(pack('vv', 1, 5) . pack('ll', 9, 8), $codec->encodeRow([5 => 8, 1 => 9]));
70 }
71
72 public function testIntegers(): void
73 {
74 self::assertSame([1, 65535], TableCodec::integers('v*', pack('vv', 1, 65535)));
75 self::assertSame([], TableCodec::integers('v*', ''));
76 }
77
78 public function testIntegersRejectsPartialValues(): void
79 {
80 $this->expectException(RuntimeException::class);
81
82 TableCodec::integers('l*', 'abc');
83 }
84}
85