github.com/bingoohuang/gg@v0.0.0-20240325092523-45da7dee9335/pkg/mapstruct/mapstruct_test.go (about) 1 package mapstruct 2 3 import ( 4 "encoding/json" 5 "io" 6 "reflect" 7 "sort" 8 "strings" 9 "testing" 10 "time" 11 12 "github.com/stretchr/testify/assert" 13 ) 14 15 type NullTime struct { 16 DeletedTime *time.Time 17 } 18 19 func TestNullTime(t *testing.T) { 20 var nullTimes []NullTime 21 22 decoder, err := NewDecoder(&Config{ 23 Result: &nullTimes, 24 Squash: true, 25 WeakType: true, 26 }) 27 assert.Nil(t, err) 28 29 values := []map[string]string{ 30 {"DeletedTime": ""}, 31 } 32 33 err = decoder.Decode(values) 34 assert.Nil(t, err) 35 assert.Nil(t, nullTimes[0].DeletedTime) 36 } 37 38 type Basic struct { 39 Vstring string 40 Vint int 41 Vint8 int8 42 Vint16 int16 43 Vint32 int32 44 Vint64 int64 45 Vuint uint 46 Vbool bool 47 Vfloat float64 48 Vextra string 49 vsilent bool 50 Vdata interface{} 51 VjsonInt int 52 VjsonUint uint 53 VjsonFloat float64 54 VjsonNumber json.Number 55 } 56 57 type BasicPointer struct { 58 Vstring *string 59 Vint *int 60 Vuint *uint 61 Vbool *bool 62 Vfloat *float64 63 Vextra *string 64 vsilent *bool // nolint:structcheck,unused 65 Vdata *interface{} 66 VjsonInt *int 67 VjsonFloat *float64 68 VjsonNumber *json.Number 69 } 70 71 type BasicSquash struct { 72 Test Basic `mapstruct:",squash"` 73 } 74 75 type Embedded struct { 76 Basic 77 Vunique string 78 } 79 80 type EmbeddedPointer struct { 81 *Basic 82 Vunique string 83 } 84 85 type EmbeddedSquash struct { 86 Basic `mapstruct:",squash"` 87 Vunique string 88 } 89 90 type EmbeddedPointerSquash struct { 91 *Basic `mapstruct:",squash"` 92 Vunique string 93 } 94 95 type EmbeddedAndNamed struct { 96 Basic 97 Named Basic 98 Vunique string 99 } 100 101 type SliceAlias []string 102 103 type EmbeddedSlice struct { 104 SliceAlias `mapstruct:"slice_alias"` 105 Vunique string 106 } 107 108 type ArrayAlias [2]string 109 110 type EmbeddedArray struct { 111 ArrayAlias `mapstruct:"array_alias"` 112 Vunique string 113 } 114 115 type SquashOnNonStructType struct { 116 InvalidSquashType int `mapstruct:",squash"` 117 } 118 119 type Map struct { 120 Vfoo string 121 Vother map[string]string 122 } 123 124 type MapOfStruct struct { 125 Value map[string]Basic 126 } 127 128 type Nested struct { 129 Vfoo string 130 Vbar Basic 131 } 132 133 type NestedPointer struct { 134 Vfoo string 135 Vbar *Basic 136 } 137 138 type NilInterface struct { 139 W io.Writer 140 } 141 142 type NilPointer struct { 143 Value *string 144 } 145 146 type Slice struct { 147 Vfoo string 148 Vbar []string 149 } 150 151 type SliceOfAlias struct { 152 Vfoo string 153 Vbar SliceAlias 154 } 155 156 type SliceOfStruct struct { 157 Value []Basic 158 } 159 160 type SlicePointer struct { 161 Vbar *[]string 162 } 163 164 type Array struct { 165 Vfoo string 166 Vbar [2]string 167 } 168 169 type ArrayOfStruct struct { 170 Value [2]Basic 171 } 172 173 type Func struct { 174 Foo func() string 175 } 176 177 type Tagged struct { 178 Extra string `mapstruct:"bar,what,what"` 179 Value string `mapstruct:"foo"` 180 } 181 182 type Remainder struct { 183 A string 184 Extra map[string]interface{} `mapstruct:",remain"` 185 } 186 187 type StructWithOmitEmpty struct { 188 VisibleStringField string `mapstruct:"visible-string"` 189 OmitStringField string `mapstruct:"omittable-string,omitempty"` 190 VisibleIntField int `mapstruct:"visible-int"` 191 OmitIntField int `mapstruct:"omittable-int,omitempty"` 192 VisibleFloatField float64 `mapstruct:"visible-float"` 193 OmitFloatField float64 `mapstruct:"omittable-float,omitempty"` 194 VisibleSliceField []interface{} `mapstruct:"visible-slice"` 195 OmitSliceField []interface{} `mapstruct:"omittable-slice,omitempty"` 196 VisibleMapField map[string]interface{} `mapstruct:"visible-map"` 197 OmitMapField map[string]interface{} `mapstruct:"omittable-map,omitempty"` 198 NestedField *Nested `mapstruct:"visible-nested"` 199 OmitNestedField *Nested `mapstruct:"omittable-nested,omitempty"` 200 } 201 202 type TypeConversionResult struct { 203 IntToFloat float32 204 IntToUint uint 205 IntToBool bool 206 IntToString string 207 UintToInt int 208 UintToFloat float32 209 UintToBool bool 210 UintToString string 211 BoolToInt int 212 BoolToUint uint 213 BoolToFloat float32 214 BoolToString string 215 FloatToInt int 216 FloatToUint uint 217 FloatToBool bool 218 FloatToString string 219 SliceUint8ToString string 220 StringToSliceUint8 []byte 221 ArrayUint8ToString string 222 StringToInt int 223 StringToUint uint 224 StringToBool bool 225 StringToFloat float32 226 StringToStrSlice []string 227 StringToIntSlice []int 228 StringToStrArray [1]string 229 StringToIntArray [1]int 230 SliceToMap map[string]interface{} 231 MapToSlice []interface{} 232 ArrayToMap map[string]interface{} 233 MapToArray [1]interface{} 234 } 235 236 func TestBasicTypes(t *testing.T) { 237 t.Parallel() 238 239 input := map[string]interface{}{ 240 "vstring": "foo", 241 "vint": 42, 242 "vint8": 42, 243 "vint16": 42, 244 "vint32": 42, 245 "vint64": 42, 246 "Vuint": 42, 247 "vbool": true, 248 "Vfloat": 42.42, 249 "vsilent": true, 250 "vdata": 42, 251 "vjsonInt": json.Number("1234"), 252 "vjsonUint": json.Number("1234"), 253 "vjsonFloat": json.Number("1234.5"), 254 "vjsonNumber": json.Number("1234.5"), 255 } 256 257 var result Basic 258 err := Decode(input, &result) 259 if err != nil { 260 t.Errorf("got an err: %s", err.Error()) 261 t.FailNow() 262 } 263 264 if result.Vstring != "foo" { 265 t.Errorf("vstring value should be 'foo': %#v", result.Vstring) 266 } 267 268 if result.Vint != 42 { 269 t.Errorf("vint value should be 42: %#v", result.Vint) 270 } 271 if result.Vint8 != 42 { 272 t.Errorf("vint8 value should be 42: %#v", result.Vint) 273 } 274 if result.Vint16 != 42 { 275 t.Errorf("vint16 value should be 42: %#v", result.Vint) 276 } 277 if result.Vint32 != 42 { 278 t.Errorf("vint32 value should be 42: %#v", result.Vint) 279 } 280 if result.Vint64 != 42 { 281 t.Errorf("vint64 value should be 42: %#v", result.Vint) 282 } 283 284 if result.Vuint != 42 { 285 t.Errorf("vuint value should be 42: %#v", result.Vuint) 286 } 287 288 if result.Vbool != true { 289 t.Errorf("vbool value should be true: %#v", result.Vbool) 290 } 291 292 if result.Vfloat != 42.42 { 293 t.Errorf("vfloat value should be 42.42: %#v", result.Vfloat) 294 } 295 296 if result.Vextra != "" { 297 t.Errorf("vextra value should be empty: %#v", result.Vextra) 298 } 299 300 if result.vsilent != false { 301 t.Error("vsilent should not be set, it is unexported") 302 } 303 304 if result.Vdata != 42 { 305 t.Error("vdata should be valid") 306 } 307 308 if result.VjsonInt != 1234 { 309 t.Errorf("vjsonint value should be 1234: %#v", result.VjsonInt) 310 } 311 312 if result.VjsonUint != 1234 { 313 t.Errorf("vjsonuint value should be 1234: %#v", result.VjsonUint) 314 } 315 316 if result.VjsonFloat != 1234.5 { 317 t.Errorf("vjsonfloat value should be 1234.5: %#v", result.VjsonFloat) 318 } 319 320 if !reflect.DeepEqual(result.VjsonNumber, json.Number("1234.5")) { 321 t.Errorf("vjsonnumber value should be '1234.5': %T, %#v", result.VjsonNumber, result.VjsonNumber) 322 } 323 } 324 325 func TestBasic_IntWithFloat(t *testing.T) { 326 t.Parallel() 327 328 input := map[string]interface{}{ 329 "vint": float64(42), 330 } 331 332 var result Basic 333 err := Decode(input, &result) 334 if err != nil { 335 t.Fatalf("got an err: %s", err) 336 } 337 } 338 339 func TestBasic_Merge(t *testing.T) { 340 t.Parallel() 341 342 input := map[string]interface{}{ 343 "vint": 42, 344 } 345 346 var result Basic 347 result.Vuint = 100 348 err := Decode(input, &result) 349 if err != nil { 350 t.Fatalf("got an err: %s", err) 351 } 352 353 expected := Basic{ 354 Vint: 42, 355 Vuint: 100, 356 } 357 if !reflect.DeepEqual(result, expected) { 358 t.Fatalf("bad: %#v", result) 359 } 360 } 361 362 // Test for issue #46. 363 func TestBasic_Struct(t *testing.T) { 364 t.Parallel() 365 366 input := map[string]interface{}{ 367 "vdata": map[string]interface{}{ 368 "vstring": "foo", 369 }, 370 } 371 372 var result, inner Basic 373 result.Vdata = &inner 374 err := Decode(input, &result) 375 if err != nil { 376 t.Fatalf("got an err: %s", err) 377 } 378 expected := Basic{ 379 Vdata: &Basic{ 380 Vstring: "foo", 381 }, 382 } 383 if !reflect.DeepEqual(result, expected) { 384 t.Fatalf("bad: %#v", result) 385 } 386 } 387 388 func TestBasic_interfaceStruct(t *testing.T) { 389 t.Parallel() 390 391 input := map[string]interface{}{ 392 "vstring": "foo", 393 } 394 395 var iface interface{} = &Basic{} 396 err := Decode(input, &iface) 397 if err != nil { 398 t.Fatalf("got an err: %s", err) 399 } 400 401 expected := &Basic{ 402 Vstring: "foo", 403 } 404 if !reflect.DeepEqual(iface, expected) { 405 t.Fatalf("bad: %#v", iface) 406 } 407 } 408 409 // Issue 187 410 func TestBasic_interfaceStructNonPtr(t *testing.T) { 411 t.Parallel() 412 413 input := map[string]interface{}{ 414 "vstring": "foo", 415 } 416 417 var iface interface{} = Basic{} 418 err := Decode(input, &iface) 419 if err != nil { 420 t.Fatalf("got an err: %s", err) 421 } 422 423 expected := Basic{ 424 Vstring: "foo", 425 } 426 if !reflect.DeepEqual(iface, expected) { 427 t.Fatalf("bad: %#v", iface) 428 } 429 } 430 431 func TestDecode_BasicSquash(t *testing.T) { 432 t.Parallel() 433 434 input := map[string]interface{}{ 435 "vstring": "foo", 436 } 437 438 var result BasicSquash 439 err := Decode(input, &result) 440 if err != nil { 441 t.Fatalf("got an err: %s", err.Error()) 442 } 443 444 if result.Test.Vstring != "foo" { 445 t.Errorf("vstring value should be 'foo': %#v", result.Test.Vstring) 446 } 447 } 448 449 func TestDecodeFrom_BasicSquash(t *testing.T) { 450 t.Parallel() 451 452 var v interface{} 453 var ok bool 454 455 input := BasicSquash{ 456 Test: Basic{ 457 Vstring: "foo", 458 }, 459 } 460 461 var result map[string]interface{} 462 err := Decode(input, &result) 463 if err != nil { 464 t.Fatalf("got an err: %s", err.Error()) 465 } 466 467 if _, ok = result["Test"]; ok { 468 t.Error("test should not be present in map") 469 } 470 471 v, ok = result["Vstring"] 472 if !ok { 473 t.Error("vstring should be present in map") 474 } else if !reflect.DeepEqual(v, "foo") { 475 t.Errorf("vstring value should be 'foo': %#v", v) 476 } 477 } 478 479 func TestDecode_Embedded(t *testing.T) { 480 t.Parallel() 481 482 input := map[string]interface{}{ 483 "vstring": "foo", 484 "Basic": map[string]interface{}{ 485 "vstring": "innerfoo", 486 }, 487 "vunique": "bar", 488 } 489 490 var result Embedded 491 err := Decode(input, &result) 492 if err != nil { 493 t.Fatalf("got an err: %s", err.Error()) 494 } 495 496 if result.Vstring != "innerfoo" { 497 t.Errorf("vstring value should be 'innerfoo': %#v", result.Vstring) 498 } 499 500 if result.Vunique != "bar" { 501 t.Errorf("vunique value should be 'bar': %#v", result.Vunique) 502 } 503 } 504 505 func TestDecode_EmbeddedPointer(t *testing.T) { 506 t.Parallel() 507 508 input := map[string]interface{}{ 509 "vstring": "foo", 510 "Basic": map[string]interface{}{ 511 "vstring": "innerfoo", 512 }, 513 "vunique": "bar", 514 } 515 516 var result EmbeddedPointer 517 err := Decode(input, &result) 518 if err != nil { 519 t.Fatalf("err: %s", err) 520 } 521 522 expected := EmbeddedPointer{ 523 Basic: &Basic{ 524 Vstring: "innerfoo", 525 }, 526 Vunique: "bar", 527 } 528 if !reflect.DeepEqual(result, expected) { 529 t.Fatalf("bad: %#v", result) 530 } 531 } 532 533 func TestDecode_EmbeddedSlice(t *testing.T) { 534 t.Parallel() 535 536 input := map[string]interface{}{ 537 "slice_alias": []string{"foo", "bar"}, 538 "vunique": "bar", 539 } 540 541 var result EmbeddedSlice 542 err := Decode(input, &result) 543 if err != nil { 544 t.Fatalf("got an err: %s", err.Error()) 545 } 546 547 if !reflect.DeepEqual(result.SliceAlias, SliceAlias([]string{"foo", "bar"})) { 548 t.Errorf("slice value: %#v", result.SliceAlias) 549 } 550 551 if result.Vunique != "bar" { 552 t.Errorf("vunique value should be 'bar': %#v", result.Vunique) 553 } 554 } 555 556 func TestDecode_EmbeddedArray(t *testing.T) { 557 t.Parallel() 558 559 input := map[string]interface{}{ 560 "array_alias": [2]string{"foo", "bar"}, 561 "vunique": "bar", 562 } 563 564 var result EmbeddedArray 565 err := Decode(input, &result) 566 if err != nil { 567 t.Fatalf("got an err: %s", err.Error()) 568 } 569 570 if !reflect.DeepEqual(result.ArrayAlias, ArrayAlias([2]string{"foo", "bar"})) { 571 t.Errorf("array value: %#v", result.ArrayAlias) 572 } 573 574 if result.Vunique != "bar" { 575 t.Errorf("vunique value should be 'bar': %#v", result.Vunique) 576 } 577 } 578 579 func TestDecode_EmbeddedNoSquash(t *testing.T) { 580 t.Parallel() 581 582 input := map[string]interface{}{ 583 "vstring": "foo", 584 "vunique": "bar", 585 } 586 587 var result Embedded 588 err := Decode(input, &result) 589 if err != nil { 590 t.Fatalf("got an err: %s", err.Error()) 591 } 592 593 if result.Vstring != "" { 594 t.Errorf("vstring value should be empty: %#v", result.Vstring) 595 } 596 597 if result.Vunique != "bar" { 598 t.Errorf("vunique value should be 'bar': %#v", result.Vunique) 599 } 600 } 601 602 func TestDecode_EmbeddedPointerNoSquash(t *testing.T) { 603 t.Parallel() 604 605 input := map[string]interface{}{ 606 "vstring": "foo", 607 "vunique": "bar", 608 } 609 610 result := EmbeddedPointer{ 611 Basic: &Basic{}, 612 } 613 614 err := Decode(input, &result) 615 if err != nil { 616 t.Fatalf("err: %s", err) 617 } 618 619 if result.Vstring != "" { 620 t.Errorf("vstring value should be empty: %#v", result.Vstring) 621 } 622 623 if result.Vunique != "bar" { 624 t.Errorf("vunique value should be 'bar': %#v", result.Vunique) 625 } 626 } 627 628 func TestDecode_EmbeddedSquash(t *testing.T) { 629 t.Parallel() 630 631 input := map[string]interface{}{ 632 "vstring": "foo", 633 "vunique": "bar", 634 } 635 636 var result EmbeddedSquash 637 err := Decode(input, &result) 638 if err != nil { 639 t.Fatalf("got an err: %s", err.Error()) 640 } 641 642 if result.Vstring != "foo" { 643 t.Errorf("vstring value should be 'foo': %#v", result.Vstring) 644 } 645 646 if result.Vunique != "bar" { 647 t.Errorf("vunique value should be 'bar': %#v", result.Vunique) 648 } 649 } 650 651 func TestDecodeFrom_EmbeddedSquash(t *testing.T) { 652 t.Parallel() 653 654 var v interface{} 655 var ok bool 656 657 input := EmbeddedSquash{ 658 Basic: Basic{ 659 Vstring: "foo", 660 }, 661 Vunique: "bar", 662 } 663 664 var result map[string]interface{} 665 err := Decode(input, &result) 666 if err != nil { 667 t.Fatalf("got an err: %s", err.Error()) 668 } 669 670 if _, ok = result["Basic"]; ok { 671 t.Error("basic should not be present in map") 672 } 673 674 v, ok = result["Vstring"] 675 if !ok { 676 t.Error("vstring should be present in map") 677 } else if !reflect.DeepEqual(v, "foo") { 678 t.Errorf("vstring value should be 'foo': %#v", v) 679 } 680 681 v, ok = result["Vunique"] 682 if !ok { 683 t.Error("vunique should be present in map") 684 } else if !reflect.DeepEqual(v, "bar") { 685 t.Errorf("vunique value should be 'bar': %#v", v) 686 } 687 } 688 689 func TestDecode_EmbeddedPointerSquash_FromStructToMap(t *testing.T) { 690 t.Parallel() 691 692 input := EmbeddedPointerSquash{ 693 Basic: &Basic{ 694 Vstring: "foo", 695 }, 696 Vunique: "bar", 697 } 698 699 var result map[string]interface{} 700 err := Decode(input, &result) 701 if err != nil { 702 t.Fatalf("got an err: %s", err.Error()) 703 } 704 705 if result["Vstring"] != "foo" { 706 t.Errorf("vstring value should be 'foo': %#v", result["Vstring"]) 707 } 708 709 if result["Vunique"] != "bar" { 710 t.Errorf("vunique value should be 'bar': %#v", result["Vunique"]) 711 } 712 } 713 714 func TestDecode_EmbeddedPointerSquash_FromMapToStruct(t *testing.T) { 715 t.Parallel() 716 717 input := map[string]interface{}{ 718 "Vstring": "foo", 719 "Vunique": "bar", 720 } 721 722 result := EmbeddedPointerSquash{ 723 Basic: &Basic{}, 724 } 725 err := Decode(input, &result) 726 if err != nil { 727 t.Fatalf("got an err: %s", err.Error()) 728 } 729 730 if result.Vstring != "foo" { 731 t.Errorf("vstring value should be 'foo': %#v", result.Vstring) 732 } 733 734 if result.Vunique != "bar" { 735 t.Errorf("vunique value should be 'bar': %#v", result.Vunique) 736 } 737 } 738 739 func TestDecode_EmbeddedSquashConfig(t *testing.T) { 740 t.Parallel() 741 742 input := map[string]interface{}{ 743 "vstring": "foo", 744 "vunique": "bar", 745 "Named": map[string]interface{}{ 746 "vstring": "baz", 747 }, 748 } 749 750 var result EmbeddedAndNamed 751 config := &Config{ 752 Squash: true, 753 Result: &result, 754 } 755 756 decoder, err := NewDecoder(config) 757 if err != nil { 758 t.Fatalf("err: %s", err) 759 } 760 761 err = decoder.Decode(input) 762 if err != nil { 763 t.Fatalf("got an err: %s", err) 764 } 765 766 if result.Vstring != "foo" { 767 t.Errorf("vstring value should be 'foo': %#v", result.Vstring) 768 } 769 770 if result.Vunique != "bar" { 771 t.Errorf("vunique value should be 'bar': %#v", result.Vunique) 772 } 773 774 if result.Named.Vstring != "baz" { 775 t.Errorf("Named.vstring value should be 'baz': %#v", result.Named.Vstring) 776 } 777 } 778 779 func TestDecodeFrom_EmbeddedSquashConfig(t *testing.T) { 780 t.Parallel() 781 782 input := EmbeddedAndNamed{ 783 Basic: Basic{Vstring: "foo"}, 784 Named: Basic{Vstring: "baz"}, 785 Vunique: "bar", 786 } 787 788 result := map[string]interface{}{} 789 config := &Config{ 790 Squash: true, 791 Result: &result, 792 } 793 decoder, err := NewDecoder(config) 794 if err != nil { 795 t.Fatalf("got an err: %s", err.Error()) 796 } 797 798 err = decoder.Decode(input) 799 if err != nil { 800 t.Fatalf("got an err: %s", err.Error()) 801 } 802 803 if _, ok := result["Basic"]; ok { 804 t.Error("basic should not be present in map") 805 } 806 807 v, ok := result["Vstring"] 808 if !ok { 809 t.Error("vstring should be present in map") 810 } else if !reflect.DeepEqual(v, "foo") { 811 t.Errorf("vstring value should be 'foo': %#v", v) 812 } 813 814 v, ok = result["Vunique"] 815 if !ok { 816 t.Error("vunique should be present in map") 817 } else if !reflect.DeepEqual(v, "bar") { 818 t.Errorf("vunique value should be 'bar': %#v", v) 819 } 820 821 v, ok = result["Named"] 822 if !ok { 823 t.Error("Named should be present in map") 824 } else { 825 named := v.(map[string]interface{}) 826 v, ok := named["Vstring"] 827 if !ok { 828 t.Error("Named: vstring should be present in map") 829 } else if !reflect.DeepEqual(v, "baz") { 830 t.Errorf("Named: vstring should be 'baz': %#v", v) 831 } 832 } 833 } 834 835 func TestDecode_SquashOnNonStructType(t *testing.T) { 836 t.Parallel() 837 838 input := map[string]interface{}{ 839 "InvalidSquashType": 42, 840 } 841 842 var result SquashOnNonStructType 843 err := Decode(input, &result) 844 if err == nil { 845 t.Fatal("unexpected success decoding invalid squash field type") 846 } else if !strings.Contains(err.Error(), "unsupported type for squash") { 847 t.Fatalf("unexpected error message for invalid squash field type: %s", err) 848 } 849 } 850 851 func TestDecode_DecodeHook(t *testing.T) { 852 t.Parallel() 853 854 input := map[string]interface{}{ 855 "vint": "WHAT", 856 } 857 858 decodeHook := func(from reflect.Kind, to reflect.Kind, v interface{}) (interface{}, error) { 859 if from == reflect.String && to != reflect.String { 860 return 5, nil 861 } 862 863 return v, nil 864 } 865 866 var result Basic 867 config := &Config{ 868 Hook: decodeHook, 869 Result: &result, 870 } 871 872 decoder, err := NewDecoder(config) 873 if err != nil { 874 t.Fatalf("err: %s", err) 875 } 876 877 err = decoder.Decode(input) 878 if err != nil { 879 t.Fatalf("got an err: %s", err) 880 } 881 882 if result.Vint != 5 { 883 t.Errorf("vint should be 5: %#v", result.Vint) 884 } 885 } 886 887 func TestDecode_DecodeHookType(t *testing.T) { 888 t.Parallel() 889 890 input := map[string]interface{}{ 891 "vint": "WHAT", 892 } 893 894 decodeHook := func(from reflect.Type, to reflect.Type, v interface{}) (interface{}, error) { 895 if from.Kind() == reflect.String && 896 to.Kind() != reflect.String { 897 return 5, nil 898 } 899 900 return v, nil 901 } 902 903 var result Basic 904 config := &Config{ 905 Hook: decodeHook, 906 Result: &result, 907 } 908 909 decoder, err := NewDecoder(config) 910 if err != nil { 911 t.Fatalf("err: %s", err) 912 } 913 914 err = decoder.Decode(input) 915 if err != nil { 916 t.Fatalf("got an err: %s", err) 917 } 918 919 if result.Vint != 5 { 920 t.Errorf("vint should be 5: %#v", result.Vint) 921 } 922 } 923 924 func TestDecode_Nil(t *testing.T) { 925 t.Parallel() 926 927 var input interface{} 928 result := Basic{ 929 Vstring: "foo", 930 } 931 932 err := Decode(input, &result) 933 if err != nil { 934 t.Fatalf("err: %s", err) 935 } 936 937 if result.Vstring != "foo" { 938 t.Fatalf("bad: %#v", result.Vstring) 939 } 940 } 941 942 func TestDecode_NilInterfaceHook(t *testing.T) { 943 t.Parallel() 944 945 input := map[string]interface{}{ 946 "w": "", 947 } 948 949 decodeHook := func(f, t reflect.Type, v interface{}) (interface{}, error) { 950 if t.String() == "io.Writer" { 951 return nil, nil 952 } 953 954 return v, nil 955 } 956 957 var result NilInterface 958 config := &Config{ 959 Hook: decodeHook, 960 Result: &result, 961 } 962 963 decoder, err := NewDecoder(config) 964 if err != nil { 965 t.Fatalf("err: %s", err) 966 } 967 968 err = decoder.Decode(input) 969 if err != nil { 970 t.Fatalf("got an err: %s", err) 971 } 972 973 if result.W != nil { 974 t.Errorf("W should be nil: %#v", result.W) 975 } 976 } 977 978 func TestDecode_NilPointerHook(t *testing.T) { 979 t.Parallel() 980 981 input := map[string]interface{}{ 982 "value": "", 983 } 984 985 decodeHook := func(f, t reflect.Type, v interface{}) (interface{}, error) { 986 if typed, ok := v.(string); ok { 987 if typed == "" { 988 return nil, nil 989 } 990 } 991 return v, nil 992 } 993 994 var result NilPointer 995 config := &Config{ 996 Hook: decodeHook, 997 Result: &result, 998 } 999 1000 decoder, err := NewDecoder(config) 1001 if err != nil { 1002 t.Fatalf("err: %s", err) 1003 } 1004 1005 err = decoder.Decode(input) 1006 if err != nil { 1007 t.Fatalf("got an err: %s", err) 1008 } 1009 1010 if result.Value != nil { 1011 t.Errorf("W should be nil: %#v", result.Value) 1012 } 1013 } 1014 1015 func TestDecode_FuncHook(t *testing.T) { 1016 t.Parallel() 1017 1018 input := map[string]interface{}{ 1019 "foo": "baz", 1020 } 1021 1022 decodeHook := func(f, t reflect.Type, v interface{}) (interface{}, error) { 1023 if t.Kind() != reflect.Func { 1024 return v, nil 1025 } 1026 val := v.(string) 1027 return func() string { return val }, nil 1028 } 1029 1030 var result Func 1031 config := &Config{ 1032 Hook: decodeHook, 1033 Result: &result, 1034 } 1035 1036 decoder, err := NewDecoder(config) 1037 if err != nil { 1038 t.Fatalf("err: %s", err) 1039 } 1040 1041 err = decoder.Decode(input) 1042 if err != nil { 1043 t.Fatalf("got an err: %s", err) 1044 } 1045 1046 if result.Foo() != "baz" { 1047 t.Errorf("Foo call result should be 'baz': %s", result.Foo()) 1048 } 1049 } 1050 1051 func TestDecode_NonStruct(t *testing.T) { 1052 t.Parallel() 1053 1054 input := map[string]interface{}{ 1055 "foo": "bar", 1056 "bar": "baz", 1057 } 1058 1059 var result map[string]string 1060 err := Decode(input, &result) 1061 if err != nil { 1062 t.Fatalf("err: %s", err) 1063 } 1064 1065 if result["foo"] != "bar" { 1066 t.Fatal("foo is not bar") 1067 } 1068 } 1069 1070 func TestDecode_StructMatch(t *testing.T) { 1071 t.Parallel() 1072 1073 input := map[string]interface{}{ 1074 "vbar": Basic{ 1075 Vstring: "foo", 1076 }, 1077 } 1078 1079 var result Nested 1080 err := Decode(input, &result) 1081 if err != nil { 1082 t.Fatalf("got an err: %s", err.Error()) 1083 } 1084 1085 if result.Vbar.Vstring != "foo" { 1086 t.Errorf("bad: %#v", result) 1087 } 1088 } 1089 1090 func TestDecode_TypeConversion(t *testing.T) { 1091 input := map[string]interface{}{ 1092 "IntToFloat": 42, 1093 "IntToUint": 42, 1094 "IntToBool": 1, 1095 "IntToString": 42, 1096 "UintToInt": 42, 1097 "UintToFloat": 42, 1098 "UintToBool": 42, 1099 "UintToString": 42, 1100 "BoolToInt": true, 1101 "BoolToUint": true, 1102 "BoolToFloat": true, 1103 "BoolToString": true, 1104 "FloatToInt": 42.42, 1105 "FloatToUint": 42.42, 1106 "FloatToBool": 42.42, 1107 "FloatToString": 42.42, 1108 "SliceUint8ToString": []uint8("foo"), 1109 "StringToSliceUint8": "foo", 1110 "ArrayUint8ToString": [3]uint8{'f', 'o', 'o'}, 1111 "StringToInt": "42", 1112 "StringToUint": "42", 1113 "StringToBool": "1", 1114 "StringToFloat": "42.42", 1115 "StringToStrSlice": "A", 1116 "StringToIntSlice": "42", 1117 "StringToStrArray": "A", 1118 "StringToIntArray": "42", 1119 "SliceToMap": []interface{}{}, 1120 "MapToSlice": map[string]interface{}{}, 1121 "ArrayToMap": []interface{}{}, 1122 "MapToArray": map[string]interface{}{}, 1123 } 1124 1125 expectedResultStrict := TypeConversionResult{ 1126 IntToFloat: 42.0, 1127 IntToUint: 42, 1128 UintToInt: 42, 1129 UintToFloat: 42, 1130 BoolToInt: 0, 1131 BoolToUint: 0, 1132 BoolToFloat: 0, 1133 FloatToInt: 42, 1134 FloatToUint: 42, 1135 } 1136 1137 expectedResultWeak := TypeConversionResult{ 1138 IntToFloat: 42.0, 1139 IntToUint: 42, 1140 IntToBool: true, 1141 IntToString: "42", 1142 UintToInt: 42, 1143 UintToFloat: 42, 1144 UintToBool: true, 1145 UintToString: "42", 1146 BoolToInt: 1, 1147 BoolToUint: 1, 1148 BoolToFloat: 1, 1149 BoolToString: "1", 1150 FloatToInt: 42, 1151 FloatToUint: 42, 1152 FloatToBool: true, 1153 FloatToString: "42.42", 1154 SliceUint8ToString: "foo", 1155 StringToSliceUint8: []byte("foo"), 1156 ArrayUint8ToString: "foo", 1157 StringToInt: 42, 1158 StringToUint: 42, 1159 StringToBool: true, 1160 StringToFloat: 42.42, 1161 StringToStrSlice: []string{"A"}, 1162 StringToIntSlice: []int{42}, 1163 StringToStrArray: [1]string{"A"}, 1164 StringToIntArray: [1]int{42}, 1165 SliceToMap: map[string]interface{}{}, 1166 MapToSlice: []interface{}{}, 1167 ArrayToMap: map[string]interface{}{}, 1168 MapToArray: [1]interface{}{}, 1169 } 1170 1171 // Test strict type conversion 1172 var resultStrict TypeConversionResult 1173 err := Decode(input, &resultStrict) 1174 if err == nil { 1175 t.Errorf("should return an error") 1176 } 1177 if !reflect.DeepEqual(resultStrict, expectedResultStrict) { 1178 t.Errorf("expected %v, got: %v", expectedResultStrict, resultStrict) 1179 } 1180 1181 // Test weak type conversion 1182 var decoder *Decoder 1183 var resultWeak TypeConversionResult 1184 1185 config := &Config{ 1186 WeakType: true, 1187 Result: &resultWeak, 1188 } 1189 1190 decoder, err = NewDecoder(config) 1191 if err != nil { 1192 t.Fatalf("err: %s", err) 1193 } 1194 1195 err = decoder.Decode(input) 1196 if err != nil { 1197 t.Fatalf("got an err: %s", err) 1198 } 1199 1200 if !reflect.DeepEqual(resultWeak, expectedResultWeak) { 1201 t.Errorf("expected \n%#v, got: \n%#v", expectedResultWeak, resultWeak) 1202 } 1203 } 1204 1205 func TestDecoder_ErrorUnused(t *testing.T) { 1206 t.Parallel() 1207 1208 input := map[string]interface{}{ 1209 "vstring": "hello", 1210 "foo": "bar", 1211 } 1212 1213 var result Basic 1214 config := &Config{ 1215 ErrorUnused: true, 1216 Result: &result, 1217 } 1218 1219 decoder, err := NewDecoder(config) 1220 if err != nil { 1221 t.Fatalf("err: %s", err) 1222 } 1223 1224 err = decoder.Decode(input) 1225 if err == nil { 1226 t.Fatal("expected error") 1227 } 1228 } 1229 1230 func TestDecoder_ErrorUnused_NotSetable(t *testing.T) { 1231 t.Parallel() 1232 1233 // lowercase vsilent is unexported and cannot be set 1234 input := map[string]interface{}{ 1235 "vsilent": "false", 1236 } 1237 1238 var result Basic 1239 config := &Config{ 1240 ErrorUnused: true, 1241 Result: &result, 1242 } 1243 1244 decoder, err := NewDecoder(config) 1245 if err != nil { 1246 t.Fatalf("err: %s", err) 1247 } 1248 1249 err = decoder.Decode(input) 1250 if err == nil { 1251 t.Fatal("expected error") 1252 } 1253 } 1254 1255 func TestMap(t *testing.T) { 1256 t.Parallel() 1257 1258 input := map[string]interface{}{ 1259 "vfoo": "foo", 1260 "vother": map[interface{}]interface{}{ 1261 "foo": "foo", 1262 "bar": "bar", 1263 }, 1264 } 1265 1266 var result Map 1267 err := Decode(input, &result) 1268 if err != nil { 1269 t.Fatalf("got an error: %s", err) 1270 } 1271 1272 if result.Vfoo != "foo" { 1273 t.Errorf("vfoo value should be 'foo': %#v", result.Vfoo) 1274 } 1275 1276 if result.Vother == nil { 1277 t.Fatal("vother should not be nil") 1278 } 1279 1280 if len(result.Vother) != 2 { 1281 t.Error("vother should have two items") 1282 } 1283 1284 if result.Vother["foo"] != "foo" { 1285 t.Errorf("'foo' key should be foo, got: %#v", result.Vother["foo"]) 1286 } 1287 1288 if result.Vother["bar"] != "bar" { 1289 t.Errorf("'bar' key should be bar, got: %#v", result.Vother["bar"]) 1290 } 1291 } 1292 1293 func TestMapMerge(t *testing.T) { 1294 t.Parallel() 1295 1296 input := map[string]interface{}{ 1297 "vfoo": "foo", 1298 "vother": map[interface{}]interface{}{ 1299 "foo": "foo", 1300 "bar": "bar", 1301 }, 1302 } 1303 1304 var result Map 1305 result.Vother = map[string]string{"hello": "world"} 1306 err := Decode(input, &result) 1307 if err != nil { 1308 t.Fatalf("got an error: %s", err) 1309 } 1310 1311 if result.Vfoo != "foo" { 1312 t.Errorf("vfoo value should be 'foo': %#v", result.Vfoo) 1313 } 1314 1315 expected := map[string]string{ 1316 "foo": "foo", 1317 "bar": "bar", 1318 "hello": "world", 1319 } 1320 if !reflect.DeepEqual(result.Vother, expected) { 1321 t.Errorf("bad: %#v", result.Vother) 1322 } 1323 } 1324 1325 func TestMapOfStruct(t *testing.T) { 1326 t.Parallel() 1327 1328 input := map[string]interface{}{ 1329 "value": map[string]interface{}{ 1330 "foo": map[string]string{"vstring": "one"}, 1331 "bar": map[string]string{"vstring": "two"}, 1332 }, 1333 } 1334 1335 var result MapOfStruct 1336 err := Decode(input, &result) 1337 if err != nil { 1338 t.Fatalf("got an err: %s", err) 1339 } 1340 1341 if result.Value == nil { 1342 t.Fatal("value should not be nil") 1343 } 1344 1345 if len(result.Value) != 2 { 1346 t.Error("value should have two items") 1347 } 1348 1349 if result.Value["foo"].Vstring != "one" { 1350 t.Errorf("foo value should be 'one', got: %s", result.Value["foo"].Vstring) 1351 } 1352 1353 if result.Value["bar"].Vstring != "two" { 1354 t.Errorf("bar value should be 'two', got: %s", result.Value["bar"].Vstring) 1355 } 1356 } 1357 1358 func TestNestedType(t *testing.T) { 1359 t.Parallel() 1360 1361 input := map[string]interface{}{ 1362 "vfoo": "foo", 1363 "vbar": map[string]interface{}{ 1364 "vstring": "foo", 1365 "vint": 42, 1366 "vbool": true, 1367 }, 1368 } 1369 1370 var result Nested 1371 err := Decode(input, &result) 1372 if err != nil { 1373 t.Fatalf("got an err: %s", err.Error()) 1374 } 1375 1376 if result.Vfoo != "foo" { 1377 t.Errorf("vfoo value should be 'foo': %#v", result.Vfoo) 1378 } 1379 1380 if result.Vbar.Vstring != "foo" { 1381 t.Errorf("vstring value should be 'foo': %#v", result.Vbar.Vstring) 1382 } 1383 1384 if result.Vbar.Vint != 42 { 1385 t.Errorf("vint value should be 42: %#v", result.Vbar.Vint) 1386 } 1387 1388 if result.Vbar.Vbool != true { 1389 t.Errorf("vbool value should be true: %#v", result.Vbar.Vbool) 1390 } 1391 1392 if result.Vbar.Vextra != "" { 1393 t.Errorf("vextra value should be empty: %#v", result.Vbar.Vextra) 1394 } 1395 } 1396 1397 func TestNestedTypePointer(t *testing.T) { 1398 t.Parallel() 1399 1400 input := map[string]interface{}{ 1401 "vfoo": "foo", 1402 "vbar": &map[string]interface{}{ 1403 "vstring": "foo", 1404 "vint": 42, 1405 "vbool": true, 1406 }, 1407 } 1408 1409 var result NestedPointer 1410 err := Decode(input, &result) 1411 if err != nil { 1412 t.Fatalf("got an err: %s", err.Error()) 1413 } 1414 1415 if result.Vfoo != "foo" { 1416 t.Errorf("vfoo value should be 'foo': %#v", result.Vfoo) 1417 } 1418 1419 if result.Vbar.Vstring != "foo" { 1420 t.Errorf("vstring value should be 'foo': %#v", result.Vbar.Vstring) 1421 } 1422 1423 if result.Vbar.Vint != 42 { 1424 t.Errorf("vint value should be 42: %#v", result.Vbar.Vint) 1425 } 1426 1427 if result.Vbar.Vbool != true { 1428 t.Errorf("vbool value should be true: %#v", result.Vbar.Vbool) 1429 } 1430 1431 if result.Vbar.Vextra != "" { 1432 t.Errorf("vextra value should be empty: %#v", result.Vbar.Vextra) 1433 } 1434 } 1435 1436 // Test for issue #46. 1437 func TestNestedTypeInterface(t *testing.T) { 1438 t.Parallel() 1439 1440 input := map[string]interface{}{ 1441 "vfoo": "foo", 1442 "vbar": &map[string]interface{}{ 1443 "vstring": "foo", 1444 "vint": 42, 1445 "vbool": true, 1446 1447 "vdata": map[string]interface{}{ 1448 "vstring": "bar", 1449 }, 1450 }, 1451 } 1452 1453 var result NestedPointer 1454 result.Vbar = new(Basic) 1455 result.Vbar.Vdata = new(Basic) 1456 err := Decode(input, &result) 1457 if err != nil { 1458 t.Fatalf("got an err: %s", err.Error()) 1459 } 1460 1461 if result.Vfoo != "foo" { 1462 t.Errorf("vfoo value should be 'foo': %#v", result.Vfoo) 1463 } 1464 1465 if result.Vbar.Vstring != "foo" { 1466 t.Errorf("vstring value should be 'foo': %#v", result.Vbar.Vstring) 1467 } 1468 1469 if result.Vbar.Vint != 42 { 1470 t.Errorf("vint value should be 42: %#v", result.Vbar.Vint) 1471 } 1472 1473 if result.Vbar.Vbool != true { 1474 t.Errorf("vbool value should be true: %#v", result.Vbar.Vbool) 1475 } 1476 1477 if result.Vbar.Vextra != "" { 1478 t.Errorf("vextra value should be empty: %#v", result.Vbar.Vextra) 1479 } 1480 1481 if result.Vbar.Vdata.(*Basic).Vstring != "bar" { 1482 t.Errorf("vstring value should be 'bar': %#v", result.Vbar.Vdata.(*Basic).Vstring) 1483 } 1484 } 1485 1486 func TestSlice(t *testing.T) { 1487 t.Parallel() 1488 1489 inputStringSlice := map[string]interface{}{ 1490 "vfoo": "foo", 1491 "vbar": []string{"foo", "bar", "baz"}, 1492 } 1493 1494 inputStringSlicePointer := map[string]interface{}{ 1495 "vfoo": "foo", 1496 "vbar": &[]string{"foo", "bar", "baz"}, 1497 } 1498 1499 outputStringSlice := &Slice{ 1500 "foo", 1501 []string{"foo", "bar", "baz"}, 1502 } 1503 1504 testSliceInput(t, inputStringSlice, outputStringSlice) 1505 testSliceInput(t, inputStringSlicePointer, outputStringSlice) 1506 } 1507 1508 func TestInvalidSlice(t *testing.T) { 1509 t.Parallel() 1510 1511 input := map[string]interface{}{ 1512 "vfoo": "foo", 1513 "vbar": 42, 1514 } 1515 1516 result := Slice{} 1517 err := Decode(input, &result) 1518 if err == nil { 1519 t.Errorf("expected failure") 1520 } 1521 } 1522 1523 func TestSliceOfStruct(t *testing.T) { 1524 t.Parallel() 1525 1526 input := map[string]interface{}{ 1527 "value": []map[string]interface{}{ 1528 {"vstring": "one"}, 1529 {"vstring": "two"}, 1530 }, 1531 } 1532 1533 var result SliceOfStruct 1534 err := Decode(input, &result) 1535 if err != nil { 1536 t.Fatalf("got unexpected error: %s", err) 1537 } 1538 1539 if len(result.Value) != 2 { 1540 t.Fatalf("expected two values, got %d", len(result.Value)) 1541 } 1542 1543 if result.Value[0].Vstring != "one" { 1544 t.Errorf("first value should be 'one', got: %s", result.Value[0].Vstring) 1545 } 1546 1547 if result.Value[1].Vstring != "two" { 1548 t.Errorf("second value should be 'two', got: %s", result.Value[1].Vstring) 1549 } 1550 } 1551 1552 func TestSliceCornerCases(t *testing.T) { 1553 t.Parallel() 1554 1555 // Input with a map with zero values 1556 input := map[string]interface{}{} 1557 var resultWeak []Basic 1558 1559 err := Decode(input, &resultWeak, WithWeakType(true)) 1560 if err != nil { 1561 t.Fatalf("got unexpected error: %s", err) 1562 } 1563 1564 if len(resultWeak) != 0 { 1565 t.Errorf("length should be 0") 1566 } 1567 // Input with more values 1568 input = map[string]interface{}{ 1569 "Vstring": "foo", 1570 } 1571 1572 resultWeak = nil 1573 err = Decode(input, &resultWeak, WithWeakType(true)) 1574 if err != nil { 1575 t.Fatalf("got unexpected error: %s", err) 1576 } 1577 1578 if resultWeak[0].Vstring != "foo" { 1579 t.Errorf("value does not match") 1580 } 1581 } 1582 1583 func TestSliceToMap(t *testing.T) { 1584 t.Parallel() 1585 1586 input := []map[string]interface{}{ 1587 { 1588 "foo": "bar", 1589 }, 1590 { 1591 "bar": "baz", 1592 }, 1593 } 1594 1595 var result map[string]interface{} 1596 err := Decode(input, &result, WithWeakType(true)) 1597 if err != nil { 1598 t.Fatalf("got an error: %s", err) 1599 } 1600 1601 expected := map[string]interface{}{ 1602 "foo": "bar", 1603 "bar": "baz", 1604 } 1605 if !reflect.DeepEqual(result, expected) { 1606 t.Errorf("bad: %#v", result) 1607 } 1608 } 1609 1610 func TestArray(t *testing.T) { 1611 t.Parallel() 1612 1613 inputStringArray := map[string]interface{}{ 1614 "vfoo": "foo", 1615 "vbar": [2]string{"foo", "bar"}, 1616 } 1617 1618 inputStringArrayPointer := map[string]interface{}{ 1619 "vfoo": "foo", 1620 "vbar": &[2]string{"foo", "bar"}, 1621 } 1622 1623 outputStringArray := &Array{ 1624 "foo", 1625 [2]string{"foo", "bar"}, 1626 } 1627 1628 testArrayInput(t, inputStringArray, outputStringArray) 1629 testArrayInput(t, inputStringArrayPointer, outputStringArray) 1630 } 1631 1632 func TestInvalidArray(t *testing.T) { 1633 t.Parallel() 1634 1635 input := map[string]interface{}{ 1636 "vfoo": "foo", 1637 "vbar": 42, 1638 } 1639 1640 result := Array{} 1641 err := Decode(input, &result) 1642 if err == nil { 1643 t.Errorf("expected failure") 1644 } 1645 } 1646 1647 func TestArrayOfStruct(t *testing.T) { 1648 t.Parallel() 1649 1650 input := map[string]interface{}{ 1651 "value": []map[string]interface{}{ 1652 {"vstring": "one"}, 1653 {"vstring": "two"}, 1654 }, 1655 } 1656 1657 var result ArrayOfStruct 1658 err := Decode(input, &result) 1659 if err != nil { 1660 t.Fatalf("got unexpected error: %s", err) 1661 } 1662 1663 if len(result.Value) != 2 { 1664 t.Fatalf("expected two values, got %d", len(result.Value)) 1665 } 1666 1667 if result.Value[0].Vstring != "one" { 1668 t.Errorf("first value should be 'one', got: %s", result.Value[0].Vstring) 1669 } 1670 1671 if result.Value[1].Vstring != "two" { 1672 t.Errorf("second value should be 'two', got: %s", result.Value[1].Vstring) 1673 } 1674 } 1675 1676 func TestArrayToMap(t *testing.T) { 1677 t.Parallel() 1678 1679 input := []map[string]interface{}{ 1680 { 1681 "foo": "bar", 1682 }, 1683 { 1684 "bar": "baz", 1685 }, 1686 } 1687 1688 var result map[string]interface{} 1689 err := Decode(input, &result, WithWeakType(true)) 1690 if err != nil { 1691 t.Fatalf("got an error: %s", err) 1692 } 1693 1694 expected := map[string]interface{}{ 1695 "foo": "bar", 1696 "bar": "baz", 1697 } 1698 if !reflect.DeepEqual(result, expected) { 1699 t.Errorf("bad: %#v", result) 1700 } 1701 } 1702 1703 func TestDecodeTable(t *testing.T) { 1704 t.Parallel() 1705 1706 // We need to make new types so that we don't get the short-circuit 1707 // copy functionality. We want to test the deep copying functionality. 1708 type BasicCopy Basic 1709 type NestedPointerCopy NestedPointer 1710 type MapCopy Map 1711 1712 tests := []struct { 1713 name string 1714 in interface{} 1715 target interface{} 1716 out interface{} 1717 wantErr bool 1718 }{ 1719 { 1720 "basic struct input", 1721 &Basic{ 1722 Vstring: "vstring", 1723 Vint: 2, 1724 Vint8: 2, 1725 Vint16: 2, 1726 Vint32: 2, 1727 Vint64: 2, 1728 Vuint: 3, 1729 Vbool: true, 1730 Vfloat: 4.56, 1731 Vextra: "vextra", 1732 vsilent: true, 1733 Vdata: []byte("data"), 1734 }, 1735 &map[string]interface{}{}, 1736 &map[string]interface{}{ 1737 "Vstring": "vstring", 1738 "Vint": 2, 1739 "Vint8": int8(2), 1740 "Vint16": int16(2), 1741 "Vint32": int32(2), 1742 "Vint64": int64(2), 1743 "Vuint": uint(3), 1744 "Vbool": true, 1745 "Vfloat": 4.56, 1746 "Vextra": "vextra", 1747 "Vdata": []byte("data"), 1748 "VjsonInt": 0, 1749 "VjsonUint": uint(0), 1750 "VjsonFloat": 0.0, 1751 "VjsonNumber": json.Number(""), 1752 }, 1753 false, 1754 }, 1755 { 1756 "embedded struct input", 1757 &Embedded{ 1758 Vunique: "vunique", 1759 Basic: Basic{ 1760 Vstring: "vstring", 1761 Vint: 2, 1762 Vint8: 2, 1763 Vint16: 2, 1764 Vint32: 2, 1765 Vint64: 2, 1766 Vuint: 3, 1767 Vbool: true, 1768 Vfloat: 4.56, 1769 Vextra: "vextra", 1770 vsilent: true, 1771 Vdata: []byte("data"), 1772 }, 1773 }, 1774 &map[string]interface{}{}, 1775 &map[string]interface{}{ 1776 "Vunique": "vunique", 1777 "Basic": map[string]interface{}{ 1778 "Vstring": "vstring", 1779 "Vint": 2, 1780 "Vint8": int8(2), 1781 "Vint16": int16(2), 1782 "Vint32": int32(2), 1783 "Vint64": int64(2), 1784 "Vuint": uint(3), 1785 "Vbool": true, 1786 "Vfloat": 4.56, 1787 "Vextra": "vextra", 1788 "Vdata": []byte("data"), 1789 "VjsonInt": 0, 1790 "VjsonUint": uint(0), 1791 "VjsonFloat": 0.0, 1792 "VjsonNumber": json.Number(""), 1793 }, 1794 }, 1795 false, 1796 }, 1797 { 1798 "struct => struct", 1799 &Basic{ 1800 Vstring: "vstring", 1801 Vint: 2, 1802 Vuint: 3, 1803 Vbool: true, 1804 Vfloat: 4.56, 1805 Vextra: "vextra", 1806 Vdata: []byte("data"), 1807 vsilent: true, 1808 }, 1809 &BasicCopy{}, 1810 &BasicCopy{ 1811 Vstring: "vstring", 1812 Vint: 2, 1813 Vuint: 3, 1814 Vbool: true, 1815 Vfloat: 4.56, 1816 Vextra: "vextra", 1817 Vdata: []byte("data"), 1818 }, 1819 false, 1820 }, 1821 { 1822 "struct => struct with pointers", 1823 &NestedPointer{ 1824 Vfoo: "hello", 1825 Vbar: nil, 1826 }, 1827 &NestedPointerCopy{}, 1828 &NestedPointerCopy{ 1829 Vfoo: "hello", 1830 }, 1831 false, 1832 }, 1833 { 1834 "basic pointer to non-pointer", 1835 &BasicPointer{ 1836 Vstring: stringPtr("vstring"), 1837 Vint: intPtr(2), 1838 Vuint: uintPtr(3), 1839 Vbool: boolPtr(true), 1840 Vfloat: floatPtr(4.56), 1841 Vdata: interfacePtr([]byte("data")), 1842 }, 1843 &Basic{}, 1844 &Basic{ 1845 Vstring: "vstring", 1846 Vint: 2, 1847 Vuint: 3, 1848 Vbool: true, 1849 Vfloat: 4.56, 1850 Vdata: []byte("data"), 1851 }, 1852 false, 1853 }, 1854 { 1855 "slice non-pointer to pointer", 1856 &Slice{}, 1857 &SlicePointer{}, 1858 &SlicePointer{}, 1859 false, 1860 }, 1861 { 1862 "slice non-pointer to pointer, zero field", 1863 &Slice{}, 1864 &SlicePointer{ 1865 Vbar: &[]string{"yo"}, 1866 }, 1867 &SlicePointer{}, 1868 false, 1869 }, 1870 { 1871 "slice to slice alias", 1872 &Slice{}, 1873 &SliceOfAlias{}, 1874 &SliceOfAlias{}, 1875 false, 1876 }, 1877 { 1878 "nil map to map", 1879 &Map{}, 1880 &MapCopy{}, 1881 &MapCopy{}, 1882 false, 1883 }, 1884 { 1885 "nil map to non-empty map", 1886 &Map{}, 1887 &MapCopy{Vother: map[string]string{"foo": "bar"}}, 1888 &MapCopy{}, 1889 false, 1890 }, 1891 1892 { 1893 "slice input - should error", 1894 []string{"foo", "bar"}, 1895 &map[string]interface{}{}, 1896 &map[string]interface{}{}, 1897 true, 1898 }, 1899 { 1900 "struct with slice property", 1901 &Slice{ 1902 Vfoo: "vfoo", 1903 Vbar: []string{"foo", "bar"}, 1904 }, 1905 &map[string]interface{}{}, 1906 &map[string]interface{}{ 1907 "Vfoo": "vfoo", 1908 "Vbar": []string{"foo", "bar"}, 1909 }, 1910 false, 1911 }, 1912 { 1913 "struct with empty slice", 1914 &map[string]interface{}{ 1915 "Vbar": []string{}, 1916 }, 1917 &Slice{}, 1918 &Slice{ 1919 Vbar: []string{}, 1920 }, 1921 false, 1922 }, 1923 { 1924 "struct with slice of struct property", 1925 &SliceOfStruct{ 1926 Value: []Basic{ 1927 { 1928 Vstring: "vstring", 1929 Vint: 2, 1930 Vuint: 3, 1931 Vbool: true, 1932 Vfloat: 4.56, 1933 Vextra: "vextra", 1934 vsilent: true, 1935 Vdata: []byte("data"), 1936 }, 1937 }, 1938 }, 1939 &map[string]interface{}{}, 1940 &map[string]interface{}{ 1941 "Value": []Basic{ 1942 { 1943 Vstring: "vstring", 1944 Vint: 2, 1945 Vuint: 3, 1946 Vbool: true, 1947 Vfloat: 4.56, 1948 Vextra: "vextra", 1949 vsilent: true, 1950 Vdata: []byte("data"), 1951 }, 1952 }, 1953 }, 1954 false, 1955 }, 1956 { 1957 "struct with map property", 1958 &Map{ 1959 Vfoo: "vfoo", 1960 Vother: map[string]string{"vother": "vother"}, 1961 }, 1962 &map[string]interface{}{}, 1963 &map[string]interface{}{ 1964 "Vfoo": "vfoo", 1965 "Vother": map[string]string{ 1966 "vother": "vother", 1967 }, 1968 }, 1969 false, 1970 }, 1971 { 1972 "tagged struct", 1973 &Tagged{ 1974 Extra: "extra", 1975 Value: "value", 1976 }, 1977 &map[string]string{}, 1978 &map[string]string{ 1979 "bar": "extra", 1980 "foo": "value", 1981 }, 1982 false, 1983 }, 1984 { 1985 "omit tag struct", 1986 &struct { 1987 Value string `mapstruct:"value"` 1988 Omit string `mapstruct:"-"` 1989 }{ 1990 Value: "value", 1991 Omit: "omit", 1992 }, 1993 &map[string]string{}, 1994 &map[string]string{ 1995 "value": "value", 1996 }, 1997 false, 1998 }, 1999 { 2000 "decode to wrong map type", 2001 &struct { 2002 Value string 2003 }{ 2004 Value: "string", 2005 }, 2006 &map[string]int{}, 2007 &map[string]int{}, 2008 true, 2009 }, 2010 { 2011 "remainder", 2012 map[string]interface{}{ 2013 "A": "hello", 2014 "B": "goodbye", 2015 "C": "yo", 2016 }, 2017 &Remainder{}, 2018 &Remainder{ 2019 A: "hello", 2020 Extra: map[string]interface{}{ 2021 "B": "goodbye", 2022 "C": "yo", 2023 }, 2024 }, 2025 false, 2026 }, 2027 { 2028 "remainder with no extra", 2029 map[string]interface{}{ 2030 "A": "hello", 2031 }, 2032 &Remainder{}, 2033 &Remainder{ 2034 A: "hello", 2035 Extra: nil, 2036 }, 2037 false, 2038 }, 2039 { 2040 "struct with omitempty tag return non-empty values", 2041 &struct { 2042 VisibleField interface{} `mapstruct:"visible"` 2043 OmitField interface{} `mapstruct:"omittable,omitempty"` 2044 }{ 2045 VisibleField: nil, 2046 OmitField: "string", 2047 }, 2048 &map[string]interface{}{}, 2049 &map[string]interface{}{"visible": nil, "omittable": "string"}, 2050 false, 2051 }, 2052 { 2053 "struct with omitempty tag ignore empty values", 2054 &struct { 2055 VisibleField interface{} `mapstruct:"visible"` 2056 OmitField interface{} `mapstruct:"omittable,omitempty"` 2057 }{ 2058 VisibleField: nil, 2059 OmitField: nil, 2060 }, 2061 &map[string]interface{}{}, 2062 &map[string]interface{}{"visible": nil}, 2063 false, 2064 }, 2065 } 2066 2067 for _, tt := range tests { 2068 t.Run(tt.name, func(t *testing.T) { 2069 if err := Decode(tt.in, tt.target); (err != nil) != tt.wantErr { 2070 t.Fatalf("%q: TestMapOutputForStructuredInputs() unexpected error: %s", tt.name, err) 2071 } 2072 2073 if !reflect.DeepEqual(tt.out, tt.target) { 2074 t.Fatalf("%q: TestMapOutputForStructuredInputs() expected: %#v, got: %#v", tt.name, tt.out, tt.target) 2075 } 2076 }) 2077 } 2078 } 2079 2080 func TestInvalidType(t *testing.T) { 2081 t.Parallel() 2082 2083 input := map[string]interface{}{ 2084 "vstring": 42, 2085 } 2086 2087 var result Basic 2088 err := Decode(input, &result) 2089 if err == nil { 2090 t.Fatal("error should exist") 2091 } 2092 2093 derr, ok := err.(*Error) 2094 if !ok { 2095 t.Fatalf("error should be kind of Error, instead: %#v", err) 2096 } 2097 2098 if derr.Errors[0] != 2099 "'Vstring' expected type 'string', got unconvertible type 'int', value: '42'" { 2100 t.Errorf("got unexpected error: %s", err) 2101 } 2102 2103 inputNegIntUint := map[string]interface{}{ 2104 "vuint": -42, 2105 } 2106 2107 err = Decode(inputNegIntUint, &result) 2108 if err == nil { 2109 t.Fatal("error should exist") 2110 } 2111 2112 derr, ok = err.(*Error) 2113 if !ok { 2114 t.Fatalf("error should be kind of Error, instead: %#v", err) 2115 } 2116 2117 if derr.Errors[0] != "cannot parse 'Vuint', -42 overflows uint" { 2118 t.Errorf("got unexpected error: %s", err) 2119 } 2120 2121 inputNegFloatUint := map[string]interface{}{ 2122 "vuint": -42.0, 2123 } 2124 2125 err = Decode(inputNegFloatUint, &result) 2126 if err == nil { 2127 t.Fatal("error should exist") 2128 } 2129 2130 derr, ok = err.(*Error) 2131 if !ok { 2132 t.Fatalf("error should be kind of Error, instead: %#v", err) 2133 } 2134 2135 if derr.Errors[0] != "cannot parse 'Vuint', -42.000000 overflows uint" { 2136 t.Errorf("got unexpected error: %s", err) 2137 } 2138 } 2139 2140 func TestDecodeMetadata(t *testing.T) { 2141 t.Parallel() 2142 2143 input := map[string]interface{}{ 2144 "vfoo": "foo", 2145 "vbar": map[string]interface{}{ 2146 "vstring": "foo", 2147 "Vuint": 42, 2148 "vsilent": "false", 2149 "foo": "bar", 2150 }, 2151 "bar": "nil", 2152 } 2153 2154 var md Metadata 2155 var result Nested 2156 2157 err := Decode(input, &result, WithMetadata(&md)) 2158 if err != nil { 2159 t.Fatalf("err: %s", err.Error()) 2160 } 2161 2162 expectedKeys := []string{"Vbar", "Vbar.Vstring", "Vbar.Vuint", "Vfoo"} 2163 sort.Strings(md.Keys) 2164 if !reflect.DeepEqual(md.Keys, expectedKeys) { 2165 t.Fatalf("bad keys: %#v", md.Keys) 2166 } 2167 2168 expectedUnused := []string{"Vbar.foo", "Vbar.vsilent", "bar"} 2169 sort.Strings(md.Unused) 2170 if !reflect.DeepEqual(md.Unused, expectedUnused) { 2171 t.Fatalf("bad unused: %#v", md.Unused) 2172 } 2173 } 2174 2175 func TestMetadata(t *testing.T) { 2176 t.Parallel() 2177 2178 type testResult struct { 2179 Vfoo string 2180 Vbar BasicPointer 2181 } 2182 2183 input := map[string]interface{}{ 2184 "vfoo": "foo", 2185 "vbar": map[string]interface{}{ 2186 "vstring": "foo", 2187 "Vuint": 42, 2188 "vsilent": "false", 2189 "foo": "bar", 2190 }, 2191 "bar": "nil", 2192 } 2193 2194 var md Metadata 2195 var result testResult 2196 config := &Config{ 2197 Metadata: &md, 2198 Result: &result, 2199 } 2200 2201 decoder, err := NewDecoder(config) 2202 if err != nil { 2203 t.Fatalf("err: %s", err) 2204 } 2205 2206 err = decoder.Decode(input) 2207 if err != nil { 2208 t.Fatalf("err: %s", err.Error()) 2209 } 2210 2211 expectedKeys := []string{"Vbar", "Vbar.Vstring", "Vbar.Vuint", "Vfoo"} 2212 sort.Strings(md.Keys) 2213 if !reflect.DeepEqual(md.Keys, expectedKeys) { 2214 t.Fatalf("bad keys: %#v", md.Keys) 2215 } 2216 2217 expectedUnused := []string{"Vbar.foo", "Vbar.vsilent", "bar"} 2218 sort.Strings(md.Unused) 2219 if !reflect.DeepEqual(md.Unused, expectedUnused) { 2220 t.Fatalf("bad unused: %#v", md.Unused) 2221 } 2222 } 2223 2224 func TestMetadata_Embedded(t *testing.T) { 2225 t.Parallel() 2226 2227 input := map[string]interface{}{ 2228 "vstring": "foo", 2229 "vunique": "bar", 2230 } 2231 2232 var md Metadata 2233 var result EmbeddedSquash 2234 config := &Config{ 2235 Metadata: &md, 2236 Result: &result, 2237 } 2238 2239 decoder, err := NewDecoder(config) 2240 if err != nil { 2241 t.Fatalf("err: %s", err) 2242 } 2243 2244 err = decoder.Decode(input) 2245 if err != nil { 2246 t.Fatalf("err: %s", err.Error()) 2247 } 2248 2249 expectedKeys := []string{"Vstring", "Vunique"} 2250 2251 sort.Strings(md.Keys) 2252 if !reflect.DeepEqual(md.Keys, expectedKeys) { 2253 t.Fatalf("bad keys: %#v", md.Keys) 2254 } 2255 2256 expectedUnused := []string{} 2257 if !reflect.DeepEqual(md.Unused, expectedUnused) { 2258 t.Fatalf("bad unused: %#v", md.Unused) 2259 } 2260 } 2261 2262 func TestNonPtrValue(t *testing.T) { 2263 t.Parallel() 2264 2265 err := Decode(map[string]interface{}{}, Basic{}) 2266 if err == nil { 2267 t.Fatal("error should exist") 2268 } 2269 2270 if err.Error() != "result must be a pointer" { 2271 t.Errorf("got unexpected error: %s", err) 2272 } 2273 } 2274 2275 func TestTagged(t *testing.T) { 2276 t.Parallel() 2277 2278 input := map[string]interface{}{ 2279 "foo": "bar", 2280 "bar": "value", 2281 } 2282 2283 var result Tagged 2284 err := Decode(input, &result) 2285 if err != nil { 2286 t.Fatalf("unexpected error: %s", err) 2287 } 2288 2289 if result.Value != "bar" { 2290 t.Errorf("value should be 'bar', got: %#v", result.Value) 2291 } 2292 2293 if result.Extra != "value" { 2294 t.Errorf("extra should be 'value', got: %#v", result.Extra) 2295 } 2296 } 2297 2298 func TestWeakDecode(t *testing.T) { 2299 t.Parallel() 2300 2301 input := map[string]interface{}{ 2302 "foo": "4", 2303 "bar": "value", 2304 } 2305 2306 var result struct { 2307 Foo int 2308 Bar string 2309 } 2310 2311 if err := Decode(input, &result, WithWeakType(true)); err != nil { 2312 t.Fatalf("err: %s", err) 2313 } 2314 if result.Foo != 4 { 2315 t.Fatalf("bad: %#v", result) 2316 } 2317 if result.Bar != "value" { 2318 t.Fatalf("bad: %#v", result) 2319 } 2320 } 2321 2322 func TestWeakDecodeMetadata(t *testing.T) { 2323 t.Parallel() 2324 2325 input := map[string]interface{}{ 2326 "foo": "4", 2327 "bar": "value", 2328 "unused": "value", 2329 "unexported": "value", 2330 } 2331 2332 var md Metadata 2333 var result struct { 2334 Foo int 2335 Bar string 2336 unexported string 2337 } 2338 2339 if err := Decode(input, &result, WithWeakType(true), WithMetadata(&md)); err != nil { 2340 t.Fatalf("err: %s", err) 2341 } 2342 if result.Foo != 4 { 2343 t.Fatalf("bad: %#v", result) 2344 } 2345 if result.Bar != "value" { 2346 t.Fatalf("bad: %#v", result) 2347 } 2348 2349 expectedKeys := []string{"Bar", "Foo"} 2350 sort.Strings(md.Keys) 2351 if !reflect.DeepEqual(md.Keys, expectedKeys) { 2352 t.Fatalf("bad keys: %#v", md.Keys) 2353 } 2354 2355 expectedUnused := []string{"unexported", "unused"} 2356 sort.Strings(md.Unused) 2357 if !reflect.DeepEqual(md.Unused, expectedUnused) { 2358 t.Fatalf("bad unused: %#v", md.Unused) 2359 } 2360 } 2361 2362 func TestDecode_StructTaggedWithOmitempty_OmitEmptyValues(t *testing.T) { 2363 t.Parallel() 2364 2365 input := &StructWithOmitEmpty{} 2366 2367 var emptySlice []interface{} 2368 var emptyMap map[string]interface{} 2369 var emptyNested *Nested 2370 expected := &map[string]interface{}{ 2371 "visible-string": "", 2372 "visible-int": 0, 2373 "visible-float": 0.0, 2374 "visible-slice": emptySlice, 2375 "visible-map": emptyMap, 2376 "visible-nested": emptyNested, 2377 } 2378 2379 actual := &map[string]interface{}{} 2380 _ = Decode(input, actual) 2381 2382 if !reflect.DeepEqual(actual, expected) { 2383 t.Fatalf("Decode() expected: %#v, got: %#v", expected, actual) 2384 } 2385 } 2386 2387 func TestDecode_StructTaggedWithOmitempty_KeepNonEmptyValues(t *testing.T) { 2388 t.Parallel() 2389 2390 input := &StructWithOmitEmpty{ 2391 VisibleStringField: "", 2392 OmitStringField: "string", 2393 VisibleIntField: 0, 2394 OmitIntField: 1, 2395 VisibleFloatField: 0.0, 2396 OmitFloatField: 1.0, 2397 VisibleSliceField: nil, 2398 OmitSliceField: []interface{}{1}, 2399 VisibleMapField: nil, 2400 OmitMapField: map[string]interface{}{"k": "v"}, 2401 NestedField: nil, 2402 OmitNestedField: &Nested{}, 2403 } 2404 2405 var emptySlice []interface{} 2406 var emptyMap map[string]interface{} 2407 var emptyNested *Nested 2408 expected := &map[string]interface{}{ 2409 "visible-string": "", 2410 "omittable-string": "string", 2411 "visible-int": 0, 2412 "omittable-int": 1, 2413 "visible-float": 0.0, 2414 "omittable-float": 1.0, 2415 "visible-slice": emptySlice, 2416 "omittable-slice": []interface{}{1}, 2417 "visible-map": emptyMap, 2418 "omittable-map": map[string]interface{}{"k": "v"}, 2419 "visible-nested": emptyNested, 2420 "omittable-nested": &Nested{}, 2421 } 2422 2423 actual := &map[string]interface{}{} 2424 _ = Decode(input, actual) 2425 2426 if !reflect.DeepEqual(actual, expected) { 2427 t.Fatalf("Decode() expected: %#v, got: %#v", expected, actual) 2428 } 2429 } 2430 2431 func TestDecode_mapToStruct(t *testing.T) { 2432 type Target struct { 2433 String string 2434 StringPtr *string 2435 } 2436 2437 expected := Target{ 2438 String: "hello", 2439 } 2440 2441 var target Target 2442 err := Decode(map[string]interface{}{ 2443 "string": "hello", 2444 "StringPtr": "goodbye", 2445 }, &target) 2446 if err != nil { 2447 t.Fatalf("got error: %s", err) 2448 } 2449 2450 // Pointers fail reflect test so do those manually 2451 if target.StringPtr == nil || *target.StringPtr != "goodbye" { 2452 t.Fatalf("bad: %#v", target) 2453 } 2454 target.StringPtr = nil 2455 2456 if !reflect.DeepEqual(target, expected) { 2457 t.Fatalf("bad: %#v", target) 2458 } 2459 } 2460 2461 func testSliceInput(t *testing.T, input map[string]interface{}, expected *Slice) { 2462 var result Slice 2463 err := Decode(input, &result) 2464 if err != nil { 2465 t.Fatalf("got error: %s", err) 2466 } 2467 2468 if result.Vfoo != expected.Vfoo { 2469 t.Errorf("Vfoo expected '%s', got '%s'", expected.Vfoo, result.Vfoo) 2470 } 2471 2472 if result.Vbar == nil { 2473 t.Fatalf("Vbar a slice, got '%#v'", result.Vbar) 2474 } 2475 2476 if len(result.Vbar) != len(expected.Vbar) { 2477 t.Errorf("Vbar length should be %d, got %d", len(expected.Vbar), len(result.Vbar)) 2478 } 2479 2480 for i, v := range result.Vbar { 2481 if v != expected.Vbar[i] { 2482 t.Errorf( 2483 "Vbar[%d] should be '%#v', got '%#v'", 2484 i, expected.Vbar[i], v) 2485 } 2486 } 2487 } 2488 2489 func testArrayInput(t *testing.T, input map[string]interface{}, expected *Array) { 2490 var result Array 2491 err := Decode(input, &result) 2492 if err != nil { 2493 t.Fatalf("got error: %s", err) 2494 } 2495 2496 if result.Vfoo != expected.Vfoo { 2497 t.Errorf("Vfoo expected '%s', got '%s'", expected.Vfoo, result.Vfoo) 2498 } 2499 2500 if result.Vbar == [2]string{} { 2501 t.Fatalf("Vbar a slice, got '%#v'", result.Vbar) 2502 } 2503 2504 if len(result.Vbar) != len(expected.Vbar) { 2505 t.Errorf("Vbar length should be %d, got %d", len(expected.Vbar), len(result.Vbar)) 2506 } 2507 2508 for i, v := range result.Vbar { 2509 if v != expected.Vbar[i] { 2510 t.Errorf( 2511 "Vbar[%d] should be '%#v', got '%#v'", 2512 i, expected.Vbar[i], v) 2513 } 2514 } 2515 } 2516 2517 func stringPtr(v string) *string { return &v } 2518 func intPtr(v int) *int { return &v } 2519 func uintPtr(v uint) *uint { return &v } 2520 func boolPtr(v bool) *bool { return &v } 2521 func floatPtr(v float64) *float64 { return &v } 2522 func interfacePtr(v interface{}) *interface{} { return &v }