packages/ztd-query-sqlite/tests/Unit/Shadow/Mutation/Upsert/ExpressionTokenDecoderTest.php

1<?php
2
3declare(strict_types=1);
4
5namespace Tests\Unit\Shadow\Mutation\Upsert;
6
7use PHPUnit\Framework\Attributes\CoversClass;
8use PHPUnit\Framework\TestCase;
9use ZtdQuery\Platform\Sqlite\Shadow\Mutation\Upsert\ExpressionTokenDecoder;
10use ZtdQuery\Sql\SqlToken;
11use ZtdQuery\Sql\SqlTokenKind;
12
13#[CoversClass(ExpressionTokenDecoder::class)]
14final class ExpressionTokenDecoderTest extends TestCase
15{
16    public function testIsSymbolRequiresSymbolToken(): void
17    {
18        $decoder = new ExpressionTokenDecoder('');
19        self::assertTrue($decoder->isSymbol(new SqlToken(SqlTokenKind::Symbol, '+', 0, 0, 0), ['+', '-']));
20        self::assertFalse($decoder->isSymbol(new SqlToken(SqlTokenKind::Word, '+', 0, 0, 0), ['+']));
21        self::assertFalse($decoder->isSymbol(new SqlToken(SqlTokenKind::Symbol, '*', 0, 0, 0), ['+']));
22    }
23
24    public function testIsIdentifierRecognizesOnlyNames(): void
25    {
26        $decoder = new ExpressionTokenDecoder('');
27        self::assertTrue($decoder->isIdentifier(new SqlToken(SqlTokenKind::Word, 'name', 0, 0, 0)));
28        self::assertTrue($decoder->isIdentifier(new SqlToken(SqlTokenKind::QuotedIdentifier, '"name"', 0, 0, 0)));
29        self::assertFalse($decoder->isIdentifier(new SqlToken(SqlTokenKind::Number, '1', 0, 0, 0)));
30    }
31
32    public function testIdentifierDecodesEscapedQuote(): void
33    {
34        $decoder = new ExpressionTokenDecoder('');
35        self::assertSame('name', $decoder->identifier(new SqlToken(SqlTokenKind::Word, 'name', 0, 0, 0)));
36        self::assertSame('a"b', $decoder->identifier(new SqlToken(SqlTokenKind::QuotedIdentifier, '"a""b"', 0, 0, 0)));
37    }
38
39    public function testNumberPreservesNumericFamilies(): void
40    {
41        $decoder = new ExpressionTokenDecoder('');
42        self::assertSame(1024, $decoder->number('1_024'));
43        self::assertSame(1.25, $decoder->number('1.25'));
44        self::assertSame(100.0, $decoder->number('1e2'));
45    }
46
47    public function testStringDecodesSqlEscapes(): void
48    {
49        self::assertSame("a'b", (new ExpressionTokenDecoder(''))->string("'a''b'"));
50    }
51
52    public function testUnsupportedRetainsOriginalSql(): void
53    {
54        $error = (new ExpressionTokenDecoder('count || name'))->unsupported();
55        self::assertSame('count || name', $error->getSql());
56        self::assertStringContainsString('Unsupported UPSERT expression', $error->getMessage());
57    }
58
59}
60