vitess.io/vitess@v0.16.2/go/vt/sqlparser/token_test.go (about) 1 /* 2 Copyright 2019 The Vitess Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package sqlparser 18 19 import ( 20 "fmt" 21 "testing" 22 23 "github.com/stretchr/testify/require" 24 ) 25 26 func TestLiteralID(t *testing.T) { 27 testcases := []struct { 28 in string 29 id int 30 out string 31 }{{ 32 in: "`aa`", 33 id: ID, 34 out: "aa", 35 }, { 36 in: "```a```", 37 id: ID, 38 out: "`a`", 39 }, { 40 in: "`a``b`", 41 id: ID, 42 out: "a`b", 43 }, { 44 in: "`a``b`c", 45 id: ID, 46 out: "a`b", 47 }, { 48 in: "`a``b", 49 id: LEX_ERROR, 50 out: "a`b", 51 }, { 52 in: "`a``b``", 53 id: LEX_ERROR, 54 out: "a`b`", 55 }, { 56 in: "``", 57 id: LEX_ERROR, 58 out: "", 59 }, { 60 in: "@x", 61 id: AT_ID, 62 out: "x", 63 }, { 64 in: "@@x", 65 id: AT_AT_ID, 66 out: "x", 67 }, { 68 in: "@@`x y`", 69 id: AT_AT_ID, 70 out: "x y", 71 }, { 72 in: "@@`@x @y`", 73 id: AT_AT_ID, 74 out: "@x @y", 75 }} 76 77 for _, tcase := range testcases { 78 t.Run(tcase.in, func(t *testing.T) { 79 tkn := NewStringTokenizer(tcase.in) 80 id, out := tkn.Scan() 81 require.Equal(t, tcase.id, id) 82 require.Equal(t, tcase.out, string(out)) 83 }) 84 } 85 } 86 87 func tokenName(id int) string { 88 if id == STRING { 89 return "STRING" 90 } else if id == LEX_ERROR { 91 return "LEX_ERROR" 92 } 93 return fmt.Sprintf("%d", id) 94 } 95 96 func TestString(t *testing.T) { 97 testcases := []struct { 98 in string 99 id int 100 want string 101 }{{ 102 in: "''", 103 id: STRING, 104 want: "", 105 }, { 106 in: "''''", 107 id: STRING, 108 want: "'", 109 }, { 110 in: "'hello'", 111 id: STRING, 112 want: "hello", 113 }, { 114 in: "'\\n'", 115 id: STRING, 116 want: "\n", 117 }, { 118 in: "'\\nhello\\n'", 119 id: STRING, 120 want: "\nhello\n", 121 }, { 122 in: "'a''b'", 123 id: STRING, 124 want: "a'b", 125 }, { 126 in: "'a\\'b'", 127 id: STRING, 128 want: "a'b", 129 }, { 130 in: "'\\'", 131 id: LEX_ERROR, 132 want: "'", 133 }, { 134 in: "'", 135 id: LEX_ERROR, 136 want: "", 137 }, { 138 in: "'hello\\'", 139 id: LEX_ERROR, 140 want: "hello'", 141 }, { 142 in: "'hello", 143 id: LEX_ERROR, 144 want: "hello", 145 }, { 146 in: "'hello\\", 147 id: LEX_ERROR, 148 want: "hello", 149 }} 150 151 for _, tcase := range testcases { 152 t.Run(tcase.in, func(t *testing.T) { 153 id, got := NewStringTokenizer(tcase.in).Scan() 154 require.Equal(t, tcase.id, id, "Scan(%q) = (%s), want (%s)", tcase.in, tokenName(id), tokenName(tcase.id)) 155 require.Equal(t, tcase.want, string(got)) 156 }) 157 } 158 } 159 160 func TestSplitStatement(t *testing.T) { 161 testcases := []struct { 162 in string 163 sql string 164 rem string 165 }{{ 166 in: "select * from table", 167 sql: "select * from table", 168 }, { 169 in: "select * from table; ", 170 sql: "select * from table", 171 rem: " ", 172 }, { 173 in: "select * from table; select * from table2;", 174 sql: "select * from table", 175 rem: " select * from table2;", 176 }, { 177 in: "select * from /* comment */ table;", 178 sql: "select * from /* comment */ table", 179 }, { 180 in: "select * from /* comment ; */ table;", 181 sql: "select * from /* comment ; */ table", 182 }, { 183 in: "select * from table where semi = ';';", 184 sql: "select * from table where semi = ';'", 185 }, { 186 in: "-- select * from table", 187 sql: "-- select * from table", 188 }, { 189 in: " ", 190 sql: " ", 191 }, { 192 in: "", 193 sql: "", 194 }} 195 196 for _, tcase := range testcases { 197 t.Run(tcase.in, func(t *testing.T) { 198 sql, rem, err := SplitStatement(tcase.in) 199 if err != nil { 200 t.Errorf("EndOfStatementPosition(%s): ERROR: %v", tcase.in, err) 201 return 202 } 203 204 if tcase.sql != sql { 205 t.Errorf("EndOfStatementPosition(%s) got sql \"%s\" want \"%s\"", tcase.in, sql, tcase.sql) 206 } 207 208 if tcase.rem != rem { 209 t.Errorf("EndOfStatementPosition(%s) got remainder \"%s\" want \"%s\"", tcase.in, rem, tcase.rem) 210 } 211 }) 212 } 213 } 214 215 func TestVersion(t *testing.T) { 216 testcases := []struct { 217 version string 218 in string 219 id []int 220 }{{ 221 version: "50709", 222 in: "/*!80102 SELECT*/ FROM IN EXISTS", 223 id: []int{FROM, IN, EXISTS, 0}, 224 }, { 225 version: "80101", 226 in: "/*!80102 SELECT*/ FROM IN EXISTS", 227 id: []int{FROM, IN, EXISTS, 0}, 228 }, { 229 version: "80201", 230 in: "/*!80102 SELECT*/ FROM IN EXISTS", 231 id: []int{SELECT, FROM, IN, EXISTS, 0}, 232 }, { 233 version: "80102", 234 in: "/*!80102 SELECT*/ FROM IN EXISTS", 235 id: []int{SELECT, FROM, IN, EXISTS, 0}, 236 }} 237 238 for _, tcase := range testcases { 239 t.Run(tcase.version+"_"+tcase.in, func(t *testing.T) { 240 mySQLParserVersion = tcase.version 241 tok := NewStringTokenizer(tcase.in) 242 for _, expectedID := range tcase.id { 243 id, _ := tok.Scan() 244 require.Equal(t, expectedID, id) 245 } 246 }) 247 } 248 } 249 250 func TestExtractMySQLComment(t *testing.T) { 251 testcases := []struct { 252 comment string 253 version string 254 }{{ 255 comment: "/*!50108 SELECT * FROM */", 256 version: "50108", 257 }, { 258 comment: "/*!5018 SELECT * FROM */", 259 version: "", 260 }, { 261 comment: "/*!SELECT * FROM */", 262 version: "", 263 }} 264 265 for _, tcase := range testcases { 266 t.Run(tcase.version, func(t *testing.T) { 267 output, _ := ExtractMysqlComment(tcase.comment) 268 require.Equal(t, tcase.version, output) 269 }) 270 } 271 } 272 273 func TestIntegerAndID(t *testing.T) { 274 testcases := []struct { 275 in string 276 id int 277 out string 278 }{{ 279 in: "334", 280 id: INTEGRAL, 281 }, { 282 in: "33.4", 283 id: DECIMAL, 284 }, { 285 in: "0x33", 286 id: HEXNUM, 287 }, { 288 in: "33e4", 289 id: FLOAT, 290 }, { 291 in: "33.4e-3", 292 id: FLOAT, 293 }, { 294 in: "33t4", 295 id: ID, 296 }, { 297 in: "0x2et3", 298 id: ID, 299 }, { 300 in: "3e2t3", 301 id: LEX_ERROR, 302 out: "3e2", 303 }, { 304 in: "3.2t", 305 id: LEX_ERROR, 306 out: "3.2", 307 }} 308 309 for _, tcase := range testcases { 310 t.Run(tcase.in, func(t *testing.T) { 311 tkn := NewStringTokenizer(tcase.in) 312 id, out := tkn.Scan() 313 require.Equal(t, tcase.id, id) 314 expectedOut := tcase.out 315 if expectedOut == "" { 316 expectedOut = tcase.in 317 } 318 require.Equal(t, expectedOut, out) 319 }) 320 } 321 }