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