github.com/qiniu/dyn@v1.3.0/text/internal/encoding/json/decode_test.go (about) 1 // Copyright 2010 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package json 6 7 import ( 8 "bytes" 9 "fmt" 10 "reflect" 11 "strings" 12 "testing" 13 ) 14 15 type T struct { 16 X string 17 Y int 18 Z int `json:"-"` 19 } 20 21 type tx struct { 22 x int 23 } 24 25 var txType = reflect.TypeOf((*tx)(nil)).Elem() 26 27 // A type that can unmarshal itself. 28 29 type unmarshaler struct { 30 T bool 31 } 32 33 func (u *unmarshaler) UnmarshalJSON(b []byte) error { 34 *u = unmarshaler{true} // All we need to see that UnmarshalJson is called. 35 return nil 36 } 37 38 type ustruct struct { 39 M unmarshaler 40 } 41 42 var ( 43 um0, um1 unmarshaler // target2 of unmarshaling 44 ump = &um1 45 umtrue = unmarshaler{true} 46 umslice = []unmarshaler{{true}} 47 umslicep = new([]unmarshaler) 48 umstruct = ustruct{unmarshaler{true}} 49 ) 50 51 type unmarshalTest struct { 52 in string 53 ptr interface{} 54 out interface{} 55 err error 56 } 57 58 var unmarshalTests = []unmarshalTest{ 59 // basic types 60 {`true`, new(bool), true, nil}, 61 {`1`, new(int), 1, nil}, 62 {`1.2`, new(float64), 1.2, nil}, 63 {`-5`, new(int16), int16(-5), nil}, 64 {`"a\u1234"`, new(string), "a\u1234", nil}, 65 {`"http:\/\/"`, new(string), "http://", nil}, 66 {`"g-clef: \uD834\uDD1E"`, new(string), "g-clef: \U0001D11E", nil}, 67 {`"invalid: \uD834x\uDD1E"`, new(string), "invalid: \uFFFDx\uFFFD", nil}, 68 {"null", new(interface{}), nil, nil}, 69 {`{"X": [1,2,3], "Y": 4}`, new(T), T{Y: 4}, &UnmarshalTypeError{"array", reflect.TypeOf("")}}, 70 {`{"x": 1}`, new(tx), tx{}, &UnmarshalFieldError{"x", txType, txType.Field(0)}}, 71 72 // Z has a "-" tag. 73 {`{"Y": 1, "Z": 2}`, new(T), T{Y: 1}, nil}, 74 75 // syntax errors 76 {`{"X": "foo", "Y"}`, nil, nil, &SyntaxError{"invalid character '}' after object key", 17}}, 77 {`[1, 2, 3+]`, nil, nil, &SyntaxError{"invalid character '+' after array element", 9}}, 78 79 // array tests 80 {`[1, 2, 3]`, new([3]int), [3]int{1, 2, 3}, nil}, 81 {`[1, 2, 3]`, new([1]int), [1]int{1}, nil}, 82 {`[1, 2, 3]`, new([5]int), [5]int{1, 2, 3, 0, 0}, nil}, 83 84 // composite tests 85 {allValueIndent, new(All), allValue, nil}, 86 {allValueCompact, new(All), allValue, nil}, 87 {allValueIndent, new(*All), &allValue, nil}, 88 {allValueCompact, new(*All), &allValue, nil}, 89 {pallValueIndent, new(All), pallValue, nil}, 90 {pallValueCompact, new(All), pallValue, nil}, 91 {pallValueIndent, new(*All), &pallValue, nil}, 92 {pallValueCompact, new(*All), &pallValue, nil}, 93 94 // unmarshal interface test 95 {`{"T":false}`, &um0, umtrue, nil}, // use "false" so test will fail if custom unmarshaler is not called 96 {`{"T":false}`, &ump, &umtrue, nil}, 97 {`[{"T":false}]`, &umslice, umslice, nil}, 98 {`[{"T":false}]`, &umslicep, &umslice, nil}, 99 {`{"M":{"T":false}}`, &umstruct, umstruct, nil}, 100 } 101 102 func TestMarshal(t *testing.T) { 103 b, err := Marshal(allValue) 104 if err != nil { 105 t.Fatalf("Marshal allValue: %v", err) 106 } 107 if string(b) != allValueCompact { 108 t.Errorf("Marshal allValueCompact") 109 diff(t, b, []byte(allValueCompact)) 110 return 111 } 112 113 b, err = Marshal(pallValue) 114 if err != nil { 115 t.Fatalf("Marshal pallValue: %v", err) 116 } 117 if string(b) != pallValueCompact { 118 t.Errorf("Marshal pallValueCompact") 119 diff(t, b, []byte(pallValueCompact)) 120 return 121 } 122 } 123 124 func TestMarshalBadUTF8(t *testing.T) { 125 s := "hello\xffworld" 126 b, err := Marshal(s) 127 if err != nil { 128 t.Fatal("Marshal bad UTF8: no error") 129 } 130 if string(b) != `""` { 131 t.Fatal("Marshal returned data") 132 } 133 // if _, ok := err.(*InvalidUTF8Error); !ok { 134 // t.Fatalf("Marshal did not return InvalidUTF8Error: %T %v", err, err) 135 // } 136 } 137 138 func TestUnmarshal(t *testing.T) { 139 for i, tt := range unmarshalTests { 140 var scan scanner 141 in := []byte(tt.in) 142 if err := checkValid(in, &scan); err != nil { 143 if !reflect.DeepEqual(err, tt.err) { 144 t.Errorf("#%d: checkValid: %#v", i, err) 145 continue 146 } 147 } 148 if tt.ptr == nil { 149 continue 150 } 151 // v = new(right-type) 152 v := reflect.New(reflect.TypeOf(tt.ptr).Elem()) 153 if err := Unmarshal([]byte(in), v.Interface()); !reflect.DeepEqual(err, tt.err) { 154 t.Errorf("#%d: %v want %v", i, err, tt.err) 155 continue 156 } 157 if !reflect.DeepEqual(v.Elem().Interface(), tt.out) { 158 t.Errorf("#%d: mismatch\nhave: %#+v\nwant: %#+v", i, v.Elem().Interface(), tt.out) 159 data, _ := Marshal(v.Elem().Interface()) 160 println(string(data)) 161 data, _ = Marshal(tt.out) 162 println(string(data)) 163 continue 164 } 165 } 166 } 167 168 func TestUnmarshalMarshal(t *testing.T) { 169 initBig() 170 var v interface{} 171 if err := Unmarshal(jsonBig, &v); err != nil { 172 t.Fatalf("Unmarshal: %v", err) 173 } 174 b, err := Marshal(v) 175 if err != nil { 176 t.Fatalf("Marshal: %v", err) 177 } 178 if bytes.Compare(jsonBig, b) != 0 { 179 t.Errorf("Marshal jsonBig") 180 diff(t, b, jsonBig) 181 return 182 } 183 } 184 185 func TestLargeByteSlice(t *testing.T) { 186 s0 := make([]byte, 2000) 187 for i := range s0 { 188 s0[i] = byte(i) 189 } 190 b, err := Marshal(s0) 191 if err != nil { 192 t.Fatalf("Marshal: %v", err) 193 } 194 var s1 []byte 195 if err := Unmarshal(b, &s1); err != nil { 196 t.Fatalf("Unmarshal: %v", err) 197 } 198 if bytes.Compare(s0, s1) != 0 { 199 t.Errorf("Marshal large byte slice") 200 diff(t, s0, s1) 201 } 202 } 203 204 type Xint struct { 205 X int 206 } 207 208 func TestUnmarshalInterface(t *testing.T) { 209 var xint Xint 210 var i interface{} = &xint 211 if err := Unmarshal([]byte(`{"X":1}`), &i); err != nil { 212 t.Fatalf("Unmarshal: %v", err) 213 } 214 if xint.X != 1 { 215 t.Fatalf("Did not write to xint") 216 } 217 } 218 219 func TestUnmarshalPtrPtr(t *testing.T) { 220 var xint Xint 221 pxint := &xint 222 if err := Unmarshal([]byte(`{"X":1}`), &pxint); err != nil { 223 t.Fatalf("Unmarshal: %v", err) 224 } 225 if xint.X != 1 { 226 t.Fatalf("Did not write to xint") 227 } 228 } 229 230 func TestEscape(t *testing.T) { 231 const input = `"foobar"<html>` 232 const expected = `"\"foobar\"\u003chtml\u003e"` 233 b, err := Marshal(input) 234 if err != nil { 235 t.Fatalf("Marshal error: %v", err) 236 } 237 if s := string(b); s != expected { 238 t.Errorf("Encoding of [%s] was [%s], want [%s]", input, s, expected) 239 } 240 } 241 242 // WrongString is a struct that's misusing the ,string modifier. 243 type WrongString struct { 244 Message string `json:"result,string"` 245 } 246 247 type wrongStringTest struct { 248 in, err string 249 } 250 251 var wrongStringTests = []wrongStringTest{ 252 {`{"result":"x"}`, `json: invalid use of ,string struct tag, trying to unmarshal "x" into string`}, 253 {`{"result":"foo"}`, `json: invalid use of ,string struct tag, trying to unmarshal "foo" into string`}, 254 {`{"result":"123"}`, `json: invalid use of ,string struct tag, trying to unmarshal "123" into string`}, 255 } 256 257 // If people misuse the ,string modifier, the error message should be 258 // helpful, telling the user that they're doing it wrong. 259 func TestErrorMessageFromMisusedString(t *testing.T) { 260 for n, tt := range wrongStringTests { 261 r := strings.NewReader(tt.in) 262 var s WrongString 263 err := NewDecoder(r).Decode(&s) 264 got := fmt.Sprintf("%v", err) 265 if got != tt.err { 266 t.Errorf("%d. got err = %q, want %q", n, got, tt.err) 267 } 268 } 269 } 270 271 func noSpace(c rune) rune { 272 if isSpace(c) { 273 return -1 274 } 275 return c 276 } 277 278 type All struct { 279 Bool bool 280 Int int 281 Int8 int8 282 Int16 int16 283 Int32 int32 284 Int64 int64 285 Uint uint 286 Uint8 uint8 287 Uint16 uint16 288 Uint32 uint32 289 Uint64 uint64 290 Uintptr uintptr 291 Float32 float32 292 Float64 float64 293 294 Foo string `json:"bar"` 295 Foo2 string `json:"bar2,dummyopt"` 296 297 IntStr int64 `json:",string"` 298 299 PBool *bool 300 PInt *int 301 PInt8 *int8 302 PInt16 *int16 303 PInt32 *int32 304 PInt64 *int64 305 PUint *uint 306 PUint8 *uint8 307 PUint16 *uint16 308 PUint32 *uint32 309 PUint64 *uint64 310 PUintptr *uintptr 311 PFloat32 *float32 312 PFloat64 *float64 313 314 String string 315 PString *string 316 317 Map map[string]Small 318 MapP map[string]*Small 319 PMap *map[string]Small 320 PMapP *map[string]*Small 321 322 EmptyMap map[string]Small 323 NilMap map[string]Small 324 325 Slice []Small 326 SliceP []*Small 327 PSlice *[]Small 328 PSliceP *[]*Small 329 330 EmptySlice []Small 331 NilSlice []Small 332 333 StringSlice []string 334 ByteSlice []byte 335 336 Small Small 337 PSmall *Small 338 PPSmall **Small 339 340 Interface interface{} 341 PInterface *interface{} 342 343 unexported int 344 } 345 346 type Small struct { 347 Tag string 348 } 349 350 var allValue = All{ 351 Bool: true, 352 Int: 2, 353 Int8: 3, 354 Int16: 4, 355 Int32: 5, 356 Int64: 6, 357 Uint: 7, 358 Uint8: 8, 359 Uint16: 9, 360 Uint32: 10, 361 Uint64: 11, 362 Uintptr: 12, 363 Float32: 14.1, 364 Float64: 15.1, 365 Foo: "foo", 366 Foo2: "foo2", 367 IntStr: 42, 368 String: "16", 369 Map: map[string]Small{ 370 "17": {Tag: "tag17"}, 371 "18": {Tag: "tag18"}, 372 }, 373 MapP: map[string]*Small{ 374 "19": {Tag: "tag19"}, 375 "20": nil, 376 }, 377 EmptyMap: map[string]Small{}, 378 Slice: []Small{{Tag: "tag20"}, {Tag: "tag21"}}, 379 SliceP: []*Small{{Tag: "tag22"}, nil, {Tag: "tag23"}}, 380 EmptySlice: []Small{}, 381 StringSlice: []string{"str24", "str25", "str26"}, 382 ByteSlice: []byte{27, 28, 29}, 383 Small: Small{Tag: "tag30"}, 384 PSmall: &Small{Tag: "tag31"}, 385 Interface: 5.2, 386 } 387 388 var pallValue = All{ 389 PBool: &allValue.Bool, 390 PInt: &allValue.Int, 391 PInt8: &allValue.Int8, 392 PInt16: &allValue.Int16, 393 PInt32: &allValue.Int32, 394 PInt64: &allValue.Int64, 395 PUint: &allValue.Uint, 396 PUint8: &allValue.Uint8, 397 PUint16: &allValue.Uint16, 398 PUint32: &allValue.Uint32, 399 PUint64: &allValue.Uint64, 400 PUintptr: &allValue.Uintptr, 401 PFloat32: &allValue.Float32, 402 PFloat64: &allValue.Float64, 403 PString: &allValue.String, 404 PMap: &allValue.Map, 405 PMapP: &allValue.MapP, 406 PSlice: &allValue.Slice, 407 PSliceP: &allValue.SliceP, 408 PPSmall: &allValue.PSmall, 409 PInterface: &allValue.Interface, 410 } 411 412 var allValueIndent = `{ 413 "Bool": true, 414 "Int": 2, 415 "Int8": 3, 416 "Int16": 4, 417 "Int32": 5, 418 "Int64": 6, 419 "Uint": 7, 420 "Uint8": 8, 421 "Uint16": 9, 422 "Uint32": 10, 423 "Uint64": 11, 424 "Uintptr": 12, 425 "Float32": 14.1, 426 "Float64": 15.1, 427 "bar": "foo", 428 "bar2": "foo2", 429 "IntStr": "42", 430 "PBool": null, 431 "PInt": null, 432 "PInt8": null, 433 "PInt16": null, 434 "PInt32": null, 435 "PInt64": null, 436 "PUint": null, 437 "PUint8": null, 438 "PUint16": null, 439 "PUint32": null, 440 "PUint64": null, 441 "PUintptr": null, 442 "PFloat32": null, 443 "PFloat64": null, 444 "String": "16", 445 "PString": null, 446 "Map": { 447 "17": { 448 "Tag": "tag17" 449 }, 450 "18": { 451 "Tag": "tag18" 452 } 453 }, 454 "MapP": { 455 "19": { 456 "Tag": "tag19" 457 }, 458 "20": null 459 }, 460 "PMap": null, 461 "PMapP": null, 462 "EmptyMap": {}, 463 "NilMap": null, 464 "Slice": [ 465 { 466 "Tag": "tag20" 467 }, 468 { 469 "Tag": "tag21" 470 } 471 ], 472 "SliceP": [ 473 { 474 "Tag": "tag22" 475 }, 476 null, 477 { 478 "Tag": "tag23" 479 } 480 ], 481 "PSlice": null, 482 "PSliceP": null, 483 "EmptySlice": [], 484 "NilSlice": null, 485 "StringSlice": [ 486 "str24", 487 "str25", 488 "str26" 489 ], 490 "ByteSlice": "Gxwd", 491 "Small": { 492 "Tag": "tag30" 493 }, 494 "PSmall": { 495 "Tag": "tag31" 496 }, 497 "PPSmall": null, 498 "Interface": 5.2, 499 "PInterface": null 500 }` 501 502 var allValueCompact = strings.Map(noSpace, allValueIndent) 503 504 var pallValueIndent = `{ 505 "Bool": false, 506 "Int": 0, 507 "Int8": 0, 508 "Int16": 0, 509 "Int32": 0, 510 "Int64": 0, 511 "Uint": 0, 512 "Uint8": 0, 513 "Uint16": 0, 514 "Uint32": 0, 515 "Uint64": 0, 516 "Uintptr": 0, 517 "Float32": 0, 518 "Float64": 0, 519 "bar": "", 520 "bar2": "", 521 "IntStr": "0", 522 "PBool": true, 523 "PInt": 2, 524 "PInt8": 3, 525 "PInt16": 4, 526 "PInt32": 5, 527 "PInt64": 6, 528 "PUint": 7, 529 "PUint8": 8, 530 "PUint16": 9, 531 "PUint32": 10, 532 "PUint64": 11, 533 "PUintptr": 12, 534 "PFloat32": 14.1, 535 "PFloat64": 15.1, 536 "String": "", 537 "PString": "16", 538 "Map": null, 539 "MapP": null, 540 "PMap": { 541 "17": { 542 "Tag": "tag17" 543 }, 544 "18": { 545 "Tag": "tag18" 546 } 547 }, 548 "PMapP": { 549 "19": { 550 "Tag": "tag19" 551 }, 552 "20": null 553 }, 554 "EmptyMap": null, 555 "NilMap": null, 556 "Slice": null, 557 "SliceP": null, 558 "PSlice": [ 559 { 560 "Tag": "tag20" 561 }, 562 { 563 "Tag": "tag21" 564 } 565 ], 566 "PSliceP": [ 567 { 568 "Tag": "tag22" 569 }, 570 null, 571 { 572 "Tag": "tag23" 573 } 574 ], 575 "EmptySlice": null, 576 "NilSlice": null, 577 "StringSlice": null, 578 "ByteSlice": null, 579 "Small": { 580 "Tag": "" 581 }, 582 "PSmall": null, 583 "PPSmall": { 584 "Tag": "tag31" 585 }, 586 "Interface": null, 587 "PInterface": 5.2 588 }` 589 590 var pallValueCompact = strings.Map(noSpace, pallValueIndent) 591 592 func TestRefUnmarshal(t *testing.T) { 593 type S struct { 594 // Ref is defined in encode_test.go. 595 R0 Ref 596 R1 *Ref 597 } 598 want := S{ 599 R0: 12, 600 R1: new(Ref), 601 } 602 *want.R1 = 12 603 604 var got S 605 if err := Unmarshal([]byte(`{"R0":"ref","R1":"ref"}`), &got); err != nil { 606 t.Fatalf("Unmarshal: %v", err) 607 } 608 if !reflect.DeepEqual(got, want) { 609 t.Errorf("got %+v, want %+v", got, want) 610 } 611 } 612 613 // Test that anonymous fields are ignored. 614 // We may assign meaning to them later. 615 func TestAnonymous(t *testing.T) { 616 type S struct { 617 T 618 N int 619 } 620 621 data, err := Marshal(new(S)) 622 if err != nil { 623 t.Fatalf("Marshal: %v", err) 624 } 625 want := `{"N":0}` 626 if string(data) != want { 627 t.Fatalf("Marshal = %#q, want %#q", string(data), want) 628 } 629 630 var s S 631 if err := Unmarshal([]byte(`{"T": 1, "T": {"Y": 1}, "N": 2}`), &s); err != nil { 632 t.Fatalf("Unmarshal: %v", err) 633 } 634 if s.N != 2 { 635 t.Fatal("Unmarshal: did not set N") 636 } 637 if s.T.Y != 0 { 638 t.Fatal("Unmarshal: did set T.Y") 639 } 640 } 641 642 // Test that the empty string doesn't panic decoding when ,string is specified 643 // Issue 3450 644 func TestEmptyString(t *testing.T) { 645 type T2 struct { 646 Number1 int `json:",string"` 647 Number2 int `json:",string"` 648 } 649 data := `{"Number1":"1", "Number2":""}` 650 dec := NewDecoder(strings.NewReader(data)) 651 var t2 T2 652 err := dec.Decode(&t2) 653 if err == nil { 654 t.Fatal("Decode: did not return error") 655 } 656 if t2.Number1 != 1 { 657 t.Fatal("Decode: did not set Number1") 658 } 659 } 660 661 func intp(x int) *int { 662 p := new(int) 663 *p = x 664 return p 665 } 666 667 func intpp(x *int) **int { 668 pp := new(*int) 669 *pp = x 670 return pp 671 } 672 673 var interfaceSetTests = []struct { 674 pre interface{} 675 json string 676 post interface{} 677 }{ 678 {"foo", `"bar"`, "bar"}, 679 {"foo", `2`, 2.0}, 680 {"foo", `true`, true}, 681 {"foo", `null`, nil}, 682 683 {nil, `null`, nil}, 684 {new(int), `null`, nil}, 685 {(*int)(nil), `null`, nil}, 686 {new(*int), `null`, new(*int)}, 687 {(**int)(nil), `null`, nil}, 688 {intp(1), `null`, nil}, 689 {intpp(nil), `null`, intpp(nil)}, 690 {intpp(intp(1)), `null`, intpp(nil)}, 691 } 692 693 func TestInterfaceSet(t *testing.T) { 694 for _, tt := range interfaceSetTests { 695 b := struct{ X interface{} }{tt.pre} 696 blob := `{"X":` + tt.json + `}` 697 if err := Unmarshal([]byte(blob), &b); err != nil { 698 t.Errorf("Unmarshal %#q: %v", blob, err) 699 continue 700 } 701 if !reflect.DeepEqual(b.X, tt.post) { 702 t.Errorf("Unmarshal %#q into %#v: X=%#v, want %#v", blob, tt.pre, b.X, tt.post) 703 } 704 } 705 }