1
2
3
18
19 package sonic
20
21 import (
22 `bytes`
23 `encoding/hex`
24 `encoding/json`
25 `fmt`
26 `math/rand`
27 `reflect`
28 `strings`
29 `testing`
30 `time`
31
32 `github.com/davecgh/go-spew/spew`
33 `github.com/stretchr/testify/assert`
34 `github.com/bytedance/sonic/ast`
35 )
36
37 func Parse(src string) (*ast.Node, error) {
38 node, err := ast.NewParser(src).Parse()
39 if err != 0 {
40 return &node, fmt.Errorf("parsing error: %v", err)
41 }
42 return &node, nil
43 }
44
45 func assertCond(cond bool) {
46 if !cond {
47 panic("assertCond failed")
48 }
49 }
50
51 func TestExampleSearch(t *testing.T) {
52 data := []byte(` { "xx" : [] ,"yy" :{ }, "test" : [ true , 0.1 , "abc", ["h"], {"a":"bc"} ] } `)
53
54 node, e := Get(data, "test", 0)
55 x, _ := node.Bool()
56 if e != nil || x != true {
57 t.Fatalf("node: %v, err: %v", node, e)
58 }
59
60 node, e = Get(data, "test", 1)
61 a, _ := node.Float64()
62 if e != nil || a != 0.1 {
63 t.Fatalf("node: %v, err: %v", node, e)
64 }
65
66 node, e = Get(data, "test", 2)
67 b, _ := node.String()
68 if e != nil || b != "abc" {
69 t.Fatalf("node: %v, err: %v", node, e)
70 }
71
72 node, e = Get(data, "test", 3)
73 arr, _ := node.Array()
74 if e != nil || arr[0] != "h" {
75 t.Fatalf("node: %v, err: %v", node, e)
76 }
77
78 node, e = Get(data, "test", 4, "a")
79 c, _ := node.String()
80 if e != nil || c != "bc" {
81 t.Fatalf("node: %v, err: %v", node, e)
82 }
83 }
84
85 func TestExampleSearchEscapedKey(t *testing.T) {
86 data := []byte(`
87 {
88 "xx" : [] ,
89 "yy" :{ },
90 "test\"" : [
91 true ,
92 0.1 ,
93 "abc",
94 [
95 "h"
96 ],
97 {
98 "a\u0008": {},
99 "b\\\\": null,
100 "\u2028\u2028": "\u2028\u2029",
101 "\u0026":2,
102 "0":1
103 }
104 ],
105 ",,,,,,,,,,(,,15": ",",
106 ",,,,,,,,,,(,,,16": "a,]}",
107 ",,,,,,,,,,(,,,,17": 1,
108 ",,,,,,,,,,(,,,,,,,,,,,,,,,,(,,,,34": "c"
109 } `)
110
111 type getTest struct{
112 path []interface{}
113 expect interface{}
114 }
115
116 tests := []getTest {
117 {[]interface{}{"test\"", 0}, true},
118 {[]interface{}{"test\"", 1}, 0.1},
119 {[]interface{}{"test\"", 2}, "abc"},
120 {[]interface{}{"test\"", 3}, []interface{}{"h"}},
121 {[]interface{}{"test\"", 4, "a\u0008"}, map[string]interface{}{}},
122 {[]interface{}{"test\"", 4, "b\\\\"}, nil},
123 {[]interface{}{"test\"", 4, "\u2028\u2028"}, "\u2028\u2029"},
124 {[]interface{}{"test\"", 4, "0"}, float64(1)},
125 {[]interface{}{",,,,,,,,,,(,,15"}, ","},
126 {[]interface{}{",,,,,,,,,,(,,,16"}, "a,]}"},
127 {[]interface{}{",,,,,,,,,,(,,,,17"}, float64(1)},
128 {[]interface{}{",,,,,,,,,,(,,,,,,,,,,,,,,,,(,,,,34"}, "c"},
129 }
130
131 for _, test := range(tests) {
132 node, err := Get(data, test.path...)
133 assert.NoErrorf(t, err, "get return errors")
134 got, err := node.Interface()
135 assert.NoErrorf(t, err, "get convert errors")
136 assert.Equalf(t, test.expect, got, "get result is wrong from path %#v", test.path)
137 }
138 }
139
140 func TestExampleSearchErr(t *testing.T) {
141 data := []byte(` { "xx" : [] ,"yy" :{ }, "test" : [ true , 0.1 , "abc", ["h"], {"a":"bc"} ] } `)
142 node, e := Get(data, "zz")
143 if e == nil {
144 t.Fatalf("node: %v, err: %v", node, e)
145 }
146 fmt.Println(e)
147
148 node, e = Get(data, "xx", 4)
149 if e == nil {
150 t.Fatalf("node: %v, err: %v", node, e)
151 }
152 fmt.Println(e)
153
154 node, e = Get(data, "yy", "a")
155 if e == nil {
156 t.Fatalf("node: %v, err: %v", node, e)
157 }
158 fmt.Println(e)
159
160 node, e = Get(data, "test", 4, "x")
161 if e == nil {
162 t.Fatalf("node: %v, err: %v", node, e)
163 }
164 fmt.Println(e)
165 }
166
167 func TestExampleSearchEscapedKeyError(t *testing.T) {
168 data := []byte(` { "xx" : [] ,"yy" :{ }, "x\u0008" : [] ,"y\\\"y" :{ }, "test" : [ true , 0.1 , "abc", ["h"], {"a":"bc"} ] } `)
169 node, e := Get(data, "zz")
170 if e == nil {
171 t.Fatalf("node: %v, err: %v", node, e)
172 }
173 fmt.Println(e)
174
175 node, e = Get(data, "x\u0008", 4)
176 if e == nil {
177 t.Fatalf("node: %v, err: %v", node, e)
178 }
179 fmt.Println(e)
180
181 node, e = Get(data, "yy", "a")
182 if e == nil {
183 t.Fatalf("node: %v, err: %v", node, e)
184 }
185 fmt.Println(e)
186
187 node, e = Get(data, "test", 4, "x")
188 if e == nil {
189 t.Fatalf("node: %v, err: %v", node, e)
190 }
191
192 node, e = Get(data, "y\\\"y", 4, "x")
193 if e == nil {
194 t.Fatalf("node: %v, err: %v", node, e)
195 }
196 fmt.Println(e)
197 }
198
199 func TestRandomData(t *testing.T) {
200 var lstr string
201 defer func() {
202 if v := recover(); v != nil {
203 println("'" + hex.Dump([]byte(lstr)) + "'")
204 println(lstr)
205 panic(v)
206 }
207 }()
208 data := []byte(`"�-mp�`)
209 _, err := ast.NewParser(string(data)).Parse()
210 if err != 0 {
211 fmt.Println(hex.Dump(data))
212 fmt.Println(string(data))
213 }
214 rand.Seed(time.Now().UnixNano())
215 b := make([]byte, 200)
216 for i := 0; i < 1000000; i++ {
217 n, ee := rand.Read(b[:rand.Int()%len(b)])
218 if ee != nil {
219 t.Fatalf("get random bytes failed: %v,", ee)
220 return
221 }
222 lstr = string(b[:n])
223 _, _ = ast.NewParser(lstr).Parse()
224 }
225 }
226
227 func TestRandomValidStrings(t *testing.T) {
228 rand.Seed(time.Now().UnixNano())
229 b := make([]byte, 200)
230 for i := 0; i < 1000; i++ {
231 n, err := rand.Read(b[:rand.Int()%len(b)])
232 if err != nil {
233 t.Fatal("get random data failed:", err)
234 }
235 sm, err := json.Marshal(string(b[:n]))
236 if err != nil {
237 t.Fatal("marshal data failed:",err)
238 }
239 var su string
240 if err := json.Unmarshal(sm, &su); err != nil {
241 t.Fatal("unmarshal data failed:",err)
242 }
243 token, err := GetFromString(`{"str":`+string(sm)+`}`, "str")
244 if err != nil {
245 spew.Dump(string(sm))
246 t.Fatal("search data failed:",err)
247 }
248 x, _ := token.Interface()
249 st, ok := x.(string)
250 if !ok {
251 t.Fatalf("type mismatch, exp: %v, got: %v", su, x)
252 }
253 if st != su {
254 t.Fatalf("string mismatch, exp: %v, got: %v", su, x)
255 }
256 }
257 }
258
259
260 func TestEmoji(t *testing.T) {
261 var input = []byte(`{"utf8":"Example emoji, KO: \ud83d\udd13, \ud83c\udfc3 ` +
262 `OK: \u2764\ufe0f "}`)
263 value, err := Get(input, "utf8")
264 if err != nil {
265 t.Fatal(err)
266 }
267 var v map[string]interface{}
268 if err := json.Unmarshal(input, &v); err != nil {
269 t.Fatal(err)
270 }
271 s, _ := v["utf8"].(string)
272 x, _ := value.String()
273 if x != s {
274 t.Fatalf("expected '%v', got '%v'", s, x)
275 }
276 }
277
278 func testEscapePath(t *testing.T, json, expect string, path ...interface{}) {
279 n, e := Get([]byte(json), path...)
280 if e != nil {
281 t.Fatal(e)
282 }
283 x, _ := n.String()
284 if x != expect {
285 x, _ := n.Interface()
286 t.Fatalf("expected '%v', got '%v'", expect, x)
287 }
288 }
289
290 func TestEscapePath(t *testing.T) {
291 data := `{
292 "test":{
293 "*":"valZ",
294 "*v":"val0",
295 "keyv*":"val1",
296 "key*v":"val2",
297 "keyv?":"val3",
298 "key?v":"val4",
299 "keyv.":"val5",
300 "key.v":"val6",
301 "keyk*":{"key?":"val7"}
302 }
303 }`
304
305 testEscapePath(t, data, "valZ", "test", "*")
306 testEscapePath(t, data, "val0", "test", "*v")
307 testEscapePath(t, data, "val1", "test", "keyv*")
308 testEscapePath(t, data, "val2", "test", "key*v")
309 testEscapePath(t, data, "val3", "test", "keyv?")
310 testEscapePath(t, data, "val4", "test", "key?v")
311 testEscapePath(t, data, "val5", "test", "keyv.")
312 testEscapePath(t, data, "val6", "test", "key.v")
313 testEscapePath(t, data, "val7", "test", "keyk*", "key?")
314 }
315
316 func TestParseAny(t *testing.T) {
317 n, e := Parse("100")
318 assertCond(e == nil)
319 if n == nil {
320 panic("n is nil")
321 }
322 x, _ := n.Float64()
323 assertCond(x == 100)
324 n, e = Parse("true")
325 assertCond(e == nil)
326 if n == nil {
327 panic("n is nil")
328 }
329
330 a, _ := n.Bool()
331 assertCond(a)
332 n, e = Parse("false")
333 assertCond(e == nil)
334 if n == nil {
335 panic("n is nil")
336 }
337 b, _ := n.Bool()
338 assertCond(b == false)
339 n, e = Parse("yikes")
340 assertCond(e != nil)
341 }
342
343 func TestTime(t *testing.T) {
344 data := []byte(`{
345 "code": 0,
346 "msg": "",
347 "data": {
348 "sz002024": {
349 "qfqday": [
350 [
351 "2014-01-02",
352 "8.93",
353 "9.03",
354 "9.17",
355 "8.88",
356 "621143.00"
357 ],
358 [
359 "2014-01-03",
360 "9.03",
361 "9.30",
362 "9.47",
363 "8.98",
364 "1624438.00"
365 ]
366 ]
367 }
368 }
369 }`)
370
371 var num []string
372 n, e := Get(data, "data", "sz002024", "qfqday", 0)
373 if e != nil {
374 t.Fatal(e)
375 }
376
377 arr, _ := n.Array()
378 for _, v := range arr {
379 s := v.(string)
380 num = append(num, s)
381 }
382 if fmt.Sprintf("%v", num) != "[2014-01-02 8.93 9.03 9.17 8.88 621143.00]" {
383 t.Fatalf("invalid result")
384 }
385 }
386
387 var exampleJSON = `{
388 "widget": {
389 "debug": "on",
390 "window": {
391 "title": "Sample Konfabulator Widget",
392 "name": "main_window",
393 "width": 500,
394 "height": 500
395 },
396 "image": {
397 "src": "Images/Sun.png",
398 "hOffset": 250,
399 "vOffset": 250,
400 "alignment": "center"
401 },
402 "text": {
403 "data": "Click Here",
404 "size": 36,
405 "style": "bold",
406 "vOffset": 100,
407 "alignment": "center",
408 "onMouseUp": "sun1.opacity = (sun1.opacity / 100) * 90;"
409 }
410 }
411 }`
412
413 func TestUnmarshalMap(t *testing.T) {
414 n, err := Parse(exampleJSON)
415 if err != nil || n == nil {
416 t.Fatal(err)
417 }
418 m1, _ := n.Map()
419 var m2 map[string]interface{}
420 if err := json.Unmarshal([]byte(exampleJSON), &m2); err != nil {
421 t.Fatal(err)
422 }
423 b1, err := json.Marshal(m1)
424 if err != nil {
425 t.Fatal(err)
426 }
427 b2, err := json.Marshal(m2)
428 if err != nil {
429 t.Fatal(err)
430 }
431 if !bytes.Equal(b1, b2) {
432 t.Fatalf("b1 != b2\n b1: %v\nb2: %v", string(b1), string(b2))
433 }
434 }
435
436 func GetMany(src2 string, path ...string) (ret []string) {
437 src := []byte(src2)
438 for _, p := range path {
439 pathes := strings.Split(p, ".")
440 if len(pathes) == 0 {
441 panic(fmt.Sprintf("invalid path: %v", p))
442 }
443 ps := make([]interface{}, 0, len(pathes))
444 for _, p := range pathes {
445 ps = append(ps, p)
446 }
447 n, e := Get(src, ps...)
448 if e != nil {
449 ret = append(ret, "")
450 continue
451 }
452 x, _ := n.Interface()
453 ret = append(ret, fmt.Sprintf("%v", x))
454 }
455 return
456 }
457
458 func get(str string, path string) *ast.Node {
459 src := []byte(str)
460 pathes := strings.Split(path, ".")
461 if len(pathes) == 0 {
462 panic(fmt.Sprintf("invalid path: %v", path))
463 }
464 ps := make([]interface{}, 0, len(pathes))
465 for _, p := range pathes {
466 ps = append(ps, p)
467 }
468 n, e := Get(src, ps...)
469 if e != nil {
470 return nil
471 }
472 return &n
473 }
474
475 func TestSingleArrayValue(t *testing.T) {
476 var data = []byte(`{"key": "value","key2":[1,2,3,4,"A"]}`)
477 array, _ := get(string(data), "key2").Array()
478 if len(array) != 5 {
479 t.Fatalf("got '%v', expected '%v'", len(array), 5)
480 }
481
482 _, e := Get(data, "key3")
483 if e == nil {
484 t.Fatalf("got '%v', expected '%v'", e, nil)
485 }
486 }
487
488 var manyJSON = ` {
489 "a":{"a":{"a":{"a":{"a":{"a":{"a":{"a":{"a":{"a":{
490 "a":{"a":{"a":{"a":{"a":{"a":{"a":{"a":{"a":{"a":{
491 "a":{"a":{"a":{"a":{"a":{"a":{"a":{"a":{"a":{"a":{
492 "a":{"a":{"a":{"a":{"a":{"a":{"a":{"a":{"a":{"a":{
493 "a":{"a":{"a":{"a":{"a":{"a":{"a":{"a":{"a":{"a":{
494 "a":{"a":{"a":{"a":{"a":{"a":{"a":{"a":{"a":{"a":{
495 "a":{"a":{"a":{"a":{"a":{"a":{"a":{"a":{"a":{"a":{"hello":"world"
496 }}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}},
497 "position":{"type":"Point","coordinates":[-115.24,33.09]},
498 "loves":["world peace"],
499 "name":{"last":"Anderson","first":"Nancy"},
500 "age":31,
501 "x":{"a":"emptya","b":"emptyb"},
502 "name_last":"Yellow",
503 "name_first":"Cat",
504 }`
505
506 func TestManyBasic(t *testing.T) {
507 testMany := func(shouldFallback bool, expect string, paths ...string) {
508 println()
509 rs := GetMany(
510 manyJSON,
511 paths...,
512 )
513
514
515
516 var results = "[" + strings.Join(rs, " ") + "]"
517 if results != expect {
518 fmt.Printf("%v\n", paths)
519 t.Fatalf("expected %v, got %v", expect, results)
520 }
521 }
522 testMany(false, "[Point]", "position.type")
523 testMany(false, `[emptya [world peace] 31]`, "x.a", "loves", "age")
524 testMany(false, `[[world peace]]`, "loves")
525 testMany(false, `[map[first:Nancy last:Anderson] Nancy]`, "name",
526 "name.first")
527 testMany(true, `[]`, strings.Repeat("a.", 40)+"hello")
528 res := get(manyJSON, strings.Repeat("a.", 48)+"a")
529 assertCond(res != nil)
530 x, _ := res.Interface()
531 testMany(true, "["+fmt.Sprint(x)+"]", strings.Repeat("a.", 48)+"a")
532
533 testMany(true, `[Cat Nancy]`, "name_first", "name.first")
534 testMany(true, `[world]`, strings.Repeat("a.", 70)+"hello")
535 }
536
537 func testMany(t *testing.T, json string, paths, expected []string) {
538 testManyAny(t, json, paths, expected)
539 testManyAny(t, json, paths, expected)
540 }
541
542 func testManyAny(t *testing.T, json string, paths, expected []string) {
543 var result []string
544 for i := 0; i < 2; i++ {
545 var which string
546 if i == 0 {
547 which = "Get"
548 result = nil
549 for j := 0; j < len(expected); j++ {
550 x, _ := get(json, paths[j]).Interface()
551 result = append(result, fmt.Sprintf("%v", x))
552 }
553 } else if i == 1 {
554 which = "GetMany"
555 result = GetMany(json, paths...)
556 }
557 if result == nil {
558 panic("result is nil")
559 }
560 for j := 0; j < len(expected); j++ {
561 if result[j] != expected[j] {
562 t.Fatalf("Using key '%s' for '%s'\nexpected '%v', got '%v'",
563 paths[j], which, expected[j], result[j])
564 }
565 }
566 }
567 }
568
569 func TestNested(t *testing.T) {
570 data := `{ "name": "FirstName", "name1": "FirstName1", ` +
571 `"address": "address1", "addressDetails": "address2", }`
572 paths := []string{"name", "name1", "address", "addressDetails"}
573 expected := []string{"FirstName", "FirstName1", "address1", "address2"}
574 t.Run("SingleMany", func(t *testing.T) {
575 testMany(t, data, paths,
576 expected)
577 })
578 }
579
580 func TestMultiLevelFields(t *testing.T) {
581 data := `{ "Level1Field1":3,
582 "Level1Field4":4,
583 "Level1Field2":{ "Level2Field1":[ "value1", "value2" ],
584 "Level2Field2":{ "Level3Field1":[ { "key1":"value1" } ] } } }`
585 paths := []string{"Level1Field1", "Level1Field2.Level2Field1",
586 "Level1Field2.Level2Field2.Level3Field1", "Level1Field4"}
587 expected := []string{"3", `[value1 value2]`,
588 `[map[key1:value1]]`, "4"}
589 t.Run("SingleMany", func(t *testing.T) {
590 testMany(t, data, paths,
591 expected)
592 })
593 }
594
595 func TestRandomMany(t *testing.T) {
596 var lstr string
597 defer func() {
598 if v := recover(); v != nil {
599 println("'" + hex.EncodeToString([]byte(lstr)) + "'")
600 println("'" + lstr + "'")
601 panic(v)
602 }
603 }()
604 rand.Seed(time.Now().UnixNano())
605 b := make([]byte, 512)
606 for i := 0; i < 5000; i++ {
607 n, err := rand.Read(b[:rand.Int()%len(b)])
608 if err != nil {
609 t.Fatal(err)
610 }
611 lstr = string(b[:n])
612 paths := make([]string, rand.Int()%64)
613 for i := range paths {
614 var b []byte
615 n := rand.Int() % 5
616 for j := 0; j < n; j++ {
617 if j > 0 {
618 b = append(b, '.')
619 }
620 nn := rand.Int() % 10
621 for k := 0; k < nn; k++ {
622 b = append(b, 'a'+byte(rand.Int()%26))
623 }
624 }
625 paths[i] = string(b)
626 }
627 GetMany(lstr, paths...)
628 }
629 }
630
631 func TestGetMany(t *testing.T) {
632 data := `{"bar": {"id": 99, "mybar": "my mybar" }, "foo": ` +
633 `{"myfoo": [605]}}`
634 paths := []string{"foo.myfoo", "bar.id", "bar.mybar", "bar.mybarx"}
635 expected := []string{"[605]", "99", "my mybar", ""}
636 results := GetMany(data, paths...)
637 if len(expected) != len(results) {
638 t.Fatalf("expected %v, got %v", len(expected), len(results))
639 }
640 for i, path := range paths {
641 if results[i] != expected[i] {
642 t.Fatalf("expected '%v', got '%v' for path '%v'", expected[i],
643 results[i], path)
644 }
645 }
646 }
647
648 func TestGetMany2(t *testing.T) {
649 data := `{"bar": {"id": 99, "xyz": "my xyz"}, "foo": {"myfoo": [605]}}`
650 paths := []string{"foo.myfoo", "bar.id", "bar.xyz", "bar.abc"}
651 expected := []string{"[605]", "99", "my xyz", ""}
652 results := GetMany(data, paths...)
653 if len(expected) != len(results) {
654 t.Fatalf("expected %v, got %v", len(expected), len(results))
655 }
656 for i, path := range paths {
657 if results[i] != expected[i] {
658 t.Fatalf("expected '%v', got '%v' for path '%v'", expected[i],
659 results[i], path)
660 }
661 }
662 }
663
664 func TestNullArray(t *testing.T) {
665 n, _ := get(`{"data":null}`, "data").Interface()
666 if n != nil {
667 t.Fatalf("expected '%v', got '%v'", nil, n)
668 }
669 n = get(`{}`, "data")
670 if reflect.DeepEqual(n, nil) {
671 t.Fatalf("expected '%v', got '%v'", nil, n)
672 }
673 n = get(`{"data":[]}`, "data")
674 if reflect.DeepEqual(n, &ast.Node{}) {
675 t.Fatalf("expected '%v', got '%v'", nil, n)
676 }
677 arr, _ := get(`{"data":[null]}`, "data").Array()
678 n = len(arr)
679 if n != 1 {
680 t.Fatalf("expected '%v', got '%v'", 1, n)
681 }
682 }
683
684 func TestGetMany3(t *testing.T) {
685 var r []string
686 data := `{"MarketName":null,"Nounce":6115}`
687 r = GetMany(data, "Nounce", "Buys", "Sells", "Fills")
688 if strings.Replace(fmt.Sprintf("%v", r), " ", "", -1) != "[6115]" {
689 t.Fatalf("expected '%v', got '%v'", "[6115]",
690 strings.Replace(fmt.Sprintf("%v", r), " ", "", -1))
691 }
692 r = GetMany(data, "Nounce", "Buys", "Sells")
693 if strings.Replace(fmt.Sprintf("%v", r), " ", "", -1) != "[6115]" {
694 t.Fatalf("expected '%v', got '%v'", "[6115]",
695 strings.Replace(fmt.Sprintf("%v", r), " ", "", -1))
696 }
697 r = GetMany(data, "Nounce")
698 if strings.Replace(fmt.Sprintf("%v", r), " ", "", -1) != "[6115]" {
699 t.Fatalf("expected '%v', got '%v'", "[6115]",
700 strings.Replace(fmt.Sprintf("%v", r), " ", "", -1))
701 }
702 }
703
704 func TestGetMany4(t *testing.T) {
705 data := `{"one": {"two": 2, "three": 3}, "four": 4, "five": 5}`
706 results := GetMany(data, "four", "five", "one.two", "one.six")
707 expected := []string{"4", "5", "2", ""}
708 for i, r := range results {
709 if r != expected[i] {
710 t.Fatalf("expected %v, got %v", expected[i], r)
711 }
712 }
713 }
714
715 func TestGetNotExist(t *testing.T) {
716 var dataStr = `{"m1":{"m2":3}}`
717 ret, err := GetFromString(dataStr, "not_exist", "m3")
718 if err == nil || ret.Exists() {
719 t.Fatal("Get exist!")
720 }
721 if ret.Type() != ast.V_NONE {
722 t.Fatal(ret.Type())
723 }
724 ret, err = GetFromString(dataStr)
725 if !ret.IsRaw() || ret.Type() != ast.V_OBJECT {
726 t.Fatal(ret.Type())
727 }
728 v11 := ret.Get("not_exist")
729 if v11.Exists() {
730 t.Fatal()
731 }
732 v2 := ret.GetByPath("m1", "m2")
733 if !v2.Exists() || !v2.IsRaw() {
734 t.Fatal(ret.Type())
735 }
736 x, _ := v2.Int64()
737 if x != 3 {
738 t.Fatal(x)
739 }
740 }
View as plain text