Codebase list golang-github-mitchellh-mapstructure / 6f86571
New upstream version 1.3.2 Shengjing Zhu 3 years ago
8 changed file(s) with 888 addition(s) and 96 deletion(s). Raw diff Collapse all Expand all
00 language: go
11
22 go:
3 - "1.11.x"
3 - "1.14.x"
44 - tip
55
66 script:
77 - go test
8 - go test -bench . -benchmem
0 ## 1.3.2
1
2 * Decode into interface type with a struct value is supported [GH-187]
3
4 ## 1.3.1
5
6 * Squash should only squash embedded structs. [GH-194]
7
8 ## 1.3.0
9
10 * Added `",omitempty"` support. This will ignore zero values in the source
11 structure when encoding. [GH-145]
12
13 ## 1.2.3
14
15 * Fix duplicate entries in Keys list with pointer values. [GH-185]
16
17 ## 1.2.2
18
19 * Do not add unsettable (unexported) values to the unused metadata key
20 or "remain" value. [GH-150]
21
22 ## 1.2.1
23
24 * Go modules checksum mismatch fix
25
26 ## 1.2.0
27
28 * Added support to capture unused values in a field using the `",remain"` value
29 in the mapstructure tag. There is an example to showcase usage.
30 * Added `DecoderConfig` option to always squash embedded structs
31 * `json.Number` can decode into `uint` types
32 * Empty slices are preserved and not replaced with nil slices
33 * Fix panic that can occur in when decoding a map into a nil slice of structs
34 * Improved package documentation for godoc
35
036 ## 1.1.2
137
238 * Fix error when decode hook decodes interface implementation into interface
00 module github.com/mitchellh/mapstructure
1
2 go 1.14
0 // Package mapstructure exposes functionality to convert an arbitrary
1 // map[string]interface{} into a native Go structure.
0 // Package mapstructure exposes functionality to convert one arbitrary
1 // Go type into another, typically to convert a map[string]interface{}
2 // into a native Go structure.
23 //
34 // The Go structure can be arbitrarily complex, containing slices,
45 // other structs, etc. and the decoder will properly decode nested
56 // maps and so on into the proper structures in the native Go struct.
67 // See the examples to see what the decoder is capable of.
8 //
9 // The simplest function to start with is Decode.
10 //
11 // Field Tags
12 //
13 // When decoding to a struct, mapstructure will use the field name by
14 // default to perform the mapping. For example, if a struct has a field
15 // "Username" then mapstructure will look for a key in the source value
16 // of "username" (case insensitive).
17 //
18 // type User struct {
19 // Username string
20 // }
21 //
22 // You can change the behavior of mapstructure by using struct tags.
23 // The default struct tag that mapstructure looks for is "mapstructure"
24 // but you can customize it using DecoderConfig.
25 //
26 // Renaming Fields
27 //
28 // To rename the key that mapstructure looks for, use the "mapstructure"
29 // tag and set a value directly. For example, to change the "username" example
30 // above to "user":
31 //
32 // type User struct {
33 // Username string `mapstructure:"user"`
34 // }
35 //
36 // Embedded Structs and Squashing
37 //
38 // Embedded structs are treated as if they're another field with that name.
39 // By default, the two structs below are equivalent when decoding with
40 // mapstructure:
41 //
42 // type Person struct {
43 // Name string
44 // }
45 //
46 // type Friend struct {
47 // Person
48 // }
49 //
50 // type Friend struct {
51 // Person Person
52 // }
53 //
54 // This would require an input that looks like below:
55 //
56 // map[string]interface{}{
57 // "person": map[string]interface{}{"name": "alice"},
58 // }
59 //
60 // If your "person" value is NOT nested, then you can append ",squash" to
61 // your tag value and mapstructure will treat it as if the embedded struct
62 // were part of the struct directly. Example:
63 //
64 // type Friend struct {
65 // Person `mapstructure:",squash"`
66 // }
67 //
68 // Now the following input would be accepted:
69 //
70 // map[string]interface{}{
71 // "name": "alice",
72 // }
73 //
74 // DecoderConfig has a field that changes the behavior of mapstructure
75 // to always squash embedded structs.
76 //
77 // Remainder Values
78 //
79 // If there are any unmapped keys in the source value, mapstructure by
80 // default will silently ignore them. You can error by setting ErrorUnused
81 // in DecoderConfig. If you're using Metadata you can also maintain a slice
82 // of the unused keys.
83 //
84 // You can also use the ",remain" suffix on your tag to collect all unused
85 // values in a map. The field with this tag MUST be a map type and should
86 // probably be a "map[string]interface{}" or "map[interface{}]interface{}".
87 // See example below:
88 //
89 // type Friend struct {
90 // Name string
91 // Other map[string]interface{} `mapstructure:",remain"`
92 // }
93 //
94 // Given the input below, Other would be populated with the other
95 // values that weren't used (everything but "name"):
96 //
97 // map[string]interface{}{
98 // "name": "bob",
99 // "address": "123 Maple St.",
100 // }
101 //
102 // Omit Empty Values
103 //
104 // When decoding from a struct to any other value, you may use the
105 // ",omitempty" suffix on your tag to omit that value if it equates to
106 // the zero value. The zero value of all types is specified in the Go
107 // specification.
108 //
109 // For example, the zero type of a numeric type is zero ("0"). If the struct
110 // field value is zero and a numeric type, the field is empty, and it won't
111 // be encoded into the destination type.
112 //
113 // type Source {
114 // Age int `mapstructure:",omitempty"`
115 // }
116 //
117 // Unexported fields
118 //
119 // Since unexported (private) struct fields cannot be set outside the package
120 // where they are defined, the decoder will simply skip them.
121 //
122 // For this output type definition:
123 //
124 // type Exported struct {
125 // private string // this unexported field will be skipped
126 // Public string
127 // }
128 //
129 // Using this map as input:
130 //
131 // map[string]interface{}{
132 // "private": "I will be ignored",
133 // "Public": "I made it through!",
134 // }
135 //
136 // The following struct will be decoded:
137 //
138 // type Exported struct {
139 // private: "" // field is left with an empty string (zero value)
140 // Public: "I made it through!"
141 // }
142 //
143 // Other Configuration
144 //
145 // mapstructure is highly configurable. See the DecoderConfig struct
146 // for other features and options that are supported.
7147 package mapstructure
8148
9149 import (
79219 //
80220 WeaklyTypedInput bool
81221
222 // Squash will squash embedded structs. A squash tag may also be
223 // added to an individual struct field using a tag. For example:
224 //
225 // type Parent struct {
226 // Child `mapstructure:",squash"`
227 // }
228 Squash bool
229
82230 // Metadata is the struct that will contain extra metadata about
83231 // the decoding. If this is nil, then no metadata will be tracked.
84232 Metadata *Metadata
270418
271419 var err error
272420 outputKind := getKind(outVal)
421 addMetaKey := true
273422 switch outputKind {
274423 case reflect.Bool:
275424 err = d.decodeBool(name, input, outVal)
288437 case reflect.Map:
289438 err = d.decodeMap(name, input, outVal)
290439 case reflect.Ptr:
291 err = d.decodePtr(name, input, outVal)
440 addMetaKey, err = d.decodePtr(name, input, outVal)
292441 case reflect.Slice:
293442 err = d.decodeSlice(name, input, outVal)
294443 case reflect.Array:
302451
303452 // If we reached here, then we successfully decoded SOMETHING, so
304453 // mark the key as used if we're tracking metainput.
305 if d.config.Metadata != nil && name != "" {
454 if addMetaKey && d.config.Metadata != nil && name != "" {
306455 d.config.Metadata.Keys = append(d.config.Metadata.Keys, name)
307456 }
308457
313462 // value to "data" of that type.
314463 func (d *Decoder) decodeBasic(name string, data interface{}, val reflect.Value) error {
315464 if val.IsValid() && val.Elem().IsValid() {
316 return d.decode(name, data, val.Elem())
465 elem := val.Elem()
466
467 // If we can't address this element, then its not writable. Instead,
468 // we make a copy of the value (which is a pointer and therefore
469 // writable), decode into that, and replace the whole value.
470 copied := false
471 if !elem.CanAddr() {
472 copied = true
473
474 // Make *T
475 copy := reflect.New(elem.Type())
476
477 // *T = elem
478 copy.Elem().Set(elem)
479
480 // Set elem so we decode into it
481 elem = copy
482 }
483
484 // Decode. If we have an error then return. We also return right
485 // away if we're not a copy because that means we decoded directly.
486 if err := d.decode(name, data, elem); err != nil || !copied {
487 return err
488 }
489
490 // If we're a copy, we need to set te final result
491 val.Set(elem.Elem())
492 return nil
317493 }
318494
319495 dataVal := reflect.ValueOf(data)
437613 func (d *Decoder) decodeUint(name string, data interface{}, val reflect.Value) error {
438614 dataVal := reflect.Indirect(reflect.ValueOf(data))
439615 dataKind := getKind(dataVal)
616 dataType := dataVal.Type()
440617
441618 switch {
442619 case dataKind == reflect.Int:
468645 } else {
469646 return fmt.Errorf("cannot parse '%s' as uint: %s", name, err)
470647 }
648 case dataType.PkgPath() == "encoding/json" && dataType.Name() == "Number":
649 jn := data.(json.Number)
650 i, err := jn.Int64()
651 if err != nil {
652 return fmt.Errorf(
653 "error decoding json.Number into %s: %s", name, err)
654 }
655 if i < 0 && !d.config.WeaklyTypedInput {
656 return fmt.Errorf("cannot parse '%s', %d overflows uint",
657 name, i)
658 }
659 val.SetUint(uint64(i))
471660 default:
472661 return fmt.Errorf(
473662 "'%s' expected type '%s', got unconvertible type '%s'",
677866 }
678867
679868 tagValue := f.Tag.Get(d.config.TagName)
680 tagParts := strings.Split(tagValue, ",")
681
869 keyName := f.Name
870
871 // If Squash is set in the config, we squash the field down.
872 squash := d.config.Squash && v.Kind() == reflect.Struct && f.Anonymous
682873 // Determine the name of the key in the map
683 keyName := f.Name
684 if tagParts[0] != "" {
685 if tagParts[0] == "-" {
874 if index := strings.Index(tagValue, ","); index != -1 {
875 if tagValue[:index] == "-" {
686876 continue
687877 }
688 keyName = tagParts[0]
689 }
690
691 // If "squash" is specified in the tag, we squash the field down.
692 squash := false
693 for _, tag := range tagParts[1:] {
694 if tag == "squash" {
695 squash = true
696 break
697 }
698 }
699 if squash && v.Kind() != reflect.Struct {
700 return fmt.Errorf("cannot squash non-struct type '%s'", v.Type())
878 // If "omitempty" is specified in the tag, it ignores empty values.
879 if strings.Index(tagValue[index+1:], "omitempty") != -1 && isEmptyValue(v) {
880 continue
881 }
882
883 // If "squash" is specified in the tag, we squash the field down.
884 squash = !squash && strings.Index(tagValue[index+1:], "squash") != -1
885 if squash && v.Kind() != reflect.Struct {
886 return fmt.Errorf("cannot squash non-struct type '%s'", v.Type())
887 }
888 keyName = tagValue[:index]
889 } else if len(tagValue) > 0 {
890 if tagValue == "-" {
891 continue
892 }
893 keyName = tagValue
701894 }
702895
703896 switch v.Kind() {
737930 return nil
738931 }
739932
740 func (d *Decoder) decodePtr(name string, data interface{}, val reflect.Value) error {
933 func (d *Decoder) decodePtr(name string, data interface{}, val reflect.Value) (bool, error) {
741934 // If the input data is nil, then we want to just set the output
742935 // pointer to be nil as well.
743936 isNil := data == nil
758951 val.Set(nilValue)
759952 }
760953
761 return nil
954 return true, nil
762955 }
763956
764957 // Create an element of the concrete (non pointer) type and decode
772965 }
773966
774967 if err := d.decode(name, data, reflect.Indirect(realVal)); err != nil {
775 return err
968 return false, err
776969 }
777970
778971 val.Set(realVal)
779972 } else {
780973 if err := d.decode(name, data, reflect.Indirect(val)); err != nil {
781 return err
782 }
783 }
784 return nil
974 return false, err
975 }
976 }
977 return false, nil
785978 }
786979
787980 func (d *Decoder) decodeFunc(name string, data interface{}, val reflect.Value) error {
804997 valElemType := valType.Elem()
805998 sliceType := reflect.SliceOf(valElemType)
806999
807 valSlice := val
808 if valSlice.IsNil() || d.config.ZeroFields {
1000 // If we have a non array/slice type then we first attempt to convert.
1001 if dataValKind != reflect.Array && dataValKind != reflect.Slice {
8091002 if d.config.WeaklyTypedInput {
8101003 switch {
8111004 // Slice and array we use the normal logic
8321025 }
8331026 }
8341027
835 // Check input type
836 if dataValKind != reflect.Array && dataValKind != reflect.Slice {
837 return fmt.Errorf(
838 "'%s': source data must be an array or slice, got %s", name, dataValKind)
839
840 }
841
842 // If the input value is empty, then don't allocate since non-nil != nil
843 if dataVal.Len() == 0 {
844 return nil
845 }
846
1028 return fmt.Errorf(
1029 "'%s': source data must be an array or slice, got %s", name, dataValKind)
1030 }
1031
1032 // If the input value is nil, then don't allocate since empty != nil
1033 if dataVal.IsNil() {
1034 return nil
1035 }
1036
1037 valSlice := val
1038 if valSlice.IsNil() || d.config.ZeroFields {
8471039 // Make a new slice to hold our result, same size as the original data.
8481040 valSlice = reflect.MakeSlice(sliceType, dataVal.Len(), dataVal.Len())
8491041 }
10041196 field reflect.StructField
10051197 val reflect.Value
10061198 }
1199
1200 // remainField is set to a valid field set with the "remain" tag if
1201 // we are keeping track of remaining values.
1202 var remainField *field
1203
10071204 fields := []field{}
10081205 for len(structs) > 0 {
10091206 structVal := structs[0]
10161213 fieldKind := fieldType.Type.Kind()
10171214
10181215 // If "squash" is specified in the tag, we squash the field down.
1019 squash := false
1216 squash := d.config.Squash && fieldKind == reflect.Struct && fieldType.Anonymous
1217 remain := false
1218
1219 // We always parse the tags cause we're looking for other tags too
10201220 tagParts := strings.Split(fieldType.Tag.Get(d.config.TagName), ",")
10211221 for _, tag := range tagParts[1:] {
10221222 if tag == "squash" {
10231223 squash = true
1224 break
1225 }
1226
1227 if tag == "remain" {
1228 remain = true
10241229 break
10251230 }
10261231 }
10351240 continue
10361241 }
10371242
1038 // Normal struct field, store it away
1039 fields = append(fields, field{fieldType, structVal.Field(i)})
1243 // Build our field
1244 if remain {
1245 remainField = &field{fieldType, structVal.Field(i)}
1246 } else {
1247 // Normal struct field, store it away
1248 fields = append(fields, field{fieldType, structVal.Field(i)})
1249 }
10401250 }
10411251 }
10421252
10771287 }
10781288 }
10791289
1080 // Delete the key we're using from the unused map so we stop tracking
1081 delete(dataValKeysUnused, rawMapKey.Interface())
1082
10831290 if !fieldValue.IsValid() {
10841291 // This should never happen
10851292 panic("field is not valid")
10911298 continue
10921299 }
10931300
1301 // Delete the key we're using from the unused map so we stop tracking
1302 delete(dataValKeysUnused, rawMapKey.Interface())
1303
10941304 // If the name is empty string, then we're at the root, and we
10951305 // don't dot-join the fields.
10961306 if name != "" {
11001310 if err := d.decode(fieldName, rawMapVal.Interface(), fieldValue); err != nil {
11011311 errors = appendErrors(errors, err)
11021312 }
1313 }
1314
1315 // If we have a "remain"-tagged field and we have unused keys then
1316 // we put the unused keys directly into the remain field.
1317 if remainField != nil && len(dataValKeysUnused) > 0 {
1318 // Build a map of only the unused values
1319 remain := map[interface{}]interface{}{}
1320 for key := range dataValKeysUnused {
1321 remain[key] = dataVal.MapIndex(reflect.ValueOf(key)).Interface()
1322 }
1323
1324 // Decode it as-if we were just decoding this map onto our map.
1325 if err := d.decodeMap(name, remain, remainField.val); err != nil {
1326 errors = appendErrors(errors, err)
1327 }
1328
1329 // Set the map to nil so we have none so that the next check will
1330 // not error (ErrorUnused)
1331 dataValKeysUnused = nil
11031332 }
11041333
11051334 if d.config.ErrorUnused && len(dataValKeysUnused) > 0 {
11301359 }
11311360
11321361 return nil
1362 }
1363
1364 func isEmptyValue(v reflect.Value) bool {
1365 switch getKind(v) {
1366 case reflect.Array, reflect.Map, reflect.Slice, reflect.String:
1367 return v.Len() == 0
1368 case reflect.Bool:
1369 return !v.Bool()
1370 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
1371 return v.Int() == 0
1372 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
1373 return v.Uint() == 0
1374 case reflect.Float32, reflect.Float64:
1375 return v.Float() == 0
1376 case reflect.Interface, reflect.Ptr:
1377 return v.IsNil()
1378 }
1379 return false
11331380 }
11341381
11351382 func getKind(val reflect.Value) reflect.Kind {
44 "testing"
55 )
66
7 type Person struct {
8 Name string
9 Age int
10 Emails []string
11 Extra map[string]string
12 }
13
714 func Benchmark_Decode(b *testing.B) {
8 type Person struct {
9 Name string
10 Age int
11 Emails []string
12 Extra map[string]string
13 }
14
1515 input := map[string]interface{}{
1616 "name": "Mitchell",
1717 "age": 91,
4040 }
4141
4242 func Benchmark_DecodeViaJSON(b *testing.B) {
43 type Person struct {
44 Name string
45 Age int
46 Emails []string
47 Extra map[string]string
48 }
49
5043 input := map[string]interface{}{
5144 "name": "Mitchell",
5245 "age": 91,
6255 }
6356 }
6457
58 func Benchmark_JSONUnmarshal(b *testing.B) {
59 input := map[string]interface{}{
60 "name": "Mitchell",
61 "age": 91,
62 "emails": []string{"one", "two", "three"},
63 "extra": map[string]string{
64 "twitter": "mitchellh",
65 },
66 }
67
68 inputB, err := json.Marshal(input)
69 if err != nil {
70 b.Fatal("Failed to marshal test input:", err)
71 }
72
73 var result Person
74 for i := 0; i < b.N; i++ {
75 json.Unmarshal(inputB, &result)
76 }
77 }
78
6579 func Benchmark_DecodeBasic(b *testing.B) {
6680 input := map[string]interface{}{
67 "vstring": "foo",
68 "vint": 42,
69 "Vuint": 42,
70 "vbool": true,
71 "Vfloat": 42.42,
72 "vsilent": true,
73 "vdata": 42,
74 }
75
76 var result Basic
77 for i := 0; i < b.N; i++ {
81 "vstring": "foo",
82 "vint": 42,
83 "Vuint": 42,
84 "vbool": true,
85 "Vfloat": 42.42,
86 "vsilent": true,
87 "vdata": 42,
88 "vjsonInt": json.Number("1234"),
89 "vjsonFloat": json.Number("1234.5"),
90 "vjsonNumber": json.Number("1234.5"),
91 }
92
93 for i := 0; i < b.N; i++ {
94 var result Basic
7895 Decode(input, &result)
7996 }
8097 }
182199 }
183200
184201 func Benchmark_DecodeWeaklyTypedInput(b *testing.B) {
185 type Person struct {
186 Name string
187 Age int
188 Emails []string
189 }
190
191202 // This input can come from anywhere, but typically comes from
192203 // something like decoding JSON, generated by a weakly typed language
193204 // such as PHP.
214225 }
215226
216227 func Benchmark_DecodeMetadata(b *testing.B) {
217 type Person struct {
218 Name string
219 Age int
220 }
221
222228 input := map[string]interface{}{
223229 "name": "Mitchell",
224230 "age": 91,
457457 }
458458 }
459459 }
460
461 // #103 Check for data type before trying to access its composants prevent a panic error
462 // in decodeSlice
463 func TestDecodeBadDataTypeInSlice(t *testing.T) {
464 t.Parallel()
465
466 input := map[string]interface{}{
467 "Toto": "titi",
468 }
469 result := []struct {
470 Toto string
471 }{}
472
473 if err := Decode(input, &result); err == nil {
474 t.Error("An error was expected, got nil")
475 }
476 }
200200 // Output:
201201 // Mitchell Hashimoto, San Francisco
202202 }
203
204 func ExampleDecode_remainingData() {
205 // Note that the mapstructure tags defined in the struct type
206 // can indicate which fields the values are mapped to.
207 type Person struct {
208 Name string
209 Age int
210 Other map[string]interface{} `mapstructure:",remain"`
211 }
212
213 input := map[string]interface{}{
214 "name": "Mitchell",
215 "age": 91,
216 "email": "mitchell@example.com",
217 }
218
219 var result Person
220 err := Decode(input, &result)
221 if err != nil {
222 panic(err)
223 }
224
225 fmt.Printf("%#v", result)
226 // Output:
227 // mapstructure.Person{Name:"Mitchell", Age:91, Other:map[string]interface {}{"email":"mitchell@example.com"}}
228 }
229
230 func ExampleDecode_omitempty() {
231 // Add omitempty annotation to avoid map keys for empty values
232 type Family struct {
233 LastName string
234 }
235 type Location struct {
236 City string
237 }
238 type Person struct {
239 *Family `mapstructure:",omitempty"`
240 *Location `mapstructure:",omitempty"`
241 Age int
242 FirstName string
243 }
244
245 result := &map[string]interface{}{}
246 input := Person{FirstName: "Somebody"}
247 err := Decode(input, &result)
248 if err != nil {
249 panic(err)
250 }
251
252 fmt.Printf("%+v", result)
253 // Output:
254 // &map[Age:0 FirstName:Somebody]
255 }
1111 type Basic struct {
1212 Vstring string
1313 Vint int
14 Vint8 int8
15 Vint16 int16
16 Vint32 int32
17 Vint64 int64
1418 Vuint uint
1519 Vbool bool
1620 Vfloat float64
1822 vsilent bool
1923 Vdata interface{}
2024 VjsonInt int
25 VjsonUint uint
2126 VjsonFloat float64
2227 VjsonNumber json.Number
2328 }
5560 Vunique string
5661 }
5762
63 type EmbeddedAndNamed struct {
64 Basic
65 Named Basic
66 Vunique string
67 }
68
5869 type SliceAlias []string
5970
6071 type EmbeddedSlice struct {
134145 type Tagged struct {
135146 Extra string `mapstructure:"bar,what,what"`
136147 Value string `mapstructure:"foo"`
148 }
149
150 type Remainder struct {
151 A string
152 Extra map[string]interface{} `mapstructure:",remain"`
153 }
154
155 type StructWithOmitEmpty struct {
156 VisibleStringField string `mapstructure:"visible-string"`
157 OmitStringField string `mapstructure:"omittable-string,omitempty"`
158 VisibleIntField int `mapstructure:"visible-int"`
159 OmitIntField int `mapstructure:"omittable-int,omitempty"`
160 VisibleFloatField float64 `mapstructure:"visible-float"`
161 OmitFloatField float64 `mapstructure:"omittable-float,omitempty"`
162 VisibleSliceField []interface{} `mapstructure:"visible-slice"`
163 OmitSliceField []interface{} `mapstructure:"omittable-slice,omitempty"`
164 VisibleMapField map[string]interface{} `mapstructure:"visible-map"`
165 OmitMapField map[string]interface{} `mapstructure:"omittable-map,omitempty"`
166 NestedField *Nested `mapstructure:"visible-nested"`
167 OmitNestedField *Nested `mapstructure:"omittable-nested,omitempty"`
137168 }
138169
139170 type TypeConversionResult struct {
176207 input := map[string]interface{}{
177208 "vstring": "foo",
178209 "vint": 42,
210 "vint8": 42,
211 "vint16": 42,
212 "vint32": 42,
213 "vint64": 42,
179214 "Vuint": 42,
180215 "vbool": true,
181216 "Vfloat": 42.42,
182217 "vsilent": true,
183218 "vdata": 42,
184219 "vjsonInt": json.Number("1234"),
220 "vjsonUint": json.Number("1234"),
185221 "vjsonFloat": json.Number("1234.5"),
186222 "vjsonNumber": json.Number("1234.5"),
187223 }
200236 if result.Vint != 42 {
201237 t.Errorf("vint value should be 42: %#v", result.Vint)
202238 }
239 if result.Vint8 != 42 {
240 t.Errorf("vint8 value should be 42: %#v", result.Vint)
241 }
242 if result.Vint16 != 42 {
243 t.Errorf("vint16 value should be 42: %#v", result.Vint)
244 }
245 if result.Vint32 != 42 {
246 t.Errorf("vint32 value should be 42: %#v", result.Vint)
247 }
248 if result.Vint64 != 42 {
249 t.Errorf("vint64 value should be 42: %#v", result.Vint)
250 }
203251
204252 if result.Vuint != 42 {
205253 t.Errorf("vuint value should be 42: %#v", result.Vuint)
227275
228276 if result.VjsonInt != 1234 {
229277 t.Errorf("vjsonint value should be 1234: %#v", result.VjsonInt)
278 }
279
280 if result.VjsonUint != 1234 {
281 t.Errorf("vjsonuint value should be 1234: %#v", result.VjsonUint)
230282 }
231283
232284 if result.VjsonFloat != 1234.5 {
298350 }
299351 if !reflect.DeepEqual(result, expected) {
300352 t.Fatalf("bad: %#v", result)
353 }
354 }
355
356 func TestBasic_interfaceStruct(t *testing.T) {
357 t.Parallel()
358
359 input := map[string]interface{}{
360 "vstring": "foo",
361 }
362
363 var iface interface{} = &Basic{}
364 err := Decode(input, &iface)
365 if err != nil {
366 t.Fatalf("got an err: %s", err)
367 }
368
369 expected := &Basic{
370 Vstring: "foo",
371 }
372 if !reflect.DeepEqual(iface, expected) {
373 t.Fatalf("bad: %#v", iface)
374 }
375 }
376
377 // Issue 187
378 func TestBasic_interfaceStructNonPtr(t *testing.T) {
379 t.Parallel()
380
381 input := map[string]interface{}{
382 "vstring": "foo",
383 }
384
385 var iface interface{} = Basic{}
386 err := Decode(input, &iface)
387 if err != nil {
388 t.Fatalf("got an err: %s", err)
389 }
390
391 expected := Basic{
392 Vstring: "foo",
393 }
394 if !reflect.DeepEqual(iface, expected) {
395 t.Fatalf("bad: %#v", iface)
301396 }
302397 }
303398
449544 }
450545 }
451546
547 func TestDecode_EmbeddedNoSquash(t *testing.T) {
548 t.Parallel()
549
550 input := map[string]interface{}{
551 "vstring": "foo",
552 "vunique": "bar",
553 }
554
555 var result Embedded
556 err := Decode(input, &result)
557 if err != nil {
558 t.Fatalf("got an err: %s", err.Error())
559 }
560
561 if result.Vstring != "" {
562 t.Errorf("vstring value should be empty: %#v", result.Vstring)
563 }
564
565 if result.Vunique != "bar" {
566 t.Errorf("vunique value should be 'bar': %#v", result.Vunique)
567 }
568 }
569
570 func TestDecode_EmbeddedPointerNoSquash(t *testing.T) {
571 t.Parallel()
572
573 input := map[string]interface{}{
574 "vstring": "foo",
575 "vunique": "bar",
576 }
577
578 result := EmbeddedPointer{
579 Basic: &Basic{},
580 }
581
582 err := Decode(input, &result)
583 if err != nil {
584 t.Fatalf("err: %s", err)
585 }
586
587 if result.Vstring != "" {
588 t.Errorf("vstring value should be empty: %#v", result.Vstring)
589 }
590
591 if result.Vunique != "bar" {
592 t.Errorf("vunique value should be 'bar': %#v", result.Vunique)
593 }
594 }
595
452596 func TestDecode_EmbeddedSquash(t *testing.T) {
453597 t.Parallel()
454598
507651 t.Error("vunique should be present in map")
508652 } else if !reflect.DeepEqual(v, "bar") {
509653 t.Errorf("vunique value should be 'bar': %#v", v)
654 }
655 }
656
657 func TestDecode_EmbeddedSquashConfig(t *testing.T) {
658 t.Parallel()
659
660 input := map[string]interface{}{
661 "vstring": "foo",
662 "vunique": "bar",
663 "Named": map[string]interface{}{
664 "vstring": "baz",
665 },
666 }
667
668 var result EmbeddedAndNamed
669 config := &DecoderConfig{
670 Squash: true,
671 Result: &result,
672 }
673
674 decoder, err := NewDecoder(config)
675 if err != nil {
676 t.Fatalf("err: %s", err)
677 }
678
679 err = decoder.Decode(input)
680 if err != nil {
681 t.Fatalf("got an err: %s", err)
682 }
683
684 if result.Vstring != "foo" {
685 t.Errorf("vstring value should be 'foo': %#v", result.Vstring)
686 }
687
688 if result.Vunique != "bar" {
689 t.Errorf("vunique value should be 'bar': %#v", result.Vunique)
690 }
691
692 if result.Named.Vstring != "baz" {
693 t.Errorf("Named.vstring value should be 'baz': %#v", result.Named.Vstring)
694 }
695 }
696
697 func TestDecodeFrom_EmbeddedSquashConfig(t *testing.T) {
698 t.Parallel()
699
700 input := EmbeddedAndNamed{
701 Basic: Basic{Vstring: "foo"},
702 Named: Basic{Vstring: "baz"},
703 Vunique: "bar",
704 }
705
706 result := map[string]interface{}{}
707 config := &DecoderConfig{
708 Squash: true,
709 Result: &result,
710 }
711 decoder, err := NewDecoder(config)
712 if err != nil {
713 t.Fatalf("got an err: %s", err.Error())
714 }
715
716 err = decoder.Decode(input)
717 if err != nil {
718 t.Fatalf("got an err: %s", err.Error())
719 }
720
721 if _, ok := result["Basic"]; ok {
722 t.Error("basic should not be present in map")
723 }
724
725 v, ok := result["Vstring"]
726 if !ok {
727 t.Error("vstring should be present in map")
728 } else if !reflect.DeepEqual(v, "foo") {
729 t.Errorf("vstring value should be 'foo': %#v", v)
730 }
731
732 v, ok = result["Vunique"]
733 if !ok {
734 t.Error("vunique should be present in map")
735 } else if !reflect.DeepEqual(v, "bar") {
736 t.Errorf("vunique value should be 'bar': %#v", v)
737 }
738
739 v, ok = result["Named"]
740 if !ok {
741 t.Error("Named should be present in map")
742 } else {
743 named := v.(map[string]interface{})
744 v, ok := named["Vstring"]
745 if !ok {
746 t.Error("Named: vstring should be present in map")
747 } else if !reflect.DeepEqual(v, "baz") {
748 t.Errorf("Named: vstring should be 'baz': %#v", v)
749 }
510750 }
511751 }
512752
9051145 }
9061146 }
9071147
1148 func TestDecoder_ErrorUnused_NotSetable(t *testing.T) {
1149 t.Parallel()
1150
1151 // lowercase vsilent is unexported and cannot be set
1152 input := map[string]interface{}{
1153 "vsilent": "false",
1154 }
1155
1156 var result Basic
1157 config := &DecoderConfig{
1158 ErrorUnused: true,
1159 Result: &result,
1160 }
1161
1162 decoder, err := NewDecoder(config)
1163 if err != nil {
1164 t.Fatalf("err: %s", err)
1165 }
1166
1167 err = decoder.Decode(input)
1168 if err == nil {
1169 t.Fatal("expected error")
1170 }
1171 }
1172
9081173 func TestMap(t *testing.T) {
9091174 t.Parallel()
9101175
13741639 &Basic{
13751640 Vstring: "vstring",
13761641 Vint: 2,
1642 Vint8: 2,
1643 Vint16: 2,
1644 Vint32: 2,
1645 Vint64: 2,
13771646 Vuint: 3,
13781647 Vbool: true,
13791648 Vfloat: 4.56,
13851654 &map[string]interface{}{
13861655 "Vstring": "vstring",
13871656 "Vint": 2,
1657 "Vint8": int8(2),
1658 "Vint16": int16(2),
1659 "Vint32": int32(2),
1660 "Vint64": int64(2),
13881661 "Vuint": uint(3),
13891662 "Vbool": true,
13901663 "Vfloat": 4.56,
13911664 "Vextra": "vextra",
13921665 "Vdata": []byte("data"),
13931666 "VjsonInt": 0,
1667 "VjsonUint": uint(0),
13941668 "VjsonFloat": 0.0,
13951669 "VjsonNumber": json.Number(""),
13961670 },
14031677 Basic: Basic{
14041678 Vstring: "vstring",
14051679 Vint: 2,
1680 Vint8: 2,
1681 Vint16: 2,
1682 Vint32: 2,
1683 Vint64: 2,
14061684 Vuint: 3,
14071685 Vbool: true,
14081686 Vfloat: 4.56,
14171695 "Basic": map[string]interface{}{
14181696 "Vstring": "vstring",
14191697 "Vint": 2,
1698 "Vint8": int8(2),
1699 "Vint16": int16(2),
1700 "Vint32": int32(2),
1701 "Vint64": int64(2),
14201702 "Vuint": uint(3),
14211703 "Vbool": true,
14221704 "Vfloat": 4.56,
14231705 "Vextra": "vextra",
14241706 "Vdata": []byte("data"),
14251707 "VjsonInt": 0,
1708 "VjsonUint": uint(0),
14261709 "VjsonFloat": 0.0,
14271710 "VjsonNumber": json.Number(""),
14281711 },
15411824 &map[string]interface{}{
15421825 "Vfoo": "vfoo",
15431826 "Vbar": []string{"foo", "bar"},
1827 },
1828 false,
1829 },
1830 {
1831 "struct with empty slice",
1832 &map[string]interface{}{
1833 "Vbar": []string{},
1834 },
1835 &Slice{},
1836 &Slice{
1837 Vbar: []string{},
15441838 },
15451839 false,
15461840 },
16301924 &map[string]int{},
16311925 true,
16321926 },
1927 {
1928 "remainder",
1929 map[string]interface{}{
1930 "A": "hello",
1931 "B": "goodbye",
1932 "C": "yo",
1933 },
1934 &Remainder{},
1935 &Remainder{
1936 A: "hello",
1937 Extra: map[string]interface{}{
1938 "B": "goodbye",
1939 "C": "yo",
1940 },
1941 },
1942 false,
1943 },
1944 {
1945 "remainder with no extra",
1946 map[string]interface{}{
1947 "A": "hello",
1948 },
1949 &Remainder{},
1950 &Remainder{
1951 A: "hello",
1952 Extra: nil,
1953 },
1954 false,
1955 },
1956 {
1957 "struct with omitempty tag return non-empty values",
1958 &struct {
1959 VisibleField interface{} `mapstructure:"visible"`
1960 OmitField interface{} `mapstructure:"omittable,omitempty"`
1961 }{
1962 VisibleField: nil,
1963 OmitField: "string",
1964 },
1965 &map[string]interface{}{},
1966 &map[string]interface{}{"visible": nil, "omittable": "string"},
1967 false,
1968 },
1969 {
1970 "struct with omitempty tag ignore empty values",
1971 &struct {
1972 VisibleField interface{} `mapstructure:"visible"`
1973 OmitField interface{} `mapstructure:"omittable,omitempty"`
1974 }{
1975 VisibleField: nil,
1976 OmitField: nil,
1977 },
1978 &map[string]interface{}{},
1979 &map[string]interface{}{"visible": nil},
1980 false,
1981 },
16331982 }
16341983
16351984 for _, tt := range tests {
17122061 "vbar": map[string]interface{}{
17132062 "vstring": "foo",
17142063 "Vuint": 42,
2064 "vsilent": "false",
17152065 "foo": "bar",
17162066 },
17172067 "bar": "nil",
17312081 t.Fatalf("bad keys: %#v", md.Keys)
17322082 }
17332083
1734 expectedUnused := []string{"Vbar.foo", "bar"}
2084 expectedUnused := []string{"Vbar.foo", "Vbar.vsilent", "bar"}
2085 sort.Strings(md.Unused)
17352086 if !reflect.DeepEqual(md.Unused, expectedUnused) {
17362087 t.Fatalf("bad unused: %#v", md.Unused)
17372088 }
17392090
17402091 func TestMetadata(t *testing.T) {
17412092 t.Parallel()
2093
2094 type testResult struct {
2095 Vfoo string
2096 Vbar BasicPointer
2097 }
17422098
17432099 input := map[string]interface{}{
17442100 "vfoo": "foo",
17452101 "vbar": map[string]interface{}{
17462102 "vstring": "foo",
17472103 "Vuint": 42,
2104 "vsilent": "false",
17482105 "foo": "bar",
17492106 },
17502107 "bar": "nil",
17512108 }
17522109
17532110 var md Metadata
1754 var result Nested
2111 var result testResult
17552112 config := &DecoderConfig{
17562113 Metadata: &md,
17572114 Result: &result,
17732130 t.Fatalf("bad keys: %#v", md.Keys)
17742131 }
17752132
1776 expectedUnused := []string{"Vbar.foo", "bar"}
2133 expectedUnused := []string{"Vbar.foo", "Vbar.vsilent", "bar"}
2134 sort.Strings(md.Unused)
17772135 if !reflect.DeepEqual(md.Unused, expectedUnused) {
17782136 t.Fatalf("bad unused: %#v", md.Unused)
17792137 }
18812239 t.Parallel()
18822240
18832241 input := map[string]interface{}{
1884 "foo": "4",
1885 "bar": "value",
1886 "unused": "value",
2242 "foo": "4",
2243 "bar": "value",
2244 "unused": "value",
2245 "unexported": "value",
18872246 }
18882247
18892248 var md Metadata
18902249 var result struct {
1891 Foo int
1892 Bar string
2250 Foo int
2251 Bar string
2252 unexported string
18932253 }
18942254
18952255 if err := WeakDecodeMetadata(input, &result, &md); err != nil {
19082268 t.Fatalf("bad keys: %#v", md.Keys)
19092269 }
19102270
1911 expectedUnused := []string{"unused"}
2271 expectedUnused := []string{"unexported", "unused"}
2272 sort.Strings(md.Unused)
19122273 if !reflect.DeepEqual(md.Unused, expectedUnused) {
19132274 t.Fatalf("bad unused: %#v", md.Unused)
2275 }
2276 }
2277
2278 func TestDecode_StructTaggedWithOmitempty_OmitEmptyValues(t *testing.T) {
2279 t.Parallel()
2280
2281 input := &StructWithOmitEmpty{}
2282
2283 var emptySlice []interface{}
2284 var emptyMap map[string]interface{}
2285 var emptyNested *Nested
2286 expected := &map[string]interface{}{
2287 "visible-string": "",
2288 "visible-int": 0,
2289 "visible-float": 0.0,
2290 "visible-slice": emptySlice,
2291 "visible-map": emptyMap,
2292 "visible-nested": emptyNested,
2293 }
2294
2295 actual := &map[string]interface{}{}
2296 Decode(input, actual)
2297
2298 if !reflect.DeepEqual(actual, expected) {
2299 t.Fatalf("Decode() expected: %#v, got: %#v", expected, actual)
2300 }
2301 }
2302
2303 func TestDecode_StructTaggedWithOmitempty_KeepNonEmptyValues(t *testing.T) {
2304 t.Parallel()
2305
2306 input := &StructWithOmitEmpty{
2307 VisibleStringField: "",
2308 OmitStringField: "string",
2309 VisibleIntField: 0,
2310 OmitIntField: 1,
2311 VisibleFloatField: 0.0,
2312 OmitFloatField: 1.0,
2313 VisibleSliceField: nil,
2314 OmitSliceField: []interface{}{1},
2315 VisibleMapField: nil,
2316 OmitMapField: map[string]interface{}{"k": "v"},
2317 NestedField: nil,
2318 OmitNestedField: &Nested{},
2319 }
2320
2321 var emptySlice []interface{}
2322 var emptyMap map[string]interface{}
2323 var emptyNested *Nested
2324 expected := &map[string]interface{}{
2325 "visible-string": "",
2326 "omittable-string": "string",
2327 "visible-int": 0,
2328 "omittable-int": 1,
2329 "visible-float": 0.0,
2330 "omittable-float": 1.0,
2331 "visible-slice": emptySlice,
2332 "omittable-slice": []interface{}{1},
2333 "visible-map": emptyMap,
2334 "omittable-map": map[string]interface{}{"k": "v"},
2335 "visible-nested": emptyNested,
2336 "omittable-nested": &Nested{},
2337 }
2338
2339 actual := &map[string]interface{}{}
2340 Decode(input, actual)
2341
2342 if !reflect.DeepEqual(actual, expected) {
2343 t.Fatalf("Decode() expected: %#v, got: %#v", expected, actual)
19142344 }
19152345 }
19162346