packages/ztd-query-postgres/tests/Unit/Sql/PgSqlLexerProfileTest.php

1<?php
2
3declare(strict_types=1);
4
5namespace Tests\Unit\Sql;
6
7use PHPUnit\Framework\Attributes\CoversClass;
8use PHPUnit\Framework\TestCase;
9use ZtdQuery\Platform\Postgres\Sql\PgSqlLexerProfile;
10use ZtdQuery\Sql\SqlToken;
11use ZtdQuery\Sql\SqlTokenKind;
12use ZtdQuery\Sql\SqlTokenStream;
13
14#[CoversClass(PgSqlLexerProfile::class)]
15final class PgSqlLexerProfileTest extends TestCase
16{
17    public function testCreateSelectsPostgreSqlLexicalCapabilities(): void
18    {
19        $profile = PgSqlLexerProfile::create();
20        $tokens = SqlTokenStream::tokenize(
21            'SELECT `plain`, "quoted", $$body;still-string$$, $1',
22            $profile,
23        )->significantTokens();
24
25        self::assertSame(
26            [
27                SqlTokenKind::Word,
28                SqlTokenKind::Symbol,
29                SqlTokenKind::Word,
30                SqlTokenKind::Symbol,
31                SqlTokenKind::Symbol,
32                SqlTokenKind::QuotedIdentifier,
33                SqlTokenKind::Symbol,
34                SqlTokenKind::String,
35                SqlTokenKind::Symbol,
36                SqlTokenKind::Parameter,
37            ],
38            array_map(static fn (SqlToken $token): SqlTokenKind => $token->kind, $tokens),
39        );
40        self::assertSame(
41            ["'a\\'", 'tail'],
42            array_map(
43                static fn (SqlToken $token): string => $token->text,
44                SqlTokenStream::tokenize("'a\\' tail", $profile)->significantTokens(),
45            ),
46        );
47        self::assertSame(
48            ['E', "'a\\'b'", 'tail'],
49            array_map(
50                static fn (SqlToken $token): string => $token->text,
51                SqlTokenStream::tokenize("E'a\\'b' tail", $profile)->significantTokens(),
52            ),
53        );
54        self::assertTrue($profile->startsLineComment('-- comment', 0));
55        self::assertSame(['/*', '*/'], $profile->blockCommentAt('/* comment */', 0));
56        self::assertTrue($profile->isBracketOpening('['));
57        self::assertTrue($profile->isBracketClosing(']'));
58        self::assertTrue($profile->isNestingOpening('('));
59        self::assertTrue($profile->isNestingClosing(')'));
60        self::assertTrue($profile->supportsNestedBlockComments());
61        self::assertSame(2, $profile->positionalParameterLengthAt('$1', 0));
62        self::assertSame(1, $profile->positionalParameterLengthAt('?1', 0));
63    }
64
65    public function testRecognizesRadixNumbersAndDoesNotMisclassifyCastOperator(): void
66    {
67        $tokens = SqlTokenStream::tokenize(
68            '0xCA_FE 0o_755 0b10_01 1_000.25_5 value::text :bound',
69            PgSqlLexerProfile::create(),
70        )->significantTokens();
71
72        self::assertSame(
73            ['0xCA_FE', '0o_755', '0b10_01', '1_000.25_5'],
74            array_map(static fn (SqlToken $token): string => $token->text, array_slice($tokens, 0, 4)),
75        );
76        self::assertSame(
77            [SqlTokenKind::Word, SqlTokenKind::Symbol, SqlTokenKind::Symbol, SqlTokenKind::Word, SqlTokenKind::Parameter],
78            array_map(static fn (SqlToken $token): SqlTokenKind => $token->kind, array_slice($tokens, 4)),
79        );
80        self::assertSame(':bound', $tokens[8]->text);
81    }
82}
83