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