github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/util/json/json_test.go (about) 1 // Copyright 2017 The Cockroach Authors. 2 // 3 // Use of this software is governed by the Business Source License 4 // included in the file licenses/BSL.txt. 5 // 6 // As of the Change Date specified in that file, in accordance with 7 // the Business Source License, use of this software will be governed 8 // by the Apache License, Version 2.0, included in the file 9 // licenses/APL.txt. 10 11 package json 12 13 import ( 14 "bytes" 15 "encoding/json" 16 "fmt" 17 "math/rand" 18 "strconv" 19 "strings" 20 "testing" 21 22 "github.com/cockroachdb/apd" 23 "github.com/cockroachdb/cockroach/pkg/sql/pgwire/pgerror" 24 "github.com/cockroachdb/cockroach/pkg/util/encoding" 25 "github.com/cockroachdb/cockroach/pkg/util/timeutil" 26 "github.com/cockroachdb/cockroach/pkg/util/unique" 27 ) 28 29 func eachPair(a, b JSON, f func(a, b JSON)) { 30 f(a, a) 31 f(a, b) 32 f(b, a) 33 f(b, b) 34 } 35 36 func eachComparison(a, b JSON, c, d JSON, f func(a, b JSON)) { 37 f(a, c) 38 f(a, d) 39 f(b, c) 40 f(b, d) 41 } 42 43 func runDecodedAndEncoded(t *testing.T, testName string, j JSON, f func(t *testing.T, j JSON)) { 44 t.Run(testName, func(t *testing.T) { 45 f(t, j) 46 }) 47 t.Run(testName+` (encoded)`, func(t *testing.T) { 48 encoding, err := EncodeJSON(nil, j) 49 if err != nil { 50 t.Fatal(err) 51 } 52 encoded, err := newEncodedFromRoot(encoding) 53 if err != nil { 54 t.Fatal(err) 55 } 56 f(t, encoded) 57 }) 58 } 59 60 func TestJSONOrdering(t *testing.T) { 61 // We test here that every element in order sorts before every one that comes 62 // after it, and is equal to itself. 63 sources := []string{ 64 `null`, 65 `"a"`, 66 `"aa"`, 67 `"b"`, 68 `"bb"`, 69 `1`, 70 `2`, 71 `100`, 72 `false`, 73 `true`, 74 // In Postgres's sorting rules, the empty array comes before everything (even null), 75 // so this is a departure. 76 // Shorter arrays sort before longer arrays (this is the same as in Postgres). 77 `[]`, 78 `[1]`, 79 `[2]`, 80 `[1, 2]`, 81 `[1, 3]`, 82 // Objects with fewer keys come before objects with more keys. 83 `{}`, 84 `{"a": 1}`, 85 `{"a": 2}`, 86 // In Postgres, keys which are shorter sort before keys which are longer. This 87 // is not true for us (right now). TODO(justin): unclear if it should be. 88 `{"aa": 1}`, 89 `{"b": 1}`, 90 `{"b": 2}`, 91 // Objects are compared key-1, value-1, key-2, value-2, ... 92 `{"a": 2, "c": 3}`, 93 `{"a": 3, "b": 3}`, 94 } 95 jsons := make([]JSON, len(sources)) 96 encJSONs := make([]JSON, len(sources)) 97 for i := range sources { 98 j, err := ParseJSON(sources[i]) 99 if err != nil { 100 t.Fatal(err) 101 } 102 jsons[i] = j 103 b, err := EncodeJSON(nil, j) 104 if err != nil { 105 t.Fatal(err) 106 } 107 encJSONs[i], err = newEncodedFromRoot(b) 108 if err != nil { 109 t.Fatal(err) 110 } 111 } 112 for i := range jsons { 113 eachPair(jsons[i], encJSONs[i], func(a, b JSON) { 114 c, err := a.Compare(b) 115 if err != nil { 116 t.Fatal(err) 117 } 118 if c != 0 { 119 t.Errorf("%s not equal to %s", a, b) 120 } 121 }) 122 for j := i + 1; j < len(jsons); j++ { 123 eachComparison(jsons[i], encJSONs[i], jsons[j], encJSONs[j], func(a, b JSON) { 124 c, err := a.Compare(b) 125 if err != nil { 126 t.Fatal(err) 127 } 128 if c != -1 { 129 t.Errorf("expected %s < %s", a, b) 130 } 131 }) 132 eachComparison(jsons[j], encJSONs[j], jsons[i], encJSONs[i], func(a, b JSON) { 133 c, err := a.Compare(b) 134 if err != nil { 135 t.Fatal(err) 136 } 137 if c != 1 { 138 t.Errorf("expected %s > %s", a, b) 139 } 140 }) 141 } 142 } 143 } 144 145 func TestJSONRoundTrip(t *testing.T) { 146 testCases := []string{ 147 `1`, 148 `-5`, 149 `1.00`, 150 `1.00000000000`, 151 `100000000000000000000000000000000000000000`, 152 `1.3e100`, 153 `true`, 154 ` true `, 155 ` 156 157 true 158 `, 159 `false`, 160 `"hello"`, 161 `"hel\"\n\r\tlo"`, 162 `[1, true, "three"]`, 163 `[1, 1.0, 1.00, 1.000, 1.0000, 1.00000]`, 164 `[[[[[[[[[[[[[[[]]]]]]]]]]]]]]]`, 165 `"日本語"`, 166 `["日本語"]`, 167 `{"日本語": "日本語"}`, 168 `{"a": "b"}`, 169 `{"a\nb": "a"}`, 170 `{"a": "b", "b": "c"}`, 171 `{"a": "b", "b": 1}`, 172 `{"a": "b", "b": 1, "c": [1, 2, {"a": 3}]}`, 173 `"🤔"`, 174 `{"🤔": "🤔"}`, 175 `"\u0000"`, 176 `"\u0001"`, 177 `"\u0002"`, 178 `"\u0003"`, 179 `"\u0004"`, 180 `"\u0005"`, 181 `"\u0006"`, 182 `"\u0007"`, 183 `"\u0008"`, 184 `"\t"`, 185 `"\n"`, 186 `"\u000b"`, 187 `"\u000c"`, 188 `"\r"`, 189 `"\u000e"`, 190 `"\u000f"`, 191 `"\u0010"`, 192 `"\u0011"`, 193 `"\u0012"`, 194 `"\u0013"`, 195 `"\u0014"`, 196 `"\u0015"`, 197 `"\u0016"`, 198 `"\u0017"`, 199 `"\u0018"`, 200 `"\u0019"`, 201 `"\u001a"`, 202 `"\u001b"`, 203 `"\u001c"`, 204 `"\u001d"`, 205 `"\u001e"`, 206 `"\u001f"`, 207 `"\uffff"`, 208 `"\\"`, 209 `"\""`, 210 // We don't expect to get any invalid UTF8, but check one anyway. We could do 211 // a validation that the input is valid UTF8, but that seems wasteful when it 212 // should be checked higher up. 213 string([]byte{'"', 0xa7, '"'}), 214 `[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]`, 215 } 216 for i, tc := range testCases { 217 j, err := ParseJSON(tc) 218 if err != nil { 219 t.Fatal(err) 220 } 221 // We don't include the actual string here because TeamCity doesn't handle 222 // test names with emojis in them well. 223 runDecodedAndEncoded(t, fmt.Sprintf("%d", i), j, func(t *testing.T, j JSON) { 224 s := j.String() 225 226 j2, err := ParseJSON(s) 227 if err != nil { 228 t.Fatalf("error while parsing %v: %s", s, err) 229 } 230 c, err := j.Compare(j2) 231 if err != nil { 232 t.Fatal(err) 233 } 234 if c != 0 { 235 t.Fatalf("%v should equal %v", tc, s) 236 } 237 s2 := j2.String() 238 if s != s2 { 239 t.Fatalf("%v should equal %v", s, s2) 240 } 241 }) 242 } 243 } 244 245 func TestJSONErrors(t *testing.T) { 246 testCases := []struct { 247 input string 248 msg string 249 }{ 250 {`true false`, `trailing characters after JSON document`}, 251 {`trues`, `trailing characters after JSON document`}, 252 {`1 2 3`, `trailing characters after JSON document`}, 253 // Here the decoder just grabs the 0 and leaves the 1. JSON numbers can't have 254 // leading 0s. 255 {`01`, `trailing characters after JSON document`}, 256 {`{foo: 1}`, `invalid character 'f' looking for beginning of object key string`}, 257 {`{'foo': 1}`, `invalid character '\'' looking for beginning of object key string`}, 258 {`{"foo": 01}`, `invalid character '1' after object key:value pair`}, 259 {`{`, `unexpected EOF`}, 260 {`"\v"`, `invalid character 'v' in string escape code`}, 261 {`"\x00"`, `invalid character 'x' in string escape code`}, 262 {string([]byte{'"', '\n', '"'}), `invalid character`}, 263 {string([]byte{'"', 8, '"'}), `invalid character`}, 264 } 265 for _, tc := range testCases { 266 t.Run(tc.input, func(t *testing.T) { 267 j, err := ParseJSON(tc.input) 268 if err == nil { 269 t.Fatalf("expected parsing '%v' to error with '%s', but no error occurred and parsed as %s", tc.input, tc.msg, j) 270 } 271 if !strings.Contains(err.Error(), tc.msg) { 272 t.Fatalf("expected error message to be '%s', but was '%s'", tc.msg, err.Error()) 273 } 274 if !pgerror.HasCandidateCode(err) { 275 t.Fatalf("expected parsing '%s' to provide a pg error code", tc.input) 276 } 277 }) 278 } 279 } 280 281 func TestJSONSize(t *testing.T) { 282 testCases := []struct { 283 input string 284 size uintptr 285 }{ 286 // These numbers aren't set in stone, they're just here to make sure this 287 // function makes some amount of sense. 288 {`true`, 0}, 289 {`false`, 0}, 290 {`null`, 0}, 291 {`""`, stringHeaderSize}, 292 {`"hello"`, stringHeaderSize + 5}, 293 {`[]`, sliceHeaderSize}, 294 {`[null]`, sliceHeaderSize + jsonInterfaceSize}, 295 {`[""]`, sliceHeaderSize + jsonInterfaceSize + stringHeaderSize}, 296 {`[[]]`, sliceHeaderSize + jsonInterfaceSize + sliceHeaderSize}, 297 {`[{}]`, sliceHeaderSize + jsonInterfaceSize + sliceHeaderSize}, 298 {`["hello","goodbye"]`, sliceHeaderSize + 2*jsonInterfaceSize + 2*stringHeaderSize + 12}, 299 {`{}`, sliceHeaderSize}, 300 {`{"":null}`, sliceHeaderSize + keyValuePairSize}, 301 {`{"":{}}`, sliceHeaderSize + keyValuePairSize + sliceHeaderSize}, 302 {`{"a":"b"}`, sliceHeaderSize + keyValuePairSize + 1 + stringHeaderSize + 1}, 303 } 304 largeBuf := make([]byte, 0, 10240) 305 for _, tc := range testCases { 306 t.Run(tc.input, func(t *testing.T) { 307 j, err := ParseJSON(tc.input) 308 if err != nil { 309 t.Fatal(err) 310 } 311 if j.Size() != tc.size { 312 t.Fatalf("expected %v to have size %d, but had size %d", j, tc.size, j.Size()) 313 } 314 315 t.Run("jsonEncodedSize", func(t *testing.T) { 316 largeBuf = largeBuf[:0] 317 var buf []byte 318 var err error 319 320 if buf, err = EncodeJSON(buf, j); err != nil { 321 t.Fatal(err) 322 } 323 if largeBuf, err = EncodeJSON(largeBuf, j); err != nil { 324 t.Fatal(err) 325 } 326 327 encoded, err := newEncodedFromRoot(buf) 328 if err != nil { 329 t.Fatal(err) 330 } 331 encodedFromLargeBuf, err := newEncodedFromRoot(largeBuf) 332 if err != nil { 333 t.Fatal(err) 334 } 335 if encodedFromLargeBuf.Size() != encoded.Size() { 336 t.Errorf("expected jsonEncoded on a large buf for %v to have size %d, found %d", j, encoded.Size(), encodedFromLargeBuf.Size()) 337 } 338 }) 339 }) 340 } 341 } 342 343 func TestJSONLen(t *testing.T) { 344 testCases := []struct { 345 input string 346 len int 347 }{ 348 {`true`, 0}, 349 {`false`, 0}, 350 {`null`, 0}, 351 {`"a"`, 0}, 352 {`[]`, 0}, 353 {`["a","b"]`, 2}, 354 {`{}`, 0}, 355 {`{"a":"b"}`, 1}, 356 } 357 for _, tc := range testCases { 358 j, err := ParseJSON(tc.input) 359 if err != nil { 360 t.Fatal(err) 361 } 362 runDecodedAndEncoded(t, tc.input, j, func(t *testing.T, j JSON) { 363 if j.Len() != tc.len { 364 t.Fatalf("expected %d, got %d", tc.len, j.Len()) 365 } 366 }) 367 } 368 } 369 370 func TestMakeJSON(t *testing.T) { 371 testCases := []struct { 372 input interface{} 373 expected string 374 }{ 375 // These tests are limited because they only really need to exercise the 376 // parts not exercised by the ParseJSON tests - that is, those involving 377 // int/int64/float64. 378 {json.Number("1.00"), "1.00"}, 379 {1, "1"}, 380 {int64(1), "1"}, 381 {1.4, "1.4"}, 382 {map[string]interface{}{"foo": 4}, `{"foo": 4}`}, 383 } 384 385 for _, tc := range testCases { 386 t.Run(tc.expected, func(t *testing.T) { 387 result, err := MakeJSON(tc.input) 388 if err != nil { 389 t.Fatal(err) 390 } 391 392 expectedResult, err := ParseJSON(tc.expected) 393 if err != nil { 394 t.Fatal(err) 395 } 396 397 c, err := result.Compare(expectedResult) 398 if err != nil { 399 t.Fatal(err) 400 } 401 if c != 0 { 402 t.Fatalf("expected %v to equal %v", result, expectedResult) 403 } 404 }) 405 } 406 } 407 408 func TestArrayBuilderWithCounter(t *testing.T) { 409 testCases := []struct { 410 input []interface{} 411 }{ 412 {[]interface{}{}}, 413 {[]interface{}{"a"}}, 414 {[]interface{}{1, 2, "abc", nil, 1.2}}, 415 {[]interface{}{"a", "aa", "aaa", "aaaa"}}, 416 } 417 for _, tc := range testCases { 418 t.Run(fmt.Sprintf("array %v", tc.input), func(t *testing.T) { 419 builder := NewArrayBuilderWithCounter() 420 for _, e := range tc.input { 421 j, err := MakeJSON(e) 422 if err != nil { 423 t.Fatal(err) 424 } 425 builder.Add(j) 426 } 427 result := builder.Build() 428 expectedJSON, err := MakeJSON(tc.input) 429 if err != nil { 430 t.Fatal(err) 431 } 432 c, err := result.Compare(expectedJSON) 433 if err != nil { 434 t.Fatal(err) 435 } 436 if c != 0 { 437 t.Fatalf("expected %v to equal %v", result, expectedJSON) 438 } 439 if builder.Size() != result.Size() { 440 t.Fatalf("expected %v to equal %v", builder.Size(), result.Size()) 441 } 442 }) 443 } 444 } 445 446 func TestBuildJSONObject(t *testing.T) { 447 testCases := []struct { 448 input []string 449 }{ 450 {[]string{}}, 451 {[]string{"a"}}, 452 {[]string{"a", "c", "a", "b", "a"}}, 453 {[]string{"2", "1", "10", "3", "10", "1"}}, 454 } 455 for _, tc := range testCases { 456 t.Run(fmt.Sprintf("keys %v", tc.input), func(t *testing.T) { 457 m := map[string]interface{}{} 458 b := NewObjectBuilder(0) 459 for i, k := range tc.input { 460 j := FromString(fmt.Sprintf("%d", i)) 461 m[k] = j 462 b.Add(k, j) 463 } 464 expectedResult, err := MakeJSON(m) 465 if err != nil { 466 t.Fatal(err) 467 } 468 result := b.Build() 469 c, err := result.Compare(expectedResult) 470 if err != nil { 471 t.Fatal(err) 472 } 473 if c != 0 { 474 t.Fatalf("expected %v to equal %v", result, expectedResult) 475 } 476 }) 477 } 478 } 479 480 func jsonTestShorthand(s string) JSON { 481 j, err := ParseJSON(s) 482 if err != nil { 483 panic(fmt.Sprintf("bad json: %s", s)) 484 } 485 return j 486 } 487 488 func TestJSONFetch(t *testing.T) { 489 // Shorthand for tests. 490 json := jsonTestShorthand 491 cases := map[string][]struct { 492 key string 493 expected JSON 494 }{ 495 `{}`: { 496 {``, nil}, 497 {`foo`, nil}, 498 }, 499 `{"foo": 1, "bar": "baz"}`: { 500 {``, nil}, 501 {`foo`, json(`1`)}, 502 {`bar`, json(`"baz"`)}, 503 {`baz`, nil}, 504 }, 505 `{"foo": [1, 2, 3], "bar": {"a": "b"}}`: { 506 {``, nil}, 507 {`foo`, json(`[1, 2, 3]`)}, 508 {`bar`, json(`{"a": "b"}`)}, 509 {`baz`, nil}, 510 }, 511 `["a"]`: {{``, nil}, {`0`, nil}, {`a`, nil}}, 512 `"a"`: {{``, nil}, {`0`, nil}, {`a`, nil}}, 513 `1`: {{``, nil}, {`0`, nil}, {`a`, nil}}, 514 `true`: {{``, nil}, {`0`, nil}, {`a`, nil}}, 515 } 516 517 for k, tests := range cases { 518 left, err := ParseJSON(k) 519 if err != nil { 520 t.Fatal(err) 521 } 522 523 for _, tc := range tests { 524 runDecodedAndEncoded(t, k+`->`+tc.key, left, func(t *testing.T, j JSON) { 525 result, err := j.FetchValKey(tc.key) 526 if err != nil { 527 t.Fatal(err) 528 } 529 if result == nil || tc.expected == nil { 530 if result == tc.expected { 531 return 532 } 533 t.Fatalf("expected %s, got %s", tc.expected, result) 534 } 535 c, err := result.Compare(tc.expected) 536 if err != nil { 537 t.Fatal(err) 538 } 539 if c != 0 { 540 t.Fatalf("expected %s, got %s", tc.expected, result) 541 } 542 }) 543 } 544 } 545 } 546 547 func TestJSONRandomFetch(t *testing.T) { 548 rng := rand.New(rand.NewSource(timeutil.Now().Unix())) 549 for i := 0; i < 1000; i++ { 550 // We want a big object to trigger the binary search behavior in FetchValKey. 551 j, err := Random(1000, rng) 552 if err != nil { 553 t.Fatal(err) 554 } 555 if obj, ok := j.(jsonObject); ok { 556 // Pick a key: 557 idx := rand.Intn(len(obj)) 558 result, err := obj.FetchValKey(string(obj[idx].k)) 559 if err != nil { 560 t.Fatal(err) 561 } 562 c, err := result.Compare(obj[idx].v) 563 if err != nil { 564 t.Fatal(err) 565 } 566 if c != 0 { 567 t.Fatalf("%s: expected fetching %s to give %s got %s", obj, obj[idx].k, obj[idx].v, result) 568 } 569 } 570 } 571 } 572 573 func TestJSONFetchFromBig(t *testing.T) { 574 size := 100 575 576 obj := make(map[string]interface{}) 577 for i := 0; i < size; i++ { 578 obj[fmt.Sprintf("key%d", i)] = i 579 } 580 j, err := MakeJSON(obj) 581 if err != nil { 582 t.Fatal(err) 583 } 584 585 runDecodedAndEncoded(t, "fetch big", j, func(t *testing.T, j JSON) { 586 for i := 0; i < size; i++ { 587 result, err := j.FetchValKey(fmt.Sprintf("key%d", i)) 588 if err != nil { 589 t.Fatal(err) 590 } 591 592 expected, err := MakeJSON(i) 593 if err != nil { 594 t.Fatal(err) 595 } 596 597 cmp, err := result.Compare(expected) 598 if err != nil { 599 t.Fatal(err) 600 } 601 if cmp != 0 { 602 t.Errorf("expected %d, got %d", i, result) 603 } 604 } 605 }) 606 } 607 608 func TestJSONFetchIdx(t *testing.T) { 609 json := jsonTestShorthand 610 cases := map[string][]struct { 611 idx int 612 expected JSON 613 }{ 614 `{}`: {{1, nil}, {2, nil}}, 615 `{"foo": 1, "1": "baz"}`: {{0, nil}, {1, nil}, {2, nil}}, 616 `[]`: {{-1, nil}, {0, nil}, {1, nil}}, 617 `["a", "b", "c"]`: { 618 // Negative indices count from the back. 619 {-4, nil}, 620 {-3, json(`"a"`)}, 621 {-2, json(`"b"`)}, 622 {-1, json(`"c"`)}, 623 {0, json(`"a"`)}, 624 {1, json(`"b"`)}, 625 {2, json(`"c"`)}, 626 {3, nil}, 627 }, 628 `[1, 2, {"foo":"bar"}]`: { 629 {0, json(`1`)}, 630 {1, json(`2`)}, 631 {2, json(`{"foo":"bar"}`)}, 632 }, 633 // Trigger the offset-value 634 `[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40]`: { 635 {0, json(`0`)}, 636 {1, json(`1`)}, 637 {2, json(`2`)}, 638 {10, json(`10`)}, 639 {35, json(`35`)}, 640 }, 641 } 642 643 for k, tests := range cases { 644 left, err := ParseJSON(k) 645 if err != nil { 646 t.Fatal(err) 647 } 648 649 for _, tc := range tests { 650 runDecodedAndEncoded(t, fmt.Sprintf("%s->%d", k, tc.idx), left, func(t *testing.T, j JSON) { 651 result, err := j.FetchValIdx(tc.idx) 652 if err != nil { 653 t.Fatal(err) 654 } 655 if result == nil || tc.expected == nil { 656 if result == tc.expected { 657 return 658 } 659 t.Fatalf("expected %s, got %s", tc.expected, result) 660 } 661 c, err := result.Compare(tc.expected) 662 if err != nil { 663 t.Fatal(err) 664 } 665 if c != 0 { 666 t.Fatalf("expected %s, got %s", tc.expected, result) 667 } 668 }) 669 } 670 } 671 } 672 673 func TestJSONExists(t *testing.T) { 674 cases := map[string][]struct { 675 key string 676 exists bool 677 }{ 678 `{}`: { 679 {``, false}, 680 {`foo`, false}, 681 }, 682 `{"foo": 1, "bar": "baz"}`: { 683 {``, false}, 684 {`foo`, true}, 685 {`bar`, true}, 686 {`baz`, false}, 687 }, 688 `{"foo": [1, 2, 3], "bar": {"a": "b"}}`: { 689 {``, false}, 690 {`foo`, true}, 691 {`bar`, true}, 692 {`baz`, false}, 693 }, 694 `["a"]`: {{``, false}, {`0`, false}, {`a`, true}}, 695 `"a"`: {{``, false}, {`0`, false}, {`a`, true}}, 696 `1`: {{``, false}, {`0`, false}, {`a`, false}}, 697 `true`: {{``, false}, {`0`, false}, {`a`, false}}, 698 } 699 700 for k, tests := range cases { 701 left, err := ParseJSON(k) 702 if err != nil { 703 t.Fatal(err) 704 } 705 706 for _, tc := range tests { 707 t.Run(k+` ? `+tc.key, func(t *testing.T) { 708 result, err := left.Exists(tc.key) 709 if err != nil { 710 t.Fatal(err) 711 } 712 if result != tc.exists { 713 if tc.exists { 714 t.Fatalf("expected %s ? %s", left, tc.key) 715 } 716 t.Fatalf("expected %s to NOT ? %s", left, tc.key) 717 } 718 }) 719 720 t.Run(k+` ? `+tc.key+` (encoded)`, func(t *testing.T) { 721 encoding, err := EncodeJSON(nil, left) 722 if err != nil { 723 t.Fatal(err) 724 } 725 encoded, err := newEncodedFromRoot(encoding) 726 if err != nil { 727 t.Fatal(err) 728 } 729 730 result, err := encoded.Exists(tc.key) 731 if err != nil { 732 t.Fatal(err) 733 } 734 if result != tc.exists { 735 if tc.exists { 736 t.Fatalf("expected %s ? %s", encoded, tc.key) 737 } 738 t.Fatalf("expected %s to NOT ? %s", encoded, tc.key) 739 } 740 }) 741 } 742 } 743 } 744 745 func TestJSONStripNulls(t *testing.T) { 746 testcases := []struct { 747 input string 748 needToStrip bool 749 expected string 750 }{ 751 {`null`, false, `null`}, 752 {`1`, false, `1`}, 753 {`"a"`, false, `"a"`}, 754 {`true`, false, `true`}, 755 {`false`, false, `false`}, 756 {`[]`, false, `[]`}, 757 {`[1, "a", null, true, {"a":1, "b":[null]}]`, false, `[1, "a", null, true, {"a":1, "b":[null]}]`}, 758 {`[{"a":null}]`, true, `[{}]`}, 759 {`[[{"a":null}]]`, true, `[[{}]]`}, 760 {`[null, {"a":null}, {"a":null}]`, true, `[null, {}, {}]`}, 761 {`[{"a":null}, {"a":null}, null]`, true, `[{}, {}, null]`}, 762 {`{}`, false, `{}`}, 763 {`{"a":[null], "b":1, "c":{"a":1}}`, false, `{"a":[null], "b":1, "c":{"a":1}}`}, 764 {`{"a":null}`, true, `{}`}, 765 {`{"a":{"a":null}}`, true, `{"a":{}}`}, 766 {`{"a":[{"a":null}]}`, true, `{"a":[{}]}`}, 767 {`{"a":[null], "b":null, "c":{"a":null}}`, true, `{"a":[null], "c":{}}`}, 768 {`{"a":[null], "b":{"a":null}, "c":{"a":null}}`, true, `{"a":[null], "b":{}, "c":{}}`}, 769 {`{"a":{"a":null}, "b":{"a":null}, "c":[null]}`, true, `{"a":{}, "b":{}, "c":[null]}`}, 770 } 771 for _, tc := range testcases { 772 j, err := ParseJSON(tc.input) 773 if err != nil { 774 t.Fatal(err) 775 } 776 expectedResult, err := ParseJSON(tc.expected) 777 if err != nil { 778 t.Fatal(err) 779 } 780 runDecodedAndEncoded(t, tc.input, j, func(t *testing.T, j JSON) { 781 result, needToStrip, err := j.StripNulls() 782 if err != nil { 783 t.Fatal(err) 784 } 785 c, err := result.Compare(expectedResult) 786 if err != nil { 787 t.Fatal(err) 788 } 789 if needToStrip != tc.needToStrip { 790 t.Fatalf("expected %t, got %t", tc.needToStrip, needToStrip) 791 } 792 if c != 0 { 793 t.Fatalf("expected %s, got %s", tc.expected, result) 794 } 795 // Check whether j is not changed. 796 originInput, err := ParseJSON(tc.input) 797 if err != nil { 798 t.Fatal(err) 799 } 800 if c, err = j.Compare(originInput); err != nil { 801 t.Fatal(err) 802 } 803 if c != 0 { 804 t.Fatalf("expected %s, got %s", originInput, j) 805 } 806 }) 807 } 808 } 809 810 func TestJSONFetchPath(t *testing.T) { 811 json := jsonTestShorthand 812 cases := map[string][]struct { 813 path []string 814 expected JSON 815 }{ 816 `{}`: { 817 {[]string{`a`}, nil}, 818 }, 819 `{"foo": "bar"}`: { 820 {[]string{`foo`}, json(`"bar"`)}, 821 {[]string{`goo`}, nil}, 822 }, 823 `{"foo": {"bar": "baz"}}`: { 824 {[]string{`foo`}, json(`{"bar": "baz"}`)}, 825 {[]string{`foo`, `bar`}, json(`"baz"`)}, 826 {[]string{`foo`, `baz`}, nil}, 827 }, 828 `{"foo": [1, 2, {"bar": "baz"}]}`: { 829 {[]string{`foo`}, json(`[1, 2, {"bar": "baz"}]`)}, 830 {[]string{`foo`, `0`}, json(`1`)}, 831 {[]string{`foo`, `1`}, json(`2`)}, 832 {[]string{`foo`, `2`}, json(`{"bar": "baz"}`)}, 833 {[]string{`foo`, `2`, "bar"}, json(`"baz"`)}, 834 {[]string{`foo`, `-1`, "bar"}, json(`"baz"`)}, 835 {[]string{`foo`, `3`}, nil}, 836 {[]string{`foo`, `3`, "bar"}, nil}, 837 }, 838 `[1, 2, [1, 2, [1, 2]]]`: { 839 {[]string{`"foo"`}, nil}, 840 {[]string{`0`}, json(`1`)}, 841 {[]string{`1`}, json(`2`)}, 842 {[]string{`0`, `0`}, nil}, 843 {[]string{`2`}, json(`[1, 2, [1, 2]]`)}, 844 {[]string{`2`, `0`}, json(`1`)}, 845 {[]string{`2`, `1`}, json(`2`)}, 846 {[]string{`2`, `2`}, json(`[1, 2]`)}, 847 {[]string{`2`, `2`, `0`}, json(`1`)}, 848 {[]string{`2`, `2`, `1`}, json(`2`)}, 849 {[]string{`-1`, `-1`, `-1`}, json(`2`)}, 850 }, 851 } 852 853 for k, tests := range cases { 854 left, err := ParseJSON(k) 855 if err != nil { 856 t.Fatal(err) 857 } 858 859 for _, tc := range tests { 860 t.Run(fmt.Sprintf("%s#>%v", k, tc.path), func(t *testing.T) { 861 result, err := FetchPath(left, tc.path) 862 if err != nil { 863 t.Fatal(err) 864 } 865 if result == nil || tc.expected == nil { 866 if result == tc.expected { 867 return 868 } 869 t.Fatalf("expected %s, got %s", tc.expected, result) 870 } 871 c, err := result.Compare(tc.expected) 872 if err != nil { 873 t.Fatal(err) 874 } 875 if c != 0 { 876 t.Fatalf("expected %s, got %s", tc.expected, result) 877 } 878 }) 879 } 880 881 for _, tc := range tests { 882 t.Run(fmt.Sprintf("%s#>%v (encoded)", k, tc.path), func(t *testing.T) { 883 encoding, err := EncodeJSON(nil, left) 884 if err != nil { 885 t.Fatal(err) 886 } 887 encoded, err := newEncodedFromRoot(encoding) 888 if err != nil { 889 t.Fatal(err) 890 } 891 result, err := FetchPath(encoded, tc.path) 892 if err != nil { 893 t.Fatal(err) 894 } 895 if result == nil || tc.expected == nil { 896 if result == tc.expected { 897 return 898 } 899 t.Fatalf("expected %s, got %s", tc.expected, result) 900 } 901 c, err := result.Compare(tc.expected) 902 if err != nil { 903 t.Fatal(err) 904 } 905 if c != 0 { 906 t.Fatalf("expected %s, got %s", tc.expected, result) 907 } 908 }) 909 } 910 } 911 } 912 913 func TestJSONDeepSet(t *testing.T) { 914 cases := map[string][]struct { 915 path []string 916 to string 917 createMissing bool 918 expected string 919 }{ 920 `{}`: { 921 {[]string{}, `1`, true, `{}`}, 922 {[]string{`a`}, `1`, true, `{"a": 1}`}, 923 {[]string{`a`}, `1`, false, `{}`}, 924 {[]string{`a`, `b`}, `1`, true, `{}`}, 925 }, 926 `{"a": 1}`: { 927 {[]string{}, `2`, true, `{"a": 1}`}, 928 {[]string{`a`}, `2`, true, `{"a": 2}`}, 929 {[]string{`a`}, `2`, false, `{"a": 2}`}, 930 {[]string{`a`, `b`}, `2`, true, `{"a": 1}`}, 931 }, 932 `{"a": {"b": 1}}`: { 933 {[]string{}, `2`, true, `{"a": {"b": 1}}`}, 934 {[]string{`a`}, `2`, true, `{"a": 2}`}, 935 {[]string{`a`, `b`}, `2`, true, `{"a": {"b": 2}}`}, 936 {[]string{`a`, `b`}, `2`, false, `{"a": {"b": 2}}`}, 937 {[]string{`a`, `c`}, `3`, true, `{"a": {"b": 1, "c": 3}}`}, 938 {[]string{`a`, `c`}, `3`, false, `{"a": {"b": 1}}`}, 939 {[]string{`b`}, `2`, true, `{"a": {"b": 1}, "b": 2}`}, 940 {[]string{`b`}, `2`, false, `{"a": {"b": 1}}`}, 941 }, 942 `{"b": 1}`: { 943 {[]string{`a`}, `2`, true, `{"a": 2, "b": 1}`}, 944 {[]string{`b`}, `2`, true, `{"b": 2}`}, 945 {[]string{`c`}, `2`, true, `{"b": 1, "c": 2}`}, 946 }, 947 `[]`: { 948 {[]string{`-2`}, `1`, true, `[1]`}, 949 {[]string{`-1`}, `1`, true, `[1]`}, 950 {[]string{`0`}, `1`, true, `[1]`}, 951 {[]string{`1`}, `1`, true, `[1]`}, 952 {[]string{`2`}, `1`, true, `[1]`}, 953 {[]string{`-2`}, `1`, false, `[]`}, 954 {[]string{`-1`}, `1`, false, `[]`}, 955 {[]string{`0`}, `1`, false, `[]`}, 956 {[]string{`1`}, `1`, false, `[]`}, 957 {[]string{`2`}, `1`, false, `[]`}, 958 {[]string{`2`, `0`}, `1`, true, `[]`}, 959 }, 960 `[10]`: { 961 {[]string{`-2`}, `1`, true, `[1, 10]`}, 962 {[]string{`-1`}, `1`, true, `[1]`}, 963 {[]string{`0`}, `1`, true, `[1]`}, 964 {[]string{`1`}, `1`, true, `[10, 1]`}, 965 {[]string{`2`}, `1`, true, `[10, 1]`}, 966 {[]string{`-2`}, `1`, false, `[10]`}, 967 {[]string{`-1`}, `1`, false, `[1]`}, 968 {[]string{`0`}, `1`, false, `[1]`}, 969 {[]string{`1`}, `1`, false, `[10]`}, 970 {[]string{`2`}, `1`, false, `[10]`}, 971 }, 972 `[10, 20]`: { 973 {[]string{`-3`}, `1`, true, `[1, 10, 20]`}, 974 {[]string{`-2`}, `1`, true, `[1, 20]`}, 975 {[]string{`-1`}, `1`, true, `[10, 1]`}, 976 {[]string{`0`}, `1`, true, `[1, 20]`}, 977 {[]string{`1`}, `1`, true, `[10, 1]`}, 978 {[]string{`2`}, `1`, true, `[10, 20, 1]`}, 979 {[]string{`3`}, `1`, true, `[10, 20, 1]`}, 980 {[]string{`3`, `1`}, `1`, true, `[10, 20]`}, 981 }, 982 `[[10], [20, 30], {"a": 1}]`: { 983 {[]string{`0`}, `1`, true, `[1, [20, 30], {"a": 1}]`}, 984 {[]string{`0`, `0`}, `1`, true, `[[1], [20, 30], {"a": 1}]`}, 985 {[]string{`0`, `1`}, `1`, true, `[[10, 1], [20, 30], {"a": 1}]`}, 986 {[]string{`1`, `0`}, `1`, true, `[[10], [1, 30], {"a": 1}]`}, 987 {[]string{`2`, `a`}, `2`, true, `[[10], [20, 30], {"a": 2}]`}, 988 {[]string{`2`, `b`}, `2`, true, `[[10], [20, 30], {"a": 1, "b": 2}]`}, 989 {[]string{`2`, `a`, `c`}, `2`, true, `[[10], [20, 30], {"a": 1}]`}, 990 {[]string{`2`, `b`, `c`}, `2`, true, `[[10], [20, 30], {"a": 1}]`}, 991 }, 992 `[{"a": [1]}]`: { 993 {[]string{`0`, `a`, `0`}, `2`, true, `[{"a": [2]}]`}, 994 {[]string{`0`, `a`, `0`, `0`}, `2`, true, `[{"a": [1]}]`}, 995 }, 996 } 997 998 for k, tests := range cases { 999 j := jsonTestShorthand(k) 1000 for _, tc := range tests { 1001 t.Run(fmt.Sprintf(`set(%s, %s, %s)`, k, tc.path, tc.to), func(t *testing.T) { 1002 result, err := DeepSet(j, tc.path, jsonTestShorthand(tc.to), tc.createMissing) 1003 if err != nil { 1004 t.Fatal(err) 1005 } 1006 1007 cmp, err := result.Compare(jsonTestShorthand(tc.expected)) 1008 if err != nil { 1009 t.Fatal(err) 1010 } 1011 1012 if cmp != 0 { 1013 t.Fatalf("expected %s, got %s", tc.expected, result) 1014 } 1015 }) 1016 } 1017 } 1018 } 1019 1020 func TestJSONRemoveString(t *testing.T) { 1021 json := jsonTestShorthand 1022 cases := map[string][]struct { 1023 key string 1024 ok bool 1025 expected JSON 1026 errMsg string 1027 }{ 1028 `{}`: { 1029 {key: ``, ok: false, expected: json(`{}`)}, 1030 {key: `foo`, ok: false, expected: json(`{}`)}, 1031 }, 1032 `{"foo": 1, "bar": "baz"}`: { 1033 {key: ``, ok: false, expected: json(`{"foo": 1, "bar": "baz"}`)}, 1034 {key: `foo`, ok: true, expected: json(`{"bar": "baz"}`)}, 1035 {key: `bar`, ok: true, expected: json(`{"foo": 1}`)}, 1036 {key: `baz`, ok: false, expected: json(`{"foo": 1, "bar": "baz"}`)}, 1037 }, 1038 // Deleting a string key from an array never has any effect. 1039 `["a", "b", "c"]`: { 1040 {key: ``, ok: false, expected: json(`["a", "b", "c"]`)}, 1041 {key: `foo`, ok: false, expected: json(`["a", "b", "c"]`)}, 1042 {key: `0`, ok: false, expected: json(`["a", "b", "c"]`)}, 1043 {key: `1`, ok: false, expected: json(`["a", "b", "c"]`)}, 1044 {key: `-1`, ok: false, expected: json(`["a", "b", "c"]`)}, 1045 }, 1046 `5`: {{key: `a`, errMsg: "cannot delete from scalar"}}, 1047 `"b"`: {{key: `a`, errMsg: "cannot delete from scalar"}}, 1048 `true`: {{key: `a`, errMsg: "cannot delete from scalar"}}, 1049 `false`: {{key: `a`, errMsg: "cannot delete from scalar"}}, 1050 `null`: {{key: `a`, errMsg: "cannot delete from scalar"}}, 1051 } 1052 1053 for k, tests := range cases { 1054 left, err := ParseJSON(k) 1055 if err != nil { 1056 t.Fatal(err) 1057 } 1058 1059 for _, tc := range tests { 1060 runDecodedAndEncoded(t, k+`-`+tc.key, left, func(t *testing.T, j JSON) { 1061 result, ok, err := j.RemoveString(tc.key) 1062 if tc.errMsg != "" { 1063 if err == nil { 1064 t.Fatal("expected error") 1065 } else if !strings.Contains(err.Error(), tc.errMsg) { 1066 t.Fatalf(`expected error message "%s" to contain "%s"`, err.Error(), tc.errMsg) 1067 } 1068 return 1069 } 1070 if err != nil { 1071 t.Fatal(err) 1072 } 1073 if tc.ok != ok { 1074 t.Fatalf("expected %t, got %t", tc.ok, ok) 1075 } 1076 c, err := result.Compare(tc.expected) 1077 if err != nil { 1078 t.Fatal(err) 1079 } 1080 if c != 0 { 1081 t.Fatalf("expected %s, got %s", tc.expected, result) 1082 } 1083 }) 1084 } 1085 } 1086 } 1087 1088 func TestJSONRemoveIndex(t *testing.T) { 1089 json := jsonTestShorthand 1090 cases := map[string][]struct { 1091 idx int 1092 ok bool 1093 expected JSON 1094 errMsg string 1095 }{ 1096 `{"foo": 1, "bar": "baz"}`: { 1097 {idx: 0, errMsg: "cannot delete from object using integer"}, 1098 }, 1099 `["a", "b", "c"]`: { 1100 {idx: -4, ok: false, expected: json(`["a", "b", "c"]`)}, 1101 {idx: -3, ok: true, expected: json(`["b", "c"]`)}, 1102 {idx: -2, ok: true, expected: json(`["a", "c"]`)}, 1103 {idx: -1, ok: true, expected: json(`["a", "b"]`)}, 1104 {idx: 0, ok: true, expected: json(`["b", "c"]`)}, 1105 {idx: 1, ok: true, expected: json(`["a", "c"]`)}, 1106 {idx: 2, ok: true, expected: json(`["a", "b"]`)}, 1107 {idx: 3, ok: false, expected: json(`["a", "b", "c"]`)}, 1108 }, 1109 `[{}, {"a":"b"}, {"c":"d"}]`: { 1110 {idx: 0, ok: true, expected: json(`[{"a":"b"},{"c":"d"}]`)}, 1111 {idx: 1, ok: true, expected: json(`[{},{"c":"d"}]`)}, 1112 {idx: 2, ok: true, expected: json(`[{},{"a":"b"}]`)}, 1113 }, 1114 `[]`: { 1115 {idx: -1, ok: false, expected: json(`[]`)}, 1116 {idx: 0, ok: false, expected: json(`[]`)}, 1117 {idx: 1, ok: false, expected: json(`[]`)}, 1118 }, 1119 `5`: {{idx: 0, errMsg: "cannot delete from scalar"}}, 1120 `"b"`: {{idx: 0, errMsg: "cannot delete from scalar"}}, 1121 `true`: {{idx: 0, errMsg: "cannot delete from scalar"}}, 1122 `false`: {{idx: 0, errMsg: "cannot delete from scalar"}}, 1123 `null`: {{idx: 0, errMsg: "cannot delete from scalar"}}, 1124 } 1125 1126 for k, tests := range cases { 1127 left, err := ParseJSON(k) 1128 if err != nil { 1129 t.Fatal(err) 1130 } 1131 1132 for _, tc := range tests { 1133 runDecodedAndEncoded(t, fmt.Sprintf("%s-%d", k, tc.idx), left, func(t *testing.T, j JSON) { 1134 result, ok, err := j.RemoveIndex(tc.idx) 1135 if tc.errMsg != "" { 1136 if err == nil { 1137 t.Fatal("expected error") 1138 } else if !strings.Contains(err.Error(), tc.errMsg) { 1139 t.Fatalf(`expected error message "%s" to contain "%s"`, err.Error(), tc.errMsg) 1140 } 1141 return 1142 } 1143 if err != nil { 1144 t.Fatal(err) 1145 } 1146 if tc.ok != ok { 1147 t.Fatalf("expected %t, got %t", tc.ok, ok) 1148 } 1149 c, err := result.Compare(tc.expected) 1150 if err != nil { 1151 t.Fatal(err) 1152 } 1153 if c != 0 { 1154 t.Fatalf("expected %s, got %s", tc.expected, result) 1155 } 1156 }) 1157 } 1158 } 1159 } 1160 1161 func TestEncodeDecodeJSONInvertedIndex(t *testing.T) { 1162 testCases := []struct { 1163 value string 1164 expEnc []string 1165 }{ 1166 {`{"a":"b"}`, []string{`/"a"/"b"`}}, 1167 {`null`, []string{`/NULL`}}, 1168 {`false`, []string{`/False`}}, 1169 {`true`, []string{`/True`}}, 1170 {`1.23`, []string{`/1.23`}}, 1171 {`"a"`, []string{`/"a"`}}, 1172 {`[]`, []string{`/[]`}}, 1173 {`{}`, []string{`/{}`}}, 1174 {`["c", {"a":"b"}]`, []string{`/Arr/"c"`, `/Arr/"a"/"b"`}}, 1175 {`["c", {"a":["c","d"]}]`, []string{`/Arr/"c"`, 1176 `/Arr/"a"/Arr/"c"`, 1177 `/Arr/"a"/Arr/"d"`}}, 1178 {`{"a":[]}`, []string{`/"a"/[]`}}, 1179 {`{"a":[{}]}`, []string{`/"a"/Arr/{}`}}, 1180 {`[[],{}]`, []string{`/Arr/[]`, `/Arr/{}`}}, 1181 {`[["a"]]`, []string{`/Arr/Arr/"a"`}}, 1182 } 1183 1184 for _, c := range testCases { 1185 enc, err := EncodeInvertedIndexKeys(nil, jsonTestShorthand(c.value)) 1186 if err != nil { 1187 t.Fatal(err) 1188 } 1189 1190 for j, path := range enc { 1191 str := encoding.PrettyPrintValue(nil, path, "/") 1192 if str != c.expEnc[j] { 1193 t.Errorf("unexpected encoding mismatch for %v. expected [%s], got [%s]", 1194 c.value, c.expEnc[j], str) 1195 } 1196 } 1197 } 1198 } 1199 1200 func getApdEncoding(num float64) *apd.Decimal { 1201 dec := &apd.Decimal{} 1202 dec, _ = dec.SetFloat64(num) 1203 return dec 1204 } 1205 1206 func TestEncodeJSONInvertedIndex(t *testing.T) { 1207 jsonPrefix := make([]byte, 1, 100) 1208 jsonPrefix[0] = 0x37 1209 1210 terminator := make([]byte, 2, 100) 1211 terminator[0] = 0x00 1212 terminator[1] = 0x01 1213 1214 objectSeparator := make([]byte, 2, 100) 1215 objectSeparator[0] = 0x00 1216 objectSeparator[1] = 0x02 1217 1218 arrayPrefix := make([]byte, 2, 100) 1219 arrayPrefix[0] = 0x00 1220 arrayPrefix[1] = 0x03 1221 1222 aEncoding := make([]byte, 1, 100) 1223 aEncoding[0] = 0x61 1224 1225 bEncoding := make([]byte, 1, 100) 1226 bEncoding[0] = 0x62 1227 1228 emptyObjectEncoding := make([]byte, 1, 100) 1229 emptyObjectEncoding[0] = 0x39 1230 1231 emptyArrayEncoding := make([]byte, 1, 100) 1232 emptyArrayEncoding[0] = 0x38 1233 1234 testCases := []struct { 1235 value string 1236 expEnc [][]byte 1237 }{ 1238 {`{"a":"b"}`, [][]byte{bytes.Join([][]byte{jsonPrefix, aEncoding, terminator, encoding.EncodeStringAscending(nil, "b")}, 1239 nil)}}, 1240 {`{"a":{"b":"c"}}`, [][]byte{bytes.Join([][]byte{jsonPrefix, aEncoding, objectSeparator, bEncoding, terminator, encoding.EncodeStringAscending(nil, "c")}, 1241 nil)}}, 1242 {`{"a":{"b":[]}}`, [][]byte{bytes.Join([][]byte{jsonPrefix, aEncoding, objectSeparator, bEncoding, terminator, emptyArrayEncoding}, 1243 nil)}}, 1244 {`{"a":{"b":{}}}`, [][]byte{bytes.Join([][]byte{jsonPrefix, aEncoding, objectSeparator, bEncoding, terminator, emptyObjectEncoding}, 1245 nil)}}, 1246 {`null`, [][]byte{bytes.Join([][]byte{jsonPrefix, terminator, encoding.EncodeNullAscending(nil)}, 1247 nil)}}, 1248 {`false`, [][]byte{bytes.Join([][]byte{jsonPrefix, terminator, encoding.EncodeFalseAscending(nil)}, 1249 nil)}}, 1250 {`true`, [][]byte{bytes.Join([][]byte{jsonPrefix, terminator, encoding.EncodeTrueAscending(nil)}, 1251 nil)}}, 1252 {`1.23`, [][]byte{bytes.Join([][]byte{jsonPrefix, terminator, encoding.EncodeDecimalAscending(nil, getApdEncoding(1.23))}, 1253 nil)}}, 1254 {`"a"`, [][]byte{bytes.Join([][]byte{jsonPrefix, terminator, encoding.EncodeStringAscending(nil, "a")}, 1255 nil)}}, 1256 {`[["a"]]`, [][]byte{bytes.Join([][]byte{jsonPrefix, arrayPrefix, arrayPrefix, terminator, encoding.EncodeStringAscending(nil, "a")}, 1257 nil)}}, 1258 {`{"a":["b","c"]}]`, [][]byte{bytes.Join([][]byte{jsonPrefix, aEncoding, objectSeparator, arrayPrefix, terminator, encoding.EncodeStringAscending(nil, "b")}, nil), 1259 bytes.Join([][]byte{jsonPrefix, aEncoding, objectSeparator, arrayPrefix, terminator, encoding.EncodeStringAscending(nil, "c")}, nil)}}, 1260 {`[]`, [][]byte{bytes.Join([][]byte{jsonPrefix, terminator, emptyArrayEncoding}, 1261 nil)}}, 1262 {`{}`, [][]byte{bytes.Join([][]byte{jsonPrefix, terminator, emptyObjectEncoding}, 1263 nil)}}, 1264 {`[{}, []]`, [][]byte{bytes.Join([][]byte{jsonPrefix, arrayPrefix, terminator, emptyObjectEncoding}, 1265 nil), 1266 bytes.Join([][]byte{jsonPrefix, arrayPrefix, terminator, emptyArrayEncoding}, nil)}}, 1267 {`[[[]]]`, [][]byte{bytes.Join([][]byte{jsonPrefix, arrayPrefix, arrayPrefix, terminator, emptyArrayEncoding}, 1268 nil)}}, 1269 {`[[{}]]`, [][]byte{bytes.Join([][]byte{jsonPrefix, arrayPrefix, arrayPrefix, terminator, emptyObjectEncoding}, 1270 nil)}}, 1271 } 1272 1273 for _, c := range testCases { 1274 enc, err := EncodeInvertedIndexKeys(nil, jsonTestShorthand(c.value)) 1275 if err != nil { 1276 t.Fatal(err) 1277 } 1278 // Make sure that the expected encoding slice is sorted, as well as the 1279 // output of the function under test, because the function under test can 1280 // reorder the keys it's returning if there are arrays inside. 1281 enc = unique.UniquifyByteSlices(enc) 1282 c.expEnc = unique.UniquifyByteSlices(c.expEnc) 1283 for j, path := range enc { 1284 if !bytes.Equal(path, c.expEnc[j]) { 1285 t.Errorf("unexpected encoding mismatch for %v. expected [%#v], got [%#v]", 1286 c.value, c.expEnc[j], path) 1287 } 1288 } 1289 } 1290 } 1291 1292 func TestNumInvertedIndexEntries(t *testing.T) { 1293 testCases := []struct { 1294 value string 1295 expCount int 1296 }{ 1297 {`1`, 1}, 1298 {`"a"`, 1}, 1299 {`null`, 1}, 1300 {`false`, 1}, 1301 {`true`, 1}, 1302 {`[]`, 1}, 1303 {`{}`, 1}, 1304 {`[[[]]]`, 1}, 1305 {`[[{}]]`, 1}, 1306 {`[{}, []]`, 2}, 1307 {`[1]`, 1}, 1308 {`[1, 2]`, 2}, 1309 {`[1, [1]]`, 2}, 1310 {`[1, 2, 1, 2]`, 2}, 1311 {`[[1, 2], [2, 3]]`, 3}, 1312 {`[{"a": 1, "b": 2}]`, 2}, 1313 {`[{"a": 1, "b": 2}, {"a": 1, "b": 3}]`, 3}, 1314 {`[{"a": [1, 2], "b": 2}, {"a": [1, 3], "b": 3}]`, 5}, 1315 } 1316 for _, c := range testCases { 1317 n, err := NumInvertedIndexEntries(jsonTestShorthand(c.value)) 1318 if err != nil { 1319 t.Fatal(err) 1320 } 1321 if n != c.expCount { 1322 t.Errorf("unexpected count of index entries for %v. expected %d, got %d", 1323 c.value, c.expCount, n) 1324 } 1325 } 1326 } 1327 1328 const expectError = "<<error>>" 1329 1330 func TestConcat(t *testing.T) { 1331 cases := map[string][]struct { 1332 concatWith string 1333 expected string 1334 }{ 1335 `null`: { 1336 {`null`, `[null, null]`}, 1337 {`[]`, `[null]`}, 1338 {`[1]`, `[null, 1]`}, 1339 {`{}`, expectError}, 1340 }, 1341 `true`: { 1342 {`null`, `[true, null]`}, 1343 {`[]`, `[true]`}, 1344 {`[1]`, `[true, 1]`}, 1345 {`{}`, expectError}, 1346 }, 1347 `false`: { 1348 {`null`, `[false, null]`}, 1349 {`[]`, `[false]`}, 1350 {`[1]`, `[false, 1]`}, 1351 {`{}`, expectError}, 1352 }, 1353 `123`: { 1354 {`null`, `[123, null]`}, 1355 {`[]`, `[123]`}, 1356 {`[1]`, `[123, 1]`}, 1357 {`{}`, expectError}, 1358 }, 1359 `"hello"`: { 1360 {`null`, `["hello", null]`}, 1361 {`[]`, `["hello"]`}, 1362 {`[1]`, `["hello", 1]`}, 1363 {`{}`, expectError}, 1364 }, 1365 `[1]`: { 1366 {`null`, `[1, null]`}, 1367 {`1`, `[1, 1]`}, 1368 {`"foo"`, `[1, "foo"]`}, 1369 {`[2]`, `[1, 2]`}, 1370 {`[2, 3]`, `[1, 2, 3]`}, 1371 {`{"a": 1}`, `[1, {"a": 1}]`}, 1372 }, 1373 `[1, 2]`: { 1374 {`[3]`, `[1, 2, 3]`}, 1375 {`[3, 4]`, `[1, 2, 3, 4]`}, 1376 }, 1377 `{"a": 1}`: { 1378 {`null`, expectError}, 1379 {`1`, expectError}, 1380 {`"foo"`, expectError}, 1381 {`[2]`, `[{"a": 1}, 2]`}, 1382 {`[2, 3]`, `[{"a": 1}, 2, 3]`}, 1383 {`{"b": 2}`, `{"a": 1, "b": 2}`}, 1384 {`{"a": 2}`, `{"a": 2}`}, 1385 }, 1386 `{"b": 2}`: { 1387 {`{"a": 1}`, `{"a": 1, "b": 2}`}, 1388 }, 1389 `{"a": 1, "b": 2}`: { 1390 {`{"b": 3, "c": 4}`, `{"a": 1, "b": 3, "c": 4}`}, 1391 }, 1392 } 1393 1394 for k, tcs := range cases { 1395 left := jsonTestShorthand(k) 1396 runDecodedAndEncoded(t, k, left, func(t *testing.T, left JSON) { 1397 for _, tc := range tcs { 1398 right := jsonTestShorthand(tc.concatWith) 1399 runDecodedAndEncoded(t, tc.concatWith, right, func(t *testing.T, right JSON) { 1400 if tc.expected == expectError { 1401 result, err := left.Concat(right) 1402 if err == nil { 1403 t.Fatalf("expected %s || %s to error, but got %s", left, right, result) 1404 } 1405 } else { 1406 result, err := left.Concat(right) 1407 if err != nil { 1408 t.Fatal(err) 1409 } 1410 1411 expectedResult := jsonTestShorthand(tc.expected) 1412 1413 cmp, err := result.Compare(expectedResult) 1414 if err != nil { 1415 t.Fatal(err) 1416 } 1417 1418 if cmp != 0 { 1419 t.Fatalf("expected %v || %v = %v, got %v", left, right, expectedResult, result) 1420 } 1421 } 1422 }) 1423 } 1424 }) 1425 } 1426 } 1427 1428 func TestJSONRandomRoundTrip(t *testing.T) { 1429 rng := rand.New(rand.NewSource(timeutil.Now().Unix())) 1430 for i := 0; i < 1000; i++ { 1431 j, err := Random(20, rng) 1432 if err != nil { 1433 t.Fatal(err) 1434 } 1435 j2, err := ParseJSON(j.String()) 1436 if err != nil { 1437 t.Fatal(err) 1438 } 1439 c, err := j.Compare(j2) 1440 if err != nil { 1441 t.Fatal(err) 1442 } 1443 if c != 0 { 1444 t.Fatalf("%s did not round-trip, got %s", j.String(), j2.String()) 1445 } 1446 } 1447 } 1448 1449 func TestJSONContains(t *testing.T) { 1450 cases := map[string][]struct { 1451 other string 1452 expected bool 1453 }{ 1454 `10`: { 1455 {`10`, true}, 1456 {`9`, false}, 1457 }, 1458 `[1, 2, 3]`: { 1459 {`{}`, false}, 1460 {`[]`, true}, 1461 {`[1]`, true}, 1462 {`[1.0]`, true}, 1463 {`[1.00]`, true}, 1464 {`[1, 2]`, true}, 1465 {`[1, 2, 2]`, true}, 1466 {`[2, 1]`, true}, 1467 {`[1, 4]`, false}, 1468 {`[4, 1]`, false}, 1469 {`[4]`, false}, 1470 // This is a unique, special case that only applies to arrays and 1471 // scalars. 1472 {`1`, true}, 1473 {`2`, true}, 1474 {`3`, true}, 1475 {`4`, false}, 1476 }, 1477 `[[1, 2], 3]`: { 1478 {`[1, 2]`, false}, 1479 {`[[1, 2]]`, true}, 1480 {`[[2, 1]]`, true}, 1481 {`[3, [1, 2]]`, true}, 1482 {`[[1, 2], 3]`, true}, 1483 {`[[1], [2], 3]`, true}, 1484 {`[[1], 3]`, true}, 1485 {`[[2]]`, true}, 1486 {`[[3]]`, false}, 1487 }, 1488 `[]`: { 1489 {`[]`, true}, 1490 {`[1]`, false}, 1491 {`1`, false}, 1492 {`{}`, false}, 1493 }, 1494 `{}`: { 1495 {`{}`, true}, 1496 {`1`, false}, 1497 {`{"a":"b"}`, false}, 1498 {`{"":""}`, false}, 1499 }, 1500 `[[1, 2], [3, 4]]`: { 1501 {`[[1, 2]]`, true}, 1502 {`[[3, 4]]`, true}, 1503 {`[[3, 4, 5]]`, false}, 1504 {`[[1, 3]]`, false}, 1505 {`[[2, 4]]`, false}, 1506 {`[1]`, false}, 1507 {`[1, 2]`, false}, 1508 }, 1509 `{"a": "b", "c": "d"}`: { 1510 {`{}`, true}, 1511 {`{"a": "b"}`, true}, 1512 {`{"c": "d"}`, true}, 1513 {`{"a": "b", "c": "d"}`, true}, 1514 {`{"a": "x"}`, false}, 1515 {`{"c": "x"}`, false}, 1516 {`{"y": "x"}`, false}, 1517 {`{"a": "b", "c": "x"}`, false}, 1518 {`{"a": "x", "c": "y"}`, false}, 1519 }, 1520 `{"a": [1, 2, 3], "c": {"foo": "bar"}}`: { 1521 {`{}`, true}, 1522 {`{"a": [1, 2, 3], "c": {"foo": "bar"}}`, true}, 1523 {`{"a": [1, 2]}`, true}, 1524 {`{"a": [2, 1]}`, true}, 1525 {`{"a": []}`, true}, 1526 {`{"a": [4]}`, false}, 1527 {`{"a": [3], "c": {}}`, true}, 1528 {`{"a": [4], "c": {}}`, false}, 1529 {`{"a": [3], "c": {"foo": "gup"}}`, false}, 1530 {`{"a": 3}`, false}, 1531 }, 1532 `[{"a": 1}, {"b": 2, "c": 3}, [1], true, false, null, "hello"]`: { 1533 {`[]`, true}, 1534 {`{}`, false}, 1535 {`{"a": 1}`, false}, 1536 {`[{"a": 1}]`, true}, 1537 {`[{"b": 2}]`, true}, 1538 {`[{"b": 2, "d": 4}]`, false}, 1539 {`[{"b": 2, "c": 3}]`, true}, 1540 {`[{"a": 1}, {"b": 2}, {"c": 3}]`, true}, 1541 {`[{}]`, true}, 1542 {`[true]`, true}, 1543 {`[true, false]`, true}, 1544 {`[false, true]`, true}, 1545 {`[[1]]`, true}, 1546 {`[[]]`, true}, 1547 {`[null, "hello"]`, true}, 1548 {`["hello", "hello", []]`, true}, 1549 {`["hello", {"a": 1}, "hello", []]`, true}, 1550 {`["hello", {"a": 1, "b": 2}, "hello", []]`, false}, 1551 {`"hello"`, true}, 1552 {`true`, true}, 1553 {`false`, true}, 1554 {`null`, true}, 1555 {`[1]`, false}, 1556 {`[[1]]`, true}, 1557 {`1`, false}, 1558 }, 1559 `[{"Ck@P":{"7RZ2\"mZBH":null,"|__v":[1.685483]},"EM%&":{"I{TH":[],"}p@]7sIKC\\$":[]},"f}?#z~":{"#e9>m\"v75'&+":false,"F;,+&r9":{}}},[{}],false,0.498401]`: { 1560 {`[false,{}]`, true}, 1561 }, 1562 } 1563 1564 for k, tests := range cases { 1565 left, err := ParseJSON(k) 1566 if err != nil { 1567 t.Fatal(err) 1568 } 1569 1570 for _, tc := range tests { 1571 t.Run(fmt.Sprintf("%s @> %s", k, tc.other), func(t *testing.T) { 1572 other, err := ParseJSON(tc.other) 1573 if err != nil { 1574 t.Fatal(err) 1575 } 1576 result, err := Contains(left, other) 1577 if err != nil { 1578 t.Fatal(err) 1579 } 1580 1581 checkResult := slowContains(left, other) 1582 if result != checkResult { 1583 t.Fatal("mismatch between actual contains and slowContains") 1584 } 1585 1586 if tc.expected && !result { 1587 t.Fatalf("expected %s @> %s", left, other) 1588 } else if !tc.expected && result { 1589 t.Fatalf("expected %s to not @> %s", left, other) 1590 } 1591 }) 1592 } 1593 } 1594 } 1595 1596 // TestPositiveRandomJSONContains randomly generates a JSON document, generates 1597 // a subdocument of it, then verifies that it matches under contains. 1598 func TestPositiveRandomJSONContains(t *testing.T) { 1599 rng := rand.New(rand.NewSource(timeutil.Now().Unix())) 1600 for i := 0; i < 1000; i++ { 1601 j, err := Random(20, rng) 1602 if err != nil { 1603 t.Fatal(err) 1604 } 1605 1606 subdoc := j.(containsTester).subdocument(true /* isRoot */, rng) 1607 1608 c, err := Contains(j, subdoc) 1609 if err != nil { 1610 t.Fatal(err) 1611 } 1612 if !c { 1613 t.Fatal(fmt.Sprintf("%s should contain %s", j, subdoc)) 1614 } 1615 if !slowContains(j, subdoc) { 1616 t.Fatal(fmt.Sprintf("%s should slowContains %s", j, subdoc)) 1617 } 1618 } 1619 } 1620 1621 // We expect that this almost always results in a non-contained pair.. 1622 func TestNegativeRandomJSONContains(t *testing.T) { 1623 rng := rand.New(rand.NewSource(timeutil.Now().Unix())) 1624 for i := 0; i < 1000; i++ { 1625 j1, err := Random(20, rng) 1626 if err != nil { 1627 t.Fatal(err) 1628 } 1629 1630 j2, err := Random(20, rng) 1631 if err != nil { 1632 t.Fatal(err) 1633 } 1634 1635 realResult, err := Contains(j1, j2) 1636 if err != nil { 1637 t.Fatal(err) 1638 } 1639 slowResult := slowContains(j1, j2) 1640 if realResult != slowResult { 1641 t.Fatal("mismatch for document " + j1.String() + " @> " + j2.String()) 1642 } 1643 } 1644 } 1645 1646 func TestPretty(t *testing.T) { 1647 cases := []struct { 1648 input string 1649 expected string 1650 }{ 1651 {`true`, `true`}, 1652 {`1`, `1`}, 1653 {`1.0`, `1.0`}, 1654 {`1.00`, `1.00`}, 1655 {`"hello"`, `"hello"`}, 1656 {`["hello"]`, 1657 `[ 1658 "hello" 1659 ]`}, 1660 {`["hello", "world"]`, 1661 `[ 1662 "hello", 1663 "world" 1664 ]`}, 1665 {`["hello", ["world"]]`, 1666 `[ 1667 "hello", 1668 [ 1669 "world" 1670 ] 1671 ]`}, 1672 {`{"a": 1}`, 1673 `{ 1674 "a": 1 1675 }`}, 1676 {`{"a": 1, "b": 2}`, 1677 `{ 1678 "a": 1, 1679 "b": 2 1680 }`}, 1681 {`{"a": 1, "b": {"c": 3}}`, 1682 `{ 1683 "a": 1, 1684 "b": { 1685 "c": 3 1686 } 1687 }`}, 1688 } 1689 1690 for _, tc := range cases { 1691 j := jsonTestShorthand(tc.input) 1692 runDecodedAndEncoded(t, tc.input, j, func(t *testing.T, j JSON) { 1693 pretty, err := Pretty(j) 1694 if err != nil { 1695 t.Fatal(err) 1696 } 1697 if pretty != tc.expected { 1698 t.Fatalf("expected:\n%s\ngot:\n%s\n", tc.expected, pretty) 1699 } 1700 }) 1701 } 1702 } 1703 1704 func TestHasContainerLeaf(t *testing.T) { 1705 cases := []struct { 1706 input string 1707 expected bool 1708 }{ 1709 {`true`, false}, 1710 {`false`, false}, 1711 {`1`, false}, 1712 {`[]`, true}, 1713 {`{}`, true}, 1714 {`{"a": 1}`, false}, 1715 {`{"a": {"b": 3}, "x": "y", "c": []}`, true}, 1716 {`{"a": {"b": 3}, "c": [], "x": "y"}`, true}, 1717 {`{"a": {}}`, true}, 1718 {`{"a": []}`, true}, 1719 {`[]`, true}, 1720 {`[[]]`, true}, 1721 {`[1, 2, 3, []]`, true}, 1722 {`[1, 2, [], 3]`, true}, 1723 {`[[], 1, 2, 3]`, true}, 1724 {`[1, 2, 3]`, false}, 1725 {`[[1, 2, 3]]`, false}, 1726 {`[[1, 2], 3]`, false}, 1727 {`[1, 2, 3, [4]]`, false}, 1728 } 1729 1730 for _, tc := range cases { 1731 j := jsonTestShorthand(tc.input) 1732 runDecodedAndEncoded(t, tc.input, j, func(t *testing.T, j JSON) { 1733 result, err := j.HasContainerLeaf() 1734 if err != nil { 1735 t.Fatal(err) 1736 } 1737 if result != tc.expected { 1738 t.Fatalf("expected:\n%v\ngot:\n%v\n", tc.expected, result) 1739 } 1740 }) 1741 } 1742 } 1743 1744 func BenchmarkBuildJSONObject(b *testing.B) { 1745 for _, objectSize := range []int{1, 10, 100, 1000, 10000, 100000} { 1746 keys := make([]string, objectSize) 1747 for i := 0; i < objectSize; i++ { 1748 keys[i] = fmt.Sprintf("key%d", i) 1749 } 1750 for i := 0; i < objectSize; i++ { 1751 p := rand.Intn(objectSize-i) + i 1752 keys[i], keys[p] = keys[p], keys[i] 1753 } 1754 b.Run(fmt.Sprintf("object size %d", objectSize), func(b *testing.B) { 1755 b.Run("from builder", func(b *testing.B) { 1756 for n := 0; n < b.N; n++ { 1757 builder := NewObjectBuilder(0) 1758 for i, k := range keys { 1759 builder.Add(k, FromInt(i)) 1760 } 1761 _ = builder.Build() 1762 } 1763 }) 1764 1765 b.Run("from go map", func(b *testing.B) { 1766 for n := 0; n < b.N; n++ { 1767 m := map[string]interface{}{} 1768 for i, k := range keys { 1769 m[k] = FromInt(i) 1770 } 1771 if _, err := fromMap(m); err != nil { 1772 b.Fatal(err) 1773 } 1774 } 1775 }) 1776 }) 1777 } 1778 } 1779 1780 func BenchmarkArrayConcat(b *testing.B) { 1781 for _, arraySize := range []int{1, 10, 100, 1000, 10000} { 1782 b.Run(fmt.Sprintf("concat two arrays with size %d", arraySize), func(b *testing.B) { 1783 arr := make([]interface{}, arraySize) 1784 for i := 0; i < arraySize; i++ { 1785 arr[i] = i 1786 } 1787 left, err := MakeJSON(arr) 1788 if err != nil { 1789 b.Fatal(err) 1790 } 1791 right, err := MakeJSON(arr) 1792 if err != nil { 1793 b.Fatal(err) 1794 } 1795 b.ResetTimer() 1796 for i := 0; i < b.N; i++ { 1797 _, err = left.Concat(right) 1798 if err != nil { 1799 b.Fatal(err) 1800 } 1801 } 1802 }) 1803 } 1804 } 1805 1806 func BenchmarkObjectStripNulls(b *testing.B) { 1807 for _, objectSize := range []int{1, 10, 100, 1000} { 1808 b.Run(fmt.Sprintf("object size %d no need to strip", objectSize), func(b *testing.B) { 1809 builder := NewObjectBuilder(0) 1810 for i := 0; i < objectSize; i++ { 1811 builder.Add(strconv.Itoa(i), FromInt(i)) 1812 } 1813 obj := builder.Build() 1814 b.ResetTimer() 1815 for i := 0; i < b.N; i++ { 1816 _, _, err := obj.StripNulls() 1817 if err != nil { 1818 b.Fatal(err) 1819 } 1820 } 1821 }) 1822 b.Run(fmt.Sprintf("object size %d need to strip", objectSize), func(b *testing.B) { 1823 builder := NewObjectBuilder(0) 1824 builder.Add(strconv.Itoa(0), NullJSONValue) 1825 for i := 1; i < objectSize; i++ { 1826 builder.Add(strconv.Itoa(i), FromInt(i)) 1827 } 1828 obj := builder.Build() 1829 b.ResetTimer() 1830 for i := 0; i < b.N; i++ { 1831 _, _, err := obj.StripNulls() 1832 if err != nil { 1833 b.Fatal(err) 1834 } 1835 } 1836 }) 1837 } 1838 } 1839 1840 func BenchmarkFetchFromArray(b *testing.B) { 1841 for _, arraySize := range []int{1, 10, 100, 1000} { 1842 b.Run(fmt.Sprintf("array size %d", arraySize), func(b *testing.B) { 1843 ary := make([]interface{}, arraySize) 1844 for i := 0; i < len(ary); i++ { 1845 ary[i] = i 1846 } 1847 j, err := MakeJSON(ary) 1848 if err != nil { 1849 b.Fatal(err) 1850 } 1851 1852 _, encoding, err := j.encode(nil) 1853 if err != nil { 1854 b.Fatal(err) 1855 } 1856 1857 encoded, err := newEncodedFromRoot(encoding) 1858 if err != nil { 1859 b.Fatal(err) 1860 } 1861 1862 b.ResetTimer() 1863 1864 for i := 0; i < b.N; i++ { 1865 _, _ = encoded.FetchValIdx(rand.Intn(arraySize)) 1866 } 1867 }) 1868 } 1869 } 1870 1871 func BenchmarkFetchKey(b *testing.B) { 1872 for _, objectSize := range []int{1, 10, 100, 1000} { 1873 b.Run(fmt.Sprintf("object size %d", objectSize), func(b *testing.B) { 1874 keys := make([]string, objectSize) 1875 1876 obj := make(map[string]interface{}) 1877 for i := 0; i < objectSize; i++ { 1878 key := fmt.Sprintf("key%d", i) 1879 keys = append(keys, key) 1880 obj[key] = i 1881 } 1882 j, err := MakeJSON(obj) 1883 if err != nil { 1884 b.Fatal(err) 1885 } 1886 1887 b.Run("fetch key", func(b *testing.B) { 1888 for i := 0; i < b.N; i++ { 1889 _, _ = j.FetchValKey(keys[rand.Intn(len(keys))]) 1890 } 1891 }) 1892 1893 encoding, err := EncodeJSON(nil, j) 1894 if err != nil { 1895 b.Fatal(err) 1896 } 1897 1898 encoded, err := newEncodedFromRoot(encoding) 1899 if err != nil { 1900 b.Fatal(err) 1901 } 1902 1903 b.Run("fetch key by decoding and then reading", func(b *testing.B) { 1904 for i := 0; i < b.N; i++ { 1905 // This is a hack to get around the decoded caching. 1906 encoded.mu.cachedDecoded = nil 1907 1908 decoded, err := encoded.shallowDecode() 1909 if err != nil { 1910 b.Fatal(err) 1911 } 1912 _, _ = decoded.FetchValKey(keys[rand.Intn(len(keys))]) 1913 } 1914 }) 1915 1916 b.Run("fetch key encoded", func(b *testing.B) { 1917 encoded, err := newEncodedFromRoot(encoding) 1918 if err != nil { 1919 b.Fatal(err) 1920 } 1921 for i := 0; i < b.N; i++ { 1922 _, _ = encoded.FetchValKey(keys[rand.Intn(len(keys))]) 1923 } 1924 }) 1925 }) 1926 } 1927 } 1928 1929 func BenchmarkJSONNumInvertedIndexEntries(b *testing.B) { 1930 j := jsonTestShorthand(sampleJSON) 1931 b.ResetTimer() 1932 for i := 0; i < b.N; i++ { 1933 _, _ = NumInvertedIndexEntries(j) 1934 } 1935 } 1936 1937 func TestJSONRemovePath(t *testing.T) { 1938 queryTests := map[string][]struct { 1939 path []string 1940 ok bool 1941 expected string 1942 errMsg string 1943 }{ 1944 `{"foo": 1}`: { 1945 {path: []string{"foa"}, ok: false, expected: `{"foo": 1}`}, 1946 {path: []string{"foo"}, ok: true, expected: `{}`}, 1947 {path: []string{"foz"}, ok: false, expected: `{"foo": 1}`}, 1948 {path: []string{}, ok: false, expected: `{"foo": 1}`}, 1949 {path: []string{"bar"}, ok: false, expected: `{"foo": 1}`}, 1950 }, 1951 `{"foo": {"bar": 1, "baz": 2}}`: { 1952 {path: []string{}, ok: false, expected: `{"foo": {"bar": 1, "baz": 2}}`}, 1953 {path: []string{"foo"}, ok: true, expected: `{}`}, 1954 {path: []string{"foo", "bar"}, ok: true, expected: `{"foo": {"baz": 2}}`}, 1955 {path: []string{"foo", "bar", "gup"}, ok: false, expected: `{"foo": {"bar": 1, "baz": 2}}`}, 1956 {path: []string{"foo", "baz"}, ok: true, expected: `{"foo": {"bar": 1}}`}, 1957 }, 1958 `{"foo": {"bar": 1, "baz": {"gup": 3}}}`: { 1959 {path: []string{}, ok: false, expected: `{"foo": {"bar": 1, "baz": {"gup": 3}}}`}, 1960 {path: []string{"foo"}, ok: true, expected: `{}`}, 1961 {path: []string{"foo", "bar"}, ok: true, expected: `{"foo": {"baz": {"gup": 3}}}`}, 1962 {path: []string{"foo", "baz"}, ok: true, expected: `{"foo": {"bar": 1}}`}, 1963 {path: []string{"foo", "baz", "gup"}, ok: true, expected: `{"foo": {"bar": 1, "baz": {}}}`}, 1964 }, 1965 `{"foo": [1, 2, {"bar": 3}]}`: { 1966 {path: []string{}, ok: false, expected: `{"foo": [1, 2, {"bar": 3}]}`}, 1967 {path: []string{`foo`}, ok: true, expected: `{}`}, 1968 {path: []string{`foo`, `0`}, ok: true, expected: `{"foo": [2, {"bar": 3}]}`}, 1969 {path: []string{`foo`, `1`}, ok: true, expected: `{"foo": [1, {"bar": 3}]}`}, 1970 {path: []string{`foo`, `2`}, ok: true, expected: `{"foo": [1, 2]}`}, 1971 {path: []string{`foo`, `2`, `bar`}, ok: true, expected: `{"foo": [1, 2, {}]}`}, 1972 {path: []string{`foo`, `-3`}, ok: true, expected: `{"foo": [2, {"bar": 3}]}`}, 1973 {path: []string{`foo`, `-2`}, ok: true, expected: `{"foo": [1, {"bar": 3}]}`}, 1974 {path: []string{`foo`, `-1`}, ok: true, expected: `{"foo": [1, 2]}`}, 1975 {path: []string{`foo`, `-1`, `bar`}, ok: true, expected: `{"foo": [1, 2, {}]}`}, 1976 }, 1977 `[[1]]`: { 1978 {path: []string{"0", "0"}, ok: true, expected: `[[]]`}, 1979 }, 1980 `[1]`: { 1981 {path: []string{"foo"}, ok: false, expected: "", errMsg: "a path element is not an integer: foo"}, 1982 {path: []string{""}, ok: false, expected: "", errMsg: "a path element is not an integer: "}, 1983 {path: []string{"0"}, ok: true, expected: `[]`}, 1984 {path: []string{"0", "0"}, ok: false, expected: `[1]`}, 1985 }, 1986 `1`: { 1987 {path: []string{"foo"}, errMsg: "cannot delete path in scalar"}, 1988 }, 1989 } 1990 1991 for k, tests := range queryTests { 1992 left, err := ParseJSON(k) 1993 if err != nil { 1994 t.Fatal(err) 1995 } 1996 1997 for _, tc := range tests { 1998 t.Run(fmt.Sprintf("%s #- %v", k, tc.path), func(t *testing.T) { 1999 result, ok, err := left.RemovePath(tc.path) 2000 if tc.errMsg != "" { 2001 if err == nil { 2002 t.Fatal("expected error") 2003 } else if !strings.Contains(err.Error(), tc.errMsg) { 2004 t.Fatalf(`expected error message "%s" to contain "%s"`, err.Error(), tc.errMsg) 2005 } 2006 return 2007 } 2008 if err != nil { 2009 t.Fatal(err) 2010 } 2011 if tc.ok != ok { 2012 t.Fatalf("expected %t, got %t", tc.ok, ok) 2013 } 2014 cmp, err := result.Compare(jsonTestShorthand(tc.expected)) 2015 if err != nil { 2016 t.Fatal(err) 2017 } 2018 if cmp != 0 { 2019 t.Fatalf("expected %s, got %s", tc.expected, result.String()) 2020 } 2021 }) 2022 } 2023 } 2024 }