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 Vuint uint 16 Vbool bool 17 Vfloat float64 18 Vextra string 19 vsilent bool 20 Vdata interface{} 21 VjsonInt int 22 VjsonFloat float64 23 VjsonNumber json.Number 24} 25 26type BasicSquash struct { 27 Test Basic `mapstructure:",squash"` 28} 29 30type Embedded struct { 31 Basic 32 Vunique string 33} 34 35type EmbeddedPointer struct { 36 *Basic 37 Vunique string 38} 39 40type EmbeddedSquash struct { 41 Basic `mapstructure:",squash"` 42 Vunique string 43} 44 45type SliceAlias []string 46 47type EmbeddedSlice struct { 48 SliceAlias `mapstructure:"slice_alias"` 49 Vunique string 50} 51 52type ArrayAlias [2]string 53 54type EmbeddedArray struct { 55 ArrayAlias `mapstructure:"array_alias"` 56 Vunique string 57} 58 59type SquashOnNonStructType struct { 60 InvalidSquashType int `mapstructure:",squash"` 61} 62 63type Map struct { 64 Vfoo string 65 Vother map[string]string 66} 67 68type MapOfStruct struct { 69 Value map[string]Basic 70} 71 72type Nested struct { 73 Vfoo string 74 Vbar Basic 75} 76 77type NestedPointer struct { 78 Vfoo string 79 Vbar *Basic 80} 81 82type NilInterface struct { 83 W io.Writer 84} 85 86type Slice struct { 87 Vfoo string 88 Vbar []string 89} 90 91type SliceOfStruct struct { 92 Value []Basic 93} 94 95type Array struct { 96 Vfoo string 97 Vbar [2]string 98} 99 100type ArrayOfStruct struct { 101 Value [2]Basic 102} 103 104type Func struct { 105 Foo func() string 106} 107 108type Tagged struct { 109 Extra string `mapstructure:"bar,what,what"` 110 Value string `mapstructure:"foo"` 111} 112 113type TypeConversionResult struct { 114 IntToFloat float32 115 IntToUint uint 116 IntToBool bool 117 IntToString string 118 UintToInt int 119 UintToFloat float32 120 UintToBool bool 121 UintToString string 122 BoolToInt int 123 BoolToUint uint 124 BoolToFloat float32 125 BoolToString string 126 FloatToInt int 127 FloatToUint uint 128 FloatToBool bool 129 FloatToString string 130 SliceUint8ToString string 131 StringToSliceUint8 []byte 132 ArrayUint8ToString string 133 StringToInt int 134 StringToUint uint 135 StringToBool bool 136 StringToFloat float32 137 StringToStrSlice []string 138 StringToIntSlice []int 139 StringToStrArray [1]string 140 StringToIntArray [1]int 141 SliceToMap map[string]interface{} 142 MapToSlice []interface{} 143 ArrayToMap map[string]interface{} 144 MapToArray [1]interface{} 145} 146 147func TestBasicTypes(t *testing.T) { 148 t.Parallel() 149 150 input := map[string]interface{}{ 151 "vstring": "foo", 152 "vint": 42, 153 "Vuint": 42, 154 "vbool": true, 155 "Vfloat": 42.42, 156 "vsilent": true, 157 "vdata": 42, 158 "vjsonInt": json.Number("1234"), 159 "vjsonFloat": json.Number("1234.5"), 160 "vjsonNumber": json.Number("1234.5"), 161 } 162 163 var result Basic 164 err := Decode(input, &result) 165 if err != nil { 166 t.Errorf("got an err: %s", err.Error()) 167 t.FailNow() 168 } 169 170 if result.Vstring != "foo" { 171 t.Errorf("vstring value should be 'foo': %#v", result.Vstring) 172 } 173 174 if result.Vint != 42 { 175 t.Errorf("vint value should be 42: %#v", result.Vint) 176 } 177 178 if result.Vuint != 42 { 179 t.Errorf("vuint value should be 42: %#v", result.Vuint) 180 } 181 182 if result.Vbool != true { 183 t.Errorf("vbool value should be true: %#v", result.Vbool) 184 } 185 186 if result.Vfloat != 42.42 { 187 t.Errorf("vfloat value should be 42.42: %#v", result.Vfloat) 188 } 189 190 if result.Vextra != "" { 191 t.Errorf("vextra value should be empty: %#v", result.Vextra) 192 } 193 194 if result.vsilent != false { 195 t.Error("vsilent should not be set, it is unexported") 196 } 197 198 if result.Vdata != 42 { 199 t.Error("vdata should be valid") 200 } 201 202 if result.VjsonInt != 1234 { 203 t.Errorf("vjsonint value should be 1234: %#v", result.VjsonInt) 204 } 205 206 if result.VjsonFloat != 1234.5 { 207 t.Errorf("vjsonfloat value should be 1234.5: %#v", result.VjsonFloat) 208 } 209 210 if !reflect.DeepEqual(result.VjsonNumber, json.Number("1234.5")) { 211 t.Errorf("vjsonnumber value should be '1234.5': %T, %#v", result.VjsonNumber, result.VjsonNumber) 212 } 213} 214 215func TestBasic_IntWithFloat(t *testing.T) { 216 t.Parallel() 217 218 input := map[string]interface{}{ 219 "vint": float64(42), 220 } 221 222 var result Basic 223 err := Decode(input, &result) 224 if err != nil { 225 t.Fatalf("got an err: %s", err) 226 } 227} 228 229func TestBasic_Merge(t *testing.T) { 230 t.Parallel() 231 232 input := map[string]interface{}{ 233 "vint": 42, 234 } 235 236 var result Basic 237 result.Vuint = 100 238 err := Decode(input, &result) 239 if err != nil { 240 t.Fatalf("got an err: %s", err) 241 } 242 243 expected := Basic{ 244 Vint: 42, 245 Vuint: 100, 246 } 247 if !reflect.DeepEqual(result, expected) { 248 t.Fatalf("bad: %#v", result) 249 } 250} 251 252// Test for issue #46. 253func TestBasic_Struct(t *testing.T) { 254 t.Parallel() 255 256 input := map[string]interface{}{ 257 "vdata": map[string]interface{}{ 258 "vstring": "foo", 259 }, 260 } 261 262 var result, inner Basic 263 result.Vdata = &inner 264 err := Decode(input, &result) 265 if err != nil { 266 t.Fatalf("got an err: %s", err) 267 } 268 expected := Basic{ 269 Vdata: &Basic{ 270 Vstring: "foo", 271 }, 272 } 273 if !reflect.DeepEqual(result, expected) { 274 t.Fatalf("bad: %#v", result) 275 } 276} 277 278func TestDecode_BasicSquash(t *testing.T) { 279 t.Parallel() 280 281 input := map[string]interface{}{ 282 "vstring": "foo", 283 } 284 285 var result BasicSquash 286 err := Decode(input, &result) 287 if err != nil { 288 t.Fatalf("got an err: %s", err.Error()) 289 } 290 291 if result.Test.Vstring != "foo" { 292 t.Errorf("vstring value should be 'foo': %#v", result.Test.Vstring) 293 } 294} 295 296func TestDecode_Embedded(t *testing.T) { 297 t.Parallel() 298 299 input := map[string]interface{}{ 300 "vstring": "foo", 301 "Basic": map[string]interface{}{ 302 "vstring": "innerfoo", 303 }, 304 "vunique": "bar", 305 } 306 307 var result Embedded 308 err := Decode(input, &result) 309 if err != nil { 310 t.Fatalf("got an err: %s", err.Error()) 311 } 312 313 if result.Vstring != "innerfoo" { 314 t.Errorf("vstring value should be 'innerfoo': %#v", result.Vstring) 315 } 316 317 if result.Vunique != "bar" { 318 t.Errorf("vunique value should be 'bar': %#v", result.Vunique) 319 } 320} 321 322func TestDecode_EmbeddedPointer(t *testing.T) { 323 t.Parallel() 324 325 input := map[string]interface{}{ 326 "vstring": "foo", 327 "Basic": map[string]interface{}{ 328 "vstring": "innerfoo", 329 }, 330 "vunique": "bar", 331 } 332 333 var result EmbeddedPointer 334 err := Decode(input, &result) 335 if err != nil { 336 t.Fatalf("err: %s", err) 337 } 338 339 expected := EmbeddedPointer{ 340 Basic: &Basic{ 341 Vstring: "innerfoo", 342 }, 343 Vunique: "bar", 344 } 345 if !reflect.DeepEqual(result, expected) { 346 t.Fatalf("bad: %#v", result) 347 } 348} 349 350func TestDecode_EmbeddedSlice(t *testing.T) { 351 t.Parallel() 352 353 input := map[string]interface{}{ 354 "slice_alias": []string{"foo", "bar"}, 355 "vunique": "bar", 356 } 357 358 var result EmbeddedSlice 359 err := Decode(input, &result) 360 if err != nil { 361 t.Fatalf("got an err: %s", err.Error()) 362 } 363 364 if !reflect.DeepEqual(result.SliceAlias, SliceAlias([]string{"foo", "bar"})) { 365 t.Errorf("slice value: %#v", result.SliceAlias) 366 } 367 368 if result.Vunique != "bar" { 369 t.Errorf("vunique value should be 'bar': %#v", result.Vunique) 370 } 371} 372 373func TestDecode_EmbeddedArray(t *testing.T) { 374 t.Parallel() 375 376 input := map[string]interface{}{ 377 "array_alias": [2]string{"foo", "bar"}, 378 "vunique": "bar", 379 } 380 381 var result EmbeddedArray 382 err := Decode(input, &result) 383 if err != nil { 384 t.Fatalf("got an err: %s", err.Error()) 385 } 386 387 if !reflect.DeepEqual(result.ArrayAlias, ArrayAlias([2]string{"foo", "bar"})) { 388 t.Errorf("array value: %#v", result.ArrayAlias) 389 } 390 391 if result.Vunique != "bar" { 392 t.Errorf("vunique value should be 'bar': %#v", result.Vunique) 393 } 394} 395 396func TestDecode_EmbeddedSquash(t *testing.T) { 397 t.Parallel() 398 399 input := map[string]interface{}{ 400 "vstring": "foo", 401 "vunique": "bar", 402 } 403 404 var result EmbeddedSquash 405 err := Decode(input, &result) 406 if err != nil { 407 t.Fatalf("got an err: %s", err.Error()) 408 } 409 410 if result.Vstring != "foo" { 411 t.Errorf("vstring value should be 'foo': %#v", result.Vstring) 412 } 413 414 if result.Vunique != "bar" { 415 t.Errorf("vunique value should be 'bar': %#v", result.Vunique) 416 } 417} 418 419func TestDecode_SquashOnNonStructType(t *testing.T) { 420 t.Parallel() 421 422 input := map[string]interface{}{ 423 "InvalidSquashType": 42, 424 } 425 426 var result SquashOnNonStructType 427 err := Decode(input, &result) 428 if err == nil { 429 t.Fatal("unexpected success decoding invalid squash field type") 430 } else if !strings.Contains(err.Error(), "unsupported type for squash") { 431 t.Fatalf("unexpected error message for invalid squash field type: %s", err) 432 } 433} 434 435func TestDecode_DecodeHook(t *testing.T) { 436 t.Parallel() 437 438 input := map[string]interface{}{ 439 "vint": "WHAT", 440 } 441 442 decodeHook := func(from reflect.Kind, to reflect.Kind, v interface{}) (interface{}, error) { 443 if from == reflect.String && to != reflect.String { 444 return 5, nil 445 } 446 447 return v, nil 448 } 449 450 var result Basic 451 config := &DecoderConfig{ 452 DecodeHook: decodeHook, 453 Result: &result, 454 } 455 456 decoder, err := NewDecoder(config) 457 if err != nil { 458 t.Fatalf("err: %s", err) 459 } 460 461 err = decoder.Decode(input) 462 if err != nil { 463 t.Fatalf("got an err: %s", err) 464 } 465 466 if result.Vint != 5 { 467 t.Errorf("vint should be 5: %#v", result.Vint) 468 } 469} 470 471func TestDecode_DecodeHookType(t *testing.T) { 472 t.Parallel() 473 474 input := map[string]interface{}{ 475 "vint": "WHAT", 476 } 477 478 decodeHook := func(from reflect.Type, to reflect.Type, v interface{}) (interface{}, error) { 479 if from.Kind() == reflect.String && 480 to.Kind() != reflect.String { 481 return 5, nil 482 } 483 484 return v, nil 485 } 486 487 var result Basic 488 config := &DecoderConfig{ 489 DecodeHook: decodeHook, 490 Result: &result, 491 } 492 493 decoder, err := NewDecoder(config) 494 if err != nil { 495 t.Fatalf("err: %s", err) 496 } 497 498 err = decoder.Decode(input) 499 if err != nil { 500 t.Fatalf("got an err: %s", err) 501 } 502 503 if result.Vint != 5 { 504 t.Errorf("vint should be 5: %#v", result.Vint) 505 } 506} 507 508func TestDecode_Nil(t *testing.T) { 509 t.Parallel() 510 511 var input interface{} 512 result := Basic{ 513 Vstring: "foo", 514 } 515 516 err := Decode(input, &result) 517 if err != nil { 518 t.Fatalf("err: %s", err) 519 } 520 521 if result.Vstring != "foo" { 522 t.Fatalf("bad: %#v", result.Vstring) 523 } 524} 525 526func TestDecode_NilInterfaceHook(t *testing.T) { 527 t.Parallel() 528 529 input := map[string]interface{}{ 530 "w": "", 531 } 532 533 decodeHook := func(f, t reflect.Type, v interface{}) (interface{}, error) { 534 if t.String() == "io.Writer" { 535 return nil, nil 536 } 537 538 return v, nil 539 } 540 541 var result NilInterface 542 config := &DecoderConfig{ 543 DecodeHook: decodeHook, 544 Result: &result, 545 } 546 547 decoder, err := NewDecoder(config) 548 if err != nil { 549 t.Fatalf("err: %s", err) 550 } 551 552 err = decoder.Decode(input) 553 if err != nil { 554 t.Fatalf("got an err: %s", err) 555 } 556 557 if result.W != nil { 558 t.Errorf("W should be nil: %#v", result.W) 559 } 560} 561 562func TestDecode_FuncHook(t *testing.T) { 563 t.Parallel() 564 565 input := map[string]interface{}{ 566 "foo": "baz", 567 } 568 569 decodeHook := func(f, t reflect.Type, v interface{}) (interface{}, error) { 570 if t.Kind() != reflect.Func { 571 return v, nil 572 } 573 val := v.(string) 574 return func() string { return val }, nil 575 } 576 577 var result Func 578 config := &DecoderConfig{ 579 DecodeHook: decodeHook, 580 Result: &result, 581 } 582 583 decoder, err := NewDecoder(config) 584 if err != nil { 585 t.Fatalf("err: %s", err) 586 } 587 588 err = decoder.Decode(input) 589 if err != nil { 590 t.Fatalf("got an err: %s", err) 591 } 592 593 if result.Foo() != "baz" { 594 t.Errorf("Foo call result should be 'baz': %s", result.Foo()) 595 } 596} 597 598func TestDecode_NonStruct(t *testing.T) { 599 t.Parallel() 600 601 input := map[string]interface{}{ 602 "foo": "bar", 603 "bar": "baz", 604 } 605 606 var result map[string]string 607 err := Decode(input, &result) 608 if err != nil { 609 t.Fatalf("err: %s", err) 610 } 611 612 if result["foo"] != "bar" { 613 t.Fatal("foo is not bar") 614 } 615} 616 617func TestDecode_StructMatch(t *testing.T) { 618 t.Parallel() 619 620 input := map[string]interface{}{ 621 "vbar": Basic{ 622 Vstring: "foo", 623 }, 624 } 625 626 var result Nested 627 err := Decode(input, &result) 628 if err != nil { 629 t.Fatalf("got an err: %s", err.Error()) 630 } 631 632 if result.Vbar.Vstring != "foo" { 633 t.Errorf("bad: %#v", result) 634 } 635} 636 637func TestDecode_TypeConversion(t *testing.T) { 638 input := map[string]interface{}{ 639 "IntToFloat": 42, 640 "IntToUint": 42, 641 "IntToBool": 1, 642 "IntToString": 42, 643 "UintToInt": 42, 644 "UintToFloat": 42, 645 "UintToBool": 42, 646 "UintToString": 42, 647 "BoolToInt": true, 648 "BoolToUint": true, 649 "BoolToFloat": true, 650 "BoolToString": true, 651 "FloatToInt": 42.42, 652 "FloatToUint": 42.42, 653 "FloatToBool": 42.42, 654 "FloatToString": 42.42, 655 "SliceUint8ToString": []uint8("foo"), 656 "StringToSliceUint8": "foo", 657 "ArrayUint8ToString": [3]uint8{'f', 'o', 'o'}, 658 "StringToInt": "42", 659 "StringToUint": "42", 660 "StringToBool": "1", 661 "StringToFloat": "42.42", 662 "StringToStrSlice": "A", 663 "StringToIntSlice": "42", 664 "StringToStrArray": "A", 665 "StringToIntArray": "42", 666 "SliceToMap": []interface{}{}, 667 "MapToSlice": map[string]interface{}{}, 668 "ArrayToMap": []interface{}{}, 669 "MapToArray": map[string]interface{}{}, 670 } 671 672 expectedResultStrict := TypeConversionResult{ 673 IntToFloat: 42.0, 674 IntToUint: 42, 675 UintToInt: 42, 676 UintToFloat: 42, 677 BoolToInt: 0, 678 BoolToUint: 0, 679 BoolToFloat: 0, 680 FloatToInt: 42, 681 FloatToUint: 42, 682 } 683 684 expectedResultWeak := TypeConversionResult{ 685 IntToFloat: 42.0, 686 IntToUint: 42, 687 IntToBool: true, 688 IntToString: "42", 689 UintToInt: 42, 690 UintToFloat: 42, 691 UintToBool: true, 692 UintToString: "42", 693 BoolToInt: 1, 694 BoolToUint: 1, 695 BoolToFloat: 1, 696 BoolToString: "1", 697 FloatToInt: 42, 698 FloatToUint: 42, 699 FloatToBool: true, 700 FloatToString: "42.42", 701 SliceUint8ToString: "foo", 702 StringToSliceUint8: []byte("foo"), 703 ArrayUint8ToString: "foo", 704 StringToInt: 42, 705 StringToUint: 42, 706 StringToBool: true, 707 StringToFloat: 42.42, 708 StringToStrSlice: []string{"A"}, 709 StringToIntSlice: []int{42}, 710 StringToStrArray: [1]string{"A"}, 711 StringToIntArray: [1]int{42}, 712 SliceToMap: map[string]interface{}{}, 713 MapToSlice: []interface{}{}, 714 ArrayToMap: map[string]interface{}{}, 715 MapToArray: [1]interface{}{}, 716 } 717 718 // Test strict type conversion 719 var resultStrict TypeConversionResult 720 err := Decode(input, &resultStrict) 721 if err == nil { 722 t.Errorf("should return an error") 723 } 724 if !reflect.DeepEqual(resultStrict, expectedResultStrict) { 725 t.Errorf("expected %v, got: %v", expectedResultStrict, resultStrict) 726 } 727 728 // Test weak type conversion 729 var decoder *Decoder 730 var resultWeak TypeConversionResult 731 732 config := &DecoderConfig{ 733 WeaklyTypedInput: true, 734 Result: &resultWeak, 735 } 736 737 decoder, err = NewDecoder(config) 738 if err != nil { 739 t.Fatalf("err: %s", err) 740 } 741 742 err = decoder.Decode(input) 743 if err != nil { 744 t.Fatalf("got an err: %s", err) 745 } 746 747 if !reflect.DeepEqual(resultWeak, expectedResultWeak) { 748 t.Errorf("expected \n%#v, got: \n%#v", expectedResultWeak, resultWeak) 749 } 750} 751 752func TestDecoder_ErrorUnused(t *testing.T) { 753 t.Parallel() 754 755 input := map[string]interface{}{ 756 "vstring": "hello", 757 "foo": "bar", 758 } 759 760 var result Basic 761 config := &DecoderConfig{ 762 ErrorUnused: true, 763 Result: &result, 764 } 765 766 decoder, err := NewDecoder(config) 767 if err != nil { 768 t.Fatalf("err: %s", err) 769 } 770 771 err = decoder.Decode(input) 772 if err == nil { 773 t.Fatal("expected error") 774 } 775} 776 777func TestMap(t *testing.T) { 778 t.Parallel() 779 780 input := map[string]interface{}{ 781 "vfoo": "foo", 782 "vother": map[interface{}]interface{}{ 783 "foo": "foo", 784 "bar": "bar", 785 }, 786 } 787 788 var result Map 789 err := Decode(input, &result) 790 if err != nil { 791 t.Fatalf("got an error: %s", err) 792 } 793 794 if result.Vfoo != "foo" { 795 t.Errorf("vfoo value should be 'foo': %#v", result.Vfoo) 796 } 797 798 if result.Vother == nil { 799 t.Fatal("vother should not be nil") 800 } 801 802 if len(result.Vother) != 2 { 803 t.Error("vother should have two items") 804 } 805 806 if result.Vother["foo"] != "foo" { 807 t.Errorf("'foo' key should be foo, got: %#v", result.Vother["foo"]) 808 } 809 810 if result.Vother["bar"] != "bar" { 811 t.Errorf("'bar' key should be bar, got: %#v", result.Vother["bar"]) 812 } 813} 814 815func TestMapMerge(t *testing.T) { 816 t.Parallel() 817 818 input := map[string]interface{}{ 819 "vfoo": "foo", 820 "vother": map[interface{}]interface{}{ 821 "foo": "foo", 822 "bar": "bar", 823 }, 824 } 825 826 var result Map 827 result.Vother = map[string]string{"hello": "world"} 828 err := Decode(input, &result) 829 if err != nil { 830 t.Fatalf("got an error: %s", err) 831 } 832 833 if result.Vfoo != "foo" { 834 t.Errorf("vfoo value should be 'foo': %#v", result.Vfoo) 835 } 836 837 expected := map[string]string{ 838 "foo": "foo", 839 "bar": "bar", 840 "hello": "world", 841 } 842 if !reflect.DeepEqual(result.Vother, expected) { 843 t.Errorf("bad: %#v", result.Vother) 844 } 845} 846 847func TestMapOfStruct(t *testing.T) { 848 t.Parallel() 849 850 input := map[string]interface{}{ 851 "value": map[string]interface{}{ 852 "foo": map[string]string{"vstring": "one"}, 853 "bar": map[string]string{"vstring": "two"}, 854 }, 855 } 856 857 var result MapOfStruct 858 err := Decode(input, &result) 859 if err != nil { 860 t.Fatalf("got an err: %s", err) 861 } 862 863 if result.Value == nil { 864 t.Fatal("value should not be nil") 865 } 866 867 if len(result.Value) != 2 { 868 t.Error("value should have two items") 869 } 870 871 if result.Value["foo"].Vstring != "one" { 872 t.Errorf("foo value should be 'one', got: %s", result.Value["foo"].Vstring) 873 } 874 875 if result.Value["bar"].Vstring != "two" { 876 t.Errorf("bar value should be 'two', got: %s", result.Value["bar"].Vstring) 877 } 878} 879 880func TestNestedType(t *testing.T) { 881 t.Parallel() 882 883 input := map[string]interface{}{ 884 "vfoo": "foo", 885 "vbar": map[string]interface{}{ 886 "vstring": "foo", 887 "vint": 42, 888 "vbool": true, 889 }, 890 } 891 892 var result Nested 893 err := Decode(input, &result) 894 if err != nil { 895 t.Fatalf("got an err: %s", err.Error()) 896 } 897 898 if result.Vfoo != "foo" { 899 t.Errorf("vfoo value should be 'foo': %#v", result.Vfoo) 900 } 901 902 if result.Vbar.Vstring != "foo" { 903 t.Errorf("vstring value should be 'foo': %#v", result.Vbar.Vstring) 904 } 905 906 if result.Vbar.Vint != 42 { 907 t.Errorf("vint value should be 42: %#v", result.Vbar.Vint) 908 } 909 910 if result.Vbar.Vbool != true { 911 t.Errorf("vbool value should be true: %#v", result.Vbar.Vbool) 912 } 913 914 if result.Vbar.Vextra != "" { 915 t.Errorf("vextra value should be empty: %#v", result.Vbar.Vextra) 916 } 917} 918 919func TestNestedTypePointer(t *testing.T) { 920 t.Parallel() 921 922 input := map[string]interface{}{ 923 "vfoo": "foo", 924 "vbar": &map[string]interface{}{ 925 "vstring": "foo", 926 "vint": 42, 927 "vbool": true, 928 }, 929 } 930 931 var result NestedPointer 932 err := Decode(input, &result) 933 if err != nil { 934 t.Fatalf("got an err: %s", err.Error()) 935 } 936 937 if result.Vfoo != "foo" { 938 t.Errorf("vfoo value should be 'foo': %#v", result.Vfoo) 939 } 940 941 if result.Vbar.Vstring != "foo" { 942 t.Errorf("vstring value should be 'foo': %#v", result.Vbar.Vstring) 943 } 944 945 if result.Vbar.Vint != 42 { 946 t.Errorf("vint value should be 42: %#v", result.Vbar.Vint) 947 } 948 949 if result.Vbar.Vbool != true { 950 t.Errorf("vbool value should be true: %#v", result.Vbar.Vbool) 951 } 952 953 if result.Vbar.Vextra != "" { 954 t.Errorf("vextra value should be empty: %#v", result.Vbar.Vextra) 955 } 956} 957 958// Test for issue #46. 959func TestNestedTypeInterface(t *testing.T) { 960 t.Parallel() 961 962 input := map[string]interface{}{ 963 "vfoo": "foo", 964 "vbar": &map[string]interface{}{ 965 "vstring": "foo", 966 "vint": 42, 967 "vbool": true, 968 969 "vdata": map[string]interface{}{ 970 "vstring": "bar", 971 }, 972 }, 973 } 974 975 var result NestedPointer 976 result.Vbar = new(Basic) 977 result.Vbar.Vdata = new(Basic) 978 err := Decode(input, &result) 979 if err != nil { 980 t.Fatalf("got an err: %s", err.Error()) 981 } 982 983 if result.Vfoo != "foo" { 984 t.Errorf("vfoo value should be 'foo': %#v", result.Vfoo) 985 } 986 987 if result.Vbar.Vstring != "foo" { 988 t.Errorf("vstring value should be 'foo': %#v", result.Vbar.Vstring) 989 } 990 991 if result.Vbar.Vint != 42 { 992 t.Errorf("vint value should be 42: %#v", result.Vbar.Vint) 993 } 994 995 if result.Vbar.Vbool != true { 996 t.Errorf("vbool value should be true: %#v", result.Vbar.Vbool) 997 } 998 999 if result.Vbar.Vextra != "" { 1000 t.Errorf("vextra value should be empty: %#v", result.Vbar.Vextra) 1001 } 1002 1003 if result.Vbar.Vdata.(*Basic).Vstring != "bar" { 1004 t.Errorf("vstring value should be 'bar': %#v", result.Vbar.Vdata.(*Basic).Vstring) 1005 } 1006} 1007 1008func TestSlice(t *testing.T) { 1009 t.Parallel() 1010 1011 inputStringSlice := map[string]interface{}{ 1012 "vfoo": "foo", 1013 "vbar": []string{"foo", "bar", "baz"}, 1014 } 1015 1016 inputStringSlicePointer := map[string]interface{}{ 1017 "vfoo": "foo", 1018 "vbar": &[]string{"foo", "bar", "baz"}, 1019 } 1020 1021 outputStringSlice := &Slice{ 1022 "foo", 1023 []string{"foo", "bar", "baz"}, 1024 } 1025 1026 testSliceInput(t, inputStringSlice, outputStringSlice) 1027 testSliceInput(t, inputStringSlicePointer, outputStringSlice) 1028} 1029 1030func TestInvalidSlice(t *testing.T) { 1031 t.Parallel() 1032 1033 input := map[string]interface{}{ 1034 "vfoo": "foo", 1035 "vbar": 42, 1036 } 1037 1038 result := Slice{} 1039 err := Decode(input, &result) 1040 if err == nil { 1041 t.Errorf("expected failure") 1042 } 1043} 1044 1045func TestSliceOfStruct(t *testing.T) { 1046 t.Parallel() 1047 1048 input := map[string]interface{}{ 1049 "value": []map[string]interface{}{ 1050 {"vstring": "one"}, 1051 {"vstring": "two"}, 1052 }, 1053 } 1054 1055 var result SliceOfStruct 1056 err := Decode(input, &result) 1057 if err != nil { 1058 t.Fatalf("got unexpected error: %s", err) 1059 } 1060 1061 if len(result.Value) != 2 { 1062 t.Fatalf("expected two values, got %d", len(result.Value)) 1063 } 1064 1065 if result.Value[0].Vstring != "one" { 1066 t.Errorf("first value should be 'one', got: %s", result.Value[0].Vstring) 1067 } 1068 1069 if result.Value[1].Vstring != "two" { 1070 t.Errorf("second value should be 'two', got: %s", result.Value[1].Vstring) 1071 } 1072} 1073 1074func TestSliceToMap(t *testing.T) { 1075 t.Parallel() 1076 1077 input := []map[string]interface{}{ 1078 { 1079 "foo": "bar", 1080 }, 1081 { 1082 "bar": "baz", 1083 }, 1084 } 1085 1086 var result map[string]interface{} 1087 err := WeakDecode(input, &result) 1088 if err != nil { 1089 t.Fatalf("got an error: %s", err) 1090 } 1091 1092 expected := map[string]interface{}{ 1093 "foo": "bar", 1094 "bar": "baz", 1095 } 1096 if !reflect.DeepEqual(result, expected) { 1097 t.Errorf("bad: %#v", result) 1098 } 1099} 1100 1101func TestArray(t *testing.T) { 1102 t.Parallel() 1103 1104 inputStringArray := map[string]interface{}{ 1105 "vfoo": "foo", 1106 "vbar": [2]string{"foo", "bar"}, 1107 } 1108 1109 inputStringArrayPointer := map[string]interface{}{ 1110 "vfoo": "foo", 1111 "vbar": &[2]string{"foo", "bar"}, 1112 } 1113 1114 outputStringArray := &Array{ 1115 "foo", 1116 [2]string{"foo", "bar"}, 1117 } 1118 1119 testArrayInput(t, inputStringArray, outputStringArray) 1120 testArrayInput(t, inputStringArrayPointer, outputStringArray) 1121} 1122 1123func TestInvalidArray(t *testing.T) { 1124 t.Parallel() 1125 1126 input := map[string]interface{}{ 1127 "vfoo": "foo", 1128 "vbar": 42, 1129 } 1130 1131 result := Array{} 1132 err := Decode(input, &result) 1133 if err == nil { 1134 t.Errorf("expected failure") 1135 } 1136} 1137 1138func TestArrayOfStruct(t *testing.T) { 1139 t.Parallel() 1140 1141 input := map[string]interface{}{ 1142 "value": []map[string]interface{}{ 1143 {"vstring": "one"}, 1144 {"vstring": "two"}, 1145 }, 1146 } 1147 1148 var result ArrayOfStruct 1149 err := Decode(input, &result) 1150 if err != nil { 1151 t.Fatalf("got unexpected error: %s", err) 1152 } 1153 1154 if len(result.Value) != 2 { 1155 t.Fatalf("expected two values, got %d", len(result.Value)) 1156 } 1157 1158 if result.Value[0].Vstring != "one" { 1159 t.Errorf("first value should be 'one', got: %s", result.Value[0].Vstring) 1160 } 1161 1162 if result.Value[1].Vstring != "two" { 1163 t.Errorf("second value should be 'two', got: %s", result.Value[1].Vstring) 1164 } 1165} 1166 1167func TestArrayToMap(t *testing.T) { 1168 t.Parallel() 1169 1170 input := []map[string]interface{}{ 1171 { 1172 "foo": "bar", 1173 }, 1174 { 1175 "bar": "baz", 1176 }, 1177 } 1178 1179 var result map[string]interface{} 1180 err := WeakDecode(input, &result) 1181 if err != nil { 1182 t.Fatalf("got an error: %s", err) 1183 } 1184 1185 expected := map[string]interface{}{ 1186 "foo": "bar", 1187 "bar": "baz", 1188 } 1189 if !reflect.DeepEqual(result, expected) { 1190 t.Errorf("bad: %#v", result) 1191 } 1192} 1193 1194func TestMapOutputForStructuredInputs(t *testing.T) { 1195 t.Parallel() 1196 1197 tests := []struct { 1198 name string 1199 in interface{} 1200 target interface{} 1201 out interface{} 1202 wantErr bool 1203 }{ 1204 { 1205 "basic struct input", 1206 &Basic{ 1207 Vstring: "vstring", 1208 Vint: 2, 1209 Vuint: 3, 1210 Vbool: true, 1211 Vfloat: 4.56, 1212 Vextra: "vextra", 1213 vsilent: true, 1214 Vdata: []byte("data"), 1215 }, 1216 &map[string]interface{}{}, 1217 &map[string]interface{}{ 1218 "Vstring": "vstring", 1219 "Vint": 2, 1220 "Vuint": uint(3), 1221 "Vbool": true, 1222 "Vfloat": 4.56, 1223 "Vextra": "vextra", 1224 "Vdata": []byte("data"), 1225 "VjsonInt": 0, 1226 "VjsonFloat": 0.0, 1227 "VjsonNumber": json.Number(""), 1228 }, 1229 false, 1230 }, 1231 { 1232 "embedded struct input", 1233 &Embedded{ 1234 Vunique: "vunique", 1235 Basic: Basic{ 1236 Vstring: "vstring", 1237 Vint: 2, 1238 Vuint: 3, 1239 Vbool: true, 1240 Vfloat: 4.56, 1241 Vextra: "vextra", 1242 vsilent: true, 1243 Vdata: []byte("data"), 1244 }, 1245 }, 1246 &map[string]interface{}{}, 1247 &map[string]interface{}{ 1248 "Vunique": "vunique", 1249 "Basic": map[string]interface{}{ 1250 "Vstring": "vstring", 1251 "Vint": 2, 1252 "Vuint": uint(3), 1253 "Vbool": true, 1254 "Vfloat": 4.56, 1255 "Vextra": "vextra", 1256 "Vdata": []byte("data"), 1257 "VjsonInt": 0, 1258 "VjsonFloat": 0.0, 1259 "VjsonNumber": json.Number(""), 1260 }, 1261 }, 1262 false, 1263 }, 1264 { 1265 "slice input - should error", 1266 []string{"foo", "bar"}, 1267 &map[string]interface{}{}, 1268 &map[string]interface{}{}, 1269 true, 1270 }, 1271 { 1272 "struct with slice property", 1273 &Slice{ 1274 Vfoo: "vfoo", 1275 Vbar: []string{"foo", "bar"}, 1276 }, 1277 &map[string]interface{}{}, 1278 &map[string]interface{}{ 1279 "Vfoo": "vfoo", 1280 "Vbar": []string{"foo", "bar"}, 1281 }, 1282 false, 1283 }, 1284 { 1285 "struct with slice of struct property", 1286 &SliceOfStruct{ 1287 Value: []Basic{ 1288 Basic{ 1289 Vstring: "vstring", 1290 Vint: 2, 1291 Vuint: 3, 1292 Vbool: true, 1293 Vfloat: 4.56, 1294 Vextra: "vextra", 1295 vsilent: true, 1296 Vdata: []byte("data"), 1297 }, 1298 }, 1299 }, 1300 &map[string]interface{}{}, 1301 &map[string]interface{}{ 1302 "Value": []Basic{ 1303 Basic{ 1304 Vstring: "vstring", 1305 Vint: 2, 1306 Vuint: 3, 1307 Vbool: true, 1308 Vfloat: 4.56, 1309 Vextra: "vextra", 1310 vsilent: true, 1311 Vdata: []byte("data"), 1312 }, 1313 }, 1314 }, 1315 false, 1316 }, 1317 { 1318 "struct with map property", 1319 &Map{ 1320 Vfoo: "vfoo", 1321 Vother: map[string]string{"vother": "vother"}, 1322 }, 1323 &map[string]interface{}{}, 1324 &map[string]interface{}{ 1325 "Vfoo": "vfoo", 1326 "Vother": map[string]string{ 1327 "vother": "vother", 1328 }}, 1329 false, 1330 }, 1331 { 1332 "tagged struct", 1333 &Tagged{ 1334 Extra: "extra", 1335 Value: "value", 1336 }, 1337 &map[string]string{}, 1338 &map[string]string{ 1339 "bar": "extra", 1340 "foo": "value", 1341 }, 1342 false, 1343 }, 1344 { 1345 "omit tag struct", 1346 &struct { 1347 Value string `mapstructure:"value"` 1348 Omit string `mapstructure:"-"` 1349 }{ 1350 Value: "value", 1351 Omit: "omit", 1352 }, 1353 &map[string]string{}, 1354 &map[string]string{ 1355 "value": "value", 1356 }, 1357 false, 1358 }, 1359 { 1360 "decode to wrong map type", 1361 &struct { 1362 Value string 1363 }{ 1364 Value: "string", 1365 }, 1366 &map[string]int{}, 1367 &map[string]int{}, 1368 true, 1369 }, 1370 } 1371 1372 for _, tt := range tests { 1373 t.Run(tt.name, func(t *testing.T) { 1374 if err := Decode(tt.in, tt.target); (err != nil) != tt.wantErr { 1375 t.Fatalf("%q: TestMapOutputForStructuredInputs() unexpected error: %s", tt.name, err) 1376 } 1377 1378 if !reflect.DeepEqual(tt.out, tt.target) { 1379 t.Fatalf("%q: TestMapOutputForStructuredInputs() expected: %#v, got: %#v", tt.name, tt.out, tt.target) 1380 } 1381 }) 1382 } 1383} 1384 1385func TestInvalidType(t *testing.T) { 1386 t.Parallel() 1387 1388 input := map[string]interface{}{ 1389 "vstring": 42, 1390 } 1391 1392 var result Basic 1393 err := Decode(input, &result) 1394 if err == nil { 1395 t.Fatal("error should exist") 1396 } 1397 1398 derr, ok := err.(*Error) 1399 if !ok { 1400 t.Fatalf("error should be kind of Error, instead: %#v", err) 1401 } 1402 1403 if derr.Errors[0] != "'Vstring' expected type 'string', got unconvertible type 'int'" { 1404 t.Errorf("got unexpected error: %s", err) 1405 } 1406 1407 inputNegIntUint := map[string]interface{}{ 1408 "vuint": -42, 1409 } 1410 1411 err = Decode(inputNegIntUint, &result) 1412 if err == nil { 1413 t.Fatal("error should exist") 1414 } 1415 1416 derr, ok = err.(*Error) 1417 if !ok { 1418 t.Fatalf("error should be kind of Error, instead: %#v", err) 1419 } 1420 1421 if derr.Errors[0] != "cannot parse 'Vuint', -42 overflows uint" { 1422 t.Errorf("got unexpected error: %s", err) 1423 } 1424 1425 inputNegFloatUint := map[string]interface{}{ 1426 "vuint": -42.0, 1427 } 1428 1429 err = Decode(inputNegFloatUint, &result) 1430 if err == nil { 1431 t.Fatal("error should exist") 1432 } 1433 1434 derr, ok = err.(*Error) 1435 if !ok { 1436 t.Fatalf("error should be kind of Error, instead: %#v", err) 1437 } 1438 1439 if derr.Errors[0] != "cannot parse 'Vuint', -42.000000 overflows uint" { 1440 t.Errorf("got unexpected error: %s", err) 1441 } 1442} 1443 1444func TestDecodeMetadata(t *testing.T) { 1445 t.Parallel() 1446 1447 input := map[string]interface{}{ 1448 "vfoo": "foo", 1449 "vbar": map[string]interface{}{ 1450 "vstring": "foo", 1451 "Vuint": 42, 1452 "foo": "bar", 1453 }, 1454 "bar": "nil", 1455 } 1456 1457 var md Metadata 1458 var result Nested 1459 1460 err := DecodeMetadata(input, &result, &md) 1461 if err != nil { 1462 t.Fatalf("err: %s", err.Error()) 1463 } 1464 1465 expectedKeys := []string{"Vbar", "Vbar.Vstring", "Vbar.Vuint", "Vfoo"} 1466 sort.Strings(md.Keys) 1467 if !reflect.DeepEqual(md.Keys, expectedKeys) { 1468 t.Fatalf("bad keys: %#v", md.Keys) 1469 } 1470 1471 expectedUnused := []string{"Vbar.foo", "bar"} 1472 if !reflect.DeepEqual(md.Unused, expectedUnused) { 1473 t.Fatalf("bad unused: %#v", md.Unused) 1474 } 1475} 1476 1477func TestMetadata(t *testing.T) { 1478 t.Parallel() 1479 1480 input := map[string]interface{}{ 1481 "vfoo": "foo", 1482 "vbar": map[string]interface{}{ 1483 "vstring": "foo", 1484 "Vuint": 42, 1485 "foo": "bar", 1486 }, 1487 "bar": "nil", 1488 } 1489 1490 var md Metadata 1491 var result Nested 1492 config := &DecoderConfig{ 1493 Metadata: &md, 1494 Result: &result, 1495 } 1496 1497 decoder, err := NewDecoder(config) 1498 if err != nil { 1499 t.Fatalf("err: %s", err) 1500 } 1501 1502 err = decoder.Decode(input) 1503 if err != nil { 1504 t.Fatalf("err: %s", err.Error()) 1505 } 1506 1507 expectedKeys := []string{"Vbar", "Vbar.Vstring", "Vbar.Vuint", "Vfoo"} 1508 sort.Strings(md.Keys) 1509 if !reflect.DeepEqual(md.Keys, expectedKeys) { 1510 t.Fatalf("bad keys: %#v", md.Keys) 1511 } 1512 1513 expectedUnused := []string{"Vbar.foo", "bar"} 1514 if !reflect.DeepEqual(md.Unused, expectedUnused) { 1515 t.Fatalf("bad unused: %#v", md.Unused) 1516 } 1517} 1518 1519func TestMetadata_Embedded(t *testing.T) { 1520 t.Parallel() 1521 1522 input := map[string]interface{}{ 1523 "vstring": "foo", 1524 "vunique": "bar", 1525 } 1526 1527 var md Metadata 1528 var result EmbeddedSquash 1529 config := &DecoderConfig{ 1530 Metadata: &md, 1531 Result: &result, 1532 } 1533 1534 decoder, err := NewDecoder(config) 1535 if err != nil { 1536 t.Fatalf("err: %s", err) 1537 } 1538 1539 err = decoder.Decode(input) 1540 if err != nil { 1541 t.Fatalf("err: %s", err.Error()) 1542 } 1543 1544 expectedKeys := []string{"Vstring", "Vunique"} 1545 1546 sort.Strings(md.Keys) 1547 if !reflect.DeepEqual(md.Keys, expectedKeys) { 1548 t.Fatalf("bad keys: %#v", md.Keys) 1549 } 1550 1551 expectedUnused := []string{} 1552 if !reflect.DeepEqual(md.Unused, expectedUnused) { 1553 t.Fatalf("bad unused: %#v", md.Unused) 1554 } 1555} 1556 1557func TestNonPtrValue(t *testing.T) { 1558 t.Parallel() 1559 1560 err := Decode(map[string]interface{}{}, Basic{}) 1561 if err == nil { 1562 t.Fatal("error should exist") 1563 } 1564 1565 if err.Error() != "result must be a pointer" { 1566 t.Errorf("got unexpected error: %s", err) 1567 } 1568} 1569 1570func TestTagged(t *testing.T) { 1571 t.Parallel() 1572 1573 input := map[string]interface{}{ 1574 "foo": "bar", 1575 "bar": "value", 1576 } 1577 1578 var result Tagged 1579 err := Decode(input, &result) 1580 if err != nil { 1581 t.Fatalf("unexpected error: %s", err) 1582 } 1583 1584 if result.Value != "bar" { 1585 t.Errorf("value should be 'bar', got: %#v", result.Value) 1586 } 1587 1588 if result.Extra != "value" { 1589 t.Errorf("extra should be 'value', got: %#v", result.Extra) 1590 } 1591} 1592 1593func TestWeakDecode(t *testing.T) { 1594 t.Parallel() 1595 1596 input := map[string]interface{}{ 1597 "foo": "4", 1598 "bar": "value", 1599 } 1600 1601 var result struct { 1602 Foo int 1603 Bar string 1604 } 1605 1606 if err := WeakDecode(input, &result); err != nil { 1607 t.Fatalf("err: %s", err) 1608 } 1609 if result.Foo != 4 { 1610 t.Fatalf("bad: %#v", result) 1611 } 1612 if result.Bar != "value" { 1613 t.Fatalf("bad: %#v", result) 1614 } 1615} 1616 1617func TestWeakDecodeMetadata(t *testing.T) { 1618 t.Parallel() 1619 1620 input := map[string]interface{}{ 1621 "foo": "4", 1622 "bar": "value", 1623 "unused": "value", 1624 } 1625 1626 var md Metadata 1627 var result struct { 1628 Foo int 1629 Bar string 1630 } 1631 1632 if err := WeakDecodeMetadata(input, &result, &md); err != nil { 1633 t.Fatalf("err: %s", err) 1634 } 1635 if result.Foo != 4 { 1636 t.Fatalf("bad: %#v", result) 1637 } 1638 if result.Bar != "value" { 1639 t.Fatalf("bad: %#v", result) 1640 } 1641 1642 expectedKeys := []string{"Bar", "Foo"} 1643 sort.Strings(md.Keys) 1644 if !reflect.DeepEqual(md.Keys, expectedKeys) { 1645 t.Fatalf("bad keys: %#v", md.Keys) 1646 } 1647 1648 expectedUnused := []string{"unused"} 1649 if !reflect.DeepEqual(md.Unused, expectedUnused) { 1650 t.Fatalf("bad unused: %#v", md.Unused) 1651 } 1652} 1653 1654func testSliceInput(t *testing.T, input map[string]interface{}, expected *Slice) { 1655 var result Slice 1656 err := Decode(input, &result) 1657 if err != nil { 1658 t.Fatalf("got error: %s", err) 1659 } 1660 1661 if result.Vfoo != expected.Vfoo { 1662 t.Errorf("Vfoo expected '%s', got '%s'", expected.Vfoo, result.Vfoo) 1663 } 1664 1665 if result.Vbar == nil { 1666 t.Fatalf("Vbar a slice, got '%#v'", result.Vbar) 1667 } 1668 1669 if len(result.Vbar) != len(expected.Vbar) { 1670 t.Errorf("Vbar length should be %d, got %d", len(expected.Vbar), len(result.Vbar)) 1671 } 1672 1673 for i, v := range result.Vbar { 1674 if v != expected.Vbar[i] { 1675 t.Errorf( 1676 "Vbar[%d] should be '%#v', got '%#v'", 1677 i, expected.Vbar[i], v) 1678 } 1679 } 1680} 1681 1682func testArrayInput(t *testing.T, input map[string]interface{}, expected *Array) { 1683 var result Array 1684 err := Decode(input, &result) 1685 if err != nil { 1686 t.Fatalf("got error: %s", err) 1687 } 1688 1689 if result.Vfoo != expected.Vfoo { 1690 t.Errorf("Vfoo expected '%s', got '%s'", expected.Vfoo, result.Vfoo) 1691 } 1692 1693 if result.Vbar == [2]string{} { 1694 t.Fatalf("Vbar a slice, got '%#v'", result.Vbar) 1695 } 1696 1697 if len(result.Vbar) != len(expected.Vbar) { 1698 t.Errorf("Vbar length should be %d, got %d", len(expected.Vbar), len(result.Vbar)) 1699 } 1700 1701 for i, v := range result.Vbar { 1702 if v != expected.Vbar[i] { 1703 t.Errorf( 1704 "Vbar[%d] should be '%#v', got '%#v'", 1705 i, expected.Vbar[i], v) 1706 } 1707 } 1708} 1709