github.com/matrixorigin/matrixone@v1.2.0/pkg/sql/parsers/dialect/mysql/scanner_test.go (about) 1 // Copyright 2021 Matrix Origin 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package mysql 16 17 import ( 18 "fmt" 19 "testing" 20 21 "github.com/matrixorigin/matrixone/pkg/sql/parsers/dialect" 22 ) 23 24 func TestLiteralID(t *testing.T) { 25 testcases := []struct { 26 in string 27 id int 28 out string 29 }{{ 30 in: "`aa`", 31 id: QUOTE_ID, 32 out: "aa", 33 }, { 34 in: "```a```", 35 id: QUOTE_ID, 36 out: "`a`", 37 }, { 38 in: "`a``b`", 39 id: QUOTE_ID, 40 out: "a`b", 41 }, { 42 in: "`a``b`c", 43 id: QUOTE_ID, 44 out: "a`b", 45 }, { 46 in: "`a``b", 47 id: LEX_ERROR, 48 out: "a`b", 49 }, { 50 in: "`a``b``", 51 id: LEX_ERROR, 52 out: "a`b`", 53 }, { 54 in: "``", 55 id: LEX_ERROR, 56 out: "", 57 }, { 58 in: "```a``b``", 59 id: LEX_ERROR, 60 out: "`a`b`", 61 }, { 62 in: "```", 63 id: LEX_ERROR, 64 out: "`", 65 }} 66 67 for _, tcase := range testcases { 68 s := NewScanner(dialect.MYSQL, tcase.in) 69 id, out := s.Scan() 70 if tcase.id != id || string(out) != tcase.out { 71 t.Errorf("Scan(%s): %d, %s, want %d, %s", tcase.in, id, out, tcase.id, tcase.out) 72 } 73 } 74 } 75 76 func tokenName(id int) string { 77 if id == STRING { 78 return "STRING" 79 } else if id == HEXNUM { 80 return "HEXNUM" 81 } else if id == BIT_LITERAL { 82 return "BIT_LITERAL" 83 } else if id == LEX_ERROR { 84 return "LEX_ERROR" 85 } 86 return fmt.Sprintf("%d", id) 87 } 88 89 func TestString(t *testing.T) { 90 testcases := []struct { 91 in string 92 id int 93 want string 94 }{{ 95 in: "''", 96 id: STRING, 97 want: "", 98 }, { 99 in: "''''", 100 id: STRING, 101 want: "'", 102 }, { 103 in: "'hello'", 104 id: STRING, 105 want: "hello", 106 }, { 107 in: "'\\n'", 108 id: STRING, 109 want: "\n", 110 }, { 111 in: "'\\nhello\\n'", 112 id: STRING, 113 want: "\nhello\n", 114 }, { 115 in: "'a''b'", 116 id: STRING, 117 want: "a'b", 118 }, { 119 in: "'a\\'b'", 120 id: STRING, 121 want: "a'b", 122 }, { 123 in: "'\\'", 124 id: LEX_ERROR, 125 want: "'", 126 }, { 127 in: "'", 128 id: LEX_ERROR, 129 want: "", 130 }, { 131 in: "'hello\\'", 132 id: LEX_ERROR, 133 want: "hello'", 134 }, { 135 in: "'hello", 136 id: LEX_ERROR, 137 want: "hello", 138 }, { 139 in: "'hello\\", 140 id: LEX_ERROR, 141 want: "hello", 142 }, { 143 in: "'C:\\Program Files(x86)'", 144 id: STRING, 145 want: "C:Program Files(x86)", 146 }, { 147 in: "'C:\\\\Program Files(x86)'", 148 id: STRING, 149 want: "C:\\Program Files(x86)", 150 }} 151 152 for _, tcase := range testcases { 153 id, got := NewScanner(dialect.MYSQL, tcase.in).Scan() 154 if tcase.id != id || string(got) != tcase.want { 155 t.Errorf("Scan(%q) = (%s, %q), want (%s, %q)", tcase.in, tokenName(id), got, tokenName(tcase.id), tcase.want) 156 } 157 } 158 } 159 160 func TestBuffer(t *testing.T) { 161 testcases := []struct { 162 in string 163 id int 164 want string 165 }{{ 166 in: "'webapp'@'localhost'", 167 id: STRING, 168 want: "webapp", 169 }} 170 171 for _, tcase := range testcases { 172 id, got := NewScanner(dialect.MYSQL, tcase.in).Scan() 173 if tcase.id != id || string(got) != tcase.want { 174 t.Errorf("Scan(%q) = (%s, %q), want (%s, %q)", tcase.in, tokenName(id), got, tokenName(tcase.id), tcase.want) 175 } 176 } 177 } 178 179 func TestComment(t *testing.T) { 180 testcases := []struct { 181 name string 182 in string 183 id int 184 want string 185 want2 string 186 }{ 187 { 188 name: "1", 189 in: "abc /* abc */ abc", 190 id: COMMENT, 191 want: "/* abc */", 192 }, 193 { 194 name: "1", 195 in: "abc /** abc **/ abc", 196 id: COMMENT, 197 want: "/** abc **/", 198 }, 199 { 200 name: "*/ after comment", 201 in: "abc /** abc **/*/ abc", 202 id: COMMENT, 203 want: "/** abc **/", 204 }, 205 { 206 name: "//comment", 207 in: "abc //** abc **/*/ abc", 208 id: COMMENT, 209 want: "//** abc **/*/ abc", 210 }, 211 { 212 name: "// in block comment", 213 in: "abc /** //abc **/*/ abc", 214 id: COMMENT, 215 want: "/** //abc **/", 216 }, 217 { 218 name: "embedded block comment", 219 in: "abc /** /* /abc **/*/ abc", 220 id: COMMENT, 221 want: "/** /* /abc **/", 222 }, 223 { 224 name: "no comment", 225 in: "abc /a/a abc", 226 id: eofChar, 227 want: "", 228 }, 229 { 230 name: "no comment", 231 in: "abc /a/a abc/", 232 id: eofChar, 233 want: "", 234 }, 235 { 236 name: "nothing", 237 in: "", 238 id: eofChar, 239 want: "", 240 }, 241 { 242 name: "newline", 243 in: "\n", 244 id: eofChar, 245 want: "", 246 }, 247 { 248 name: "newline", 249 in: "dfa fda \r\n", 250 id: eofChar, 251 want: "", 252 }, 253 { 254 name: "no newline", 255 in: "dfa fda ", 256 id: eofChar, 257 want: "", 258 }, 259 { 260 name: "incomplete line comment", 261 in: " / ", 262 id: eofChar, 263 want: "", 264 }, 265 { 266 name: "incomplete block comment", 267 in: " /* ", 268 id: LEX_ERROR, 269 want: "", 270 }, 271 { 272 name: "incomplete block comment", 273 in: " /* * ", 274 id: LEX_ERROR, 275 want: "", 276 }, 277 { 278 name: "incomplete block comment", 279 in: " /* * /", 280 id: LEX_ERROR, 281 want: "", 282 }, 283 { 284 name: "incomplete block comment", 285 in: " / * * /", 286 id: eofChar, 287 want: "", 288 }, 289 { 290 name: "block comment", 291 in: " /* * / /* */ ", 292 id: COMMENT, 293 want: "/* * / /* */", 294 }, 295 { 296 name: "block comment", 297 in: " /* * / /* */ ", 298 id: COMMENT, 299 want: "/* * / /* */", 300 }, 301 { 302 name: "two block comment", 303 in: " /* * / /* */ /* abc */ ", 304 id: COMMENT, 305 want: "/* * / /* */", 306 want2: "/* abc */", 307 }, 308 { 309 name: "two block comment", 310 in: " /* * / /* */ // ", 311 id: COMMENT, 312 want: "/* * / /* */", 313 want2: "// ", 314 }, 315 } 316 317 for _, tcase := range testcases { 318 scan := NewScanner(dialect.MYSQL, tcase.in) 319 id, got := scan.ScanComment() 320 if tcase.id != id || id != LEX_ERROR && string(got) != tcase.want { 321 t.Errorf("ScanComment(%q) = (%s, %q), want (%s, %q)", tcase.in, tokenName(id), got, tokenName(tcase.id), tcase.want) 322 } 323 324 if tcase.want2 != "" { 325 id, got = scan.ScanComment() 326 if tcase.id != id || id != LEX_ERROR && string(got) != tcase.want2 { 327 t.Errorf("ScanComment(%q) = (%s, %q), want (%s, %q)", tcase.in, tokenName(id), got, tokenName(tcase.id), tcase.want2) 328 } 329 } 330 } 331 } 332 333 func TestBitValueLiteral(t *testing.T) { 334 testcases := []struct { 335 in string 336 id int 337 want string 338 }{{ 339 in: "b'00011011'", 340 id: BIT_LITERAL, 341 want: "0b00011011", 342 }, { 343 in: "0b00011011", 344 id: BIT_LITERAL, 345 want: "0b00011011", 346 }, { 347 in: "0b", 348 id: ID, 349 want: "0b", 350 }, { 351 in: "0b0a1fg", 352 id: ID, 353 want: "0b0a1fg", 354 }} 355 356 for _, tcase := range testcases { 357 id, got := NewScanner(dialect.MYSQL, tcase.in).Scan() 358 if tcase.id != id || got != tcase.want { 359 t.Errorf("Scan(%q) = (%s, %q), want (%s, %q)", tcase.in, tokenName(id), got, tokenName(tcase.id), tcase.want) 360 } 361 } 362 } 363 364 func TestHexadecimalLiteral(t *testing.T) { 365 testcases := []struct { 366 in string 367 id int 368 want string 369 }{{ 370 in: "x'616263'", 371 id: HEXNUM, 372 want: "0x616263", 373 }, { 374 in: "0x616263", 375 id: HEXNUM, 376 want: "0x616263", 377 }, { 378 in: "0x", 379 id: ID, 380 want: "0x", 381 }, { 382 in: "0X0a1fg", 383 id: ID, 384 want: "0x0a1fg", 385 }} 386 387 for _, tcase := range testcases { 388 id, got := NewScanner(dialect.MYSQL, tcase.in).Scan() 389 if tcase.id != id || got != tcase.want { 390 t.Errorf("Scan(%q) = (%s, %q), want (%s, %q)", tcase.in, tokenName(id), got, tokenName(tcase.id), tcase.want) 391 } 392 } 393 }