fix #1700: update tests to use local viper instance (#1791)

* fix:test to use local viper instance

* fix linting

* fix typo

* remove unsed function
This commit is contained in:
sandeep 2024-04-07 04:09:02 -07:00 committed by GitHub
parent 947eb59667
commit 2e9148610a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 295 additions and 283 deletions

View file

@ -1791,12 +1791,6 @@ func (v *Viper) writeConfig(filename string, force bool) error {
return f.Sync() 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 { func (v *Viper) unmarshalReader(in io.Reader, c map[string]any) error {
buf := new(bytes.Buffer) buf := new(bytes.Buffer)
buf.ReadFrom(in) buf.ReadFrom(in)

View file

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