packages/sql-faker/tests/Unit/Compiler/Bison/BisonPreambleReaderTest.php
1<?php
2
3declare(strict_types=1);
4
5namespace Tests\Unit\SqlFaker\Compiler\Bison;
6
7use PHPUnit\Framework\Attributes\CoversClass;
8use PHPUnit\Framework\Attributes\UsesClass;
9use PHPUnit\Framework\TestCase;
10use SqlFaker\Compiler\Bison\Ast\BisonStartDeclaration;
11use SqlFaker\Compiler\Bison\Ast\BisonTokenDeclaration;
12use SqlFaker\Compiler\Bison\Ast\BisonTokenDefinition;
13use SqlFaker\Compiler\Bison\Ast\BisonUnknownDeclaration;
14use SqlFaker\Compiler\Bison\BisonPreamble;
15use SqlFaker\Compiler\Bison\BisonPreambleReader;
16use SqlFaker\Compiler\Bison\Directive\BisonDeclarationBoundary;
17use SqlFaker\Compiler\Bison\Directive\BisonDirectiveReaderChain;
18use SqlFaker\Compiler\Bison\Directive\DefineDirectiveReader;
19use SqlFaker\Compiler\Bison\Directive\ExpectDirectiveReader;
20use SqlFaker\Compiler\Bison\Directive\ParamDirectiveReader;
21use SqlFaker\Compiler\Bison\Directive\PrecedenceDirectiveReader;
22use SqlFaker\Compiler\Bison\Directive\StartDirectiveReader;
23use SqlFaker\Compiler\Bison\Directive\TokenDirectiveReader;
24use SqlFaker\Compiler\Bison\Directive\TypeDirectiveReader;
25use SqlFaker\Compiler\Bison\Directive\UnknownDirectiveReader;
26use SqlFaker\Compiler\Bison\Lexer\ActionScanner;
27use SqlFaker\Compiler\Bison\Lexer\BisonLexeme;
28use SqlFaker\Compiler\Bison\Lexer\BisonLexer;
29use SqlFaker\Compiler\Bison\Lexer\BisonScannerChain;
30use SqlFaker\Compiler\Bison\Lexer\BisonToken;
31use SqlFaker\Compiler\Bison\Lexer\BisonTokenStream;
32use SqlFaker\Compiler\Bison\Lexer\BisonTrivia;
33use SqlFaker\Compiler\Bison\Lexer\DirectiveScanner;
34use SqlFaker\Compiler\Bison\Lexer\IdentifierScanner;
35use SqlFaker\Compiler\Bison\Lexer\NumberScanner;
36use SqlFaker\Compiler\Bison\Lexer\QuotedLiteralScanner;
37use SqlFaker\Compiler\Bison\Lexer\SourceCursor;
38use SqlFaker\Compiler\Bison\Lexer\TypeTagScanner;
39
40#[CoversClass(BisonPreambleReader::class)]
41#[UsesClass(BisonDeclarationBoundary::class)]
42#[UsesClass(BisonDirectiveReaderChain::class)]
43#[UsesClass(BisonLexeme::class)]
44#[UsesClass(BisonLexer::class)]
45#[UsesClass(BisonPreamble::class)]
46#[UsesClass(BisonScannerChain::class)]
47#[UsesClass(BisonStartDeclaration::class)]
48#[UsesClass(BisonToken::class)]
49#[UsesClass(BisonTokenDeclaration::class)]
50#[UsesClass(BisonTokenDefinition::class)]
51#[UsesClass(BisonTokenStream::class)]
52#[UsesClass(BisonTrivia::class)]
53#[UsesClass(BisonUnknownDeclaration::class)]
54#[UsesClass(DefineDirectiveReader::class)]
55#[UsesClass(ExpectDirectiveReader::class)]
56#[UsesClass(ParamDirectiveReader::class)]
57#[UsesClass(PrecedenceDirectiveReader::class)]
58#[UsesClass(SourceCursor::class)]
59#[UsesClass(StartDirectiveReader::class)]
60#[UsesClass(TokenDirectiveReader::class)]
61#[UsesClass(TypeDirectiveReader::class)]
62#[UsesClass(UnknownDirectiveReader::class)]
63#[UsesClass(ActionScanner::class)]
64#[UsesClass(DirectiveScanner::class)]
65#[UsesClass(IdentifierScanner::class)]
66#[UsesClass(NumberScanner::class)]
67#[UsesClass(QuotedLiteralScanner::class)]
68#[UsesClass(TypeTagScanner::class)]
69#[UsesClass(\SqlFaker\Compiler\Bison\Ast\BisonDefineDeclaration::class)]
70#[UsesClass(\SqlFaker\Compiler\Bison\Ast\BisonExpectDeclaration::class)]
71#[UsesClass(\SqlFaker\Compiler\Bison\Ast\BisonParamDeclaration::class)]
72#[UsesClass(\SqlFaker\Compiler\Bison\Ast\BisonPrecedenceDeclaration::class)]
73#[UsesClass(\SqlFaker\Compiler\Bison\Ast\BisonTypeDeclaration::class)]
74#[UsesClass(\SqlFaker\Compiler\Bison\Lexer\PunctuationScanner::class)]
75#[UsesClass(\SqlFaker\Compiler\GrammarParseException::class)]
76final class BisonPreambleReaderTest extends TestCase
77{
78 public function testReadTakesThePrologueAndTheDeclarations(): void
79 {
80 $preamble = (new BisonPreambleReader())->read(
81 BisonTokenStream::over("%{ int x; %}\n%start statement\n%token IDENT\n%%"),
82 );
83
84 self::assertSame(' int x; ', $preamble->prologue);
85 self::assertCount(2, $preamble->declarations);
86 self::assertInstanceOf(BisonStartDeclaration::class, $preamble->declarations[0]);
87 self::assertInstanceOf(BisonTokenDeclaration::class, $preamble->declarations[1]);
88 }
89
90 public function testReadReportsNoPrologueWhenTheFileHasNone(): void
91 {
92 $preamble = (new BisonPreambleReader())->read(BisonTokenStream::over("%start statement\n%%"));
93
94 self::assertNull($preamble->prologue);
95 }
96
97 public function testReadConsumesTheSectionSeparatorSoTheRulesFollow(): void
98 {
99 $stream = BisonTokenStream::over("%start statement\n%%\nexpr : a ;");
100
101 (new BisonPreambleReader())->read($stream);
102
103 self::assertSame('expr', $stream->next()->value);
104 }
105
106 public function testReadStopsAtTheEndOfAFileWithoutASeparator(): void
107 {
108 $preamble = (new BisonPreambleReader())->read(BisonTokenStream::over('%start statement'));
109
110 self::assertCount(1, $preamble->declarations);
111 }
112
113 public function testReadDropsADeclarationWhoseArgumentsDoNotFitItsDirective(): void
114 {
115 $preamble = (new BisonPreambleReader())->read(BisonTokenStream::over("%start\n%%"));
116
117 self::assertSame([], $preamble->declarations);
118 }
119
120 public function testReadKeepsADirectiveItHasNoModelFor(): void
121 {
122 $preamble = (new BisonPreambleReader())->read(BisonTokenStream::over("%glr-parser\n%%"));
123
124 self::assertCount(1, $preamble->declarations);
125 self::assertInstanceOf(BisonUnknownDeclaration::class, $preamble->declarations[0]);
126 }
127
128 public function testReadKeepsTheLastPrologueWhenAFileHasSeveral(): void
129 {
130 $preamble = (new BisonPreambleReader())->read(
131 BisonTokenStream::over('%{ first %} %{ second %} %%'),
132 );
133
134 self::assertSame(' second ', $preamble->prologue);
135 }
136
137 public function testReadUsesTheDirectiveChainItWasGiven(): void
138 {
139 $reader = new BisonPreambleReader(new BisonDirectiveReaderChain([new StartDirectiveReader()]));
140
141 $preamble = $reader->read(BisonTokenStream::over("%start statement\n%glr-parser\n%%"));
142
143 self::assertCount(1, $preamble->declarations);
144 self::assertInstanceOf(BisonStartDeclaration::class, $preamble->declarations[0]);
145 }
146}
147