1+ package com .clickhouse .client .api .sql ;
2+
3+ import org .apache .commons .lang3 .StringUtils ;
4+ import org .testng .annotations .DataProvider ;
5+ import org .testng .annotations .Test ;
6+
7+ import static org .testng .Assert .assertEquals ;
8+
9+ @ Test (groups = {"unit" })
10+ public class SQLUtilsTest {
11+ // Test data for enquoteLiteral
12+ @ DataProvider (name = "enquoteLiteralTestData" )
13+ public Object [][] enquoteLiteralTestData () {
14+ return new Object [][] {
15+ // input, expected output
16+ {"test 123" , "'test 123'" },
17+ {"こんにちは世界" , "'こんにちは世界'" },
18+ {"O'Reilly" , "'O''Reilly'" },
19+ {"😊👍" , "'😊👍'" },
20+ {"" , "''" },
21+ {"single'quote'double''quote\" " , "'single''quote''double''''quote\" '" }
22+ };
23+ }
24+
25+ // Test data for enquoteIdentifier
26+ @ DataProvider (name = "enquoteIdentifierTestData" )
27+ public Object [][] enquoteIdentifierTestData () {
28+ return new Object [][] {
29+ // input, expected output
30+ {"column1" , "\" column1\" " },
31+ {"table.name" , "\" table.name\" " },
32+ {"column with spaces" , "\" column with spaces\" " },
33+ {"column\" with\" quotes" , "\" column\" \" with\" \" quotes\" " },
34+ {"UPPERCASE" , "\" UPPERCASE\" " },
35+ {"1column" , "\" 1column\" " },
36+ {"column-with-hyphen" , "\" column-with-hyphen\" " },
37+ {"😊👍" , "\" 😊👍\" " },
38+ {"" , "\" \" " }
39+ };
40+ }
41+
42+ @ Test (dataProvider = "enquoteLiteralTestData" )
43+ public void testEnquoteLiteral (String input , String expected ) {
44+ assertEquals (SQLUtils .enquoteLiteral (input ), expected );
45+ }
46+
47+ @ Test (expectedExceptions = IllegalArgumentException .class )
48+ public void testEnquoteLiteral_NullInput () {
49+ SQLUtils .enquoteLiteral (null );
50+ }
51+
52+ @ Test (dataProvider = "enquoteIdentifierTestData" )
53+ public void testEnquoteIdentifier (String input , String expected ) {
54+ // Test with quotesRequired = true (always quote)
55+ assertEquals (SQLUtils .enquoteIdentifier (input ), expected );
56+ assertEquals (SQLUtils .enquoteIdentifier (input , true ), expected );
57+
58+ // Test with quotesRequired = false (quote only if needed)
59+ boolean needsQuoting = !input .matches ("[a-zA-Z_][a-zA-Z0-9_]*" );
60+ String expectedUnquoted = needsQuoting ? expected : input ;
61+ assertEquals (SQLUtils .enquoteIdentifier (input , false ), expectedUnquoted );
62+ }
63+
64+ @ Test (expectedExceptions = IllegalArgumentException .class )
65+ public void testEnquoteIdentifier_NullInput () {
66+ SQLUtils .enquoteIdentifier (null );
67+ }
68+
69+ @ Test (expectedExceptions = IllegalArgumentException .class )
70+ public void testEnquoteIdentifier_NullInput_WithQuotesRequired () {
71+ SQLUtils .enquoteIdentifier (null , true );
72+ }
73+
74+ @ Test
75+ public void testEnquoteIdentifier_NoQuotesWhenNotNeeded () {
76+ // These identifiers don't need quoting
77+ String [] simpleIdentifiers = {
78+ "column1" , "table_name" , "_id" , "a1b2c3" , "ColumnName"
79+ };
80+
81+ for (String id : simpleIdentifiers ) {
82+ // With quotesRequired=false, should return as-is
83+ assertEquals (SQLUtils .enquoteIdentifier (id , false ), id );
84+ // With quotesRequired=true, should be quoted
85+ assertEquals (SQLUtils .enquoteIdentifier (id , true ), "\" " + id + "\" " );
86+ }
87+ }
88+
89+ @ DataProvider (name = "simpleIdentifierTestData" )
90+ public Object [][] simpleIdentifierTestData () {
91+ return new Object [][] {
92+ // identifier, expected result
93+ {"Hello" , true },
94+ {"hello_world" , true },
95+ {"Hello123" , true },
96+ {"H" , true }, // minimum length
97+ {StringUtils .repeat ("a" , 128 ), true }, // maximum length
98+
99+ // Test cases from requirements
100+ {"G'Day" , false },
101+ {"\" \" Bruce Wayne\" \" " , false },
102+ {"GoodDay$" , false },
103+ {"Hello\" \" World" , false },
104+ {"\" \" Hello\" \" World\" \" " , false },
105+
106+ // Additional test cases
107+ {"" , false }, // empty string
108+ {"123test" , false }, // starts with number
109+ {"_test" , false }, // starts with underscore
110+ {"test-name" , false }, // contains hyphen
111+ {"test name" , false }, // contains space
112+ {"test\" name" , false }, // contains quote
113+ {"test.name" , false }, // contains dot
114+ {StringUtils .repeat ("a" , 129 ), false }, // exceeds max length
115+ {"testName" , true },
116+ {"TEST_NAME" , true },
117+ {"test123" , true },
118+ {"t123" , true },
119+ {"t" , true }
120+ };
121+ }
122+
123+ @ Test (dataProvider = "simpleIdentifierTestData" )
124+ public void testIsSimpleIdentifier (String identifier , boolean expected ) {
125+ assertEquals (SQLUtils .isSimpleIdentifier (identifier ), expected ,
126+ String .format ("Failed for identifier: %s" , identifier ));
127+ }
128+
129+ @ Test (expectedExceptions = IllegalArgumentException .class )
130+ public void testIsSimpleIdentifier_NullInput () {
131+ SQLUtils .isSimpleIdentifier (null );
132+ }
133+
134+ @ Test
135+ public void testUnquoteIdentifier () {
136+ String [] names = new String []{"test" , "`test name1`" , "\" test name 2\" " };
137+ String [] expected = new String []{"test" , "test name1" , "test name 2" };
138+
139+ for (int i = 0 ; i < names .length ; i ++) {
140+ assertEquals (SQLUtils .unquoteIdentifier (names [i ]), expected [i ]);
141+ }
142+ }
143+ }
0 commit comments