packages/sql-parser/tests/Unit/MySql/Lexer/NumberScannerTest.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\MySql\Lexer\KeywordTable;
14use SqlParser\MySql\Lexer\LexerState;
15use SqlParser\MySql\Lexer\NumberScanner;
16use SqlParser\MySql\Lexer\Scan;
17use SqlParser\MySql\Lexer\WordScanner;
18use SqlParser\MySql\MySqlVersion;
19use SqlParser\MySql\SqlMode;
20
21#[CoversClass(NumberScanner::class)]
22#[UsesClass(Cursor::class)]
23#[UsesClass(Lexeme::class)]
24#[UsesClass(KeywordTable::class)]
25#[UsesClass(MySqlVersion::class)]
26#[UsesClass(Scan::class)]
27#[UsesClass(SqlMode::class)]
28#[UsesClass(WordScanner::class)]
29#[UsesClass(\SqlParser\Resource\SqlVersion::class)]
30#[UsesClass(\SqlParser\Resource\VersionRegistry::class)]
31#[Small]
32final class NumberScannerTest extends TestCase
33{
34    public function testScan(): void
35    {
36        $scanner = new NumberScanner();
37        $words = new WordScanner();
38        $version = MySqlVersion::resolve();
39        $scan = static fn (string $sql): Scan => new Scan(new Cursor($sql), new KeywordTable([], []), new SqlMode(), $version);
40
41        self::assertSame('NUM', $scanner->scan($scan('42 '), $words)?->name);
42        self::assertSame('HEX_NUM', $scanner->scan($scan('0x1F'), $words)?->name);
43        self::assertSame('BIN_NUM', $scanner->scan($scan('0b01 '), $words)?->name);
44        self::assertSame('IDENT', $scanner->scan($scan('0xZZ'), $words)?->name);
45        self::assertSame('DECIMAL_NUM', $scanner->scan($scan('1.5'), $words)?->name);
46        self::assertSame('DECIMAL_NUM', $scanner->scan($scan('.5'), $words)?->name);
47        self::assertSame('FLOAT_NUM', $scanner->scan($scan('1e5'), $words)?->name);
48        self::assertSame('FLOAT_NUM', $scanner->scan($scan('1.5E-3'), $words)?->name);
49        self::assertSame('IDENT', $scanner->scan($scan('1e'), $words)?->name);
50        self::assertSame('IDENT', $scanner->scan($scan('1abc'), $words)?->name);
51        self::assertNull($scanner->scan($scan('abc'), $words));
52    }
53
54    public function testScanNotesAQualifiedIdentifierThatStartsWithADigit(): void
55    {
56        $scan = new Scan(new Cursor('1a.b'), new KeywordTable([], []), new SqlMode(), MySqlVersion::resolve());
57
58        self::assertSame('1a', (new NumberScanner())->scan($scan, new WordScanner())?->text);
59        self::assertSame(LexerState::IdentifierSeparator, $scan->next);
60    }
61
62    public function testFraction(): void
63    {
64        $scan = new Scan(new Cursor('.25e2x'), new KeywordTable([], []), new SqlMode(), MySqlVersion::resolve());
65        $lexeme = (new NumberScanner())->fraction($scan, 0);
66
67        self::assertSame('FLOAT_NUM', $lexeme->name);
68        self::assertSame('.25e2', $lexeme->text);
69    }
70
71    public function testIntegerTerminal(): void
72    {
73        self::assertSame('NUM', NumberScanner::integerTerminal('0002147483647'));
74        self::assertSame('LONG_NUM', NumberScanner::integerTerminal('2147483648'));
75        self::assertSame('LONG_NUM', NumberScanner::integerTerminal('9223372036854775807'));
76        self::assertSame('ULONGLONG_NUM', NumberScanner::integerTerminal('9223372036854775808'));
77        self::assertSame('ULONGLONG_NUM', NumberScanner::integerTerminal('18446744073709551615'));
78        self::assertSame('DECIMAL_NUM', NumberScanner::integerTerminal('18446744073709551616'));
79        self::assertSame('NUM', NumberScanner::integerTerminal('000'));
80    }
81}
82