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