packages/ztd-query-mysql/tests/Unit/Sql/MySqlIdentifierQuoterTest.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\MySql\Sql\MySqlIdentifierQuoter;
10
11#[CoversClass(MySqlIdentifierQuoter::class)]
12final class MySqlIdentifierQuoterTest extends TestCase
13{
14    public function testQuoteReturnsNonEmptyString(): void
15    {
16        $result = (new MySqlIdentifierQuoter())->quote('users');
17        self::assertNotEmpty($result);
18    }
19
20    public function testQuoteWrapsWithBackticks(): void
21    {
22        $result = (new MySqlIdentifierQuoter())->quote('users');
23        self::assertSame('`users`', $result);
24    }
25
26    public function testQuoteSimpleIdentifier(): void
27    {
28        self::assertSame('`column_name`', (new MySqlIdentifierQuoter())->quote('column_name'));
29    }
30
31    public function testQuoteDoesNotDoubleQuoteAlreadyQuoted(): void
32    {
33        $result = (new MySqlIdentifierQuoter())->quote('`users`');
34        self::assertSame('`users`', $result);
35    }
36
37    public function testQuoteEscapesBacktickInIdentifier(): void
38    {
39        $result = (new MySqlIdentifierQuoter())->quote('col`name');
40        self::assertSame('`col``name`', $result);
41    }
42
43    public function testQuoteIsDeterministic(): void
44    {
45        $result1 = (new MySqlIdentifierQuoter())->quote('users');
46        $result2 = (new MySqlIdentifierQuoter())->quote('users');
47        self::assertSame($result1, $result2);
48    }
49
50    public function testQuotedIdentifierContainsOriginalName(): void
51    {
52        $identifier = 'my_table';
53        $result = (new MySqlIdentifierQuoter())->quote($identifier);
54        $inner = substr($result, 1, -1);
55        $recovered = str_replace('``', '`', $inner);
56        self::assertSame($identifier, $recovered);
57    }
58
59    public function testQuoteAlreadyQuotedWithEscapedBacktick(): void
60    {
61        $result = (new MySqlIdentifierQuoter())->quote('`col``name`');
62        self::assertSame('`col``name`', $result);
63    }
64
65    public function testQuoteEmptyStringProducesBacktickPair(): void
66    {
67        $result = (new MySqlIdentifierQuoter())->quote('');
68        self::assertSame('``', $result);
69    }
70
71    public function testQuoteReservedWord(): void
72    {
73        $result = (new MySqlIdentifierQuoter())->quote('select');
74        self::assertSame('`select`', $result);
75    }
76
77    public function testQuoteWithSpaces(): void
78    {
79        $result = (new MySqlIdentifierQuoter())->quote('my table');
80        self::assertSame('`my table`', $result);
81    }
82
83    public function testQuoteEmptyBacktickPairStripsWrapping(): void
84    {
85        $result = (new MySqlIdentifierQuoter())->quote('``');
86        self::assertSame('``', $result);
87    }
88
89    public function testQuoteWrapsIdentifier(): void
90    {
91        $quoter = new MySqlIdentifierQuoter();
92        $char = '`';
93        $result = $quoter->quote('table_name');
94        self::assertStringStartsWith($char, $result);
95        self::assertStringEndsWith($char, $result);
96    }
97
98    public function testQuoteEscapesQuoteCharacterInIdentifier(): void
99    {
100        $quoter = new MySqlIdentifierQuoter();
101        $char = '`';
102        $identifier = 'col' . $char . 'name';
103        $result = $quoter->quote($identifier);
104        self::assertNotEmpty($result);
105        self::assertStringStartsWith($char, $result);
106        self::assertStringEndsWith($char, $result);
107        $simpleQuoted = $char . $identifier . $char;
108        self::assertGreaterThanOrEqual(strlen($simpleQuoted), strlen($result), 'Escaped identifier should be at least as long as non-escaped form');
109    }
110
111    public function testQuoteProducesExactResult(): void
112    {
113        $quoter = new MySqlIdentifierQuoter();
114        $char = '`';
115        $result = $quoter->quote('users');
116        self::assertSame($char . 'users' . $char, $result);
117    }
118
119    public function testQuoteEscapesEmbeddedQuoteExactly(): void
120    {
121        $quoter = new MySqlIdentifierQuoter();
122        $char = '`';
123        $result = $quoter->quote('col' . $char . 'name');
124        $expected = $char . 'col' . $char . $char . 'name' . $char;
125        self::assertSame($expected, $result);
126    }
127}
128