mirror of
https://github.com/spf13/viper
synced 2025-05-06 20:27:17 +00:00
Added functionality to mock the environment variable store, for tests
This commit is contained in:
parent
d9cca5ef33
commit
da4885ce3d
3 changed files with 90 additions and 13 deletions
14
util.go
14
util.go
|
@ -94,16 +94,16 @@ func insensitiviseMap(m map[string]interface{}) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func absPathify(inPath string) string {
|
func absPathify(inPath string, envStore EnvStore) string {
|
||||||
jww.INFO.Println("Trying to resolve absolute path to", inPath)
|
jww.INFO.Println("Trying to resolve absolute path to", inPath)
|
||||||
|
|
||||||
if strings.HasPrefix(inPath, "$HOME") {
|
if strings.HasPrefix(inPath, "$HOME") {
|
||||||
inPath = userHomeDir() + inPath[5:]
|
inPath = userHomeDir(envStore) + inPath[5:]
|
||||||
}
|
}
|
||||||
|
|
||||||
if strings.HasPrefix(inPath, "$") {
|
if strings.HasPrefix(inPath, "$") {
|
||||||
end := strings.Index(inPath, string(os.PathSeparator))
|
end := strings.Index(inPath, string(os.PathSeparator))
|
||||||
inPath = os.Getenv(inPath[1:end]) + inPath[end:]
|
inPath = envStore.Get(inPath[1:end]) + inPath[end:]
|
||||||
}
|
}
|
||||||
|
|
||||||
if filepath.IsAbs(inPath) {
|
if filepath.IsAbs(inPath) {
|
||||||
|
@ -141,15 +141,15 @@ func stringInSlice(a string, list []string) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func userHomeDir() string {
|
func userHomeDir(store EnvStore) string {
|
||||||
if runtime.GOOS == "windows" {
|
if runtime.GOOS == "windows" {
|
||||||
home := os.Getenv("HOMEDRIVE") + os.Getenv("HOMEPATH")
|
home := store.Get("HOMEDRIVE") + store.Get("HOMEPATH")
|
||||||
if home == "" {
|
if home == "" {
|
||||||
home = os.Getenv("USERPROFILE")
|
home = store.Get("USERPROFILE")
|
||||||
}
|
}
|
||||||
return home
|
return home
|
||||||
}
|
}
|
||||||
return os.Getenv("HOME")
|
return store.Get("HOME")
|
||||||
}
|
}
|
||||||
|
|
||||||
func unmarshallConfigReader(in io.Reader, c map[string]interface{}, configType string) error {
|
func unmarshallConfigReader(in io.Reader, c map[string]interface{}, configType string) error {
|
||||||
|
|
45
viper.go
45
viper.go
|
@ -96,6 +96,16 @@ func (fnfe ConfigFileNotFoundError) Error() string {
|
||||||
return fmt.Sprintf("Config File %q Not Found in %q", fnfe.name, fnfe.locations)
|
return fmt.Sprintf("Config File %q Not Found in %q", fnfe.name, fnfe.locations)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type EnvStore interface {
|
||||||
|
Get(key string) string
|
||||||
|
}
|
||||||
|
|
||||||
|
type RealEnvStore struct {}
|
||||||
|
|
||||||
|
func (e *RealEnvStore) Get(key string) string {
|
||||||
|
return os.Getenv(key)
|
||||||
|
}
|
||||||
|
|
||||||
// Viper is a prioritized configuration registry. It
|
// Viper is a prioritized configuration registry. It
|
||||||
// maintains a set of configuration sources, fetches
|
// maintains a set of configuration sources, fetches
|
||||||
// values to populate those, and provides them according
|
// values to populate those, and provides them according
|
||||||
|
@ -163,10 +173,11 @@ type Viper struct {
|
||||||
typeByDefValue bool
|
typeByDefValue bool
|
||||||
|
|
||||||
onConfigChange func(fsnotify.Event)
|
onConfigChange func(fsnotify.Event)
|
||||||
|
|
||||||
|
envStore EnvStore
|
||||||
}
|
}
|
||||||
|
|
||||||
// New returns an initialized Viper instance.
|
func baseNew() *Viper {
|
||||||
func New() *Viper {
|
|
||||||
v := new(Viper)
|
v := new(Viper)
|
||||||
v.keyDelim = "."
|
v.keyDelim = "."
|
||||||
v.configName = "config"
|
v.configName = "config"
|
||||||
|
@ -179,10 +190,27 @@ func New() *Viper {
|
||||||
v.env = make(map[string]string)
|
v.env = make(map[string]string)
|
||||||
v.aliases = make(map[string]string)
|
v.aliases = make(map[string]string)
|
||||||
v.typeByDefValue = false
|
v.typeByDefValue = false
|
||||||
|
v.envStore = new(RealEnvStore)
|
||||||
|
|
||||||
return v
|
return v
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// New returns an initialized Viper instance.
|
||||||
|
func New() *Viper {
|
||||||
|
v := baseNew()
|
||||||
|
v.fs = afero.NewOsFs()
|
||||||
|
v.envStore = new(RealEnvStore)
|
||||||
|
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
func newFrom(from *Viper) *Viper {
|
||||||
|
v := baseNew()
|
||||||
|
v.fs = from.fs
|
||||||
|
v.envStore = from.envStore
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
// Intended for testing, will reset all to default settings.
|
// Intended for testing, will reset all to default settings.
|
||||||
// In the public interface for the viper package so applications
|
// In the public interface for the viper package so applications
|
||||||
// can use it in their testing as well.
|
// can use it in their testing as well.
|
||||||
|
@ -313,14 +341,14 @@ func (v *Viper) mergeWithEnvPrefix(in string) string {
|
||||||
// rewriting keys many things, Ex: Get('someKey') -> some_key
|
// rewriting keys many things, Ex: Get('someKey') -> some_key
|
||||||
// (camel case to snake case for JSON keys perhaps)
|
// (camel case to snake case for JSON keys perhaps)
|
||||||
|
|
||||||
// getEnv is a wrapper around os.Getenv which replaces characters in the original
|
// getEnv is a wrapper around EnvStore.Get which replaces characters in the original
|
||||||
// key. This allows env vars which have different keys than the config object
|
// key. This allows env vars which have different keys than the config object
|
||||||
// keys.
|
// keys.
|
||||||
func (v *Viper) getEnv(key string) string {
|
func (v *Viper) getEnv(key string) string {
|
||||||
if v.envKeyReplacer != nil {
|
if v.envKeyReplacer != nil {
|
||||||
key = v.envKeyReplacer.Replace(key)
|
key = v.envKeyReplacer.Replace(key)
|
||||||
}
|
}
|
||||||
return os.Getenv(key)
|
return v.envStore.Get(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ConfigFileUsed returns the file used to populate the config registry.
|
// ConfigFileUsed returns the file used to populate the config registry.
|
||||||
|
@ -332,7 +360,7 @@ func (v *Viper) ConfigFileUsed() string { return v.configFile }
|
||||||
func AddConfigPath(in string) { v.AddConfigPath(in) }
|
func AddConfigPath(in string) { v.AddConfigPath(in) }
|
||||||
func (v *Viper) AddConfigPath(in string) {
|
func (v *Viper) AddConfigPath(in string) {
|
||||||
if in != "" {
|
if in != "" {
|
||||||
absin := absPathify(in)
|
absin := absPathify(in, v.envStore)
|
||||||
jww.INFO.Println("adding", absin, "to paths to search")
|
jww.INFO.Println("adding", absin, "to paths to search")
|
||||||
if !stringInSlice(absin, v.configPaths) {
|
if !stringInSlice(absin, v.configPaths) {
|
||||||
v.configPaths = append(v.configPaths, absin)
|
v.configPaths = append(v.configPaths, absin)
|
||||||
|
@ -630,7 +658,7 @@ func (v *Viper) Get(key string) interface{} {
|
||||||
// Sub is case-insensitive for a key.
|
// Sub is case-insensitive for a key.
|
||||||
func Sub(key string) *Viper { return v.Sub(key) }
|
func Sub(key string) *Viper { return v.Sub(key) }
|
||||||
func (v *Viper) Sub(key string) *Viper {
|
func (v *Viper) Sub(key string) *Viper {
|
||||||
subv := New()
|
subv := newFrom(v)
|
||||||
data := v.Get(key)
|
data := v.Get(key)
|
||||||
if data == nil {
|
if data == nil {
|
||||||
return nil
|
return nil
|
||||||
|
@ -1480,6 +1508,11 @@ func (v *Viper) SetFs(fs afero.Fs) {
|
||||||
v.fs = fs
|
v.fs = fs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func SetEnvStore(store EnvStore) { v.SetEnvStore(store) }
|
||||||
|
func (v *Viper) SetEnvStore(store EnvStore) {
|
||||||
|
v.envStore = store
|
||||||
|
}
|
||||||
|
|
||||||
// SetConfigName sets name for the config file.
|
// SetConfigName sets name for the config file.
|
||||||
// Does not include extension.
|
// Does not include extension.
|
||||||
func SetConfigName(in string) { v.SetConfigName(in) }
|
func SetConfigName(in string) { v.SetConfigName(in) }
|
||||||
|
|
|
@ -360,6 +360,50 @@ func TestRemotePrecedence(t *testing.T) {
|
||||||
Set("newkey", "remote")
|
Set("newkey", "remote")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type mapEnv struct {
|
||||||
|
m map[string]string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *mapEnv) Get(key string) string {
|
||||||
|
if val, ok := e.m[key]; ok {
|
||||||
|
return val
|
||||||
|
} else {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *mapEnv) Set(key, value string) {
|
||||||
|
e.m[key] = value
|
||||||
|
}
|
||||||
|
|
||||||
|
func newMapEnv() *mapEnv {
|
||||||
|
mapEnv := new(mapEnv)
|
||||||
|
mapEnv.m = make(map[string]string)
|
||||||
|
return mapEnv
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMockEnv(t *testing.T) {
|
||||||
|
e := newMapEnv()
|
||||||
|
|
||||||
|
initJSON()
|
||||||
|
v.SetEnvStore(e)
|
||||||
|
|
||||||
|
BindEnv("id")
|
||||||
|
BindEnv("f", "FOOD")
|
||||||
|
|
||||||
|
e.Set("ID", "13")
|
||||||
|
e.Set("FOOD", "apple")
|
||||||
|
e.Set("NAME", "crunk")
|
||||||
|
|
||||||
|
assert.Equal(t, "13", Get("id"))
|
||||||
|
assert.Equal(t, "apple", Get("f"))
|
||||||
|
assert.Equal(t, "Cake", Get("name"))
|
||||||
|
|
||||||
|
AutomaticEnv()
|
||||||
|
|
||||||
|
assert.Equal(t, "crunk", Get("name"))
|
||||||
|
}
|
||||||
|
|
||||||
func TestEnv(t *testing.T) {
|
func TestEnv(t *testing.T) {
|
||||||
initJSON()
|
initJSON()
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue