diff --git a/viper.go b/viper.go index 20eb4da..8bc4438 100644 --- a/viper.go +++ b/viper.go @@ -1791,12 +1791,6 @@ func (v *Viper) writeConfig(filename string, force bool) error { return f.Sync() } -// Unmarshal a Reader into a map. -// Should probably be an unexported function. -func unmarshalReader(in io.Reader, c map[string]any) error { - return v.unmarshalReader(in, c) -} - func (v *Viper) unmarshalReader(in io.Reader, c map[string]any) error { buf := new(bytes.Buffer) buf.ReadFrom(in) diff --git a/viper_test.go b/viper_test.go index 0853369..f5ac1be 100644 --- a/viper_test.go +++ b/viper_test.go @@ -136,104 +136,50 @@ Coding addict. Good man. """ # Succeeding comment`) -func initConfigs() { - Reset() +func initConfigs(v *Viper) { var r io.Reader - SetConfigType("yaml") + v.SetConfigType("yaml") r = bytes.NewReader(yamlExample) - unmarshalReader(r, v.config) + v.unmarshalReader(r, v.config) - SetConfigType("json") + v.SetConfigType("json") r = bytes.NewReader(jsonExample) - unmarshalReader(r, v.config) + v.unmarshalReader(r, v.config) - SetConfigType("hcl") + v.SetConfigType("hcl") r = bytes.NewReader(hclExample) - unmarshalReader(r, v.config) + v.unmarshalReader(r, v.config) - SetConfigType("properties") + v.SetConfigType("properties") r = bytes.NewReader(propertiesExample) - unmarshalReader(r, v.config) + v.unmarshalReader(r, v.config) - SetConfigType("toml") + v.SetConfigType("toml") r = bytes.NewReader(tomlExample) - unmarshalReader(r, v.config) + v.unmarshalReader(r, v.config) - SetConfigType("env") + v.SetConfigType("env") r = bytes.NewReader(dotenvExample) - unmarshalReader(r, v.config) + v.unmarshalReader(r, v.config) - SetConfigType("json") + v.SetConfigType("json") remote := bytes.NewReader(remoteExample) - unmarshalReader(remote, v.kvstore) + v.unmarshalReader(remote, v.kvstore) - SetConfigType("ini") + v.SetConfigType("ini") r = bytes.NewReader(iniExample) - unmarshalReader(r, v.config) + v.unmarshalReader(r, v.config) } -func initConfig(typ, config string) { - Reset() - SetConfigType(typ) +func initConfig(typ, config string, v *Viper) { + v.SetConfigType(typ) r := strings.NewReader(config) - if err := unmarshalReader(r, v.config); err != nil { + if err := v.unmarshalReader(r, v.config); err != nil { panic(err) } } -func initYAML() { - initConfig("yaml", string(yamlExample)) -} - -func initJSON() { - Reset() - SetConfigType("json") - r := bytes.NewReader(jsonExample) - - unmarshalReader(r, v.config) -} - -func initProperties() { - Reset() - SetConfigType("properties") - r := bytes.NewReader(propertiesExample) - - unmarshalReader(r, v.config) -} - -func initTOML() { - Reset() - SetConfigType("toml") - r := bytes.NewReader(tomlExample) - - unmarshalReader(r, v.config) -} - -func initDotEnv() { - Reset() - SetConfigType("env") - r := bytes.NewReader(dotenvExample) - - unmarshalReader(r, v.config) -} - -func initHcl() { - Reset() - SetConfigType("hcl") - r := bytes.NewReader(hclExample) - - unmarshalReader(r, v.config) -} - -func initIni() { - Reset() - SetConfigType("ini") - r := bytes.NewReader(iniExample) - - unmarshalReader(r, v.config) -} - // initDirs makes directories for testing. func initDirs(t *testing.T) (string, string) { var ( @@ -472,257 +418,313 @@ func TestReadInConfig(t *testing.T) { } func TestDefault(t *testing.T) { - Reset() - SetDefault("age", 45) - assert.Equal(t, 45, Get("age")) + v := New() + v.SetDefault("age", 45) + assert.Equal(t, 45, v.Get("age")) - SetDefault("clothing.jacket", "slacks") - assert.Equal(t, "slacks", Get("clothing.jacket")) + v.SetDefault("clothing.jacket", "slacks") + assert.Equal(t, "slacks", v.Get("clothing.jacket")) - SetConfigType("yaml") - err := ReadConfig(bytes.NewBuffer(yamlExample)) + v.SetConfigType("yaml") + err := v.ReadConfig(bytes.NewBuffer(yamlExample)) assert.NoError(t, err) - assert.Equal(t, "leather", Get("clothing.jacket")) + assert.Equal(t, "leather", v.Get("clothing.jacket")) } func TestUnmarshaling(t *testing.T) { - Reset() - SetConfigType("yaml") + v := New() + v.SetConfigType("yaml") r := bytes.NewReader(yamlExample) - unmarshalReader(r, v.config) - assert.True(t, InConfig("name")) - assert.True(t, InConfig("clothing.jacket")) - assert.False(t, InConfig("state")) - assert.False(t, InConfig("clothing.hat")) - assert.Equal(t, "steve", Get("name")) - assert.Equal(t, []any{"skateboarding", "snowboarding", "go"}, Get("hobbies")) - assert.Equal(t, map[string]any{"jacket": "leather", "trousers": "denim", "pants": map[string]any{"size": "large"}}, Get("clothing")) - assert.Equal(t, 35, Get("age")) + v.unmarshalReader(r, v.config) + assert.True(t, v.InConfig("name")) + assert.True(t, v.InConfig("clothing.jacket")) + assert.False(t, v.InConfig("state")) + assert.False(t, v.InConfig("clothing.hat")) + assert.Equal(t, "steve", v.Get("name")) + assert.Equal(t, []any{"skateboarding", "snowboarding", "go"}, v.Get("hobbies")) + assert.Equal(t, map[string]any{"jacket": "leather", "trousers": "denim", "pants": map[string]any{"size": "large"}}, v.Get("clothing")) + assert.Equal(t, 35, v.Get("age")) } func TestUnmarshalExact(t *testing.T) { - vip := New() + v := New() target := &testUnmarshalExtra{} - vip.SetConfigType("yaml") + v.SetConfigType("yaml") r := bytes.NewReader(yamlExampleWithExtras) - vip.ReadConfig(r) - err := vip.UnmarshalExact(target) + v.ReadConfig(r) + err := v.UnmarshalExact(target) assert.Error(t, err, "UnmarshalExact should error when populating a struct from a conf that contains unused fields") } func TestOverrides(t *testing.T) { - Set("age", 40) - assert.Equal(t, 40, Get("age")) + v := New() + v.Set("age", 40) + assert.Equal(t, 40, v.Get("age")) } func TestDefaultPost(t *testing.T) { - assert.NotEqual(t, "NYC", Get("state")) - SetDefault("state", "NYC") - assert.Equal(t, "NYC", Get("state")) + v := New() + assert.NotEqual(t, "NYC", v.Get("state")) + v.SetDefault("state", "NYC") + assert.Equal(t, "NYC", v.Get("state")) } func TestAliases(t *testing.T) { - initConfigs() - Set("age", 40) - RegisterAlias("years", "age") - assert.Equal(t, 40, Get("years")) - Set("years", 45) - assert.Equal(t, 45, Get("age")) + v := New() + v.Set("age", 40) + v.RegisterAlias("years", "age") + assert.Equal(t, 40, v.Get("years")) + v.Set("years", 45) + assert.Equal(t, 45, v.Get("age")) } func TestAliasInConfigFile(t *testing.T) { - initConfigs() - // the config file specifies "beard". If we make this an alias for - // "hasbeard", we still want the old config file to work with beard. - RegisterAlias("beard", "hasbeard") - assert.Equal(t, true, Get("hasbeard")) - Set("hasbeard", false) - assert.Equal(t, false, Get("beard")) + v := New() + + v.SetConfigType("yaml") + + // Read the YAML data into Viper configuration + require.NoError(t, v.ReadConfig(bytes.NewBuffer(yamlExample)), "Error reading YAML data") + + v.RegisterAlias("beard", "hasbeard") + assert.Equal(t, true, v.Get("hasbeard")) + + v.Set("hasbeard", false) + assert.Equal(t, false, v.Get("beard")) } func TestYML(t *testing.T) { - initYAML() - assert.Equal(t, "steve", Get("name")) + v := New() + v.SetConfigType("yaml") + + // Read the YAML data into Viper configuration + require.NoError(t, v.ReadConfig(bytes.NewBuffer(yamlExample)), "Error reading YAML data") + + assert.Equal(t, "steve", v.Get("name")) } func TestJSON(t *testing.T) { - initJSON() - assert.Equal(t, "0001", Get("id")) + v := New() + + v.SetConfigType("json") + // Read the JSON data into Viper configuration + require.NoError(t, v.ReadConfig(bytes.NewBuffer(jsonExample)), "Error reading JSON data") + + assert.Equal(t, "0001", v.Get("id")) } func TestProperties(t *testing.T) { - initProperties() - assert.Equal(t, "0001", Get("p_id")) + v := New() + + v.SetConfigType("properties") + + // Read the properties data into Viper configuration + require.NoError(t, v.ReadConfig(bytes.NewBuffer(propertiesExample)), "Error reading properties data") + + assert.Equal(t, "0001", v.Get("p_id")) } func TestTOML(t *testing.T) { - initTOML() - assert.Equal(t, "TOML Example", Get("title")) + v := New() + v.SetConfigType("toml") + + // Read the properties data into Viper configuration + require.NoError(t, v.ReadConfig(bytes.NewBuffer(tomlExample)), "Error reading toml data") + + assert.Equal(t, "TOML Example", v.Get("title")) } func TestDotEnv(t *testing.T) { - initDotEnv() - assert.Equal(t, "DotEnv Example", Get("title_dotenv")) + v := New() + v.SetConfigType("env") + // Read the properties data into Viper configuration + require.NoError(t, v.ReadConfig(bytes.NewBuffer(dotenvExample)), "Error reading env data") + + assert.Equal(t, "DotEnv Example", v.Get("title_dotenv")) } func TestHCL(t *testing.T) { - initHcl() - assert.Equal(t, "0001", Get("id")) - assert.Equal(t, 0.55, Get("ppu")) - assert.Equal(t, "donut", Get("type")) - assert.Equal(t, "Cake", Get("name")) - Set("id", "0002") - assert.Equal(t, "0002", Get("id")) - assert.NotEqual(t, "cronut", Get("type")) + v := New() + v.SetConfigType("hcl") + // Read the properties data into Viper configuration + require.NoError(t, v.ReadConfig(bytes.NewBuffer(hclExample)), "Error reading hcl data") + + // initHcl() + assert.Equal(t, "0001", v.Get("id")) + assert.Equal(t, 0.55, v.Get("ppu")) + assert.Equal(t, "donut", v.Get("type")) + assert.Equal(t, "Cake", v.Get("name")) + v.Set("id", "0002") + assert.Equal(t, "0002", v.Get("id")) + assert.NotEqual(t, "cronut", v.Get("type")) } func TestIni(t *testing.T) { - initIni() - assert.Equal(t, "ini", Get("default.name")) + // initIni() + v := New() + v.SetConfigType("ini") + // Read the properties data into Viper configuration + require.NoError(t, v.ReadConfig(bytes.NewBuffer(iniExample)), "Error reading ini data") + + assert.Equal(t, "ini", v.Get("default.name")) } func TestRemotePrecedence(t *testing.T) { - initJSON() + v := New() + v.SetConfigType("json") + // Read the properties data into Viper configuration v.config + require.NoError(t, v.ReadConfig(bytes.NewBuffer(jsonExample)), "Error reading json data") + assert.Equal(t, "0001", v.Get("id")) + + // update the kvstore with the remoteExample which should overite the key in v.config remote := bytes.NewReader(remoteExample) - assert.Equal(t, "0001", Get("id")) - unmarshalReader(remote, v.kvstore) - assert.Equal(t, "0001", Get("id")) - assert.NotEqual(t, "cronut", Get("type")) - assert.Equal(t, "remote", Get("newkey")) - Set("newkey", "newvalue") - assert.NotEqual(t, "remote", Get("newkey")) - assert.Equal(t, "newvalue", Get("newkey")) - Set("newkey", "remote") + require.NoError(t, v.unmarshalReader(remote, v.kvstore), "Error reading json data in to kvstore") + + assert.Equal(t, "0001", v.Get("id")) + assert.NotEqual(t, "cronut", v.Get("type")) + assert.Equal(t, "remote", v.Get("newkey")) + v.Set("newkey", "newvalue") + assert.NotEqual(t, "remote", v.Get("newkey")) + assert.Equal(t, "newvalue", v.Get("newkey")) } func TestEnv(t *testing.T) { - initJSON() + v := New() + v.SetConfigType("json") + // Read the properties data into Viper configuration v.config + require.NoError(t, v.ReadConfig(bytes.NewBuffer(jsonExample)), "Error reading json data") - BindEnv("id") - BindEnv("f", "FOOD", "OLD_FOOD") + v.BindEnv("id") + v.BindEnv("f", "FOOD", "OLD_FOOD") t.Setenv("ID", "13") t.Setenv("FOOD", "apple") t.Setenv("OLD_FOOD", "banana") t.Setenv("NAME", "crunk") - assert.Equal(t, "13", Get("id")) - assert.Equal(t, "apple", Get("f")) - assert.Equal(t, "Cake", Get("name")) + assert.Equal(t, "13", v.Get("id")) + assert.Equal(t, "apple", v.Get("f")) + assert.Equal(t, "Cake", v.Get("name")) - AutomaticEnv() + v.AutomaticEnv() - assert.Equal(t, "crunk", Get("name")) + assert.Equal(t, "crunk", v.Get("name")) } func TestMultipleEnv(t *testing.T) { - initJSON() + v := New() + v.SetConfigType("json") + // Read the properties data into Viper configuration v.config + require.NoError(t, v.ReadConfig(bytes.NewBuffer(jsonExample)), "Error reading json data") - BindEnv("f", "FOOD", "OLD_FOOD") + v.BindEnv("f", "FOOD", "OLD_FOOD") t.Setenv("OLD_FOOD", "banana") - assert.Equal(t, "banana", Get("f")) + assert.Equal(t, "banana", v.Get("f")) } func TestEmptyEnv(t *testing.T) { - initJSON() + v := New() + v.SetConfigType("json") + // Read the properties data into Viper configuration v.config + require.NoError(t, v.ReadConfig(bytes.NewBuffer(jsonExample)), "Error reading json data") - BindEnv("type") // Empty environment variable - BindEnv("name") // Bound, but not set environment variable + v.BindEnv("type") // Empty environment variable + v.BindEnv("name") // Bound, but not set environment variable t.Setenv("TYPE", "") - assert.Equal(t, "donut", Get("type")) - assert.Equal(t, "Cake", Get("name")) + assert.Equal(t, "donut", v.Get("type")) + assert.Equal(t, "Cake", v.Get("name")) } func TestEmptyEnv_Allowed(t *testing.T) { - initJSON() + v := New() + v.SetConfigType("json") + // Read the properties data into Viper configuration v.config + require.NoError(t, v.ReadConfig(bytes.NewBuffer(jsonExample)), "Error reading json data") - AllowEmptyEnv(true) + v.AllowEmptyEnv(true) - BindEnv("type") // Empty environment variable - BindEnv("name") // Bound, but not set environment variable + v.BindEnv("type") // Empty environment variable + v.BindEnv("name") // Bound, but not set environment variable t.Setenv("TYPE", "") - assert.Equal(t, "", Get("type")) - assert.Equal(t, "Cake", Get("name")) + assert.Equal(t, "", v.Get("type")) + assert.Equal(t, "Cake", v.Get("name")) } func TestEnvPrefix(t *testing.T) { - initJSON() + v := New() + v.SetConfigType("json") + // Read the properties data into Viper configuration v.config + require.NoError(t, v.ReadConfig(bytes.NewBuffer(jsonExample)), "Error reading json data") - SetEnvPrefix("foo") // will be uppercased automatically - BindEnv("id") - BindEnv("f", "FOOD") // not using prefix + v.SetEnvPrefix("foo") // will be uppercased automatically + v.BindEnv("id") + v.BindEnv("f", "FOOD") // not using prefix t.Setenv("FOO_ID", "13") t.Setenv("FOOD", "apple") t.Setenv("FOO_NAME", "crunk") - assert.Equal(t, "13", Get("id")) - assert.Equal(t, "apple", Get("f")) - assert.Equal(t, "Cake", Get("name")) + assert.Equal(t, "13", v.Get("id")) + assert.Equal(t, "apple", v.Get("f")) + assert.Equal(t, "Cake", v.Get("name")) - AutomaticEnv() + v.AutomaticEnv() - assert.Equal(t, "crunk", Get("name")) + assert.Equal(t, "crunk", v.Get("name")) } func TestAutoEnv(t *testing.T) { - Reset() + v := New() - AutomaticEnv() + v.AutomaticEnv() t.Setenv("FOO_BAR", "13") - assert.Equal(t, "13", Get("foo_bar")) + assert.Equal(t, "13", v.Get("foo_bar")) } func TestAutoEnvWithPrefix(t *testing.T) { - Reset() - - AutomaticEnv() - SetEnvPrefix("Baz") - + v := New() + v.AutomaticEnv() + v.SetEnvPrefix("Baz") t.Setenv("BAZ_BAR", "13") - - assert.Equal(t, "13", Get("bar")) + assert.Equal(t, "13", v.Get("bar")) } func TestSetEnvKeyReplacer(t *testing.T) { - Reset() - - AutomaticEnv() + v := New() + v.AutomaticEnv() t.Setenv("REFRESH_INTERVAL", "30s") replacer := strings.NewReplacer("-", "_") - SetEnvKeyReplacer(replacer) - - assert.Equal(t, "30s", Get("refresh-interval")) -} - -func TestEnvKeyReplacer(t *testing.T) { - v := NewWithOptions(EnvKeyReplacer(strings.NewReplacer("-", "_"))) - - v.AutomaticEnv() - - t.Setenv("REFRESH_INTERVAL", "30s") + v.SetEnvKeyReplacer(replacer) assert.Equal(t, "30s", v.Get("refresh-interval")) } -func TestEnvSubConfig(t *testing.T) { - initYAML() - +func TestEnvKeyReplacer(t *testing.T) { + v := NewWithOptions(EnvKeyReplacer(strings.NewReplacer("-", "_"))) v.AutomaticEnv() + t.Setenv("REFRESH_INTERVAL", "30s") + assert.Equal(t, "30s", v.Get("refresh-interval")) +} +func TestEnvSubConfig(t *testing.T) { + v := New() + v.SetConfigType("yaml") + // Read the properties data into Viper configuration v.config + require.NoError(t, v.ReadConfig(bytes.NewBuffer(yamlExample)), "Error reading json data") + v.AutomaticEnv() v.SetEnvKeyReplacer(strings.NewReplacer(".", "_")) t.Setenv("CLOTHING_PANTS_SIZE", "small") @@ -737,7 +739,8 @@ func TestEnvSubConfig(t *testing.T) { } func TestAllKeys(t *testing.T) { - initConfigs() + v := New() + initConfigs(v) ks := []string{ "title", @@ -843,8 +846,8 @@ func TestAllKeys(t *testing.T) { "name_dotenv": "Cake", } - assert.ElementsMatch(t, ks, AllKeys()) - assert.Equal(t, all, AllSettings()) + assert.ElementsMatch(t, ks, v.AllKeys()) + assert.Equal(t, all, v.AllSettings()) } func TestAllKeysWithEnv(t *testing.T) { @@ -862,25 +865,27 @@ func TestAllKeysWithEnv(t *testing.T) { } func TestAliasesOfAliases(t *testing.T) { - Set("Title", "Checking Case") - RegisterAlias("Foo", "Bar") - RegisterAlias("Bar", "Title") - assert.Equal(t, "Checking Case", Get("FOO")) + v := New() + v.Set("Title", "Checking Case") + v.RegisterAlias("Foo", "Bar") + v.RegisterAlias("Bar", "Title") + assert.Equal(t, "Checking Case", v.Get("FOO")) } func TestRecursiveAliases(t *testing.T) { - Set("baz", "bat") - RegisterAlias("Baz", "Roo") - RegisterAlias("Roo", "baz") - assert.Equal(t, "bat", Get("Baz")) + v := New() + v.Set("baz", "bat") + v.RegisterAlias("Baz", "Roo") + v.RegisterAlias("Roo", "baz") + assert.Equal(t, "bat", v.Get("Baz")) } func TestUnmarshal(t *testing.T) { - Reset() - SetDefault("port", 1313) - Set("name", "Steve") - Set("duration", "1s1ms") - Set("modes", []int{1, 2, 3}) + v := New() + v.SetDefault("port", 1313) + v.Set("name", "Steve") + v.Set("duration", "1s1ms") + v.Set("modes", []int{1, 2, 3}) type config struct { Port int @@ -890,9 +895,7 @@ func TestUnmarshal(t *testing.T) { } var C config - - err := Unmarshal(&C) - require.NoError(t, err, "unable to decode into struct") + require.NoError(t, v.Unmarshal(&C), "unable to decode into struct") assert.Equal( t, @@ -905,9 +908,8 @@ func TestUnmarshal(t *testing.T) { &C, ) - Set("port", 1234) - err = Unmarshal(&C) - require.NoError(t, err, "unable to decode into struct") + v.Set("port", 1234) + require.NoError(t, v.Unmarshal(&C), "unable to decode into struct") assert.Equal( t, @@ -922,7 +924,8 @@ func TestUnmarshal(t *testing.T) { } func TestUnmarshalWithDecoderOptions(t *testing.T) { - Set("credentials", "{\"foo\":\"bar\"}") + v := New() + v.Set("credentials", "{\"foo\":\"bar\"}") opt := DecodeHook(mapstructure.ComposeDecodeHookFunc( mapstructure.StringToTimeDurationHookFunc(), @@ -948,8 +951,7 @@ func TestUnmarshalWithDecoderOptions(t *testing.T) { var C config - err := Unmarshal(&C, opt) - require.NoError(t, err, "unable to decode into struct") + require.NoError(t, v.Unmarshal(&C, opt), "unable to decode into struct") assert.Equal(t, &config{ Credentials: map[string]string{"foo": "bar"}, @@ -1266,6 +1268,7 @@ func TestBindPFlagsIntSlice(t *testing.T) { } func TestBindPFlag(t *testing.T) { + v := New() testString := "testing" testValue := newStringValue(testString, &testString) @@ -1275,18 +1278,19 @@ func TestBindPFlag(t *testing.T) { Changed: false, } - BindPFlag("testvalue", flag) + v.BindPFlag("testvalue", flag) - assert.Equal(t, testString, Get("testvalue")) + assert.Equal(t, testString, v.Get("testvalue")) flag.Value.Set("testing_mutate") flag.Changed = true // hack for pflag usage - assert.Equal(t, "testing_mutate", Get("testvalue")) + assert.Equal(t, "testing_mutate", v.Get("testvalue")) } func TestBindPFlagDetectNilFlag(t *testing.T) { - result := BindPFlag("testvalue", nil) + v := New() + result := v.BindPFlag("testvalue", nil) assert.Error(t, result) } @@ -1379,14 +1383,15 @@ func TestBindPFlagStringToInt(t *testing.T) { } func TestBoundCaseSensitivity(t *testing.T) { - initConfigs() - assert.Equal(t, "brown", Get("eyes")) + v := New() + initConfigs(v) + assert.Equal(t, "brown", v.Get("eyes")) - BindEnv("eYEs", "TURTLE_EYES") + v.BindEnv("eYEs", "TURTLE_EYES") t.Setenv("TURTLE_EYES", "blue") - assert.Equal(t, "blue", Get("eyes")) + assert.Equal(t, "blue", v.Get("eyes")) testString := "green" testValue := newStringValue(testString, &testString) @@ -1397,8 +1402,8 @@ func TestBoundCaseSensitivity(t *testing.T) { Changed: true, } - BindPFlag("eYEs", flag) - assert.Equal(t, "green", Get("eyes")) + v.BindPFlag("eYEs", flag) + assert.Equal(t, "green", v.Get("eyes")) } func TestSizeInBytes(t *testing.T) { @@ -1419,10 +1424,11 @@ func TestSizeInBytes(t *testing.T) { } func TestFindsNestedKeys(t *testing.T) { - initConfigs() + v := New() + initConfigs(v) dob, _ := time.Parse(time.RFC3339, "1979-05-27T07:32:00Z") - Set("super", map[string]any{ + v.Set("super", map[string]any{ "deep": map[string]any{ "nested": "value", }, @@ -1653,8 +1659,9 @@ var yamlInvalid = []byte(`hash: map `) func TestUnwrapParseErrors(t *testing.T) { - SetConfigType("yaml") - assert.ErrorAs(t, ReadConfig(bytes.NewBuffer(yamlInvalid)), &ConfigParseError{}) + v := New() + v.SetConfigType("yaml") + assert.ErrorAs(t, v.ReadConfig(bytes.NewBuffer(yamlInvalid)), &ConfigParseError{}) } func TestSub(t *testing.T) { @@ -2208,14 +2215,16 @@ func TestUnmarshalingWithAliases(t *testing.T) { } func TestSetConfigNameClearsFileCache(t *testing.T) { - SetConfigFile("/tmp/config.yaml") - SetConfigName("default") + v := New() + v.SetConfigFile("/tmp/config.yaml") + v.SetConfigName("default") f, err := v.getConfigFile() require.Error(t, err, "config file cache should have been cleared") assert.Empty(t, f) } func TestShadowedNestedValue(t *testing.T) { + v := New() config := `name: steve clothing: jacket: leather @@ -2223,30 +2232,36 @@ clothing: pants: size: large ` - initConfig("yaml", config) + initConfig("yaml", config, v) - assert.Equal(t, "steve", GetString("name")) + assert.Equal(t, "steve", v.GetString("name")) polyester := "polyester" - SetDefault("clothing.shirt", polyester) - SetDefault("clothing.jacket.price", 100) + v.SetDefault("clothing.shirt", polyester) + v.SetDefault("clothing.jacket.price", 100) - assert.Equal(t, "leather", GetString("clothing.jacket")) - assert.Nil(t, Get("clothing.jacket.price")) - assert.Equal(t, polyester, GetString("clothing.shirt")) + assert.Equal(t, "leather", v.GetString("clothing.jacket")) + assert.Nil(t, v.Get("clothing.jacket.price")) + assert.Equal(t, polyester, v.GetString("clothing.shirt")) - clothingSettings := AllSettings()["clothing"].(map[string]any) + clothingSettings := v.AllSettings()["clothing"].(map[string]any) assert.Equal(t, "leather", clothingSettings["jacket"]) assert.Equal(t, polyester, clothingSettings["shirt"]) } func TestDotParameter(t *testing.T) { - initJSON() + v := New() + + v.SetConfigType("json") + + // Read the YAML data into Viper configuration + require.NoError(t, v.ReadConfig(bytes.NewBuffer(jsonExample)), "Error reading YAML data") + // should take precedence over batters defined in jsonExample r := bytes.NewReader([]byte(`{ "batters.batter": [ { "type": "Small" } ] }`)) - unmarshalReader(r, v.config) + v.unmarshalReader(r, v.config) - actual := Get("batters.batter") + actual := v.Get("batters.batter") expected := []any{map[string]any{"type": "Small"}} assert.Equal(t, expected, actual) } @@ -2297,7 +2312,7 @@ R = 6 } func TestCaseInsensitiveSet(t *testing.T) { - Reset() + v := New() m1 := map[string]any{ "Foo": 32, "Bar": map[any]any{ @@ -2314,28 +2329,29 @@ func TestCaseInsensitiveSet(t *testing.T) { }, } - Set("Given1", m1) - Set("Number1", 42) + v.Set("Given1", m1) + v.Set("Number1", 42) - SetDefault("Given2", m2) - SetDefault("Number2", 52) + v.SetDefault("Given2", m2) + v.SetDefault("Number2", 52) // Verify SetDefault - assert.Equal(t, 52, Get("number2")) - assert.Equal(t, 52, Get("given2.foo")) - assert.Equal(t, "A", Get("given2.bar.bcd")) + assert.Equal(t, 52, v.Get("number2")) + assert.Equal(t, 52, v.Get("given2.foo")) + assert.Equal(t, "A", v.Get("given2.bar.bcd")) _, ok := m2["Foo"] assert.True(t, ok) // Verify Set - assert.Equal(t, 42, Get("number1")) - assert.Equal(t, 32, Get("given1.foo")) - assert.Equal(t, "A", Get("given1.bar.abc")) + assert.Equal(t, 42, v.Get("number1")) + assert.Equal(t, 32, v.Get("given1.foo")) + assert.Equal(t, "A", v.Get("given1.bar.abc")) _, ok = m1["Foo"] assert.True(t, ok) } func TestParseNested(t *testing.T) { + v := New() type duration struct { Delay time.Duration } @@ -2351,7 +2367,7 @@ func TestParseNested(t *testing.T) { [parent.nested] delay="200ms" ` - initConfig("toml", config) + initConfig("toml", config, v) var items []item err := v.UnmarshalKey("parent", &items) @@ -2363,16 +2379,17 @@ func TestParseNested(t *testing.T) { } func doTestCaseInsensitive(t *testing.T, typ, config string) { - initConfig(typ, config) - Set("RfD", true) - assert.Equal(t, true, Get("rfd")) - assert.Equal(t, true, Get("rFD")) - assert.Equal(t, 1, cast.ToInt(Get("abcd"))) - assert.Equal(t, 1, cast.ToInt(Get("Abcd"))) - assert.Equal(t, 2, cast.ToInt(Get("ef.gh"))) - assert.Equal(t, 3, cast.ToInt(Get("ef.ijk"))) - assert.Equal(t, 4, cast.ToInt(Get("ef.lm.no"))) - assert.Equal(t, 5, cast.ToInt(Get("ef.lm.p.q"))) + v := New() + initConfig(typ, config, v) + v.Set("RfD", true) + assert.Equal(t, true, v.Get("rfd")) + assert.Equal(t, true, v.Get("rFD")) + assert.Equal(t, 1, cast.ToInt(v.Get("abcd"))) + assert.Equal(t, 1, cast.ToInt(v.Get("Abcd"))) + assert.Equal(t, 2, cast.ToInt(v.Get("ef.gh"))) + assert.Equal(t, 3, cast.ToInt(v.Get("ef.ijk"))) + assert.Equal(t, 4, cast.ToInt(v.Get("ef.lm.no"))) + assert.Equal(t, 5, cast.ToInt(v.Get("ef.lm.p.q"))) } func newViperWithConfigFile(t *testing.T) (*Viper, string) { @@ -2584,6 +2601,7 @@ var yamlDeepNestedSlices = []byte(`TV: `) func TestSliceIndexAccess(t *testing.T) { + v := New() v.SetConfigType("yaml") r := strings.NewReader(string(yamlDeepNestedSlices))