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 SquashOnNonStructType struct { 53 InvalidSquashType int `mapstructure:",squash"` 54} 55 56type Map struct { 57 Vfoo string 58 Vother map[string]string 59} 60 61type MapOfStruct struct { 62 Value map[string]Basic 63} 64 65type Nested struct { 66 Vfoo string 67 Vbar Basic 68} 69 70type NestedPointer struct { 71 Vfoo string 72 Vbar *Basic 73} 74 75type NilInterface struct { 76 W io.Writer 77} 78 79type Slice struct { 80 Vfoo string 81 Vbar []string 82} 83 84type SliceOfStruct struct { 85 Value []Basic 86} 87 88type Func struct { 89 Foo func() string 90} 91 92type Tagged struct { 93 Extra string `mapstructure:"bar,what,what"` 94 Value string `mapstructure:"foo"` 95} 96 97type TypeConversionResult struct { 98 IntToFloat float32 99 IntToUint uint 100 IntToBool bool 101 IntToString string 102 UintToInt int 103 UintToFloat float32 104 UintToBool bool 105 UintToString string 106 BoolToInt int 107 BoolToUint uint 108 BoolToFloat float32 109 BoolToString string 110 FloatToInt int 111 FloatToUint uint 112 FloatToBool bool 113 FloatToString string 114 SliceUint8ToString string 115 StringToInt int 116 StringToUint uint 117 StringToBool bool 118 StringToFloat float32 119 StringToStrSlice []string 120 StringToIntSlice []int 121 SliceToMap map[string]interface{} 122 MapToSlice []interface{} 123} 124 125func TestBasicTypes(t *testing.T) { 126 t.Parallel() 127 128 input := map[string]interface{}{ 129 "vstring": "foo", 130 "vint": 42, 131 "Vuint": 42, 132 "vbool": true, 133 "Vfloat": 42.42, 134 "vsilent": true, 135 "vdata": 42, 136 "vjsonInt": json.Number("1234"), 137 "vjsonFloat": json.Number("1234.5"), 138 "vjsonNumber": json.Number("1234.5"), 139 } 140 141 var result Basic 142 err := Decode(input, &result) 143 if err != nil { 144 t.Errorf("got an err: %s", err.Error()) 145 t.FailNow() 146 } 147 148 if result.Vstring != "foo" { 149 t.Errorf("vstring value should be 'foo': %#v", result.Vstring) 150 } 151 152 if result.Vint != 42 { 153 t.Errorf("vint value should be 42: %#v", result.Vint) 154 } 155 156 if result.Vuint != 42 { 157 t.Errorf("vuint value should be 42: %#v", result.Vuint) 158 } 159 160 if result.Vbool != true { 161 t.Errorf("vbool value should be true: %#v", result.Vbool) 162 } 163 164 if result.Vfloat != 42.42 { 165 t.Errorf("vfloat value should be 42.42: %#v", result.Vfloat) 166 } 167 168 if result.Vextra != "" { 169 t.Errorf("vextra value should be empty: %#v", result.Vextra) 170 } 171 172 if result.vsilent != false { 173 t.Error("vsilent should not be set, it is unexported") 174 } 175 176 if result.Vdata != 42 { 177 t.Error("vdata should be valid") 178 } 179 180 if result.VjsonInt != 1234 { 181 t.Errorf("vjsonint value should be 1234: %#v", result.VjsonInt) 182 } 183 184 if result.VjsonFloat != 1234.5 { 185 t.Errorf("vjsonfloat value should be 1234.5: %#v", result.VjsonFloat) 186 } 187 188 if !reflect.DeepEqual(result.VjsonNumber, json.Number("1234.5")) { 189 t.Errorf("vjsonnumber value should be '1234.5': %T, %#v", result.VjsonNumber, result.VjsonNumber) 190 } 191} 192 193func TestBasic_IntWithFloat(t *testing.T) { 194 t.Parallel() 195 196 input := map[string]interface{}{ 197 "vint": float64(42), 198 } 199 200 var result Basic 201 err := Decode(input, &result) 202 if err != nil { 203 t.Fatalf("got an err: %s", err) 204 } 205} 206 207func TestBasic_Merge(t *testing.T) { 208 t.Parallel() 209 210 input := map[string]interface{}{ 211 "vint": 42, 212 } 213 214 var result Basic 215 result.Vuint = 100 216 err := Decode(input, &result) 217 if err != nil { 218 t.Fatalf("got an err: %s", err) 219 } 220 221 expected := Basic{ 222 Vint: 42, 223 Vuint: 100, 224 } 225 if !reflect.DeepEqual(result, expected) { 226 t.Fatalf("bad: %#v", result) 227 } 228} 229 230func TestDecode_BasicSquash(t *testing.T) { 231 t.Parallel() 232 233 input := map[string]interface{}{ 234 "vstring": "foo", 235 } 236 237 var result BasicSquash 238 err := Decode(input, &result) 239 if err != nil { 240 t.Fatalf("got an err: %s", err.Error()) 241 } 242 243 if result.Test.Vstring != "foo" { 244 t.Errorf("vstring value should be 'foo': %#v", result.Test.Vstring) 245 } 246} 247 248func TestDecode_Embedded(t *testing.T) { 249 t.Parallel() 250 251 input := map[string]interface{}{ 252 "vstring": "foo", 253 "Basic": map[string]interface{}{ 254 "vstring": "innerfoo", 255 }, 256 "vunique": "bar", 257 } 258 259 var result Embedded 260 err := Decode(input, &result) 261 if err != nil { 262 t.Fatalf("got an err: %s", err.Error()) 263 } 264 265 if result.Vstring != "innerfoo" { 266 t.Errorf("vstring value should be 'innerfoo': %#v", result.Vstring) 267 } 268 269 if result.Vunique != "bar" { 270 t.Errorf("vunique value should be 'bar': %#v", result.Vunique) 271 } 272} 273 274func TestDecode_EmbeddedPointer(t *testing.T) { 275 t.Parallel() 276 277 input := map[string]interface{}{ 278 "vstring": "foo", 279 "Basic": map[string]interface{}{ 280 "vstring": "innerfoo", 281 }, 282 "vunique": "bar", 283 } 284 285 var result EmbeddedPointer 286 err := Decode(input, &result) 287 if err != nil { 288 t.Fatalf("err: %s", err) 289 } 290 291 expected := EmbeddedPointer{ 292 Basic: &Basic{ 293 Vstring: "innerfoo", 294 }, 295 Vunique: "bar", 296 } 297 if !reflect.DeepEqual(result, expected) { 298 t.Fatalf("bad: %#v", result) 299 } 300} 301 302func TestDecode_EmbeddedSlice(t *testing.T) { 303 t.Parallel() 304 305 input := map[string]interface{}{ 306 "slice_alias": []string{"foo", "bar"}, 307 "vunique": "bar", 308 } 309 310 var result EmbeddedSlice 311 err := Decode(input, &result) 312 if err != nil { 313 t.Fatalf("got an err: %s", err.Error()) 314 } 315 316 if !reflect.DeepEqual(result.SliceAlias, SliceAlias([]string{"foo", "bar"})) { 317 t.Errorf("slice value: %#v", result.SliceAlias) 318 } 319 320 if result.Vunique != "bar" { 321 t.Errorf("vunique value should be 'bar': %#v", result.Vunique) 322 } 323} 324 325func TestDecode_EmbeddedSquash(t *testing.T) { 326 t.Parallel() 327 328 input := map[string]interface{}{ 329 "vstring": "foo", 330 "vunique": "bar", 331 } 332 333 var result EmbeddedSquash 334 err := Decode(input, &result) 335 if err != nil { 336 t.Fatalf("got an err: %s", err.Error()) 337 } 338 339 if result.Vstring != "foo" { 340 t.Errorf("vstring value should be 'foo': %#v", result.Vstring) 341 } 342 343 if result.Vunique != "bar" { 344 t.Errorf("vunique value should be 'bar': %#v", result.Vunique) 345 } 346} 347 348func TestDecode_SquashOnNonStructType(t *testing.T) { 349 t.Parallel() 350 351 input := map[string]interface{}{ 352 "InvalidSquashType": 42, 353 } 354 355 var result SquashOnNonStructType 356 err := Decode(input, &result) 357 if err == nil { 358 t.Fatal("unexpected success decoding invalid squash field type") 359 } else if !strings.Contains(err.Error(), "unsupported type for squash") { 360 t.Fatalf("unexpected error message for invalid squash field type: %s", err) 361 } 362} 363 364func TestDecode_DecodeHook(t *testing.T) { 365 t.Parallel() 366 367 input := map[string]interface{}{ 368 "vint": "WHAT", 369 } 370 371 decodeHook := func(from reflect.Kind, to reflect.Kind, v interface{}) (interface{}, error) { 372 if from == reflect.String && to != reflect.String { 373 return 5, nil 374 } 375 376 return v, nil 377 } 378 379 var result Basic 380 config := &DecoderConfig{ 381 DecodeHook: decodeHook, 382 Result: &result, 383 } 384 385 decoder, err := NewDecoder(config) 386 if err != nil { 387 t.Fatalf("err: %s", err) 388 } 389 390 err = decoder.Decode(input) 391 if err != nil { 392 t.Fatalf("got an err: %s", err) 393 } 394 395 if result.Vint != 5 { 396 t.Errorf("vint should be 5: %#v", result.Vint) 397 } 398} 399 400func TestDecode_DecodeHookType(t *testing.T) { 401 t.Parallel() 402 403 input := map[string]interface{}{ 404 "vint": "WHAT", 405 } 406 407 decodeHook := func(from reflect.Type, to reflect.Type, v interface{}) (interface{}, error) { 408 if from.Kind() == reflect.String && 409 to.Kind() != reflect.String { 410 return 5, nil 411 } 412 413 return v, nil 414 } 415 416 var result Basic 417 config := &DecoderConfig{ 418 DecodeHook: decodeHook, 419 Result: &result, 420 } 421 422 decoder, err := NewDecoder(config) 423 if err != nil { 424 t.Fatalf("err: %s", err) 425 } 426 427 err = decoder.Decode(input) 428 if err != nil { 429 t.Fatalf("got an err: %s", err) 430 } 431 432 if result.Vint != 5 { 433 t.Errorf("vint should be 5: %#v", result.Vint) 434 } 435} 436 437func TestDecode_Nil(t *testing.T) { 438 t.Parallel() 439 440 var input interface{} 441 result := Basic{ 442 Vstring: "foo", 443 } 444 445 err := Decode(input, &result) 446 if err != nil { 447 t.Fatalf("err: %s", err) 448 } 449 450 if result.Vstring != "foo" { 451 t.Fatalf("bad: %#v", result.Vstring) 452 } 453} 454 455func TestDecode_NilInterfaceHook(t *testing.T) { 456 t.Parallel() 457 458 input := map[string]interface{}{ 459 "w": "", 460 } 461 462 decodeHook := func(f, t reflect.Type, v interface{}) (interface{}, error) { 463 if t.String() == "io.Writer" { 464 return nil, nil 465 } 466 467 return v, nil 468 } 469 470 var result NilInterface 471 config := &DecoderConfig{ 472 DecodeHook: decodeHook, 473 Result: &result, 474 } 475 476 decoder, err := NewDecoder(config) 477 if err != nil { 478 t.Fatalf("err: %s", err) 479 } 480 481 err = decoder.Decode(input) 482 if err != nil { 483 t.Fatalf("got an err: %s", err) 484 } 485 486 if result.W != nil { 487 t.Errorf("W should be nil: %#v", result.W) 488 } 489} 490 491func TestDecode_FuncHook(t *testing.T) { 492 t.Parallel() 493 494 input := map[string]interface{}{ 495 "foo": "baz", 496 } 497 498 decodeHook := func(f, t reflect.Type, v interface{}) (interface{}, error) { 499 if t.Kind() != reflect.Func { 500 return v, nil 501 } 502 val := v.(string) 503 return func() string { return val }, nil 504 } 505 506 var result Func 507 config := &DecoderConfig{ 508 DecodeHook: decodeHook, 509 Result: &result, 510 } 511 512 decoder, err := NewDecoder(config) 513 if err != nil { 514 t.Fatalf("err: %s", err) 515 } 516 517 err = decoder.Decode(input) 518 if err != nil { 519 t.Fatalf("got an err: %s", err) 520 } 521 522 if result.Foo() != "baz" { 523 t.Errorf("Foo call result should be 'baz': %s", result.Foo()) 524 } 525} 526 527func TestDecode_NonStruct(t *testing.T) { 528 t.Parallel() 529 530 input := map[string]interface{}{ 531 "foo": "bar", 532 "bar": "baz", 533 } 534 535 var result map[string]string 536 err := Decode(input, &result) 537 if err != nil { 538 t.Fatalf("err: %s", err) 539 } 540 541 if result["foo"] != "bar" { 542 t.Fatal("foo is not bar") 543 } 544} 545 546func TestDecode_StructMatch(t *testing.T) { 547 t.Parallel() 548 549 input := map[string]interface{}{ 550 "vbar": Basic{ 551 Vstring: "foo", 552 }, 553 } 554 555 var result Nested 556 err := Decode(input, &result) 557 if err != nil { 558 t.Fatalf("got an err: %s", err.Error()) 559 } 560 561 if result.Vbar.Vstring != "foo" { 562 t.Errorf("bad: %#v", result) 563 } 564} 565 566func TestDecode_TypeConversion(t *testing.T) { 567 input := map[string]interface{}{ 568 "IntToFloat": 42, 569 "IntToUint": 42, 570 "IntToBool": 1, 571 "IntToString": 42, 572 "UintToInt": 42, 573 "UintToFloat": 42, 574 "UintToBool": 42, 575 "UintToString": 42, 576 "BoolToInt": true, 577 "BoolToUint": true, 578 "BoolToFloat": true, 579 "BoolToString": true, 580 "FloatToInt": 42.42, 581 "FloatToUint": 42.42, 582 "FloatToBool": 42.42, 583 "FloatToString": 42.42, 584 "SliceUint8ToString": []uint8("foo"), 585 "StringToInt": "42", 586 "StringToUint": "42", 587 "StringToBool": "1", 588 "StringToFloat": "42.42", 589 "StringToStrSlice": "A", 590 "StringToIntSlice": "42", 591 "SliceToMap": []interface{}{}, 592 "MapToSlice": map[string]interface{}{}, 593 } 594 595 expectedResultStrict := TypeConversionResult{ 596 IntToFloat: 42.0, 597 IntToUint: 42, 598 UintToInt: 42, 599 UintToFloat: 42, 600 BoolToInt: 0, 601 BoolToUint: 0, 602 BoolToFloat: 0, 603 FloatToInt: 42, 604 FloatToUint: 42, 605 } 606 607 expectedResultWeak := TypeConversionResult{ 608 IntToFloat: 42.0, 609 IntToUint: 42, 610 IntToBool: true, 611 IntToString: "42", 612 UintToInt: 42, 613 UintToFloat: 42, 614 UintToBool: true, 615 UintToString: "42", 616 BoolToInt: 1, 617 BoolToUint: 1, 618 BoolToFloat: 1, 619 BoolToString: "1", 620 FloatToInt: 42, 621 FloatToUint: 42, 622 FloatToBool: true, 623 FloatToString: "42.42", 624 SliceUint8ToString: "foo", 625 StringToInt: 42, 626 StringToUint: 42, 627 StringToBool: true, 628 StringToFloat: 42.42, 629 StringToStrSlice: []string{"A"}, 630 StringToIntSlice: []int{42}, 631 SliceToMap: map[string]interface{}{}, 632 MapToSlice: []interface{}{}, 633 } 634 635 // Test strict type conversion 636 var resultStrict TypeConversionResult 637 err := Decode(input, &resultStrict) 638 if err == nil { 639 t.Errorf("should return an error") 640 } 641 if !reflect.DeepEqual(resultStrict, expectedResultStrict) { 642 t.Errorf("expected %v, got: %v", expectedResultStrict, resultStrict) 643 } 644 645 // Test weak type conversion 646 var decoder *Decoder 647 var resultWeak TypeConversionResult 648 649 config := &DecoderConfig{ 650 WeaklyTypedInput: true, 651 Result: &resultWeak, 652 } 653 654 decoder, err = NewDecoder(config) 655 if err != nil { 656 t.Fatalf("err: %s", err) 657 } 658 659 err = decoder.Decode(input) 660 if err != nil { 661 t.Fatalf("got an err: %s", err) 662 } 663 664 if !reflect.DeepEqual(resultWeak, expectedResultWeak) { 665 t.Errorf("expected \n%#v, got: \n%#v", expectedResultWeak, resultWeak) 666 } 667} 668 669func TestDecoder_ErrorUnused(t *testing.T) { 670 t.Parallel() 671 672 input := map[string]interface{}{ 673 "vstring": "hello", 674 "foo": "bar", 675 } 676 677 var result Basic 678 config := &DecoderConfig{ 679 ErrorUnused: true, 680 Result: &result, 681 } 682 683 decoder, err := NewDecoder(config) 684 if err != nil { 685 t.Fatalf("err: %s", err) 686 } 687 688 err = decoder.Decode(input) 689 if err == nil { 690 t.Fatal("expected error") 691 } 692} 693 694func TestMap(t *testing.T) { 695 t.Parallel() 696 697 input := map[string]interface{}{ 698 "vfoo": "foo", 699 "vother": map[interface{}]interface{}{ 700 "foo": "foo", 701 "bar": "bar", 702 }, 703 } 704 705 var result Map 706 err := Decode(input, &result) 707 if err != nil { 708 t.Fatalf("got an error: %s", err) 709 } 710 711 if result.Vfoo != "foo" { 712 t.Errorf("vfoo value should be 'foo': %#v", result.Vfoo) 713 } 714 715 if result.Vother == nil { 716 t.Fatal("vother should not be nil") 717 } 718 719 if len(result.Vother) != 2 { 720 t.Error("vother should have two items") 721 } 722 723 if result.Vother["foo"] != "foo" { 724 t.Errorf("'foo' key should be foo, got: %#v", result.Vother["foo"]) 725 } 726 727 if result.Vother["bar"] != "bar" { 728 t.Errorf("'bar' key should be bar, got: %#v", result.Vother["bar"]) 729 } 730} 731 732func TestMapMerge(t *testing.T) { 733 t.Parallel() 734 735 input := map[string]interface{}{ 736 "vfoo": "foo", 737 "vother": map[interface{}]interface{}{ 738 "foo": "foo", 739 "bar": "bar", 740 }, 741 } 742 743 var result Map 744 result.Vother = map[string]string{"hello": "world"} 745 err := Decode(input, &result) 746 if err != nil { 747 t.Fatalf("got an error: %s", err) 748 } 749 750 if result.Vfoo != "foo" { 751 t.Errorf("vfoo value should be 'foo': %#v", result.Vfoo) 752 } 753 754 expected := map[string]string{ 755 "foo": "foo", 756 "bar": "bar", 757 "hello": "world", 758 } 759 if !reflect.DeepEqual(result.Vother, expected) { 760 t.Errorf("bad: %#v", result.Vother) 761 } 762} 763 764func TestMapOfStruct(t *testing.T) { 765 t.Parallel() 766 767 input := map[string]interface{}{ 768 "value": map[string]interface{}{ 769 "foo": map[string]string{"vstring": "one"}, 770 "bar": map[string]string{"vstring": "two"}, 771 }, 772 } 773 774 var result MapOfStruct 775 err := Decode(input, &result) 776 if err != nil { 777 t.Fatalf("got an err: %s", err) 778 } 779 780 if result.Value == nil { 781 t.Fatal("value should not be nil") 782 } 783 784 if len(result.Value) != 2 { 785 t.Error("value should have two items") 786 } 787 788 if result.Value["foo"].Vstring != "one" { 789 t.Errorf("foo value should be 'one', got: %s", result.Value["foo"].Vstring) 790 } 791 792 if result.Value["bar"].Vstring != "two" { 793 t.Errorf("bar value should be 'two', got: %s", result.Value["bar"].Vstring) 794 } 795} 796 797func TestNestedType(t *testing.T) { 798 t.Parallel() 799 800 input := map[string]interface{}{ 801 "vfoo": "foo", 802 "vbar": map[string]interface{}{ 803 "vstring": "foo", 804 "vint": 42, 805 "vbool": true, 806 }, 807 } 808 809 var result Nested 810 err := Decode(input, &result) 811 if err != nil { 812 t.Fatalf("got an err: %s", err.Error()) 813 } 814 815 if result.Vfoo != "foo" { 816 t.Errorf("vfoo value should be 'foo': %#v", result.Vfoo) 817 } 818 819 if result.Vbar.Vstring != "foo" { 820 t.Errorf("vstring value should be 'foo': %#v", result.Vbar.Vstring) 821 } 822 823 if result.Vbar.Vint != 42 { 824 t.Errorf("vint value should be 42: %#v", result.Vbar.Vint) 825 } 826 827 if result.Vbar.Vbool != true { 828 t.Errorf("vbool value should be true: %#v", result.Vbar.Vbool) 829 } 830 831 if result.Vbar.Vextra != "" { 832 t.Errorf("vextra value should be empty: %#v", result.Vbar.Vextra) 833 } 834} 835 836func TestNestedTypePointer(t *testing.T) { 837 t.Parallel() 838 839 input := map[string]interface{}{ 840 "vfoo": "foo", 841 "vbar": &map[string]interface{}{ 842 "vstring": "foo", 843 "vint": 42, 844 "vbool": true, 845 }, 846 } 847 848 var result NestedPointer 849 err := Decode(input, &result) 850 if err != nil { 851 t.Fatalf("got an err: %s", err.Error()) 852 } 853 854 if result.Vfoo != "foo" { 855 t.Errorf("vfoo value should be 'foo': %#v", result.Vfoo) 856 } 857 858 if result.Vbar.Vstring != "foo" { 859 t.Errorf("vstring value should be 'foo': %#v", result.Vbar.Vstring) 860 } 861 862 if result.Vbar.Vint != 42 { 863 t.Errorf("vint value should be 42: %#v", result.Vbar.Vint) 864 } 865 866 if result.Vbar.Vbool != true { 867 t.Errorf("vbool value should be true: %#v", result.Vbar.Vbool) 868 } 869 870 if result.Vbar.Vextra != "" { 871 t.Errorf("vextra value should be empty: %#v", result.Vbar.Vextra) 872 } 873} 874 875func TestSlice(t *testing.T) { 876 t.Parallel() 877 878 inputStringSlice := map[string]interface{}{ 879 "vfoo": "foo", 880 "vbar": []string{"foo", "bar", "baz"}, 881 } 882 883 inputStringSlicePointer := map[string]interface{}{ 884 "vfoo": "foo", 885 "vbar": &[]string{"foo", "bar", "baz"}, 886 } 887 888 outputStringSlice := &Slice{ 889 "foo", 890 []string{"foo", "bar", "baz"}, 891 } 892 893 testSliceInput(t, inputStringSlice, outputStringSlice) 894 testSliceInput(t, inputStringSlicePointer, outputStringSlice) 895} 896 897func TestInvalidSlice(t *testing.T) { 898 t.Parallel() 899 900 input := map[string]interface{}{ 901 "vfoo": "foo", 902 "vbar": 42, 903 } 904 905 result := Slice{} 906 err := Decode(input, &result) 907 if err == nil { 908 t.Errorf("expected failure") 909 } 910} 911 912func TestSliceOfStruct(t *testing.T) { 913 t.Parallel() 914 915 input := map[string]interface{}{ 916 "value": []map[string]interface{}{ 917 {"vstring": "one"}, 918 {"vstring": "two"}, 919 }, 920 } 921 922 var result SliceOfStruct 923 err := Decode(input, &result) 924 if err != nil { 925 t.Fatalf("got unexpected error: %s", err) 926 } 927 928 if len(result.Value) != 2 { 929 t.Fatalf("expected two values, got %d", len(result.Value)) 930 } 931 932 if result.Value[0].Vstring != "one" { 933 t.Errorf("first value should be 'one', got: %s", result.Value[0].Vstring) 934 } 935 936 if result.Value[1].Vstring != "two" { 937 t.Errorf("second value should be 'two', got: %s", result.Value[1].Vstring) 938 } 939} 940 941func TestSliceToMap(t *testing.T) { 942 t.Parallel() 943 944 input := []map[string]interface{}{ 945 { 946 "foo": "bar", 947 }, 948 { 949 "bar": "baz", 950 }, 951 } 952 953 var result map[string]interface{} 954 err := WeakDecode(input, &result) 955 if err != nil { 956 t.Fatalf("got an error: %s", err) 957 } 958 959 expected := map[string]interface{}{ 960 "foo": "bar", 961 "bar": "baz", 962 } 963 if !reflect.DeepEqual(result, expected) { 964 t.Errorf("bad: %#v", result) 965 } 966} 967 968func TestInvalidType(t *testing.T) { 969 t.Parallel() 970 971 input := map[string]interface{}{ 972 "vstring": 42, 973 } 974 975 var result Basic 976 err := Decode(input, &result) 977 if err == nil { 978 t.Fatal("error should exist") 979 } 980 981 derr, ok := err.(*Error) 982 if !ok { 983 t.Fatalf("error should be kind of Error, instead: %#v", err) 984 } 985 986 if derr.Errors[0] != "'Vstring' expected type 'string', got unconvertible type 'int'" { 987 t.Errorf("got unexpected error: %s", err) 988 } 989 990 inputNegIntUint := map[string]interface{}{ 991 "vuint": -42, 992 } 993 994 err = Decode(inputNegIntUint, &result) 995 if err == nil { 996 t.Fatal("error should exist") 997 } 998 999 derr, ok = err.(*Error) 1000 if !ok { 1001 t.Fatalf("error should be kind of Error, instead: %#v", err) 1002 } 1003 1004 if derr.Errors[0] != "cannot parse 'Vuint', -42 overflows uint" { 1005 t.Errorf("got unexpected error: %s", err) 1006 } 1007 1008 inputNegFloatUint := map[string]interface{}{ 1009 "vuint": -42.0, 1010 } 1011 1012 err = Decode(inputNegFloatUint, &result) 1013 if err == nil { 1014 t.Fatal("error should exist") 1015 } 1016 1017 derr, ok = err.(*Error) 1018 if !ok { 1019 t.Fatalf("error should be kind of Error, instead: %#v", err) 1020 } 1021 1022 if derr.Errors[0] != "cannot parse 'Vuint', -42.000000 overflows uint" { 1023 t.Errorf("got unexpected error: %s", err) 1024 } 1025} 1026 1027func TestMetadata(t *testing.T) { 1028 t.Parallel() 1029 1030 input := map[string]interface{}{ 1031 "vfoo": "foo", 1032 "vbar": map[string]interface{}{ 1033 "vstring": "foo", 1034 "Vuint": 42, 1035 "foo": "bar", 1036 }, 1037 "bar": "nil", 1038 } 1039 1040 var md Metadata 1041 var result Nested 1042 config := &DecoderConfig{ 1043 Metadata: &md, 1044 Result: &result, 1045 } 1046 1047 decoder, err := NewDecoder(config) 1048 if err != nil { 1049 t.Fatalf("err: %s", err) 1050 } 1051 1052 err = decoder.Decode(input) 1053 if err != nil { 1054 t.Fatalf("err: %s", err.Error()) 1055 } 1056 1057 expectedKeys := []string{"Vbar", "Vbar.Vstring", "Vbar.Vuint", "Vfoo"} 1058 sort.Strings(md.Keys) 1059 if !reflect.DeepEqual(md.Keys, expectedKeys) { 1060 t.Fatalf("bad keys: %#v", md.Keys) 1061 } 1062 1063 expectedUnused := []string{"Vbar.foo", "bar"} 1064 if !reflect.DeepEqual(md.Unused, expectedUnused) { 1065 t.Fatalf("bad unused: %#v", md.Unused) 1066 } 1067} 1068 1069func TestMetadata_Embedded(t *testing.T) { 1070 t.Parallel() 1071 1072 input := map[string]interface{}{ 1073 "vstring": "foo", 1074 "vunique": "bar", 1075 } 1076 1077 var md Metadata 1078 var result EmbeddedSquash 1079 config := &DecoderConfig{ 1080 Metadata: &md, 1081 Result: &result, 1082 } 1083 1084 decoder, err := NewDecoder(config) 1085 if err != nil { 1086 t.Fatalf("err: %s", err) 1087 } 1088 1089 err = decoder.Decode(input) 1090 if err != nil { 1091 t.Fatalf("err: %s", err.Error()) 1092 } 1093 1094 expectedKeys := []string{"Vstring", "Vunique"} 1095 1096 sort.Strings(md.Keys) 1097 if !reflect.DeepEqual(md.Keys, expectedKeys) { 1098 t.Fatalf("bad keys: %#v", md.Keys) 1099 } 1100 1101 expectedUnused := []string{} 1102 if !reflect.DeepEqual(md.Unused, expectedUnused) { 1103 t.Fatalf("bad unused: %#v", md.Unused) 1104 } 1105} 1106 1107func TestNonPtrValue(t *testing.T) { 1108 t.Parallel() 1109 1110 err := Decode(map[string]interface{}{}, Basic{}) 1111 if err == nil { 1112 t.Fatal("error should exist") 1113 } 1114 1115 if err.Error() != "result must be a pointer" { 1116 t.Errorf("got unexpected error: %s", err) 1117 } 1118} 1119 1120func TestTagged(t *testing.T) { 1121 t.Parallel() 1122 1123 input := map[string]interface{}{ 1124 "foo": "bar", 1125 "bar": "value", 1126 } 1127 1128 var result Tagged 1129 err := Decode(input, &result) 1130 if err != nil { 1131 t.Fatalf("unexpected error: %s", err) 1132 } 1133 1134 if result.Value != "bar" { 1135 t.Errorf("value should be 'bar', got: %#v", result.Value) 1136 } 1137 1138 if result.Extra != "value" { 1139 t.Errorf("extra should be 'value', got: %#v", result.Extra) 1140 } 1141} 1142 1143func TestWeakDecode(t *testing.T) { 1144 t.Parallel() 1145 1146 input := map[string]interface{}{ 1147 "foo": "4", 1148 "bar": "value", 1149 } 1150 1151 var result struct { 1152 Foo int 1153 Bar string 1154 } 1155 1156 if err := WeakDecode(input, &result); err != nil { 1157 t.Fatalf("err: %s", err) 1158 } 1159 if result.Foo != 4 { 1160 t.Fatalf("bad: %#v", result) 1161 } 1162 if result.Bar != "value" { 1163 t.Fatalf("bad: %#v", result) 1164 } 1165} 1166 1167func testSliceInput(t *testing.T, input map[string]interface{}, expected *Slice) { 1168 var result Slice 1169 err := Decode(input, &result) 1170 if err != nil { 1171 t.Fatalf("got error: %s", err) 1172 } 1173 1174 if result.Vfoo != expected.Vfoo { 1175 t.Errorf("Vfoo expected '%s', got '%s'", expected.Vfoo, result.Vfoo) 1176 } 1177 1178 if result.Vbar == nil { 1179 t.Fatalf("Vbar a slice, got '%#v'", result.Vbar) 1180 } 1181 1182 if len(result.Vbar) != len(expected.Vbar) { 1183 t.Errorf("Vbar length should be %d, got %d", len(expected.Vbar), len(result.Vbar)) 1184 } 1185 1186 for i, v := range result.Vbar { 1187 if v != expected.Vbar[i] { 1188 t.Errorf( 1189 "Vbar[%d] should be '%#v', got '%#v'", 1190 i, expected.Vbar[i], v) 1191 } 1192 } 1193} 1194