summaryrefslogtreecommitdiffstats
path: root/vendor/github.com/mitchellh
diff options
context:
space:
mode:
authorChristopher Speller <crspeller@gmail.com>2018-02-16 06:47:51 -0800
committerJoram Wilander <jwawilander@gmail.com>2018-02-16 09:47:51 -0500
commit6d8f122a5160f6d9e4c51579f2429dfaa62c7271 (patch)
tree6e0242cd6709260abd74060a7ec7dc1381efa36e /vendor/github.com/mitchellh
parentb112747de76f9c11c4d8083207049fac6e435019 (diff)
downloadchat-6d8f122a5160f6d9e4c51579f2429dfaa62c7271.tar.gz
chat-6d8f122a5160f6d9e4c51579f2429dfaa62c7271.tar.bz2
chat-6d8f122a5160f6d9e4c51579f2429dfaa62c7271.zip
Upgrading server dependancies (#8308)
Diffstat (limited to 'vendor/github.com/mitchellh')
-rw-r--r--vendor/github.com/mitchellh/mapstructure/README.md2
-rw-r--r--vendor/github.com/mitchellh/mapstructure/decode_hooks.go19
-rw-r--r--vendor/github.com/mitchellh/mapstructure/decode_hooks_test.go30
-rw-r--r--vendor/github.com/mitchellh/mapstructure/mapstructure.go247
-rw-r--r--vendor/github.com/mitchellh/mapstructure/mapstructure_test.go340
5 files changed, 573 insertions, 65 deletions
diff --git a/vendor/github.com/mitchellh/mapstructure/README.md b/vendor/github.com/mitchellh/mapstructure/README.md
index 7ecc785e4..0018dc7d9 100644
--- a/vendor/github.com/mitchellh/mapstructure/README.md
+++ b/vendor/github.com/mitchellh/mapstructure/README.md
@@ -1,4 +1,4 @@
-# mapstructure [![Godoc](https://godoc.org/github.com/mitchell/mapstructure?status.svg)](https://godoc.org/github.com/mitchell/mapstructure)
+# mapstructure [![Godoc](https://godoc.org/github.com/mitchellh/mapstructure?status.svg)](https://godoc.org/github.com/mitchellh/mapstructure)
mapstructure is a Go library for decoding generic map values to structures
and vice versa, while providing helpful error handling.
diff --git a/vendor/github.com/mitchellh/mapstructure/decode_hooks.go b/vendor/github.com/mitchellh/mapstructure/decode_hooks.go
index afcfd5eed..2a727575a 100644
--- a/vendor/github.com/mitchellh/mapstructure/decode_hooks.go
+++ b/vendor/github.com/mitchellh/mapstructure/decode_hooks.go
@@ -115,6 +115,25 @@ func StringToTimeDurationHookFunc() DecodeHookFunc {
}
}
+// StringToTimeHookFunc returns a DecodeHookFunc that converts
+// strings to time.Time.
+func StringToTimeHookFunc(layout string) DecodeHookFunc {
+ return func(
+ f reflect.Type,
+ t reflect.Type,
+ data interface{}) (interface{}, error) {
+ if f.Kind() != reflect.String {
+ return data, nil
+ }
+ if t != reflect.TypeOf(time.Time{}) {
+ return data, nil
+ }
+
+ // Convert it by parsing
+ return time.Parse(layout, data.(string))
+ }
+}
+
// WeaklyTypedHook is a DecodeHookFunc which adds support for weak typing to
// the decoder.
//
diff --git a/vendor/github.com/mitchellh/mapstructure/decode_hooks_test.go b/vendor/github.com/mitchellh/mapstructure/decode_hooks_test.go
index 53289afcf..a81728e74 100644
--- a/vendor/github.com/mitchellh/mapstructure/decode_hooks_test.go
+++ b/vendor/github.com/mitchellh/mapstructure/decode_hooks_test.go
@@ -153,6 +153,36 @@ func TestStringToTimeDurationHookFunc(t *testing.T) {
}
}
+func TestStringToTimeHookFunc(t *testing.T) {
+ strType := reflect.TypeOf("")
+ timeType := reflect.TypeOf(time.Time{})
+ cases := []struct {
+ f, t reflect.Type
+ layout string
+ data interface{}
+ result interface{}
+ err bool
+ }{
+ {strType, timeType, time.RFC3339, "2006-01-02T15:04:05Z",
+ time.Date(2006, 1, 2, 15, 4, 5, 0, time.UTC), false},
+ {strType, timeType, time.RFC3339, "5", time.Time{}, true},
+ {strType, strType, time.RFC3339, "5", "5", false},
+ }
+
+ for i, tc := range cases {
+ f := StringToTimeHookFunc(tc.layout)
+ actual, err := DecodeHookExec(f, tc.f, tc.t, tc.data)
+ if tc.err != (err != nil) {
+ t.Fatalf("case %d: expected err %#v", i, tc.err)
+ }
+ if !reflect.DeepEqual(actual, tc.result) {
+ t.Fatalf(
+ "case %d: expected %#v, got %#v",
+ i, tc.result, actual)
+ }
+ }
+}
+
func TestWeaklyTypedHook(t *testing.T) {
var f DecodeHookFunc = WeaklyTypedHook
diff --git a/vendor/github.com/mitchellh/mapstructure/mapstructure.go b/vendor/github.com/mitchellh/mapstructure/mapstructure.go
index 39ec1e943..65977b654 100644
--- a/vendor/github.com/mitchellh/mapstructure/mapstructure.go
+++ b/vendor/github.com/mitchellh/mapstructure/mapstructure.go
@@ -114,12 +114,12 @@ type Metadata struct {
Unused []string
}
-// Decode takes a map and uses reflection to convert it into the
-// given Go native structure. val must be a pointer to a struct.
-func Decode(m interface{}, rawVal interface{}) error {
+// Decode takes an input structure and uses reflection to translate it to
+// the output structure. output must be a pointer to a map or struct.
+func Decode(input interface{}, output interface{}) error {
config := &DecoderConfig{
Metadata: nil,
- Result: rawVal,
+ Result: output,
}
decoder, err := NewDecoder(config)
@@ -127,7 +127,7 @@ func Decode(m interface{}, rawVal interface{}) error {
return err
}
- return decoder.Decode(m)
+ return decoder.Decode(input)
}
// WeakDecode is the same as Decode but is shorthand to enable
@@ -147,6 +147,40 @@ func WeakDecode(input, output interface{}) error {
return decoder.Decode(input)
}
+// DecodeMetadata is the same as Decode, but is shorthand to
+// enable metadata collection. See DecoderConfig for more info.
+func DecodeMetadata(input interface{}, output interface{}, metadata *Metadata) error {
+ config := &DecoderConfig{
+ Metadata: metadata,
+ Result: output,
+ }
+
+ decoder, err := NewDecoder(config)
+ if err != nil {
+ return err
+ }
+
+ return decoder.Decode(input)
+}
+
+// WeakDecodeMetadata is the same as Decode, but is shorthand to
+// enable both WeaklyTypedInput and metadata collection. See
+// DecoderConfig for more info.
+func WeakDecodeMetadata(input interface{}, output interface{}, metadata *Metadata) error {
+ config := &DecoderConfig{
+ Metadata: metadata,
+ Result: output,
+ WeaklyTypedInput: true,
+ }
+
+ decoder, err := NewDecoder(config)
+ if err != nil {
+ return err
+ }
+
+ return decoder.Decode(input)
+}
+
// NewDecoder returns a new decoder for the given configuration. Once
// a decoder has been returned, the same configuration must not be used
// again.
@@ -184,70 +218,70 @@ func NewDecoder(config *DecoderConfig) (*Decoder, error) {
// Decode decodes the given raw interface to the target pointer specified
// by the configuration.
-func (d *Decoder) Decode(raw interface{}) error {
- return d.decode("", raw, reflect.ValueOf(d.config.Result).Elem())
+func (d *Decoder) Decode(input interface{}) error {
+ return d.decode("", input, reflect.ValueOf(d.config.Result).Elem())
}
// Decodes an unknown data type into a specific reflection value.
-func (d *Decoder) decode(name string, data interface{}, val reflect.Value) error {
- if data == nil {
- // If the data is nil, then we don't set anything.
+func (d *Decoder) decode(name string, input interface{}, outVal reflect.Value) error {
+ if input == nil {
+ // If the input is nil, then we don't set anything.
return nil
}
- dataVal := reflect.ValueOf(data)
- if !dataVal.IsValid() {
- // If the data value is invalid, then we just set the value
+ inputVal := reflect.ValueOf(input)
+ if !inputVal.IsValid() {
+ // If the input value is invalid, then we just set the value
// to be the zero value.
- val.Set(reflect.Zero(val.Type()))
+ outVal.Set(reflect.Zero(outVal.Type()))
return nil
}
if d.config.DecodeHook != nil {
- // We have a DecodeHook, so let's pre-process the data.
+ // We have a DecodeHook, so let's pre-process the input.
var err error
- data, err = DecodeHookExec(
+ input, err = DecodeHookExec(
d.config.DecodeHook,
- dataVal.Type(), val.Type(), data)
+ inputVal.Type(), outVal.Type(), input)
if err != nil {
return fmt.Errorf("error decoding '%s': %s", name, err)
}
}
var err error
- dataKind := getKind(val)
- switch dataKind {
+ inputKind := getKind(outVal)
+ switch inputKind {
case reflect.Bool:
- err = d.decodeBool(name, data, val)
+ err = d.decodeBool(name, input, outVal)
case reflect.Interface:
- err = d.decodeBasic(name, data, val)
+ err = d.decodeBasic(name, input, outVal)
case reflect.String:
- err = d.decodeString(name, data, val)
+ err = d.decodeString(name, input, outVal)
case reflect.Int:
- err = d.decodeInt(name, data, val)
+ err = d.decodeInt(name, input, outVal)
case reflect.Uint:
- err = d.decodeUint(name, data, val)
+ err = d.decodeUint(name, input, outVal)
case reflect.Float32:
- err = d.decodeFloat(name, data, val)
+ err = d.decodeFloat(name, input, outVal)
case reflect.Struct:
- err = d.decodeStruct(name, data, val)
+ err = d.decodeStruct(name, input, outVal)
case reflect.Map:
- err = d.decodeMap(name, data, val)
+ err = d.decodeMap(name, input, outVal)
case reflect.Ptr:
- err = d.decodePtr(name, data, val)
+ err = d.decodePtr(name, input, outVal)
case reflect.Slice:
- err = d.decodeSlice(name, data, val)
+ err = d.decodeSlice(name, input, outVal)
case reflect.Array:
- err = d.decodeArray(name, data, val)
+ err = d.decodeArray(name, input, outVal)
case reflect.Func:
- err = d.decodeFunc(name, data, val)
+ err = d.decodeFunc(name, input, outVal)
default:
// If we reached this point then we weren't able to decode it
- return fmt.Errorf("%s: unsupported type: %s", name, dataKind)
+ return fmt.Errorf("%s: unsupported type: %s", name, inputKind)
}
// If we reached here, then we successfully decoded SOMETHING, so
- // mark the key as used if we're tracking metadata.
+ // mark the key as used if we're tracking metainput.
if d.config.Metadata != nil && name != "" {
d.config.Metadata.Keys = append(d.config.Metadata.Keys, name)
}
@@ -258,6 +292,9 @@ func (d *Decoder) decode(name string, data interface{}, val reflect.Value) error
// This decodes a basic type (bool, int, string, etc.) and sets the
// value to "data" of that type.
func (d *Decoder) decodeBasic(name string, data interface{}, val reflect.Value) error {
+ if val.IsValid() && val.Elem().IsValid() {
+ return d.decode(name, data, val.Elem())
+ }
dataVal := reflect.ValueOf(data)
if !dataVal.IsValid() {
dataVal = reflect.Zero(val.Type())
@@ -499,34 +536,50 @@ func (d *Decoder) decodeMap(name string, data interface{}, val reflect.Value) er
valMap = reflect.MakeMap(mapType)
}
- // Check input type
+ // Check input type and based on the input type jump to the proper func
dataVal := reflect.Indirect(reflect.ValueOf(data))
- if dataVal.Kind() != reflect.Map {
- // In weak mode, we accept a slice of maps as an input...
- if d.config.WeaklyTypedInput {
- switch dataVal.Kind() {
- case reflect.Array, reflect.Slice:
- // Special case for BC reasons (covered by tests)
- if dataVal.Len() == 0 {
- val.Set(valMap)
- return nil
- }
+ switch dataVal.Kind() {
+ case reflect.Map:
+ return d.decodeMapFromMap(name, dataVal, val, valMap)
- for i := 0; i < dataVal.Len(); i++ {
- err := d.decode(
- fmt.Sprintf("%s[%d]", name, i),
- dataVal.Index(i).Interface(), val)
- if err != nil {
- return err
- }
- }
+ case reflect.Struct:
+ return d.decodeMapFromStruct(name, dataVal, val, valMap)
- return nil
- }
+ case reflect.Array, reflect.Slice:
+ if d.config.WeaklyTypedInput {
+ return d.decodeMapFromSlice(name, dataVal, val, valMap)
}
+ fallthrough
+
+ default:
return fmt.Errorf("'%s' expected a map, got '%s'", name, dataVal.Kind())
}
+}
+
+func (d *Decoder) decodeMapFromSlice(name string, dataVal reflect.Value, val reflect.Value, valMap reflect.Value) error {
+ // Special case for BC reasons (covered by tests)
+ if dataVal.Len() == 0 {
+ val.Set(valMap)
+ return nil
+ }
+
+ for i := 0; i < dataVal.Len(); i++ {
+ err := d.decode(
+ fmt.Sprintf("%s[%d]", name, i),
+ dataVal.Index(i).Interface(), val)
+ if err != nil {
+ return err
+ }
+ }
+
+ return nil
+}
+
+func (d *Decoder) decodeMapFromMap(name string, dataVal reflect.Value, val reflect.Value, valMap reflect.Value) error {
+ valType := val.Type()
+ valKeyType := valType.Key()
+ valElemType := valType.Elem()
// Accumulate errors
errors := make([]string, 0)
@@ -563,22 +616,88 @@ func (d *Decoder) decodeMap(name string, data interface{}, val reflect.Value) er
return nil
}
+func (d *Decoder) decodeMapFromStruct(name string, dataVal reflect.Value, val reflect.Value, valMap reflect.Value) error {
+ typ := dataVal.Type()
+ for i := 0; i < typ.NumField(); i++ {
+ // Get the StructField first since this is a cheap operation. If the
+ // field is unexported, then ignore it.
+ f := typ.Field(i)
+ if f.PkgPath != "" {
+ continue
+ }
+
+ // Next get the actual value of this field and verify it is assignable
+ // to the map value.
+ v := dataVal.Field(i)
+ if !v.Type().AssignableTo(valMap.Type().Elem()) {
+ return fmt.Errorf("cannot assign type '%s' to map value field of type '%s'", v.Type(), valMap.Type().Elem())
+ }
+
+ // Determine the name of the key in the map
+ keyName := f.Name
+ tagValue := f.Tag.Get(d.config.TagName)
+ tagValue = strings.SplitN(tagValue, ",", 2)[0]
+ if tagValue != "" {
+ if tagValue == "-" {
+ continue
+ }
+
+ keyName = tagValue
+ }
+
+ switch v.Kind() {
+ // this is an embedded struct, so handle it differently
+ case reflect.Struct:
+ x := reflect.New(v.Type())
+ x.Elem().Set(v)
+
+ vType := valMap.Type()
+ vKeyType := vType.Key()
+ vElemType := vType.Elem()
+ mType := reflect.MapOf(vKeyType, vElemType)
+ vMap := reflect.MakeMap(mType)
+
+ err := d.decode(keyName, x.Interface(), vMap)
+ if err != nil {
+ return err
+ }
+
+ valMap.SetMapIndex(reflect.ValueOf(keyName), vMap)
+
+ default:
+ valMap.SetMapIndex(reflect.ValueOf(keyName), v)
+ }
+ }
+
+ if val.CanAddr() {
+ val.Set(valMap)
+ }
+
+ return nil
+}
+
func (d *Decoder) decodePtr(name string, data interface{}, val reflect.Value) error {
// Create an element of the concrete (non pointer) type and decode
// into that. Then set the value of the pointer to this type.
valType := val.Type()
valElemType := valType.Elem()
- realVal := val
- if realVal.IsNil() || d.config.ZeroFields {
- realVal = reflect.New(valElemType)
- }
+ if val.CanSet() {
+ realVal := val
+ if realVal.IsNil() || d.config.ZeroFields {
+ realVal = reflect.New(valElemType)
+ }
- if err := d.decode(name, data, reflect.Indirect(realVal)); err != nil {
- return err
- }
+ if err := d.decode(name, data, reflect.Indirect(realVal)); err != nil {
+ return err
+ }
- val.Set(realVal)
+ val.Set(realVal)
+ } else {
+ if err := d.decode(name, data, reflect.Indirect(val)); err != nil {
+ return err
+ }
+ }
return nil
}
@@ -614,7 +733,8 @@ func (d *Decoder) decodeSlice(name string, data interface{}, val reflect.Value)
val.Set(reflect.MakeSlice(sliceType, 0, 0))
return nil
}
-
+ case dataValKind == reflect.String && valElemType.Kind() == reflect.Uint8:
+ return d.decodeSlice(name, []byte(dataVal.String()), val)
// All other types we try to convert to the slice type
// and "lift" it into it. i.e. a string becomes a string slice.
default:
@@ -622,7 +742,6 @@ func (d *Decoder) decodeSlice(name string, data interface{}, val reflect.Value)
return d.decodeSlice(name, []interface{}{data}, val)
}
}
-
return fmt.Errorf(
"'%s': source data must be an array or slice, got %s", name, dataValKind)
diff --git a/vendor/github.com/mitchellh/mapstructure/mapstructure_test.go b/vendor/github.com/mitchellh/mapstructure/mapstructure_test.go
index 89861edda..64b122a9d 100644
--- a/vendor/github.com/mitchellh/mapstructure/mapstructure_test.go
+++ b/vendor/github.com/mitchellh/mapstructure/mapstructure_test.go
@@ -128,6 +128,7 @@ type TypeConversionResult struct {
FloatToBool bool
FloatToString string
SliceUint8ToString string
+ StringToSliceUint8 []byte
ArrayUint8ToString string
StringToInt int
StringToUint uint
@@ -248,6 +249,32 @@ func TestBasic_Merge(t *testing.T) {
}
}
+// Test for issue #46.
+func TestBasic_Struct(t *testing.T) {
+ t.Parallel()
+
+ input := map[string]interface{}{
+ "vdata": map[string]interface{}{
+ "vstring": "foo",
+ },
+ }
+
+ var result, inner Basic
+ result.Vdata = &inner
+ err := Decode(input, &result)
+ if err != nil {
+ t.Fatalf("got an err: %s", err)
+ }
+ expected := Basic{
+ Vdata: &Basic{
+ Vstring: "foo",
+ },
+ }
+ if !reflect.DeepEqual(result, expected) {
+ t.Fatalf("bad: %#v", result)
+ }
+}
+
func TestDecode_BasicSquash(t *testing.T) {
t.Parallel()
@@ -626,6 +653,7 @@ func TestDecode_TypeConversion(t *testing.T) {
"FloatToBool": 42.42,
"FloatToString": 42.42,
"SliceUint8ToString": []uint8("foo"),
+ "StringToSliceUint8": "foo",
"ArrayUint8ToString": [3]uint8{'f', 'o', 'o'},
"StringToInt": "42",
"StringToUint": "42",
@@ -671,6 +699,7 @@ func TestDecode_TypeConversion(t *testing.T) {
FloatToBool: true,
FloatToString: "42.42",
SliceUint8ToString: "foo",
+ StringToSliceUint8: []byte("foo"),
ArrayUint8ToString: "foo",
StringToInt: 42,
StringToUint: 42,
@@ -926,6 +955,56 @@ func TestNestedTypePointer(t *testing.T) {
}
}
+// Test for issue #46.
+func TestNestedTypeInterface(t *testing.T) {
+ t.Parallel()
+
+ input := map[string]interface{}{
+ "vfoo": "foo",
+ "vbar": &map[string]interface{}{
+ "vstring": "foo",
+ "vint": 42,
+ "vbool": true,
+
+ "vdata": map[string]interface{}{
+ "vstring": "bar",
+ },
+ },
+ }
+
+ var result NestedPointer
+ result.Vbar = new(Basic)
+ result.Vbar.Vdata = new(Basic)
+ 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)
+ }
+
+ if result.Vbar.Vdata.(*Basic).Vstring != "bar" {
+ t.Errorf("vstring value should be 'bar': %#v", result.Vbar.Vdata.(*Basic).Vstring)
+ }
+}
+
func TestSlice(t *testing.T) {
t.Parallel()
@@ -1112,6 +1191,197 @@ func TestArrayToMap(t *testing.T) {
}
}
+func TestMapOutputForStructuredInputs(t *testing.T) {
+ t.Parallel()
+
+ tests := []struct {
+ name string
+ in interface{}
+ target interface{}
+ out interface{}
+ wantErr bool
+ }{
+ {
+ "basic struct input",
+ &Basic{
+ Vstring: "vstring",
+ Vint: 2,
+ Vuint: 3,
+ Vbool: true,
+ Vfloat: 4.56,
+ Vextra: "vextra",
+ vsilent: true,
+ Vdata: []byte("data"),
+ },
+ &map[string]interface{}{},
+ &map[string]interface{}{
+ "Vstring": "vstring",
+ "Vint": 2,
+ "Vuint": uint(3),
+ "Vbool": true,
+ "Vfloat": 4.56,
+ "Vextra": "vextra",
+ "Vdata": []byte("data"),
+ "VjsonInt": 0,
+ "VjsonFloat": 0.0,
+ "VjsonNumber": json.Number(""),
+ },
+ false,
+ },
+ {
+ "embedded struct input",
+ &Embedded{
+ Vunique: "vunique",
+ Basic: Basic{
+ Vstring: "vstring",
+ Vint: 2,
+ Vuint: 3,
+ Vbool: true,
+ Vfloat: 4.56,
+ Vextra: "vextra",
+ vsilent: true,
+ Vdata: []byte("data"),
+ },
+ },
+ &map[string]interface{}{},
+ &map[string]interface{}{
+ "Vunique": "vunique",
+ "Basic": map[string]interface{}{
+ "Vstring": "vstring",
+ "Vint": 2,
+ "Vuint": uint(3),
+ "Vbool": true,
+ "Vfloat": 4.56,
+ "Vextra": "vextra",
+ "Vdata": []byte("data"),
+ "VjsonInt": 0,
+ "VjsonFloat": 0.0,
+ "VjsonNumber": json.Number(""),
+ },
+ },
+ false,
+ },
+ {
+ "slice input - should error",
+ []string{"foo", "bar"},
+ &map[string]interface{}{},
+ &map[string]interface{}{},
+ true,
+ },
+ {
+ "struct with slice property",
+ &Slice{
+ Vfoo: "vfoo",
+ Vbar: []string{"foo", "bar"},
+ },
+ &map[string]interface{}{},
+ &map[string]interface{}{
+ "Vfoo": "vfoo",
+ "Vbar": []string{"foo", "bar"},
+ },
+ false,
+ },
+ {
+ "struct with slice of struct property",
+ &SliceOfStruct{
+ Value: []Basic{
+ Basic{
+ Vstring: "vstring",
+ Vint: 2,
+ Vuint: 3,
+ Vbool: true,
+ Vfloat: 4.56,
+ Vextra: "vextra",
+ vsilent: true,
+ Vdata: []byte("data"),
+ },
+ },
+ },
+ &map[string]interface{}{},
+ &map[string]interface{}{
+ "Value": []Basic{
+ Basic{
+ Vstring: "vstring",
+ Vint: 2,
+ Vuint: 3,
+ Vbool: true,
+ Vfloat: 4.56,
+ Vextra: "vextra",
+ vsilent: true,
+ Vdata: []byte("data"),
+ },
+ },
+ },
+ false,
+ },
+ {
+ "struct with map property",
+ &Map{
+ Vfoo: "vfoo",
+ Vother: map[string]string{"vother": "vother"},
+ },
+ &map[string]interface{}{},
+ &map[string]interface{}{
+ "Vfoo": "vfoo",
+ "Vother": map[string]string{
+ "vother": "vother",
+ }},
+ false,
+ },
+ {
+ "tagged struct",
+ &Tagged{
+ Extra: "extra",
+ Value: "value",
+ },
+ &map[string]string{},
+ &map[string]string{
+ "bar": "extra",
+ "foo": "value",
+ },
+ false,
+ },
+ {
+ "omit tag struct",
+ &struct {
+ Value string `mapstructure:"value"`
+ Omit string `mapstructure:"-"`
+ }{
+ Value: "value",
+ Omit: "omit",
+ },
+ &map[string]string{},
+ &map[string]string{
+ "value": "value",
+ },
+ false,
+ },
+ {
+ "decode to wrong map type",
+ &struct {
+ Value string
+ }{
+ Value: "string",
+ },
+ &map[string]int{},
+ &map[string]int{},
+ true,
+ },
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ if err := Decode(tt.in, tt.target); (err != nil) != tt.wantErr {
+ t.Fatalf("%q: TestMapOutputForStructuredInputs() unexpected error: %s", tt.name, err)
+ }
+
+ if !reflect.DeepEqual(tt.out, tt.target) {
+ t.Fatalf("%q: TestMapOutputForStructuredInputs() expected: %#v, got: %#v", tt.name, tt.out, tt.target)
+ }
+ })
+ }
+}
+
func TestInvalidType(t *testing.T) {
t.Parallel()
@@ -1171,6 +1441,39 @@ func TestInvalidType(t *testing.T) {
}
}
+func TestDecodeMetadata(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
+
+ err := DecodeMetadata(input, &result, &md)
+ 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(t *testing.T) {
t.Parallel()
@@ -1311,6 +1614,43 @@ func TestWeakDecode(t *testing.T) {
}
}
+func TestWeakDecodeMetadata(t *testing.T) {
+ t.Parallel()
+
+ input := map[string]interface{}{
+ "foo": "4",
+ "bar": "value",
+ "unused": "value",
+ }
+
+ var md Metadata
+ var result struct {
+ Foo int
+ Bar string
+ }
+
+ if err := WeakDecodeMetadata(input, &result, &md); 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)
+ }
+
+ expectedKeys := []string{"Bar", "Foo"}
+ sort.Strings(md.Keys)
+ if !reflect.DeepEqual(md.Keys, expectedKeys) {
+ t.Fatalf("bad keys: %#v", md.Keys)
+ }
+
+ expectedUnused := []string{"unused"}
+ if !reflect.DeepEqual(md.Unused, expectedUnused) {
+ t.Fatalf("bad unused: %#v", md.Unused)
+ }
+}
+
func testSliceInput(t *testing.T, input map[string]interface{}, expected *Slice) {
var result Slice
err := Decode(input, &result)