packages/sql-faker/tests/Unit/PostgreSql/Generation/Lookahead/PgLookaheadTest.php

1<?php
2
3declare(strict_types=1);
4
5namespace Tests\Unit\SqlFaker\PostgreSql\Generation\Lookahead;
6
7use PHPUnit\Framework\Attributes\CoversClass;
8use PHPUnit\Framework\Attributes\DataProvider;
9use PHPUnit\Framework\TestCase;
10use SqlFaker\PostgreSql\Generation\Lookahead\PgLookahead;
11
12#[CoversClass(PgLookahead::class)]
13#[\PHPUnit\Framework\Attributes\UsesClass(\SqlFaker\Generation\Derivation\CompletionCosts::class)]
14#[\PHPUnit\Framework\Attributes\UsesClass(\SqlFaker\Generation\Derivation\DerivationNode::class)]
15final class PgLookaheadTest extends TestCase
16{
17    #[DataProvider('providerLookahead')]
18    public function testAppliedSubstitutesWhenTheFollowerCallsForIt(PgLookahead $lookahead): void
19    {
20        self::assertSame(['NOT_LA', 'NULL_P'], $lookahead->applied(['NOT', 'NULL_P']));
21    }
22
23    #[DataProvider('providerLookahead')]
24    public function testAppliedLeavesTheTokenAloneForAnotherFollower(PgLookahead $lookahead): void
25    {
26        self::assertSame(['NOT', 'IDENT'], $lookahead->applied(['NOT', 'IDENT']));
27    }
28
29    #[DataProvider('providerLookahead')]
30    public function testAppliedLeavesTheLastTokenAloneBecauseNothingFollowsIt(PgLookahead $lookahead): void
31    {
32        self::assertSame(['NOT'], $lookahead->applied(['NOT']));
33    }
34
35    #[DataProvider('providerLookahead')]
36    public function testAppliedLeavesATokenThatTriggersNothing(PgLookahead $lookahead): void
37    {
38        self::assertSame(['SELECT', 'IDENT'], $lookahead->applied(['SELECT', 'IDENT']));
39    }
40
41    #[DataProvider('providerLookahead')]
42    public function testNormalizedSettlesTheBaseTokenOnItsSubstitute(PgLookahead $lookahead): void
43    {
44        self::assertSame(['NOT_LA', 'NULL_P'], $lookahead->normalized(['NOT', 'NULL_P']));
45    }
46
47    #[DataProvider('providerLookahead')]
48    public function testNormalizedWalksASubstitutionBackWhenTheFollowerDoesNotCallForIt(
49        PgLookahead $lookahead,
50    ): void {
51        self::assertSame(['NOT', 'IDENT'], $lookahead->normalized(['NOT_LA', 'IDENT']));
52    }
53
54    #[DataProvider('providerLookahead')]
55    public function testNormalizedLeavesATerminalThatTriggersNothing(PgLookahead $lookahead): void
56    {
57        self::assertSame(['SELECT', 'IDENT'], $lookahead->normalized(['SELECT', 'IDENT']));
58    }
59
60    #[DataProvider('providerLookahead')]
61    public function testBaseOfReportsTheTokenASubstituteIsSpelledAs(PgLookahead $lookahead): void
62    {
63        self::assertSame('NOT', $lookahead->baseOf('NOT_LA'));
64    }
65
66    #[DataProvider('providerLookahead')]
67    public function testBaseOfReportsNothingForATokenThatSubstitutesForNone(PgLookahead $lookahead): void
68    {
69        self::assertNull($lookahead->baseOf('SELECT'));
70    }
71
72    public function testAppliedFindsNothingToDoWithoutRules(): void
73    {
74        self::assertSame(['NOT', 'NULL_P'], (new PgLookahead([]))->applied(['NOT', 'NULL_P']));
75    }
76
77    /**
78     * @return iterable<string, array{PgLookahead}>
79     */
80    public static function providerLookahead(): iterable
81    {
82        yield 'NOT before NULL' => [new PgLookahead([
83            'NOT' => ['token' => 'NOT_LA', 'followed_by' => ['NULL_P', 'IN_P']],
84        ])];
85    }
86
87    public function testDefinitionsKeepsTheParserLookaheadFollowersExplicit(): void
88    {
89        $definitions = PgLookahead::definitions();
90        self::assertSame('WITH_LA', $definitions['WITH']['token']);
91        self::assertSame(['TIME', 'ORDINALITY'], $definitions['WITH']['followed_by']);
92    }
93
94}
95