|  | package mapstructure | 
|  |  | 
|  | import ( | 
|  | "encoding/json" | 
|  | "io" | 
|  | "reflect" | 
|  | "sort" | 
|  | "strings" | 
|  | "testing" | 
|  | ) | 
|  |  | 
|  | type Basic struct { | 
|  | Vstring     string | 
|  | Vint        int | 
|  | Vuint       uint | 
|  | Vbool       bool | 
|  | Vfloat      float64 | 
|  | Vextra      string | 
|  | vsilent     bool | 
|  | Vdata       interface{} | 
|  | VjsonInt    int | 
|  | VjsonFloat  float64 | 
|  | VjsonNumber json.Number | 
|  | } | 
|  |  | 
|  | type BasicSquash struct { | 
|  | Test Basic `mapstructure:",squash"` | 
|  | } | 
|  |  | 
|  | type Embedded struct { | 
|  | Basic | 
|  | Vunique string | 
|  | } | 
|  |  | 
|  | type EmbeddedPointer struct { | 
|  | *Basic | 
|  | Vunique string | 
|  | } | 
|  |  | 
|  | type EmbeddedSquash struct { | 
|  | Basic   `mapstructure:",squash"` | 
|  | Vunique string | 
|  | } | 
|  |  | 
|  | type SliceAlias []string | 
|  |  | 
|  | type EmbeddedSlice struct { | 
|  | SliceAlias `mapstructure:"slice_alias"` | 
|  | Vunique    string | 
|  | } | 
|  |  | 
|  | type SquashOnNonStructType struct { | 
|  | InvalidSquashType int `mapstructure:",squash"` | 
|  | } | 
|  |  | 
|  | type Map struct { | 
|  | Vfoo   string | 
|  | Vother map[string]string | 
|  | } | 
|  |  | 
|  | type MapOfStruct struct { | 
|  | Value map[string]Basic | 
|  | } | 
|  |  | 
|  | type Nested struct { | 
|  | Vfoo string | 
|  | Vbar Basic | 
|  | } | 
|  |  | 
|  | type NestedPointer struct { | 
|  | Vfoo string | 
|  | Vbar *Basic | 
|  | } | 
|  |  | 
|  | type NilInterface struct { | 
|  | W io.Writer | 
|  | } | 
|  |  | 
|  | type Slice struct { | 
|  | Vfoo string | 
|  | Vbar []string | 
|  | } | 
|  |  | 
|  | type SliceOfStruct struct { | 
|  | Value []Basic | 
|  | } | 
|  |  | 
|  | type Func struct { | 
|  | Foo func() string | 
|  | } | 
|  |  | 
|  | type Tagged struct { | 
|  | Extra string `mapstructure:"bar,what,what"` | 
|  | Value string `mapstructure:"foo"` | 
|  | } | 
|  |  | 
|  | type TypeConversionResult struct { | 
|  | IntToFloat         float32 | 
|  | IntToUint          uint | 
|  | IntToBool          bool | 
|  | IntToString        string | 
|  | UintToInt          int | 
|  | UintToFloat        float32 | 
|  | UintToBool         bool | 
|  | UintToString       string | 
|  | BoolToInt          int | 
|  | BoolToUint         uint | 
|  | BoolToFloat        float32 | 
|  | BoolToString       string | 
|  | FloatToInt         int | 
|  | FloatToUint        uint | 
|  | FloatToBool        bool | 
|  | FloatToString      string | 
|  | SliceUint8ToString string | 
|  | StringToInt        int | 
|  | StringToUint       uint | 
|  | StringToBool       bool | 
|  | StringToFloat      float32 | 
|  | SliceToMap         map[string]interface{} | 
|  | MapToSlice         []interface{} | 
|  | } | 
|  |  | 
|  | func TestBasicTypes(t *testing.T) { | 
|  | t.Parallel() | 
|  |  | 
|  | input := map[string]interface{}{ | 
|  | "vstring":     "foo", | 
|  | "vint":        42, | 
|  | "Vuint":       42, | 
|  | "vbool":       true, | 
|  | "Vfloat":      42.42, | 
|  | "vsilent":     true, | 
|  | "vdata":       42, | 
|  | "vjsonInt":    json.Number("1234"), | 
|  | "vjsonFloat":  json.Number("1234.5"), | 
|  | "vjsonNumber": json.Number("1234.5"), | 
|  | } | 
|  |  | 
|  | var result Basic | 
|  | err := Decode(input, &result) | 
|  | if err != nil { | 
|  | t.Errorf("got an err: %s", err.Error()) | 
|  | t.FailNow() | 
|  | } | 
|  |  | 
|  | if result.Vstring != "foo" { | 
|  | t.Errorf("vstring value should be 'foo': %#v", result.Vstring) | 
|  | } | 
|  |  | 
|  | if result.Vint != 42 { | 
|  | t.Errorf("vint value should be 42: %#v", result.Vint) | 
|  | } | 
|  |  | 
|  | if result.Vuint != 42 { | 
|  | t.Errorf("vuint value should be 42: %#v", result.Vuint) | 
|  | } | 
|  |  | 
|  | if result.Vbool != true { | 
|  | t.Errorf("vbool value should be true: %#v", result.Vbool) | 
|  | } | 
|  |  | 
|  | if result.Vfloat != 42.42 { | 
|  | t.Errorf("vfloat value should be 42.42: %#v", result.Vfloat) | 
|  | } | 
|  |  | 
|  | if result.Vextra != "" { | 
|  | t.Errorf("vextra value should be empty: %#v", result.Vextra) | 
|  | } | 
|  |  | 
|  | if result.vsilent != false { | 
|  | t.Error("vsilent should not be set, it is unexported") | 
|  | } | 
|  |  | 
|  | if result.Vdata != 42 { | 
|  | t.Error("vdata should be valid") | 
|  | } | 
|  |  | 
|  | if result.VjsonInt != 1234 { | 
|  | t.Errorf("vjsonint value should be 1234: %#v", result.VjsonInt) | 
|  | } | 
|  |  | 
|  | if result.VjsonFloat != 1234.5 { | 
|  | t.Errorf("vjsonfloat value should be 1234.5: %#v", result.VjsonFloat) | 
|  | } | 
|  |  | 
|  | if !reflect.DeepEqual(result.VjsonNumber, json.Number("1234.5")) { | 
|  | t.Errorf("vjsonnumber value should be '1234.5': %T, %#v", result.VjsonNumber, result.VjsonNumber) | 
|  | } | 
|  | } | 
|  |  | 
|  | func TestBasic_IntWithFloat(t *testing.T) { | 
|  | t.Parallel() | 
|  |  | 
|  | input := map[string]interface{}{ | 
|  | "vint": float64(42), | 
|  | } | 
|  |  | 
|  | var result Basic | 
|  | err := Decode(input, &result) | 
|  | if err != nil { | 
|  | t.Fatalf("got an err: %s", err) | 
|  | } | 
|  | } | 
|  |  | 
|  | func TestBasic_Merge(t *testing.T) { | 
|  | t.Parallel() | 
|  |  | 
|  | input := map[string]interface{}{ | 
|  | "vint": 42, | 
|  | } | 
|  |  | 
|  | var result Basic | 
|  | result.Vuint = 100 | 
|  | err := Decode(input, &result) | 
|  | if err != nil { | 
|  | t.Fatalf("got an err: %s", err) | 
|  | } | 
|  |  | 
|  | expected := Basic{ | 
|  | Vint:  42, | 
|  | Vuint: 100, | 
|  | } | 
|  | if !reflect.DeepEqual(result, expected) { | 
|  | t.Fatalf("bad: %#v", result) | 
|  | } | 
|  | } | 
|  |  | 
|  | func TestDecode_BasicSquash(t *testing.T) { | 
|  | t.Parallel() | 
|  |  | 
|  | input := map[string]interface{}{ | 
|  | "vstring": "foo", | 
|  | } | 
|  |  | 
|  | var result BasicSquash | 
|  | err := Decode(input, &result) | 
|  | if err != nil { | 
|  | t.Fatalf("got an err: %s", err.Error()) | 
|  | } | 
|  |  | 
|  | if result.Test.Vstring != "foo" { | 
|  | t.Errorf("vstring value should be 'foo': %#v", result.Test.Vstring) | 
|  | } | 
|  | } | 
|  |  | 
|  | func TestDecode_Embedded(t *testing.T) { | 
|  | t.Parallel() | 
|  |  | 
|  | input := map[string]interface{}{ | 
|  | "vstring": "foo", | 
|  | "Basic": map[string]interface{}{ | 
|  | "vstring": "innerfoo", | 
|  | }, | 
|  | "vunique": "bar", | 
|  | } | 
|  |  | 
|  | var result Embedded | 
|  | err := Decode(input, &result) | 
|  | if err != nil { | 
|  | t.Fatalf("got an err: %s", err.Error()) | 
|  | } | 
|  |  | 
|  | if result.Vstring != "innerfoo" { | 
|  | t.Errorf("vstring value should be 'innerfoo': %#v", result.Vstring) | 
|  | } | 
|  |  | 
|  | if result.Vunique != "bar" { | 
|  | t.Errorf("vunique value should be 'bar': %#v", result.Vunique) | 
|  | } | 
|  | } | 
|  |  | 
|  | func TestDecode_EmbeddedPointer(t *testing.T) { | 
|  | t.Parallel() | 
|  |  | 
|  | input := map[string]interface{}{ | 
|  | "vstring": "foo", | 
|  | "Basic": map[string]interface{}{ | 
|  | "vstring": "innerfoo", | 
|  | }, | 
|  | "vunique": "bar", | 
|  | } | 
|  |  | 
|  | var result EmbeddedPointer | 
|  | err := Decode(input, &result) | 
|  | if err != nil { | 
|  | t.Fatalf("err: %s", err) | 
|  | } | 
|  |  | 
|  | expected := EmbeddedPointer{ | 
|  | Basic: &Basic{ | 
|  | Vstring: "innerfoo", | 
|  | }, | 
|  | Vunique: "bar", | 
|  | } | 
|  | if !reflect.DeepEqual(result, expected) { | 
|  | t.Fatalf("bad: %#v", result) | 
|  | } | 
|  | } | 
|  |  | 
|  | func TestDecode_EmbeddedSlice(t *testing.T) { | 
|  | t.Parallel() | 
|  |  | 
|  | input := map[string]interface{}{ | 
|  | "slice_alias": []string{"foo", "bar"}, | 
|  | "vunique":     "bar", | 
|  | } | 
|  |  | 
|  | var result EmbeddedSlice | 
|  | err := Decode(input, &result) | 
|  | if err != nil { | 
|  | t.Fatalf("got an err: %s", err.Error()) | 
|  | } | 
|  |  | 
|  | if !reflect.DeepEqual(result.SliceAlias, SliceAlias([]string{"foo", "bar"})) { | 
|  | t.Errorf("slice value: %#v", result.SliceAlias) | 
|  | } | 
|  |  | 
|  | if result.Vunique != "bar" { | 
|  | t.Errorf("vunique value should be 'bar': %#v", result.Vunique) | 
|  | } | 
|  | } | 
|  |  | 
|  | func TestDecode_EmbeddedSquash(t *testing.T) { | 
|  | t.Parallel() | 
|  |  | 
|  | input := map[string]interface{}{ | 
|  | "vstring": "foo", | 
|  | "vunique": "bar", | 
|  | } | 
|  |  | 
|  | var result EmbeddedSquash | 
|  | err := Decode(input, &result) | 
|  | if err != nil { | 
|  | t.Fatalf("got an err: %s", err.Error()) | 
|  | } | 
|  |  | 
|  | if result.Vstring != "foo" { | 
|  | t.Errorf("vstring value should be 'foo': %#v", result.Vstring) | 
|  | } | 
|  |  | 
|  | if result.Vunique != "bar" { | 
|  | t.Errorf("vunique value should be 'bar': %#v", result.Vunique) | 
|  | } | 
|  | } | 
|  |  | 
|  | func TestDecode_SquashOnNonStructType(t *testing.T) { | 
|  | t.Parallel() | 
|  |  | 
|  | input := map[string]interface{}{ | 
|  | "InvalidSquashType": 42, | 
|  | } | 
|  |  | 
|  | var result SquashOnNonStructType | 
|  | err := Decode(input, &result) | 
|  | if err == nil { | 
|  | t.Fatal("unexpected success decoding invalid squash field type") | 
|  | } else if !strings.Contains(err.Error(), "unsupported type for squash") { | 
|  | t.Fatalf("unexpected error message for invalid squash field type: %s", err) | 
|  | } | 
|  | } | 
|  |  | 
|  | func TestDecode_DecodeHook(t *testing.T) { | 
|  | t.Parallel() | 
|  |  | 
|  | input := map[string]interface{}{ | 
|  | "vint": "WHAT", | 
|  | } | 
|  |  | 
|  | decodeHook := func(from reflect.Kind, to reflect.Kind, v interface{}) (interface{}, error) { | 
|  | if from == reflect.String && to != reflect.String { | 
|  | return 5, nil | 
|  | } | 
|  |  | 
|  | return v, nil | 
|  | } | 
|  |  | 
|  | var result Basic | 
|  | config := &DecoderConfig{ | 
|  | DecodeHook: decodeHook, | 
|  | Result:     &result, | 
|  | } | 
|  |  | 
|  | decoder, err := NewDecoder(config) | 
|  | if err != nil { | 
|  | t.Fatalf("err: %s", err) | 
|  | } | 
|  |  | 
|  | err = decoder.Decode(input) | 
|  | if err != nil { | 
|  | t.Fatalf("got an err: %s", err) | 
|  | } | 
|  |  | 
|  | if result.Vint != 5 { | 
|  | t.Errorf("vint should be 5: %#v", result.Vint) | 
|  | } | 
|  | } | 
|  |  | 
|  | func TestDecode_DecodeHookType(t *testing.T) { | 
|  | t.Parallel() | 
|  |  | 
|  | input := map[string]interface{}{ | 
|  | "vint": "WHAT", | 
|  | } | 
|  |  | 
|  | decodeHook := func(from reflect.Type, to reflect.Type, v interface{}) (interface{}, error) { | 
|  | if from.Kind() == reflect.String && | 
|  | to.Kind() != reflect.String { | 
|  | return 5, nil | 
|  | } | 
|  |  | 
|  | return v, nil | 
|  | } | 
|  |  | 
|  | var result Basic | 
|  | config := &DecoderConfig{ | 
|  | DecodeHook: decodeHook, | 
|  | Result:     &result, | 
|  | } | 
|  |  | 
|  | decoder, err := NewDecoder(config) | 
|  | if err != nil { | 
|  | t.Fatalf("err: %s", err) | 
|  | } | 
|  |  | 
|  | err = decoder.Decode(input) | 
|  | if err != nil { | 
|  | t.Fatalf("got an err: %s", err) | 
|  | } | 
|  |  | 
|  | if result.Vint != 5 { | 
|  | t.Errorf("vint should be 5: %#v", result.Vint) | 
|  | } | 
|  | } | 
|  |  | 
|  | func TestDecode_Nil(t *testing.T) { | 
|  | t.Parallel() | 
|  |  | 
|  | var input interface{} = nil | 
|  | result := Basic{ | 
|  | Vstring: "foo", | 
|  | } | 
|  |  | 
|  | err := Decode(input, &result) | 
|  | if err != nil { | 
|  | t.Fatalf("err: %s", err) | 
|  | } | 
|  |  | 
|  | if result.Vstring != "foo" { | 
|  | t.Fatalf("bad: %#v", result.Vstring) | 
|  | } | 
|  | } | 
|  |  | 
|  | func TestDecode_NilInterfaceHook(t *testing.T) { | 
|  | t.Parallel() | 
|  |  | 
|  | input := map[string]interface{}{ | 
|  | "w": "", | 
|  | } | 
|  |  | 
|  | decodeHook := func(f, t reflect.Type, v interface{}) (interface{}, error) { | 
|  | if t.String() == "io.Writer" { | 
|  | return nil, nil | 
|  | } | 
|  |  | 
|  | return v, nil | 
|  | } | 
|  |  | 
|  | var result NilInterface | 
|  | config := &DecoderConfig{ | 
|  | DecodeHook: decodeHook, | 
|  | Result:     &result, | 
|  | } | 
|  |  | 
|  | decoder, err := NewDecoder(config) | 
|  | if err != nil { | 
|  | t.Fatalf("err: %s", err) | 
|  | } | 
|  |  | 
|  | err = decoder.Decode(input) | 
|  | if err != nil { | 
|  | t.Fatalf("got an err: %s", err) | 
|  | } | 
|  |  | 
|  | if result.W != nil { | 
|  | t.Errorf("W should be nil: %#v", result.W) | 
|  | } | 
|  | } | 
|  |  | 
|  | func TestDecode_FuncHook(t *testing.T) { | 
|  | t.Parallel() | 
|  |  | 
|  | input := map[string]interface{}{ | 
|  | "foo": "baz", | 
|  | } | 
|  |  | 
|  | decodeHook := func(f, t reflect.Type, v interface{}) (interface{}, error) { | 
|  | if t.Kind() != reflect.Func { | 
|  | return v, nil | 
|  | } | 
|  | val := v.(string) | 
|  | return func() string { return val }, nil | 
|  | } | 
|  |  | 
|  | var result Func | 
|  | config := &DecoderConfig{ | 
|  | DecodeHook: decodeHook, | 
|  | Result:     &result, | 
|  | } | 
|  |  | 
|  | decoder, err := NewDecoder(config) | 
|  | if err != nil { | 
|  | t.Fatalf("err: %s", err) | 
|  | } | 
|  |  | 
|  | err = decoder.Decode(input) | 
|  | if err != nil { | 
|  | t.Fatalf("got an err: %s", err) | 
|  | } | 
|  |  | 
|  | if result.Foo() != "baz" { | 
|  | t.Errorf("Foo call result should be 'baz': %s", result.Foo()) | 
|  | } | 
|  | } | 
|  |  | 
|  | func TestDecode_NonStruct(t *testing.T) { | 
|  | t.Parallel() | 
|  |  | 
|  | input := map[string]interface{}{ | 
|  | "foo": "bar", | 
|  | "bar": "baz", | 
|  | } | 
|  |  | 
|  | var result map[string]string | 
|  | err := Decode(input, &result) | 
|  | if err != nil { | 
|  | t.Fatalf("err: %s", err) | 
|  | } | 
|  |  | 
|  | if result["foo"] != "bar" { | 
|  | t.Fatal("foo is not bar") | 
|  | } | 
|  | } | 
|  |  | 
|  | func TestDecode_StructMatch(t *testing.T) { | 
|  | t.Parallel() | 
|  |  | 
|  | input := map[string]interface{}{ | 
|  | "vbar": Basic{ | 
|  | Vstring: "foo", | 
|  | }, | 
|  | } | 
|  |  | 
|  | var result Nested | 
|  | err := Decode(input, &result) | 
|  | if err != nil { | 
|  | t.Fatalf("got an err: %s", err.Error()) | 
|  | } | 
|  |  | 
|  | if result.Vbar.Vstring != "foo" { | 
|  | t.Errorf("bad: %#v", result) | 
|  | } | 
|  | } | 
|  |  | 
|  | func TestDecode_TypeConversion(t *testing.T) { | 
|  | input := map[string]interface{}{ | 
|  | "IntToFloat":         42, | 
|  | "IntToUint":          42, | 
|  | "IntToBool":          1, | 
|  | "IntToString":        42, | 
|  | "UintToInt":          42, | 
|  | "UintToFloat":        42, | 
|  | "UintToBool":         42, | 
|  | "UintToString":       42, | 
|  | "BoolToInt":          true, | 
|  | "BoolToUint":         true, | 
|  | "BoolToFloat":        true, | 
|  | "BoolToString":       true, | 
|  | "FloatToInt":         42.42, | 
|  | "FloatToUint":        42.42, | 
|  | "FloatToBool":        42.42, | 
|  | "FloatToString":      42.42, | 
|  | "SliceUint8ToString": []uint8("foo"), | 
|  | "StringToInt":        "42", | 
|  | "StringToUint":       "42", | 
|  | "StringToBool":       "1", | 
|  | "StringToFloat":      "42.42", | 
|  | "SliceToMap":         []interface{}{}, | 
|  | "MapToSlice":         map[string]interface{}{}, | 
|  | } | 
|  |  | 
|  | expectedResultStrict := TypeConversionResult{ | 
|  | IntToFloat:  42.0, | 
|  | IntToUint:   42, | 
|  | UintToInt:   42, | 
|  | UintToFloat: 42, | 
|  | BoolToInt:   0, | 
|  | BoolToUint:  0, | 
|  | BoolToFloat: 0, | 
|  | FloatToInt:  42, | 
|  | FloatToUint: 42, | 
|  | } | 
|  |  | 
|  | expectedResultWeak := TypeConversionResult{ | 
|  | IntToFloat:         42.0, | 
|  | IntToUint:          42, | 
|  | IntToBool:          true, | 
|  | IntToString:        "42", | 
|  | UintToInt:          42, | 
|  | UintToFloat:        42, | 
|  | UintToBool:         true, | 
|  | UintToString:       "42", | 
|  | BoolToInt:          1, | 
|  | BoolToUint:         1, | 
|  | BoolToFloat:        1, | 
|  | BoolToString:       "1", | 
|  | FloatToInt:         42, | 
|  | FloatToUint:        42, | 
|  | FloatToBool:        true, | 
|  | FloatToString:      "42.42", | 
|  | SliceUint8ToString: "foo", | 
|  | StringToInt:        42, | 
|  | StringToUint:       42, | 
|  | StringToBool:       true, | 
|  | StringToFloat:      42.42, | 
|  | SliceToMap:         map[string]interface{}{}, | 
|  | MapToSlice:         []interface{}{}, | 
|  | } | 
|  |  | 
|  | // Test strict type conversion | 
|  | var resultStrict TypeConversionResult | 
|  | err := Decode(input, &resultStrict) | 
|  | if err == nil { | 
|  | t.Errorf("should return an error") | 
|  | } | 
|  | if !reflect.DeepEqual(resultStrict, expectedResultStrict) { | 
|  | t.Errorf("expected %v, got: %v", expectedResultStrict, resultStrict) | 
|  | } | 
|  |  | 
|  | // Test weak type conversion | 
|  | var decoder *Decoder | 
|  | var resultWeak TypeConversionResult | 
|  |  | 
|  | config := &DecoderConfig{ | 
|  | WeaklyTypedInput: true, | 
|  | Result:           &resultWeak, | 
|  | } | 
|  |  | 
|  | decoder, err = NewDecoder(config) | 
|  | if err != nil { | 
|  | t.Fatalf("err: %s", err) | 
|  | } | 
|  |  | 
|  | err = decoder.Decode(input) | 
|  | if err != nil { | 
|  | t.Fatalf("got an err: %s", err) | 
|  | } | 
|  |  | 
|  | if !reflect.DeepEqual(resultWeak, expectedResultWeak) { | 
|  | t.Errorf("expected \n%#v, got: \n%#v", expectedResultWeak, resultWeak) | 
|  | } | 
|  | } | 
|  |  | 
|  | func TestDecoder_ErrorUnused(t *testing.T) { | 
|  | t.Parallel() | 
|  |  | 
|  | input := map[string]interface{}{ | 
|  | "vstring": "hello", | 
|  | "foo":     "bar", | 
|  | } | 
|  |  | 
|  | var result Basic | 
|  | config := &DecoderConfig{ | 
|  | ErrorUnused: true, | 
|  | Result:      &result, | 
|  | } | 
|  |  | 
|  | decoder, err := NewDecoder(config) | 
|  | if err != nil { | 
|  | t.Fatalf("err: %s", err) | 
|  | } | 
|  |  | 
|  | err = decoder.Decode(input) | 
|  | if err == nil { | 
|  | t.Fatal("expected error") | 
|  | } | 
|  | } | 
|  |  | 
|  | func TestMap(t *testing.T) { | 
|  | t.Parallel() | 
|  |  | 
|  | input := map[string]interface{}{ | 
|  | "vfoo": "foo", | 
|  | "vother": map[interface{}]interface{}{ | 
|  | "foo": "foo", | 
|  | "bar": "bar", | 
|  | }, | 
|  | } | 
|  |  | 
|  | var result Map | 
|  | err := Decode(input, &result) | 
|  | if err != nil { | 
|  | t.Fatalf("got an error: %s", err) | 
|  | } | 
|  |  | 
|  | if result.Vfoo != "foo" { | 
|  | t.Errorf("vfoo value should be 'foo': %#v", result.Vfoo) | 
|  | } | 
|  |  | 
|  | if result.Vother == nil { | 
|  | t.Fatal("vother should not be nil") | 
|  | } | 
|  |  | 
|  | if len(result.Vother) != 2 { | 
|  | t.Error("vother should have two items") | 
|  | } | 
|  |  | 
|  | if result.Vother["foo"] != "foo" { | 
|  | t.Errorf("'foo' key should be foo, got: %#v", result.Vother["foo"]) | 
|  | } | 
|  |  | 
|  | if result.Vother["bar"] != "bar" { | 
|  | t.Errorf("'bar' key should be bar, got: %#v", result.Vother["bar"]) | 
|  | } | 
|  | } | 
|  |  | 
|  | func TestMapMerge(t *testing.T) { | 
|  | t.Parallel() | 
|  |  | 
|  | input := map[string]interface{}{ | 
|  | "vfoo": "foo", | 
|  | "vother": map[interface{}]interface{}{ | 
|  | "foo": "foo", | 
|  | "bar": "bar", | 
|  | }, | 
|  | } | 
|  |  | 
|  | var result Map | 
|  | result.Vother = map[string]string{"hello": "world"} | 
|  | err := Decode(input, &result) | 
|  | if err != nil { | 
|  | t.Fatalf("got an error: %s", err) | 
|  | } | 
|  |  | 
|  | if result.Vfoo != "foo" { | 
|  | t.Errorf("vfoo value should be 'foo': %#v", result.Vfoo) | 
|  | } | 
|  |  | 
|  | expected := map[string]string{ | 
|  | "foo":   "foo", | 
|  | "bar":   "bar", | 
|  | "hello": "world", | 
|  | } | 
|  | if !reflect.DeepEqual(result.Vother, expected) { | 
|  | t.Errorf("bad: %#v", result.Vother) | 
|  | } | 
|  | } | 
|  |  | 
|  | func TestMapOfStruct(t *testing.T) { | 
|  | t.Parallel() | 
|  |  | 
|  | input := map[string]interface{}{ | 
|  | "value": map[string]interface{}{ | 
|  | "foo": map[string]string{"vstring": "one"}, | 
|  | "bar": map[string]string{"vstring": "two"}, | 
|  | }, | 
|  | } | 
|  |  | 
|  | var result MapOfStruct | 
|  | err := Decode(input, &result) | 
|  | if err != nil { | 
|  | t.Fatalf("got an err: %s", err) | 
|  | } | 
|  |  | 
|  | if result.Value == nil { | 
|  | t.Fatal("value should not be nil") | 
|  | } | 
|  |  | 
|  | if len(result.Value) != 2 { | 
|  | t.Error("value should have two items") | 
|  | } | 
|  |  | 
|  | if result.Value["foo"].Vstring != "one" { | 
|  | t.Errorf("foo value should be 'one', got: %s", result.Value["foo"].Vstring) | 
|  | } | 
|  |  | 
|  | if result.Value["bar"].Vstring != "two" { | 
|  | t.Errorf("bar value should be 'two', got: %s", result.Value["bar"].Vstring) | 
|  | } | 
|  | } | 
|  |  | 
|  | func TestNestedType(t *testing.T) { | 
|  | t.Parallel() | 
|  |  | 
|  | input := map[string]interface{}{ | 
|  | "vfoo": "foo", | 
|  | "vbar": map[string]interface{}{ | 
|  | "vstring": "foo", | 
|  | "vint":    42, | 
|  | "vbool":   true, | 
|  | }, | 
|  | } | 
|  |  | 
|  | var result Nested | 
|  | err := Decode(input, &result) | 
|  | if err != nil { | 
|  | t.Fatalf("got an err: %s", err.Error()) | 
|  | } | 
|  |  | 
|  | if result.Vfoo != "foo" { | 
|  | t.Errorf("vfoo value should be 'foo': %#v", result.Vfoo) | 
|  | } | 
|  |  | 
|  | if result.Vbar.Vstring != "foo" { | 
|  | t.Errorf("vstring value should be 'foo': %#v", result.Vbar.Vstring) | 
|  | } | 
|  |  | 
|  | if result.Vbar.Vint != 42 { | 
|  | t.Errorf("vint value should be 42: %#v", result.Vbar.Vint) | 
|  | } | 
|  |  | 
|  | if result.Vbar.Vbool != true { | 
|  | t.Errorf("vbool value should be true: %#v", result.Vbar.Vbool) | 
|  | } | 
|  |  | 
|  | if result.Vbar.Vextra != "" { | 
|  | t.Errorf("vextra value should be empty: %#v", result.Vbar.Vextra) | 
|  | } | 
|  | } | 
|  |  | 
|  | func TestNestedTypePointer(t *testing.T) { | 
|  | t.Parallel() | 
|  |  | 
|  | input := map[string]interface{}{ | 
|  | "vfoo": "foo", | 
|  | "vbar": &map[string]interface{}{ | 
|  | "vstring": "foo", | 
|  | "vint":    42, | 
|  | "vbool":   true, | 
|  | }, | 
|  | } | 
|  |  | 
|  | var result NestedPointer | 
|  | err := Decode(input, &result) | 
|  | if err != nil { | 
|  | t.Fatalf("got an err: %s", err.Error()) | 
|  | } | 
|  |  | 
|  | if result.Vfoo != "foo" { | 
|  | t.Errorf("vfoo value should be 'foo': %#v", result.Vfoo) | 
|  | } | 
|  |  | 
|  | if result.Vbar.Vstring != "foo" { | 
|  | t.Errorf("vstring value should be 'foo': %#v", result.Vbar.Vstring) | 
|  | } | 
|  |  | 
|  | if result.Vbar.Vint != 42 { | 
|  | t.Errorf("vint value should be 42: %#v", result.Vbar.Vint) | 
|  | } | 
|  |  | 
|  | if result.Vbar.Vbool != true { | 
|  | t.Errorf("vbool value should be true: %#v", result.Vbar.Vbool) | 
|  | } | 
|  |  | 
|  | if result.Vbar.Vextra != "" { | 
|  | t.Errorf("vextra value should be empty: %#v", result.Vbar.Vextra) | 
|  | } | 
|  | } | 
|  |  | 
|  | func TestSlice(t *testing.T) { | 
|  | t.Parallel() | 
|  |  | 
|  | inputStringSlice := map[string]interface{}{ | 
|  | "vfoo": "foo", | 
|  | "vbar": []string{"foo", "bar", "baz"}, | 
|  | } | 
|  |  | 
|  | inputStringSlicePointer := map[string]interface{}{ | 
|  | "vfoo": "foo", | 
|  | "vbar": &[]string{"foo", "bar", "baz"}, | 
|  | } | 
|  |  | 
|  | outputStringSlice := &Slice{ | 
|  | "foo", | 
|  | []string{"foo", "bar", "baz"}, | 
|  | } | 
|  |  | 
|  | testSliceInput(t, inputStringSlice, outputStringSlice) | 
|  | testSliceInput(t, inputStringSlicePointer, outputStringSlice) | 
|  | } | 
|  |  | 
|  | func TestInvalidSlice(t *testing.T) { | 
|  | t.Parallel() | 
|  |  | 
|  | input := map[string]interface{}{ | 
|  | "vfoo": "foo", | 
|  | "vbar": 42, | 
|  | } | 
|  |  | 
|  | result := Slice{} | 
|  | err := Decode(input, &result) | 
|  | if err == nil { | 
|  | t.Errorf("expected failure") | 
|  | } | 
|  | } | 
|  |  | 
|  | func TestSliceOfStruct(t *testing.T) { | 
|  | t.Parallel() | 
|  |  | 
|  | input := map[string]interface{}{ | 
|  | "value": []map[string]interface{}{ | 
|  | {"vstring": "one"}, | 
|  | {"vstring": "two"}, | 
|  | }, | 
|  | } | 
|  |  | 
|  | var result SliceOfStruct | 
|  | err := Decode(input, &result) | 
|  | if err != nil { | 
|  | t.Fatalf("got unexpected error: %s", err) | 
|  | } | 
|  |  | 
|  | if len(result.Value) != 2 { | 
|  | t.Fatalf("expected two values, got %d", len(result.Value)) | 
|  | } | 
|  |  | 
|  | if result.Value[0].Vstring != "one" { | 
|  | t.Errorf("first value should be 'one', got: %s", result.Value[0].Vstring) | 
|  | } | 
|  |  | 
|  | if result.Value[1].Vstring != "two" { | 
|  | t.Errorf("second value should be 'two', got: %s", result.Value[1].Vstring) | 
|  | } | 
|  | } | 
|  |  | 
|  | func TestSliceToMap(t *testing.T) { | 
|  | t.Parallel() | 
|  |  | 
|  | input := []map[string]interface{}{ | 
|  | { | 
|  | "foo": "bar", | 
|  | }, | 
|  | { | 
|  | "bar": "baz", | 
|  | }, | 
|  | } | 
|  |  | 
|  | var result map[string]interface{} | 
|  | err := WeakDecode(input, &result) | 
|  | if err != nil { | 
|  | t.Fatalf("got an error: %s", err) | 
|  | } | 
|  |  | 
|  | expected := map[string]interface{}{ | 
|  | "foo": "bar", | 
|  | "bar": "baz", | 
|  | } | 
|  | if !reflect.DeepEqual(result, expected) { | 
|  | t.Errorf("bad: %#v", result) | 
|  | } | 
|  | } | 
|  |  | 
|  | func TestInvalidType(t *testing.T) { | 
|  | t.Parallel() | 
|  |  | 
|  | input := map[string]interface{}{ | 
|  | "vstring": 42, | 
|  | } | 
|  |  | 
|  | var result Basic | 
|  | err := Decode(input, &result) | 
|  | if err == nil { | 
|  | t.Fatal("error should exist") | 
|  | } | 
|  |  | 
|  | derr, ok := err.(*Error) | 
|  | if !ok { | 
|  | t.Fatalf("error should be kind of Error, instead: %#v", err) | 
|  | } | 
|  |  | 
|  | if derr.Errors[0] != "'Vstring' expected type 'string', got unconvertible type 'int'" { | 
|  | t.Errorf("got unexpected error: %s", err) | 
|  | } | 
|  |  | 
|  | inputNegIntUint := map[string]interface{}{ | 
|  | "vuint": -42, | 
|  | } | 
|  |  | 
|  | err = Decode(inputNegIntUint, &result) | 
|  | if err == nil { | 
|  | t.Fatal("error should exist") | 
|  | } | 
|  |  | 
|  | derr, ok = err.(*Error) | 
|  | if !ok { | 
|  | t.Fatalf("error should be kind of Error, instead: %#v", err) | 
|  | } | 
|  |  | 
|  | if derr.Errors[0] != "cannot parse 'Vuint', -42 overflows uint" { | 
|  | t.Errorf("got unexpected error: %s", err) | 
|  | } | 
|  |  | 
|  | inputNegFloatUint := map[string]interface{}{ | 
|  | "vuint": -42.0, | 
|  | } | 
|  |  | 
|  | err = Decode(inputNegFloatUint, &result) | 
|  | if err == nil { | 
|  | t.Fatal("error should exist") | 
|  | } | 
|  |  | 
|  | derr, ok = err.(*Error) | 
|  | if !ok { | 
|  | t.Fatalf("error should be kind of Error, instead: %#v", err) | 
|  | } | 
|  |  | 
|  | if derr.Errors[0] != "cannot parse 'Vuint', -42.000000 overflows uint" { | 
|  | t.Errorf("got unexpected error: %s", err) | 
|  | } | 
|  | } | 
|  |  | 
|  | func TestMetadata(t *testing.T) { | 
|  | t.Parallel() | 
|  |  | 
|  | input := map[string]interface{}{ | 
|  | "vfoo": "foo", | 
|  | "vbar": map[string]interface{}{ | 
|  | "vstring": "foo", | 
|  | "Vuint":   42, | 
|  | "foo":     "bar", | 
|  | }, | 
|  | "bar": "nil", | 
|  | } | 
|  |  | 
|  | var md Metadata | 
|  | var result Nested | 
|  | config := &DecoderConfig{ | 
|  | Metadata: &md, | 
|  | Result:   &result, | 
|  | } | 
|  |  | 
|  | decoder, err := NewDecoder(config) | 
|  | if err != nil { | 
|  | t.Fatalf("err: %s", err) | 
|  | } | 
|  |  | 
|  | err = decoder.Decode(input) | 
|  | if err != nil { | 
|  | t.Fatalf("err: %s", err.Error()) | 
|  | } | 
|  |  | 
|  | expectedKeys := []string{"Vbar", "Vbar.Vstring", "Vbar.Vuint", "Vfoo"} | 
|  | sort.Strings(md.Keys) | 
|  | if !reflect.DeepEqual(md.Keys, expectedKeys) { | 
|  | t.Fatalf("bad keys: %#v", md.Keys) | 
|  | } | 
|  |  | 
|  | expectedUnused := []string{"Vbar.foo", "bar"} | 
|  | if !reflect.DeepEqual(md.Unused, expectedUnused) { | 
|  | t.Fatalf("bad unused: %#v", md.Unused) | 
|  | } | 
|  | } | 
|  |  | 
|  | func TestMetadata_Embedded(t *testing.T) { | 
|  | t.Parallel() | 
|  |  | 
|  | input := map[string]interface{}{ | 
|  | "vstring": "foo", | 
|  | "vunique": "bar", | 
|  | } | 
|  |  | 
|  | var md Metadata | 
|  | var result EmbeddedSquash | 
|  | config := &DecoderConfig{ | 
|  | Metadata: &md, | 
|  | Result:   &result, | 
|  | } | 
|  |  | 
|  | decoder, err := NewDecoder(config) | 
|  | if err != nil { | 
|  | t.Fatalf("err: %s", err) | 
|  | } | 
|  |  | 
|  | err = decoder.Decode(input) | 
|  | if err != nil { | 
|  | t.Fatalf("err: %s", err.Error()) | 
|  | } | 
|  |  | 
|  | expectedKeys := []string{"Vstring", "Vunique"} | 
|  |  | 
|  | sort.Strings(md.Keys) | 
|  | if !reflect.DeepEqual(md.Keys, expectedKeys) { | 
|  | t.Fatalf("bad keys: %#v", md.Keys) | 
|  | } | 
|  |  | 
|  | expectedUnused := []string{} | 
|  | if !reflect.DeepEqual(md.Unused, expectedUnused) { | 
|  | t.Fatalf("bad unused: %#v", md.Unused) | 
|  | } | 
|  | } | 
|  |  | 
|  | func TestNonPtrValue(t *testing.T) { | 
|  | t.Parallel() | 
|  |  | 
|  | err := Decode(map[string]interface{}{}, Basic{}) | 
|  | if err == nil { | 
|  | t.Fatal("error should exist") | 
|  | } | 
|  |  | 
|  | if err.Error() != "result must be a pointer" { | 
|  | t.Errorf("got unexpected error: %s", err) | 
|  | } | 
|  | } | 
|  |  | 
|  | func TestTagged(t *testing.T) { | 
|  | t.Parallel() | 
|  |  | 
|  | input := map[string]interface{}{ | 
|  | "foo": "bar", | 
|  | "bar": "value", | 
|  | } | 
|  |  | 
|  | var result Tagged | 
|  | err := Decode(input, &result) | 
|  | if err != nil { | 
|  | t.Fatalf("unexpected error: %s", err) | 
|  | } | 
|  |  | 
|  | if result.Value != "bar" { | 
|  | t.Errorf("value should be 'bar', got: %#v", result.Value) | 
|  | } | 
|  |  | 
|  | if result.Extra != "value" { | 
|  | t.Errorf("extra should be 'value', got: %#v", result.Extra) | 
|  | } | 
|  | } | 
|  |  | 
|  | func TestWeakDecode(t *testing.T) { | 
|  | t.Parallel() | 
|  |  | 
|  | input := map[string]interface{}{ | 
|  | "foo": "4", | 
|  | "bar": "value", | 
|  | } | 
|  |  | 
|  | var result struct { | 
|  | Foo int | 
|  | Bar string | 
|  | } | 
|  |  | 
|  | if err := WeakDecode(input, &result); err != nil { | 
|  | t.Fatalf("err: %s", err) | 
|  | } | 
|  | if result.Foo != 4 { | 
|  | t.Fatalf("bad: %#v", result) | 
|  | } | 
|  | if result.Bar != "value" { | 
|  | t.Fatalf("bad: %#v", result) | 
|  | } | 
|  | } | 
|  |  | 
|  | func testSliceInput(t *testing.T, input map[string]interface{}, expected *Slice) { | 
|  | var result Slice | 
|  | err := Decode(input, &result) | 
|  | if err != nil { | 
|  | t.Fatalf("got error: %s", err) | 
|  | } | 
|  |  | 
|  | if result.Vfoo != expected.Vfoo { | 
|  | t.Errorf("Vfoo expected '%s', got '%s'", expected.Vfoo, result.Vfoo) | 
|  | } | 
|  |  | 
|  | if result.Vbar == nil { | 
|  | t.Fatalf("Vbar a slice, got '%#v'", result.Vbar) | 
|  | } | 
|  |  | 
|  | if len(result.Vbar) != len(expected.Vbar) { | 
|  | t.Errorf("Vbar length should be %d, got %d", len(expected.Vbar), len(result.Vbar)) | 
|  | } | 
|  |  | 
|  | for i, v := range result.Vbar { | 
|  | if v != expected.Vbar[i] { | 
|  | t.Errorf( | 
|  | "Vbar[%d] should be '%#v', got '%#v'", | 
|  | i, expected.Vbar[i], v) | 
|  | } | 
|  | } | 
|  | } |