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