packages/sql-parser/tests/Unit/MySql/Lexer/VariableScannerTest.php
1<?php
2
3declare(strict_types=1);
4
5namespace Tests\Unit\MySql\Lexer;
6
7use PHPUnit\Framework\Attributes\CoversClass;
8use PHPUnit\Framework\Attributes\Small;
9use PHPUnit\Framework\Attributes\UsesClass;
10use PHPUnit\Framework\TestCase;
11use SqlParser\Lexer\Cursor;
12use SqlParser\Lexer\Lexeme;
13use SqlParser\Lexer\LexicalException;
14use SqlParser\MySql\Lexer\KeywordTable;
15use SqlParser\MySql\Lexer\LexerState;
16use SqlParser\MySql\Lexer\Scan;
17use SqlParser\MySql\Lexer\VariableScanner;
18use SqlParser\MySql\Lexer\WordScanner;
19use SqlParser\MySql\MySqlVersion;
20use SqlParser\MySql\SqlMode;
21
22#[CoversClass(VariableScanner::class)]
23#[UsesClass(Cursor::class)]
24#[UsesClass(Lexeme::class)]
25#[UsesClass(LexicalException::class)]
26#[UsesClass(KeywordTable::class)]
27#[UsesClass(MySqlVersion::class)]
28#[UsesClass(Scan::class)]
29#[UsesClass(SqlMode::class)]
30#[UsesClass(WordScanner::class)]
31#[UsesClass(\SqlParser\Lexer\SourcePosition::class)]
32#[UsesClass(\SqlParser\Resource\SqlVersion::class)]
33#[UsesClass(\SqlParser\Resource\VersionRegistry::class)]
34#[UsesClass(\SqlParser\Lexer\SourceException::class)]
35#[Small]
36final class VariableScannerTest extends TestCase
37{
38 public function testAt(): void
39 {
40 $scanner = new VariableScanner();
41 $scan = static fn (string $sql): Scan => new Scan(new Cursor($sql), new KeywordTable([], []), new SqlMode(), MySqlVersion::resolve());
42 $host = $scan('@localhost');
43 $system = $scan('@@x');
44 $quoted = $scan("@'x'");
45
46 self::assertSame('@', $scanner->at($host)->name);
47 self::assertSame(LexerState::Hostname, $host->next);
48 $scanner->at($system);
49 self::assertSame(LexerState::SystemVariable, $system->next);
50 $scanner->at($quoted);
51 self::assertSame(LexerState::Start, $quoted->next);
52 }
53
54 public function testHostname(): void
55 {
56 $scanner = new VariableScanner();
57 $named = new Scan(new Cursor('host.example$1 x'), new KeywordTable([], []), new SqlMode(), MySqlVersion::resolve());
58 $empty = new Scan(new Cursor(' x'), new KeywordTable([], []), new SqlMode(), MySqlVersion::resolve());
59
60 self::assertSame('host.example$1', $scanner->hostname($named)->text);
61 self::assertSame(LexerState::Start, $named->next);
62 self::assertSame('', $scanner->hostname($empty)->text);
63 self::assertSame('LEX_HOSTNAME', $scanner->hostname($empty)->name);
64 }
65
66 public function testSystemVariable(): void
67 {
68 $scanner = new VariableScanner();
69 $named = new Scan(new Cursor('@sql_mode'), new KeywordTable([], []), new SqlMode(), MySqlVersion::resolve());
70 $quoted = new Scan(new Cursor('@`x`'), new KeywordTable([], []), new SqlMode(), MySqlVersion::resolve());
71
72 self::assertSame('@', $scanner->systemVariable($named)->name);
73 self::assertSame(LexerState::IdentifierOrKeyword, $named->next);
74 $scanner->systemVariable($quoted);
75 self::assertSame(LexerState::Start, $quoted->next);
76 }
77
78 public function testIdentifierOrKeyword(): void
79 {
80 $scanner = new VariableScanner();
81 $keywords = new KeywordTable(['GLOBAL' => 'GLOBAL_SYM'], []);
82 $qualified = new Scan(new Cursor('global.x'), $keywords, new SqlMode(), MySqlVersion::resolve());
83 $plain = new Scan(new Cursor('sql_mode '), $keywords, new SqlMode(), MySqlVersion::resolve());
84
85 self::assertSame('GLOBAL_SYM', $scanner->identifierOrKeyword($qualified, new WordScanner())->name);
86 self::assertSame(LexerState::IdentifierSeparator, $qualified->next);
87 self::assertSame('IDENT', $scanner->identifierOrKeyword($plain, new WordScanner())->name);
88 self::assertSame(LexerState::Start, $plain->next);
89 }
90
91 public function testIdentifierOrKeywordRejectsAMissingName(): void
92 {
93 $this->expectException(LexicalException::class);
94
95 (new VariableScanner())->identifierOrKeyword(new Scan(new Cursor(' '), new KeywordTable([], []), new SqlMode(), MySqlVersion::resolve()), new WordScanner());
96 }
97}
98