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