From d468182ef2bacd3f348ba3c8597fe05e4522278d Mon Sep 17 00:00:00 2001 From: Hosh Sadiq Date: Sun, 13 Mar 2022 22:34:52 +0000 Subject: [PATCH] Fix StringMap and StringsMap When calling `StringMap`, or `StringsMap`, and the `ko.Get()` returns the value as expected, e.g. `map[string]string` for `StringMap`, the type assertion for `map[string]interface{}` does not match. This causes it to return an empty map even when there are actual values. This commit addresses this by simply returning a copy if the type assertion matches what we're supposed to return. --- getters.go | 75 ++++++++++++++++++++++++++++++++++----------------- koanf_test.go | 33 +++++++++++++++++++++++ 2 files changed, 84 insertions(+), 24 deletions(-) diff --git a/getters.go b/getters.go index c337e35..1cf9201 100644 --- a/getters.go +++ b/getters.go @@ -443,18 +443,22 @@ func (ko *Koanf) StringMap(path string) map[string]string { return out } - mp, ok := o.(map[string]interface{}) - if !ok { - return out - } - out = make(map[string]string, len(mp)) - for k, v := range mp { - switch s := v.(type) { - case string: - out[k] = s - default: - // There's a non string type. Return. - return map[string]string{} + switch mp := o.(type) { + case map[string]string: + out = make(map[string]string, len(mp)) + for k, v := range mp { + out[k] = v + } + case map[string]interface{}: + out = make(map[string]string, len(mp)) + for k, v := range mp { + switch s := v.(type) { + case string: + out[k] = s + default: + // There's a non string type. Return. + return map[string]string{} + } } } @@ -483,15 +487,19 @@ func (ko *Koanf) StringsMap(path string) map[string][]string { return out } - mp, ok := o.(map[string]interface{}) - if !ok { - return out - } - out = make(map[string][]string, len(mp)) - for k, v := range mp { - switch s := v.(type) { - case []interface{}: - for _, v := range s { + switch mp := o.(type) { + case map[string][]string: + out = make(map[string][]string, len(mp)) + for k, v := range mp { + out[k] = make([]string, 0, len(v)) + for _, s := range v { + out[k] = append(out[k], s) + } + } + case map[string][]interface{}: + out = make(map[string][]string, len(mp)) + for k, v := range mp { + for _, v := range v { switch sv := v.(type) { case string: out[k] = append(out[k], sv) @@ -499,9 +507,28 @@ func (ko *Koanf) StringsMap(path string) map[string][]string { return map[string][]string{} } } - default: - // There's a non []interface type. Return. - return map[string][]string{} + } + case map[string]interface{}: + out = make(map[string][]string, len(mp)) + for k, v := range mp { + switch s := v.(type) { + case []string: + for _, v := range s { + out[k] = append(out[k], v) + } + case []interface{}: + for _, v := range s { + switch sv := v.(type) { + case string: + out[k] = append(out[k], sv) + default: + return map[string][]string{} + } + } + default: + // There's a non []interface type. Return. + return map[string][]string{} + } } } diff --git a/koanf_test.go b/koanf_test.go index 9637b90..cbf90f6 100644 --- a/koanf_test.go +++ b/koanf_test.go @@ -1188,3 +1188,36 @@ func TestDelete(t *testing.T) { assert.Equal(false, c.koanf.Exists("empty")) } } + +func TestGetStringsMap(t *testing.T) { + assert := assert.New(t) + + k := koanf.New(delim) + + k.Load(confmap.Provider(map[string]interface{}{ + "str": map[string]string{ + "k1": "value", + }, + "strs": map[string][]string{ + "k1": {"value"}, + }, + "iface": map[string]interface{}{ + "k2": "value", + }, + "ifaces": map[string][]interface{}{ + "k2": {"value"}, + }, + "ifaces2": map[string]interface{}{ + "k2": []interface{}{"value"}, + }, + "ifaces3": map[string]interface{}{ + "k2": []string{"value"}, + }, + }, "."), nil) + assert.Equal(map[string]string{"k1": "value"}, k.StringMap("str"), "types don't match") + assert.Equal(map[string]string{"k2": "value"}, k.StringMap("iface"), "types don't match") + assert.Equal(map[string][]string{"k1": {"value"}}, k.StringsMap("strs"), "types don't match") + assert.Equal(map[string][]string{"k2": {"value"}}, k.StringsMap("ifaces"), "types don't match") + assert.Equal(map[string][]string{"k2": {"value"}}, k.StringsMap("ifaces2"), "types don't match") + assert.Equal(map[string][]string{"k2": {"value"}}, k.StringsMap("ifaces3"), "types don't match") +}