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