packages/sql-faker/tests/Unit/Sqlite/Generation/GrammarAdaptationTest.php
1<?php
2
3declare(strict_types=1);
4
5namespace Tests\Unit\SqlFaker\Sqlite\Generation;
6
7use PHPUnit\Framework\Attributes\CoversClass;
8use PHPUnit\Framework\Attributes\UsesClass;
9use PHPUnit\Framework\TestCase;
10use SqlFaker\Grammar\Model\Grammar;
11use SqlFaker\Grammar\Model\NonTerminal;
12use SqlFaker\Grammar\Model\Production;
13use SqlFaker\Grammar\Model\ProductionRule;
14use SqlFaker\Grammar\Model\Terminal;
15use SqlFaker\Sqlite\Generation\GrammarAdaptation;
16
17#[CoversClass(GrammarAdaptation::class)]
18#[UsesClass(Grammar::class)]
19#[UsesClass(NonTerminal::class)]
20#[UsesClass(Production::class)]
21#[UsesClass(ProductionRule::class)]
22#[UsesClass(Terminal::class)]
23final class GrammarAdaptationTest extends TestCase
24{
25 public function testAdaptedGivesEachStatementKindARuleOfItsOwn(): void
26 {
27 $grammar = new Grammar('cmd', [
28 'cmd' => new ProductionRule('cmd', [
29 new Production([new Terminal('DELETE'), new Terminal('FROM'), new NonTerminal('nm')]),
30 new Production([new Terminal('UPDATE'), new NonTerminal('nm')]),
31 ]),
32 ]);
33
34 self::assertSame(
35 ['cmd', 'delete', 'update'],
36 array_keys((new GrammarAdaptation())->adapted($grammar)->ruleMap),
37 );
38 }
39
40 public function testAdaptedLeavesAGrammarWithoutACmdRuleAlone(): void
41 {
42 $grammar = new Grammar('expr', ['expr' => new ProductionRule('expr', [new Production([new Terminal('NULL')])])]);
43
44 self::assertSame(['expr'], array_keys((new GrammarAdaptation())->adapted($grammar)->ruleMap));
45 }
46
47 public function testWithStatementRulesPreservesEveryImportedAlternative(): void
48 {
49 $cmd = new ProductionRule('cmd', [
50 new Production([new Terminal('DELETE'), new NonTerminal('orderby_opt')]),
51 ]);
52
53 self::assertSame($cmd->alternatives, (new GrammarAdaptation())->withStatementRules([], $cmd)['delete']->alternatives);
54 }
55
56 public function testStatementAlternativesSortsAnAlternativeByTheKeywordItLeadsWith(): void
57 {
58 $delete = new Production([new Terminal('DELETE'), new NonTerminal('nm')]);
59 $update = new Production([new Terminal('UPDATE'), new NonTerminal('nm')]);
60 $groups = (new GrammarAdaptation())->statementAlternatives(new ProductionRule('cmd', [$delete, $update]));
61
62 self::assertSame([$delete], $groups['delete']);
63 self::assertSame([$update], $groups['update']);
64 }
65
66 public function testStatementAlternativesSortsAnAlternativeThatBeginsWithAnOptionalWithClause(): void
67 {
68 $delete = new Production([new NonTerminal('with'), new Terminal('DELETE')]);
69 $insert = new Production([new NonTerminal('with'), new NonTerminal('insert_cmd')]);
70 $groups = (new GrammarAdaptation())->statementAlternatives(new ProductionRule('cmd', [$delete, $insert]));
71
72 self::assertSame([$delete], $groups['delete']);
73 self::assertSame([$insert], $groups['insert']);
74 }
75
76 public function testStatementAlternativesKeepsAlterAndDropOnlyWhenTheyActOnATable(): void
77 {
78 $alterTable = new Production([new Terminal('ALTER'), new Terminal('TABLE')]);
79 $dropTable = new Production([new Terminal('DROP'), new Terminal('TABLE')]);
80 $dropIndex = new Production([new Terminal('DROP'), new Terminal('INDEX')]);
81 $groups = (new GrammarAdaptation())->statementAlternatives(
82 new ProductionRule('cmd', [$alterTable, $dropTable, $dropIndex]),
83 );
84
85 self::assertSame([$alterTable], $groups['alter_table']);
86 self::assertSame([$dropTable], $groups['drop_table']);
87 }
88}
89