diff --git a/viper.go b/viper.go index 1875627..72083fa 100644 --- a/viper.go +++ b/viper.go @@ -1736,7 +1736,22 @@ func (v *Viper) AllSettings() map[string]interface{} { // check just in case anything changes continue } - path := strings.Split(k, v.keyDelim) + + // Build key path by splitting the key by keyDelim and checking that the parent keys + // are actually set. + // Example use case: + // Ensures sure that, for the yaml conf "foo.bar: baz", and keyDelim ".": + // the generated path is []string{"foo.bar", "baz"}, instead of []string{"foo", "bar", "baz"} + path := []string{} + splitPath := strings.Split(k, v.keyDelim) + i := 0 + for j := range splitPath { + if v.IsSet(strings.Join(splitPath[:j+1], v.keyDelim)) { + path = append(path, strings.Join(splitPath[i:j+1], v.keyDelim)) + i = j + 1 + } + } + lastKey := strings.ToLower(path[len(path)-1]) deepestMap := deepSearch(m, path[0:len(path)-1]) // set innermost value diff --git a/viper_test.go b/viper_test.go index fa3903e..abafb2e 100644 --- a/viper_test.go +++ b/viper_test.go @@ -500,6 +500,39 @@ func TestAllKeysWithEnv(t *testing.T) { assert.Equal(t, expectedKeys, keys) } +func TestAllSettingsWithDelimiterInKeys(t *testing.T) { + exampleYaml := `Hacker: true +name: steve +hobbies: +- skate.boarding +- snowboarding +clothing.summer: + jacket: leather + pants: + size: large +clothing.winter: + jacket: wool + pants: + size: medium +` + v := New() + v.SetConfigType("yaml") + r := strings.NewReader(exampleYaml) + + if err := v.unmarshalReader(r, v.config); err != nil { + panic(err) + } + + expectedAll := map[string]interface{}{"hacker": true, "name": "steve", "hobbies": []interface{}{"skate.boarding", "snowboarding"}, "clothing.summer": map[string]interface{}{"jacket": "leather", "pants": map[string]interface{}{"size": "large"}}, "clothing.winter": map[string]interface{}{"jacket": "wool", "pants": map[string]interface{}{"size": "medium"}}} + expectedKeys := sort.StringSlice{"hacker", "name", "hobbies", "clothing.summer.jacket", "clothing.summer.pants.size", "clothing.winter.jacket", "clothing.winter.pants.size"} + expectedKeys.Sort() + keys := sort.StringSlice(v.AllKeys()) + keys.Sort() + + assert.Equal(t, expectedKeys, keys) + assert.Equal(t, expectedAll, v.AllSettings()) +} + func TestAliasesOfAliases(t *testing.T) { Set("Title", "Checking Case") RegisterAlias("Foo", "Bar")