github.com/matrixorigin/matrixone@v1.2.0/pkg/container/bytejson/bytejson_test.go (about) 1 // Copyright 2022 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 bytejson 16 17 import ( 18 "strconv" 19 "testing" 20 21 "github.com/stretchr/testify/require" 22 ) 23 24 func TestLiteral(t *testing.T) { 25 j := []string{"true", "false", "null"} 26 for _, x := range j { 27 bj, err := ParseFromString(x) 28 require.Nil(t, err) 29 require.Equal(t, x, bj.String()) 30 } 31 } 32 33 func TestNumber(t *testing.T) { 34 // generate max int64 35 j := []string{ 36 "9223372036854775807", 37 "-9223372036854775808", 38 "1", 39 "-1", 40 } 41 for _, x := range j { 42 bj, err := ParseFromString(x) 43 require.Nil(t, err) 44 // transform string to int64 45 now, err := strconv.ParseInt(x, 10, 64) 46 require.Nil(t, err) 47 require.Equal(t, now, bj.GetInt64()) 48 } 49 50 // generate max uint64 51 j = []string{ 52 "18446744073709551615", 53 "0", 54 "1", 55 } 56 for _, x := range j { 57 bj, err := ParseFromString(x) 58 require.Nil(t, err) 59 // transform string to uint64 60 now, err := strconv.ParseUint(x, 10, 64) 61 require.Nil(t, err) 62 require.Equal(t, now, bj.GetUint64()) 63 } 64 65 //generate max float64 66 j = []string{ 67 "1.7976931348623157e+308", 68 "-1.7976931348623157e+308", 69 "4.940656458412465441765687928682213723651e-324", 70 "0.112131431", 71 "1.13353411", 72 } 73 for _, x := range j { 74 bj, err := ParseFromString(x) 75 require.Nil(t, err) 76 // transform string to float64 77 now, err := strconv.ParseFloat(x, 64) 78 require.Nil(t, err) 79 require.Equal(t, now, bj.GetFloat64()) 80 } 81 } 82 83 func TestObject(t *testing.T) { 84 j := []string{ 85 `{"a":1}`, 86 `{"a": 1, "b": 2, "c": true, "d": false, "e": null, "f": "string", "g": [1, 2, 3], "h": {"a": 1, "b": 2}, "i": 1.1, "j": 1.1e+10, "k": 1.1e-10}`, 87 `{"a":{}}`, 88 `{"a":{"b":{"c":{"d":[null,false,true,123,"abc",[1,2,3],{"a":1,"b":2,"c":3,"d":4,"e":5},123.456]}}}}`, 89 } 90 for _, x := range j { 91 bj, err := ParseFromString(x) 92 require.Nil(t, err) 93 require.JSONEq(t, x, bj.String()) 94 } 95 } 96 func TestArray(t *testing.T) { 97 j := []string{ 98 `[`, 99 `[{]`, 100 `[{}]`, 101 `["1"]`, 102 `{"k1": "value", "k2": [10, 20]}`, 103 `[null,false,true,123,"abc",[1,2,3],{"a":1,"b":2,"c":3,"d":4,"e":5},123.456,1.1e+10,1.1e-10]`, 104 } 105 for i, x := range j { 106 bj, err := ParseFromString(x) 107 if i > 1 { 108 require.Nil(t, err) 109 require.JSONEq(t, x, bj.String()) 110 } else { 111 require.NotNil(t, err) 112 } 113 } 114 } 115 116 func TestQuery(t *testing.T) { 117 kases := []struct { 118 jsonStr string 119 pathStr string 120 outStr string 121 }{ 122 { 123 jsonStr: `{"a": "1", "b": "2", "c": "3"}`, 124 pathStr: "$.a", 125 outStr: "\"1\"", 126 }, 127 { 128 jsonStr: `{"a": "1", "b": "2", "c": "3"}`, 129 pathStr: "$.b", 130 outStr: "\"2\"", 131 }, 132 { 133 jsonStr: `[1,2,3]`, 134 pathStr: "$[0]", 135 outStr: "1", 136 }, 137 { 138 jsonStr: `[1,2,3]`, 139 pathStr: "$[2]", 140 outStr: "3", 141 }, 142 { 143 jsonStr: `[1,2,3]`, 144 pathStr: "$[*]", 145 outStr: "[1,2,3]", 146 }, 147 { 148 jsonStr: `{"a":[1,2,3,{"b":4}]}`, 149 pathStr: "$.a[3].b", 150 outStr: "4", 151 }, 152 { 153 jsonStr: `{"a":[1,2,3,{"b":4}]}`, 154 pathStr: "$.a[3].c", 155 outStr: "null", 156 }, 157 { 158 jsonStr: `{"a":[1,2,3,{"b":4}],"c":5}`, 159 pathStr: "$.*", 160 outStr: `[[1,2,3,{"b":4}],5]`, 161 }, 162 { 163 jsonStr: `{"a":[1,2,3,{"a":4}]}`, 164 pathStr: "$**.a", 165 outStr: `[[1,2,3,{"a":4}],4]`, 166 }, 167 { 168 jsonStr: `{"a":1}`, 169 pathStr: "$[0]", 170 outStr: `{"a":1}`, 171 }, 172 { 173 jsonStr: `{"a":1}`, 174 pathStr: "$[0].a", 175 outStr: `1`, 176 }, 177 { 178 jsonStr: `{"a":1}`, 179 pathStr: "$[1]", 180 outStr: `null`, 181 }, 182 } 183 for _, kase := range kases { 184 bj, err := ParseFromString(kase.jsonStr) 185 require.Nil(t, err) 186 path, err := ParseJsonPath(kase.pathStr) 187 require.Nil(t, err) 188 out := bj.Query([]*Path{&path}) 189 require.JSONEq(t, kase.outStr, out.String()) 190 } 191 } 192 func TestUnnest(t *testing.T) { 193 kases := []struct { 194 jsonStr string 195 pathStr string 196 mode string 197 recursive bool 198 outer bool 199 outStr []string 200 valid bool 201 }{ 202 { 203 jsonStr: `{"a": "1", "b": "2", "c": "3"}`, 204 mode: "other", 205 valid: false, 206 }, 207 { 208 jsonStr: `{"a": "1", "b": "2", "c": "3"}`, 209 mode: "both", 210 pathStr: "$", 211 outStr: []string{ 212 `key: a, path: $.a, value: "1", this: {"a": "1", "b": "2", "c": "3"}`, 213 `key: b, path: $.b, value: "2", this: {"a": "1", "b": "2", "c": "3"}`, 214 `key: c, path: $.c, value: "3", this: {"a": "1", "b": "2", "c": "3"}`, 215 }, 216 valid: true, 217 }, 218 { 219 jsonStr: `{"a": "1", "b": "2", "c": "3"}`, 220 pathStr: "$.a", 221 mode: "both", 222 valid: true, 223 }, 224 { 225 jsonStr: `{"a": "1", "b": "2", "c": "3"}`, 226 mode: "object", 227 outStr: []string{ 228 `key: a, path: $.a, value: "1", this: {"a": "1", "b": "2", "c": "3"}`, 229 `key: b, path: $.b, value: "2", this: {"a": "1", "b": "2", "c": "3"}`, 230 `key: c, path: $.c, value: "3", this: {"a": "1", "b": "2", "c": "3"}`, 231 }, 232 valid: true, 233 }, 234 { 235 jsonStr: `{"a": "1", "b": "2", "c": "3"}`, 236 mode: "array", 237 valid: true, 238 }, 239 { 240 jsonStr: `[1,2,3]`, 241 mode: "array", 242 outStr: []string{ 243 `path: $[0], index: 0, value: 1, this: [1, 2, 3]`, 244 `path: $[1], index: 1, value: 2, this: [1, 2, 3]`, 245 `path: $[2], index: 2, value: 3, this: [1, 2, 3]`, 246 }, 247 valid: true, 248 }, 249 { 250 jsonStr: `[1,2,3]`, 251 mode: "object", 252 valid: true, 253 }, 254 { 255 jsonStr: `[1,2,3]`, 256 mode: "both", 257 outStr: []string{ 258 `path: $[0], index: 0, value: 1, this: [1, 2, 3]`, 259 `path: $[1], index: 1, value: 2, this: [1, 2, 3]`, 260 `path: $[2], index: 2, value: 3, this: [1, 2, 3]`, 261 }, 262 valid: true, 263 }, 264 { 265 jsonStr: `{"a": [1,2,3], "b": {"c": 4, "d": [5, 6, 7]}}`, 266 mode: "both", 267 outStr: []string{ 268 `key: a, path: $.a, value: [1, 2, 3], this: {"a": [1, 2, 3], "b": {"c": 4, "d": [5, 6, 7]}}`, 269 `key: b, path: $.b, value: {"c": 4, "d": [5, 6, 7]}, this: {"a": [1, 2, 3], "b": {"c": 4, "d": [5, 6, 7]}}`, 270 }, 271 valid: true, 272 }, 273 { 274 jsonStr: `{"a": [1,2,3], "b": {"c": 4, "d": [5, 6, 7]}}`, 275 mode: "object", 276 outStr: []string{ 277 `key: a, path: $.a, value: [1, 2, 3], this: {"a": [1, 2, 3], "b": {"c": 4, "d": [5, 6, 7]}}`, 278 `key: b, path: $.b, value: {"c": 4, "d": [5, 6, 7]}, this: {"a": [1, 2, 3], "b": {"c": 4, "d": [5, 6, 7]}}`, 279 }, 280 valid: true, 281 }, 282 { 283 jsonStr: `{"a": [1,2,3], "b": {"c": 4, "d": [5, 6, 7]}}`, 284 mode: "array", 285 outer: true, 286 outStr: []string{ 287 `path: $, this: {"a": [1, 2, 3], "b": {"c": 4, "d": [5, 6, 7]}}`, 288 }, 289 valid: true, 290 }, 291 { 292 jsonStr: `{"a": [1,2,3], "b": {"c": 4, "d": [5, 6, 7]}}`, 293 mode: "both", 294 recursive: true, 295 outStr: []string{ 296 `key: a, path: $.a, value: [1, 2, 3], this: {"a": [1, 2, 3], "b": {"c": 4, "d": [5, 6, 7]}}`, 297 `path: $.a[0], index: 0, value: 1, this: [1, 2, 3]`, 298 `path: $.a[1], index: 1, value: 2, this: [1, 2, 3]`, 299 `path: $.a[2], index: 2, value: 3, this: [1, 2, 3]`, 300 `key: b, path: $.b, value: {"c": 4, "d": [5, 6, 7]}, this: {"a": [1, 2, 3], "b": {"c": 4, "d": [5, 6, 7]}}`, 301 `key: c, path: $.b.c, value: 4, this: {"c": 4, "d": [5, 6, 7]}`, 302 `key: d, path: $.b.d, value: [5, 6, 7], this: {"c": 4, "d": [5, 6, 7]}`, 303 `path: $.b.d[0], index: 0, value: 5, this: [5, 6, 7]`, 304 `path: $.b.d[1], index: 1, value: 6, this: [5, 6, 7]`, 305 `path: $.b.d[2], index: 2, value: 7, this: [5, 6, 7]`, 306 }, 307 valid: true, 308 }, 309 { 310 jsonStr: `{"a": [1,2,3], "b": {"c": 4, "d": [5, 6, 7]}}`, 311 mode: "object", 312 recursive: true, 313 outStr: []string{ 314 `key: a, path: $.a, value: [1, 2, 3], this: {"a": [1, 2, 3], "b": {"c": 4, "d": [5, 6, 7]}}`, 315 `key: b, path: $.b, value: {"c": 4, "d": [5, 6, 7]}, this: {"a": [1, 2, 3], "b": {"c": 4, "d": [5, 6, 7]}}`, 316 `key: c, path: $.b.c, value: 4, this: {"c": 4, "d": [5, 6, 7]}`, 317 `key: d, path: $.b.d, value: [5, 6, 7], this: {"c": 4, "d": [5, 6, 7]}`, 318 }, 319 valid: true, 320 }, 321 { 322 jsonStr: `{"a": [1,2,3], "b": {"c": 4, "d": [5, 6, 7]}}`, 323 mode: "array", 324 recursive: true, 325 pathStr: "$.a", 326 outStr: []string{ 327 `path: $.a[0], index: 0, value: 1, this: [1, 2, 3]`, 328 `path: $.a[1], index: 1, value: 2, this: [1, 2, 3]`, 329 `path: $.a[2], index: 2, value: 3, this: [1, 2, 3]`, 330 }, 331 valid: true, 332 }, 333 { 334 jsonStr: `{"a": [1,2,3], "b": {"c": 4, "d": [5, 6, 7]}}`, 335 mode: "array", 336 pathStr: "$.b", 337 valid: true, 338 outer: true, 339 outStr: []string{ 340 `path: $.b, this: {"c": 4, "d": [5, 6, 7]}`, 341 }, 342 }, 343 { 344 jsonStr: `{"a": [1,2,3], "b": {"c": 4, "d": [5, 6, 7]}}`, 345 mode: "array", 346 pathStr: "$.b.d", 347 outStr: []string{ 348 `path: $.b.d[0], index: 0, value: 5, this: [5, 6, 7]`, 349 `path: $.b.d[1], index: 1, value: 6, this: [5, 6, 7]`, 350 `path: $.b.d[2], index: 2, value: 7, this: [5, 6, 7]`, 351 }, 352 valid: true, 353 }, 354 { 355 jsonStr: `{"a": [1,2,3], "b": {"c": 4, "d": [5, 6, 7]}}`, 356 mode: "object", 357 pathStr: "$.b", 358 recursive: true, 359 outStr: []string{ 360 `key: c, path: $.b.c, value: 4, this: {"c": 4, "d": [5, 6, 7]}`, 361 `key: d, path: $.b.d, value: [5, 6, 7], this: {"c": 4, "d": [5, 6, 7]}`, 362 }, 363 valid: true, 364 }, 365 { 366 jsonStr: `{"a": [1,2,3], "b": {"c": 4, "d": [5, 6, 7]}}`, 367 mode: "both", 368 pathStr: "$.*", 369 recursive: true, 370 outStr: []string{ 371 `path: $.a[0], index: 0, value: 1, this: [1, 2, 3]`, 372 `path: $.a[1], index: 1, value: 2, this: [1, 2, 3]`, 373 `path: $.a[2], index: 2, value: 3, this: [1, 2, 3]`, 374 `key: c, path: $.b.c, value: 4, this: {"c": 4, "d": [5, 6, 7]}`, 375 `key: d, path: $.b.d, value: [5, 6, 7], this: {"c": 4, "d": [5, 6, 7]}`, 376 `path: $.b.d[0], index: 0, value: 5, this: [5, 6, 7]`, 377 `path: $.b.d[1], index: 1, value: 6, this: [5, 6, 7]`, 378 `path: $.b.d[2], index: 2, value: 7, this: [5, 6, 7]`, 379 }, 380 valid: true, 381 }, 382 { 383 jsonStr: `{"a": [1,2,3], "b": {"a": {"b": 1}, "c": 4, "d": [5, 6, 7]}}`, 384 mode: "object", 385 pathStr: "$.a**.a", 386 outStr: []string{ 387 `key: b, path: $.a[0].a.b, value: 1, this: {"b": 1}`, 388 }, 389 valid: true, 390 }, 391 { 392 jsonStr: `{"a": [1,2,3,{"b":4}], "b": {"a": {"b": 1}, "c": 4, "d": [5, 6, 7]}}`, 393 mode: "both", 394 pathStr: "$**.a", 395 outStr: []string{ 396 `path: $.a[0], index: 0, value: 1, this: [1, 2, 3, {"b": 4}]`, 397 `path: $.a[1], index: 1, value: 2, this: [1, 2, 3, {"b": 4}]`, 398 `path: $.a[2], index: 2, value: 3, this: [1, 2, 3, {"b": 4}]`, 399 `path: $.a[3], index: 3, value: {"b": 4}, this: [1, 2, 3, {"b": 4}]`, 400 `key: b, path: $.b.a.b, value: 1, this: {"b": 1}`, 401 }, 402 valid: true, 403 }, 404 { 405 jsonStr: `{"a": [1,2,3,{"b":4}], "b": {"a": {"b": 1}, "c": 4, "d": [5, 6, 7]}}`, 406 mode: "both", 407 pathStr: "$**.a", 408 recursive: true, 409 outStr: []string{ 410 `path: $.a[0], index: 0, value: 1, this: [1, 2, 3, {"b": 4}]`, 411 `path: $.a[1], index: 1, value: 2, this: [1, 2, 3, {"b": 4}]`, 412 `path: $.a[2], index: 2, value: 3, this: [1, 2, 3, {"b": 4}]`, 413 `path: $.a[3], index: 3, value: {"b": 4}, this: [1, 2, 3, {"b": 4}]`, 414 `key: b, path: $.a[3].b, value: 4, this: {"b": 4}`, 415 `key: b, path: $.b.a.b, value: 1, this: {"b": 1}`, 416 }, 417 valid: true, 418 }, 419 } 420 filterMap := map[string]struct{}{ 421 "index": {}, 422 "this": {}, 423 "value": {}, 424 "path": {}, 425 "key": {}, 426 } 427 for _, kase := range kases { 428 bj, err := ParseFromString(kase.jsonStr) 429 require.Nil(t, err) 430 var path Path 431 if len(kase.pathStr) > 0 { 432 path, err = ParseJsonPath(kase.pathStr) 433 require.Nil(t, err) 434 } 435 out, err := bj.Unnest(&path, kase.outer, kase.recursive, kase.mode, filterMap) 436 if !kase.valid { 437 require.NotNil(t, err) 438 continue 439 } 440 require.Nil(t, err) 441 for i, o := range out { 442 require.Equal(t, kase.outStr[i], o.String()) 443 } 444 } 445 446 } 447 448 func TestByteJson_Unquote(t *testing.T) { 449 kases := []struct { 450 jsonStr string 451 outStr string 452 valid bool 453 }{ 454 { 455 jsonStr: `"a"`, 456 outStr: "a", 457 valid: true, 458 }, 459 { 460 jsonStr: `"a\"b"`, 461 outStr: `a"b`, 462 valid: true, 463 }, 464 { 465 jsonStr: `"a\b"`, 466 outStr: "a\b", 467 valid: true, 468 }, 469 { 470 jsonStr: `"a\r"`, 471 outStr: "a\r", 472 valid: true, 473 }, 474 { 475 jsonStr: `"a\t"`, 476 outStr: `a `, 477 valid: true, 478 }, 479 { 480 jsonStr: `"a\n"`, 481 outStr: `a 482 `, 483 valid: true, 484 }, 485 { 486 jsonStr: `"\u554a\u554a\u5361\u5361"`, 487 outStr: `啊啊卡卡`, 488 valid: true, 489 }, 490 { 491 jsonStr: `"\u4f60\u597d\uff0c\u006d\u006f"`, 492 outStr: `你好,mo`, 493 valid: true, 494 }, 495 { 496 jsonStr: `"\u4f60\u597d\uff0cmo"`, 497 outStr: `你好,mo`, 498 valid: true, 499 }, 500 { 501 jsonStr: `"\u4f60\u597d\ufc"`, 502 valid: false, 503 }, 504 } 505 for _, kase := range kases { 506 bj, err := ParseFromString(kase.jsonStr) 507 if !kase.valid { 508 require.NotNil(t, err) 509 continue 510 } 511 require.Nil(t, err) 512 out, err := bj.Unquote() 513 require.Nil(t, err) 514 require.Equal(t, kase.outStr, out) 515 } 516 }