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