packages/sql-faker/tests/Unit/MySql/Grammar/MySqlGrammarTest.php

1<?php
2
3declare(strict_types=1);
4
5namespace Tests\Unit\SqlFaker\MySql\Grammar;
6
7use PHPUnit\Framework\Attributes\CoversClass;
8use PHPUnit\Framework\Attributes\UsesClass;
9use PHPUnit\Framework\TestCase;
10use RuntimeException;
11use SqlFaker\Grammar\Model\Grammar;
12use SqlFaker\Grammar\Model\NonTerminal;
13use SqlFaker\Grammar\Model\Production;
14use SqlFaker\Grammar\Model\ProductionRule;
15use SqlFaker\Grammar\Model\Terminal;
16use SqlFaker\Grammar\Resource\SqlVersion;
17use SqlFaker\Grammar\Resource\SqlVersionRegistry;
18use SqlFaker\MySql\Grammar\MySqlGrammar;
19
20#[CoversClass(Grammar::class)]
21#[CoversClass(MySqlGrammar::class)]
22#[CoversClass(NonTerminal::class)]
23#[CoversClass(Production::class)]
24#[CoversClass(ProductionRule::class)]
25#[CoversClass(Terminal::class)]
26#[UsesClass(SqlVersion::class)]
27#[UsesClass(SqlVersionRegistry::class)]
28final class MySqlGrammarTest extends TestCase
29{
30    public function testLoad(): void
31    {
32        $grammar = MySqlGrammar::load();
33
34        self::assertNotEmpty($grammar->ruleMap);
35    }
36
37    public function testLoadWithExplicitVersion(): void
38    {
39        $grammar = MySqlGrammar::load('mysql-8.4.7');
40
41        self::assertNotEmpty($grammar->ruleMap);
42    }
43
44    public function testResolveVersionUsesExactConfiguredDefault(): void
45    {
46        self::assertSame('mysql-8.4.7', MySqlGrammar::resolveVersion());
47        self::assertSame('mysql-8.4.7', MySqlGrammar::resolveVersion('mysql-8.4.7'));
48    }
49
50    public function testLoadWithNonExistentVersionThrows(): void
51    {
52        $this->expectException(RuntimeException::class);
53
54        MySqlGrammar::load('mysql-999.999');
55    }
56
57    public function testLoadedGrammarStructure(): void
58    {
59        $grammar = MySqlGrammar::load();
60
61        self::assertArrayHasKey('start_entry', $grammar->ruleMap);
62        self::assertArrayHasKey('select_stmt', $grammar->ruleMap);
63        self::assertArrayHasKey('insert_stmt', $grammar->ruleMap);
64        self::assertArrayHasKey('update_stmt', $grammar->ruleMap);
65        self::assertArrayHasKey('delete_stmt', $grammar->ruleMap);
66    }
67
68    public function testLoadPreservesCompiledStructure(): void
69    {
70        $grammar = MySqlGrammar::load();
71
72        self::assertSame('start_entry', $grammar->startSymbol);
73        self::assertGreaterThan(100, count($grammar->ruleMap), 'MySQL grammar should have many rules');
74    }
75
76    public function testLoadWithDefaultVersion(): void
77    {
78        $grammar = MySqlGrammar::load(null);
79
80        self::assertSame('start_entry', $grammar->startSymbol);
81    }
82
83    public function testResolveVersionUsesExactConfiguredDefaultPreservesCompiledStructure(): void
84    {
85        self::assertSame('mysql-8.4.7', MySqlGrammar::resolveVersion());
86        self::assertSame('mysql-5.7.44', MySqlGrammar::resolveVersion('mysql-5.7.44'));
87    }
88
89    public function testLoadWithExplicitVersionPreservesCompiledStructure(): void
90    {
91        $grammar = MySqlGrammar::load('mysql-8.4.7');
92
93        self::assertSame('start_entry', $grammar->startSymbol);
94        self::assertGreaterThan(100, count($grammar->ruleMap));
95    }
96
97    public function testLoadWithNonExistentVersionThrowsException(): void
98    {
99        $this->expectException(RuntimeException::class);
100        $this->expectExceptionMessage('Unsupported mysql version');
101
102        MySqlGrammar::load('non-existent-version');
103    }
104
105    public function testLoadedGrammarHasExpectedStructure(): void
106    {
107        $grammar = MySqlGrammar::load();
108
109        self::assertArrayHasKey('select_stmt', $grammar->ruleMap);
110        self::assertArrayHasKey('insert_stmt', $grammar->ruleMap);
111        self::assertArrayHasKey('update_stmt', $grammar->ruleMap);
112        self::assertArrayHasKey('delete_stmt', $grammar->ruleMap);
113        self::assertArrayHasKey('create_table_stmt', $grammar->ruleMap);
114        self::assertArrayHasKey('alter_table_stmt', $grammar->ruleMap);
115        self::assertArrayHasKey('drop_table_stmt', $grammar->ruleMap);
116
117        $selectRule = $grammar->ruleMap['select_stmt'];
118        self::assertSame('select_stmt', $selectRule->lhs);
119        self::assertGreaterThanOrEqual(1, count($selectRule->alternatives));
120    }
121
122    public function testLoadedGrammarVersionsProduceDifferentRuleCounts(): void
123    {
124        $grammar56 = MySqlGrammar::load('mysql-5.6.51');
125        $grammar84 = MySqlGrammar::load('mysql-8.4.7');
126
127        self::assertNotSame(count($grammar56->ruleMap), count($grammar84->ruleMap));
128    }
129
130}
131