Merge pull request #8106 from hashicorp/dnephin/hook-translate-keys-make-a-copy

decode: do not modify the source data in HookTranslateKeys
This commit is contained in:
Daniel Nephin 2020-06-15 14:48:33 -04:00 committed by hashicorp-ci
parent 17382b583c
commit 7cf96ade22
2 changed files with 38 additions and 4 deletions

View File

@ -44,21 +44,28 @@ func HookTranslateKeys(_, to reflect.Type, data interface{}) (interface{}, error
}
rules := translationsForType(to)
// Avoid making a copy if there are no translation rules
if len(rules) == 0 {
return data, nil
}
result := make(map[string]interface{}, len(source))
for k, v := range source {
lowerK := strings.ToLower(k)
canonKey, ok := rules[lowerK]
if !ok {
result[k] = v
continue
}
delete(source, k)
// if there is a value for the canonical key then keep it
if _, ok := source[canonKey]; ok {
if canonValue, ok := source[canonKey]; ok {
// Assign the value for the case where canonKey == k
result[canonKey] = canonValue
continue
}
source[canonKey] = v
result[canonKey] = v
}
return source, nil
return result, nil
}
// TODO: could be cached if it is too slow

View File

@ -178,6 +178,33 @@ func TestHookTranslateKeys_TargetStructHasPointerReceiver(t *testing.T) {
require.Equal(t, expected, target, "decode metadata: %#v", md)
}
func TestHookTranslateKeys_DoesNotModifySourceData(t *testing.T) {
raw := map[string]interface{}{
"S": map[string]interface{}{
"None": "no translation",
"OldOne": "value1",
"oldtwo": "value2",
},
}
cfg := Config{}
decoder, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{
DecodeHook: HookTranslateKeys,
Result: &cfg,
})
require.NoError(t, err)
require.NoError(t, decoder.Decode(raw))
expected := map[string]interface{}{
"S": map[string]interface{}{
"None": "no translation",
"OldOne": "value1",
"oldtwo": "value2",
},
}
require.Equal(t, raw, expected)
}
type translateExample struct {
FieldDefaultCanonical string `alias:"first"`
FieldWithMapstructureTag string `alias:"second" mapstructure:"field_with_mapstruct_tag"`