packages/ztd-query-mysql/tests/Unit/Sql/Cte/HeaderParserTest.php
1<?php
2
3declare(strict_types=1);
4
5namespace Tests\Unit\Sql\Cte;
6
7use PHPUnit\Framework\Attributes\CoversClass;
8use PHPUnit\Framework\TestCase;
9use ZtdQuery\Platform\MySql\Sql\Cte\HeaderParser;
10
11#[\PHPUnit\Framework\Attributes\UsesClass(\ZtdQuery\Platform\MySql\Sql\MySqlLexerProfile::class)]
12#[CoversClass(HeaderParser::class)]
13final class HeaderParserTest extends TestCase
14{
15 public function testParseHeaderExtractsNamesAndStatementOffset(): void
16 {
17 $reader = new HeaderParser(\ZtdQuery\Platform\MySql\Sql\MySqlLexerProfile::create());
18 self::assertSame(['names' => ['a'], 'statementOffset' => 21], $reader->parseHeader('WITH a AS (SELECT 1) SELECT * FROM a'));
19 self::assertSame(['names' => [], 'statementOffset' => null], $reader->parseHeader('SELECT 1'));
20 self::assertSame(['names' => [], 'statementOffset' => null], $reader->parseHeader('WITH a AS ('));
21 }
22
23 public function testFindAsIndexSkipsColumnListsAndStopsAtWords(): void
24 {
25 $reader = new HeaderParser(\ZtdQuery\Platform\MySql\Sql\MySqlLexerProfile::create());
26 self::assertSame(2, $reader->findAsIndex(\ZtdQuery\Sql\SqlTokenStream::tokenize('() AS', \ZtdQuery\Platform\MySql\Sql\MySqlLexerProfile::create())->significantTokens(), 0));
27 self::assertNull($reader->findAsIndex(\ZtdQuery\Sql\SqlTokenStream::tokenize('other AS', \ZtdQuery\Platform\MySql\Sql\MySqlLexerProfile::create())->significantTokens(), 0));
28 self::assertNull($reader->findAsIndex([], 0));
29 }
30
31 public function testIdentifierNameUnquotesNamesAndRejectsSymbols(): void
32 {
33 $reader = new HeaderParser(\ZtdQuery\Platform\MySql\Sql\MySqlLexerProfile::create());
34 $tokens = \ZtdQuery\Sql\SqlTokenStream::tokenize('plain `a``b` ,', \ZtdQuery\Platform\MySql\Sql\MySqlLexerProfile::create())->significantTokens();
35 self::assertSame('plain', $reader->identifierName($tokens[0]));
36 self::assertSame('a`b', $reader->identifierName($tokens[1]));
37 self::assertNull($reader->identifierName($tokens[2]));
38 }
39
40 public function testIsSymbolRequiresTheRequestedDelimiter(): void
41 {
42 $reader = new HeaderParser(\ZtdQuery\Platform\MySql\Sql\MySqlLexerProfile::create());
43 $tokens = \ZtdQuery\Sql\SqlTokenStream::tokenize('( )', \ZtdQuery\Platform\MySql\Sql\MySqlLexerProfile::create())->significantTokens();
44 self::assertTrue($reader->isSymbol($tokens[0], '('));
45 self::assertFalse($reader->isSymbol($tokens[0], ')'));
46 self::assertFalse($reader->isSymbol(null, '('));
47 }
48
49 public function testTopLevelTokensExcludeNestedBodies(): void
50 {
51 $reader = new HeaderParser(\ZtdQuery\Platform\MySql\Sql\MySqlLexerProfile::create());
52 $tokens = $reader->topLevelTokens('WITH a AS (SELECT 1) SELECT 2');
53 self::assertSame(['WITH', 'a', 'AS', '(', ')', 'SELECT', '2'], array_map(static fn (\ZtdQuery\Sql\SqlToken $token): string => $token->text, $tokens));
54 }
55
56 public function testContentsPreservesRecursiveHeaders(): void
57 {
58 $reader = new HeaderParser(\ZtdQuery\Platform\MySql\Sql\MySqlLexerProfile::create());
59 self::assertSame(['leading' => '', 'recursive' => true, 'body' => 'a AS (SELECT 1)'], $reader->contents('WITH RECURSIVE a AS (SELECT 1) SELECT * FROM a', 31));
60 }
61
62}
63