Import upstream version 1.4.2
Debian Janitor
2 years ago
0 | |
## unreleased
|
|
0 |
## 1.4.2
|
1 | 1 |
|
2 | |
* Fix regression where `*time.Time` value would be set to empty and not be sent
|
|
2 |
* Custom name matchers to support any sort of casing, formatting, etc. for
|
|
3 |
field names. [GH-250]
|
|
4 |
* Fix possible panic in ComposeDecodeHookFunc [GH-251]
|
|
5 |
|
|
6 |
## 1.4.1
|
|
7 |
|
|
8 |
* Fix regression where `*time.Time` value would be set to empty and not be sent
|
3 | 9 |
to decode hooks properly [GH-232]
|
4 | 10 |
|
5 | 11 |
## 1.4.0
|
61 | 61 |
func ComposeDecodeHookFunc(fs ...DecodeHookFunc) DecodeHookFunc {
|
62 | 62 |
return func(f reflect.Value, t reflect.Value) (interface{}, error) {
|
63 | 63 |
var err error
|
64 | |
var data interface{}
|
|
64 |
data := f.Interface()
|
|
65 |
|
65 | 66 |
newFrom := f
|
66 | 67 |
for _, f1 := range fs {
|
67 | 68 |
data, err = DecodeHookExec(f1, newFrom, t)
|
83 | 83 |
}
|
84 | 84 |
}
|
85 | 85 |
|
|
86 |
func TestComposeDecodeHookFunc_safe_nofuncs(t *testing.T) {
|
|
87 |
f := ComposeDecodeHookFunc()
|
|
88 |
type myStruct2 struct {
|
|
89 |
MyInt int
|
|
90 |
}
|
|
91 |
|
|
92 |
type myStruct1 struct {
|
|
93 |
Blah map[string]myStruct2
|
|
94 |
}
|
|
95 |
|
|
96 |
src := &myStruct1{Blah: map[string]myStruct2{
|
|
97 |
"test": {
|
|
98 |
MyInt: 1,
|
|
99 |
},
|
|
100 |
}}
|
|
101 |
|
|
102 |
dst := &myStruct1{}
|
|
103 |
dConf := &DecoderConfig{
|
|
104 |
Result: dst,
|
|
105 |
ErrorUnused: true,
|
|
106 |
DecodeHook: f,
|
|
107 |
}
|
|
108 |
d, err := NewDecoder(dConf)
|
|
109 |
if err != nil {
|
|
110 |
t.Fatal(err)
|
|
111 |
}
|
|
112 |
err = d.Decode(src)
|
|
113 |
if err != nil {
|
|
114 |
t.Fatal(err)
|
|
115 |
}
|
|
116 |
}
|
|
117 |
|
86 | 118 |
func TestStringToSliceHookFunc(t *testing.T) {
|
87 | 119 |
f := StringToSliceHookFunc(",")
|
88 | 120 |
|
191 | 191 |
// source and target types.
|
192 | 192 |
type DecodeHookFuncKind func(reflect.Kind, reflect.Kind, interface{}) (interface{}, error)
|
193 | 193 |
|
194 | |
// DecodeHookFuncRaw is a DecodeHookFunc which has complete access to both the source and target
|
|
194 |
// DecodeHookFuncValue is a DecodeHookFunc which has complete access to both the source and target
|
195 | 195 |
// values.
|
196 | 196 |
type DecodeHookFuncValue func(from reflect.Value, to reflect.Value) (interface{}, error)
|
197 | 197 |
|
|
257 | 257 |
// The tag name that mapstructure reads for field names. This
|
258 | 258 |
// defaults to "mapstructure"
|
259 | 259 |
TagName string
|
|
260 |
|
|
261 |
// MatchName is the function used to match the map key to the struct
|
|
262 |
// field name or tag. Defaults to `strings.EqualFold`. This can be used
|
|
263 |
// to implement case-sensitive tag values, support snake casing, etc.
|
|
264 |
MatchName func(mapKey, fieldName string) bool
|
260 | 265 |
}
|
261 | 266 |
|
262 | 267 |
// A Decoder takes a raw interface value and turns it into structured
|
|
373 | 378 |
|
374 | 379 |
if config.TagName == "" {
|
375 | 380 |
config.TagName = "mapstructure"
|
|
381 |
}
|
|
382 |
|
|
383 |
if config.MatchName == nil {
|
|
384 |
config.MatchName = strings.EqualFold
|
376 | 385 |
}
|
377 | 386 |
|
378 | 387 |
result := &Decoder{
|
|
1339 | 1348 |
continue
|
1340 | 1349 |
}
|
1341 | 1350 |
|
1342 | |
if strings.EqualFold(mK, fieldName) {
|
|
1351 |
if d.config.MatchName(mK, fieldName) {
|
1343 | 1352 |
rawMapKey = dataValKey
|
1344 | 1353 |
rawMapVal = dataVal.MapIndex(dataValKey)
|
1345 | 1354 |
break
|
2430 | 2430 |
}
|
2431 | 2431 |
}
|
2432 | 2432 |
|
|
2433 |
func TestDecoder_MatchName(t *testing.T) {
|
|
2434 |
t.Parallel()
|
|
2435 |
|
|
2436 |
type Target struct {
|
|
2437 |
FirstMatch string `mapstructure:"first_match"`
|
|
2438 |
SecondMatch string
|
|
2439 |
NoMatch string `mapstructure:"no_match"`
|
|
2440 |
}
|
|
2441 |
|
|
2442 |
input := map[string]interface{}{
|
|
2443 |
"first_match": "foo",
|
|
2444 |
"SecondMatch": "bar",
|
|
2445 |
"NO_MATCH": "baz",
|
|
2446 |
}
|
|
2447 |
|
|
2448 |
expected := Target{
|
|
2449 |
FirstMatch: "foo",
|
|
2450 |
SecondMatch: "bar",
|
|
2451 |
}
|
|
2452 |
|
|
2453 |
var actual Target
|
|
2454 |
config := &DecoderConfig{
|
|
2455 |
Result: &actual,
|
|
2456 |
MatchName: func(mapKey, fieldName string) bool {
|
|
2457 |
return mapKey == fieldName
|
|
2458 |
},
|
|
2459 |
}
|
|
2460 |
|
|
2461 |
decoder, err := NewDecoder(config)
|
|
2462 |
if err != nil {
|
|
2463 |
t.Fatalf("err: %s", err)
|
|
2464 |
}
|
|
2465 |
|
|
2466 |
err = decoder.Decode(input)
|
|
2467 |
if err != nil {
|
|
2468 |
t.Fatalf("err: %s", err)
|
|
2469 |
}
|
|
2470 |
|
|
2471 |
if !reflect.DeepEqual(expected, actual) {
|
|
2472 |
t.Fatalf("Decode() expected: %#v, got: %#v", expected, actual)
|
|
2473 |
}
|
|
2474 |
}
|
|
2475 |
|
2433 | 2476 |
func testSliceInput(t *testing.T, input map[string]interface{}, expected *Slice) {
|
2434 | 2477 |
var result Slice
|
2435 | 2478 |
err := Decode(input, &result)
|