github.com/gbunt/viper@v1.4.1-0.20211229165933-536b581b46d3/viper_test.go (about)

     1  // Copyright © 2014 Steve Francia <spf@spf13.com>.
     2  //
     3  // Use of this source code is governed by an MIT-style
     4  // license that can be found in the LICENSE file.
     5  
     6  package viper
     7  
     8  import (
     9  	"bytes"
    10  	"encoding/json"
    11  	"fmt"
    12  	"io"
    13  	"io/ioutil"
    14  	"os"
    15  	"os/exec"
    16  	"path"
    17  	"reflect"
    18  	"runtime"
    19  	"sort"
    20  	"strings"
    21  	"sync"
    22  	"testing"
    23  	"time"
    24  
    25  	"github.com/fsnotify/fsnotify"
    26  	"github.com/mitchellh/mapstructure"
    27  	"github.com/spf13/afero"
    28  	"github.com/spf13/cast"
    29  
    30  	"github.com/spf13/pflag"
    31  	"github.com/stretchr/testify/assert"
    32  	"github.com/stretchr/testify/require"
    33  )
    34  
    35  var yamlExample = []byte(`Hacker: true
    36  name: steve
    37  hobbies:
    38  - skateboarding
    39  - snowboarding
    40  - go
    41  clothing:
    42    jacket: leather
    43    trousers: denim
    44    pants:
    45      size: large
    46  age: 35
    47  eyes : brown
    48  beard: true
    49  `)
    50  
    51  var yamlExampleWithExtras = []byte(`Existing: true
    52  Bogus: true
    53  `)
    54  
    55  type testUnmarshalExtra struct {
    56  	Existing bool
    57  }
    58  
    59  var tomlExample = []byte(`
    60  title = "TOML Example"
    61  
    62  [owner]
    63  organization = "MongoDB"
    64  Bio = "MongoDB Chief Developer Advocate & Hacker at Large"
    65  dob = 1979-05-27T07:32:00Z # First class dates? Why not?`)
    66  
    67  var jsonExample = []byte(`{
    68  "id": "0001",
    69  "type": "donut",
    70  "name": "Cake",
    71  "password": "p@ss&w<>rd",
    72  "ppu": 0.55,
    73  "batters": {
    74          "batter": [
    75                  { "type": "Regular" },
    76                  { "type": "Chocolate" },
    77                  { "type": "Blueberry" },
    78                  { "type": "Devil's Food" }
    79              ]
    80      }
    81  }`)
    82  
    83  var hclExample = []byte(`
    84  id = "0001"
    85  type = "donut"
    86  name = "Cake"
    87  ppu = 0.55
    88  foos {
    89  	foo {
    90  		key = 1
    91  	}
    92  	foo {
    93  		key = 2
    94  	}
    95  	foo {
    96  		key = 3
    97  	}
    98  	foo {
    99  		key = 4
   100  	}
   101  }`)
   102  
   103  var propertiesExample = []byte(`
   104  p_id: 0001
   105  p_type: donut
   106  p_name: Cake
   107  p_ppu: 0.55
   108  p_batters.batter.type: Regular
   109  `)
   110  
   111  var remoteExample = []byte(`{
   112  "id":"0002",
   113  "type":"cronut",
   114  "newkey":"remote"
   115  }`)
   116  
   117  func initConfigs() {
   118  	Reset()
   119  	var r io.Reader
   120  	SetConfigType("yaml")
   121  	r = bytes.NewReader(yamlExample)
   122  	unmarshalReader(r, v.config)
   123  
   124  	SetConfigType("json")
   125  	r = bytes.NewReader(jsonExample)
   126  	unmarshalReader(r, v.config)
   127  
   128  	SetConfigType("hcl")
   129  	r = bytes.NewReader(hclExample)
   130  	unmarshalReader(r, v.config)
   131  
   132  	SetConfigType("properties")
   133  	r = bytes.NewReader(propertiesExample)
   134  	unmarshalReader(r, v.config)
   135  
   136  	SetConfigType("toml")
   137  	r = bytes.NewReader(tomlExample)
   138  	unmarshalReader(r, v.config)
   139  
   140  	SetConfigType("json")
   141  	remote := bytes.NewReader(remoteExample)
   142  	unmarshalReader(remote, v.kvstore)
   143  }
   144  
   145  func initConfig(typ, config string) {
   146  	Reset()
   147  	SetConfigType(typ)
   148  	r := strings.NewReader(config)
   149  
   150  	if err := unmarshalReader(r, v.config); err != nil {
   151  		panic(err)
   152  	}
   153  }
   154  
   155  func initYAML() {
   156  	initConfig("yaml", string(yamlExample))
   157  }
   158  
   159  func initJSON() {
   160  	Reset()
   161  	SetConfigType("json")
   162  	r := bytes.NewReader(jsonExample)
   163  
   164  	unmarshalReader(r, v.config)
   165  }
   166  
   167  func initProperties() {
   168  	Reset()
   169  	SetConfigType("properties")
   170  	r := bytes.NewReader(propertiesExample)
   171  
   172  	unmarshalReader(r, v.config)
   173  }
   174  
   175  func initTOML() {
   176  	Reset()
   177  	SetConfigType("toml")
   178  	r := bytes.NewReader(tomlExample)
   179  
   180  	unmarshalReader(r, v.config)
   181  }
   182  
   183  func initHcl() {
   184  	Reset()
   185  	SetConfigType("hcl")
   186  	r := bytes.NewReader(hclExample)
   187  
   188  	unmarshalReader(r, v.config)
   189  }
   190  
   191  // make directories for testing
   192  func initDirs(t *testing.T) (string, string, func()) {
   193  
   194  	var (
   195  		testDirs = []string{`a a`, `b`, `c\c`, `D_`}
   196  		config   = `improbable`
   197  	)
   198  
   199  	root, err := ioutil.TempDir("", "")
   200  
   201  	cleanup := true
   202  	defer func() {
   203  		if cleanup {
   204  			os.Chdir("..")
   205  			os.RemoveAll(root)
   206  		}
   207  	}()
   208  
   209  	assert.Nil(t, err)
   210  
   211  	err = os.Chdir(root)
   212  	assert.Nil(t, err)
   213  
   214  	for _, dir := range testDirs {
   215  		err = os.Mkdir(dir, 0750)
   216  		assert.Nil(t, err)
   217  
   218  		err = ioutil.WriteFile(
   219  			path.Join(dir, config+".toml"),
   220  			[]byte("key = \"value is "+dir+"\"\n"),
   221  			0640)
   222  		assert.Nil(t, err)
   223  	}
   224  
   225  	cleanup = false
   226  	return root, config, func() {
   227  		os.Chdir("..")
   228  		os.RemoveAll(root)
   229  	}
   230  }
   231  
   232  //stubs for PFlag Values
   233  type stringValue string
   234  
   235  func newStringValue(val string, p *string) *stringValue {
   236  	*p = val
   237  	return (*stringValue)(p)
   238  }
   239  
   240  func (s *stringValue) Set(val string) error {
   241  	*s = stringValue(val)
   242  	return nil
   243  }
   244  
   245  func (s *stringValue) Type() string {
   246  	return "string"
   247  }
   248  
   249  func (s *stringValue) String() string {
   250  	return fmt.Sprintf("%s", *s)
   251  }
   252  
   253  func TestBasics(t *testing.T) {
   254  	SetConfigFile("/tmp/config.yaml")
   255  	filename, err := v.getConfigFile()
   256  	assert.Equal(t, "/tmp/config.yaml", filename)
   257  	assert.NoError(t, err)
   258  }
   259  
   260  func TestDefault(t *testing.T) {
   261  	SetDefault("age", 45)
   262  	assert.Equal(t, 45, Get("age"))
   263  
   264  	SetDefault("clothing.jacket", "slacks")
   265  	assert.Equal(t, "slacks", Get("clothing.jacket"))
   266  
   267  	SetConfigType("yaml")
   268  	err := ReadConfig(bytes.NewBuffer(yamlExample))
   269  
   270  	assert.NoError(t, err)
   271  	assert.Equal(t, "leather", Get("clothing.jacket"))
   272  }
   273  
   274  func TestUnmarshaling(t *testing.T) {
   275  	SetConfigType("yaml")
   276  	r := bytes.NewReader(yamlExample)
   277  
   278  	unmarshalReader(r, v.config)
   279  	assert.True(t, InConfig("name"))
   280  	assert.False(t, InConfig("state"))
   281  	assert.Equal(t, "steve", Get("name"))
   282  	assert.Equal(t, []interface{}{"skateboarding", "snowboarding", "go"}, Get("hobbies"))
   283  	assert.Equal(t, map[string]interface{}{"jacket": "leather", "trousers": "denim", "pants": map[string]interface{}{"size": "large"}}, Get("clothing"))
   284  	assert.Equal(t, 35, Get("age"))
   285  }
   286  
   287  func TestUnmarshalExact(t *testing.T) {
   288  	vip := New()
   289  	target := &testUnmarshalExtra{}
   290  	vip.SetConfigType("yaml")
   291  	r := bytes.NewReader(yamlExampleWithExtras)
   292  	vip.ReadConfig(r)
   293  	err := vip.UnmarshalExact(target)
   294  	if err == nil {
   295  		t.Fatal("UnmarshalExact should error when populating a struct from a conf that contains unused fields")
   296  	}
   297  }
   298  
   299  func TestOverrides(t *testing.T) {
   300  	Set("age", 40)
   301  	assert.Equal(t, 40, Get("age"))
   302  }
   303  
   304  func TestDefaultPost(t *testing.T) {
   305  	assert.NotEqual(t, "NYC", Get("state"))
   306  	SetDefault("state", "NYC")
   307  	assert.Equal(t, "NYC", Get("state"))
   308  }
   309  
   310  func TestAliases(t *testing.T) {
   311  	RegisterAlias("years", "age")
   312  	assert.Equal(t, 40, Get("years"))
   313  	Set("years", 45)
   314  	assert.Equal(t, 45, Get("age"))
   315  }
   316  
   317  func TestAliasInConfigFile(t *testing.T) {
   318  	// the config file specifies "beard".  If we make this an alias for
   319  	// "hasbeard", we still want the old config file to work with beard.
   320  	RegisterAlias("beard", "hasbeard")
   321  	assert.Equal(t, true, Get("hasbeard"))
   322  	Set("hasbeard", false)
   323  	assert.Equal(t, false, Get("beard"))
   324  }
   325  
   326  func TestYML(t *testing.T) {
   327  	initYAML()
   328  	assert.Equal(t, "steve", Get("name"))
   329  }
   330  
   331  func TestJSON(t *testing.T) {
   332  	initJSON()
   333  	assert.Equal(t, "0001", Get("id"))
   334  }
   335  
   336  func TestProperties(t *testing.T) {
   337  	initProperties()
   338  	assert.Equal(t, "0001", Get("p_id"))
   339  }
   340  
   341  func TestTOML(t *testing.T) {
   342  	initTOML()
   343  	assert.Equal(t, "TOML Example", Get("title"))
   344  }
   345  
   346  func TestHCL(t *testing.T) {
   347  	initHcl()
   348  	assert.Equal(t, "0001", Get("id"))
   349  	assert.Equal(t, 0.55, Get("ppu"))
   350  	assert.Equal(t, "donut", Get("type"))
   351  	assert.Equal(t, "Cake", Get("name"))
   352  	Set("id", "0002")
   353  	assert.Equal(t, "0002", Get("id"))
   354  	assert.NotEqual(t, "cronut", Get("type"))
   355  }
   356  
   357  func TestRemotePrecedence(t *testing.T) {
   358  	initJSON()
   359  
   360  	remote := bytes.NewReader(remoteExample)
   361  	assert.Equal(t, "0001", Get("id"))
   362  	unmarshalReader(remote, v.kvstore)
   363  	assert.Equal(t, "0001", Get("id"))
   364  	assert.NotEqual(t, "cronut", Get("type"))
   365  	assert.Equal(t, "remote", Get("newkey"))
   366  	Set("newkey", "newvalue")
   367  	assert.NotEqual(t, "remote", Get("newkey"))
   368  	assert.Equal(t, "newvalue", Get("newkey"))
   369  	Set("newkey", "remote")
   370  }
   371  
   372  func TestEnv(t *testing.T) {
   373  	initJSON()
   374  
   375  	BindEnv("id")
   376  	BindEnv("f", "FOOD")
   377  
   378  	os.Setenv("ID", "13")
   379  	os.Setenv("FOOD", "apple")
   380  	os.Setenv("NAME", "crunk")
   381  
   382  	assert.Equal(t, "13", Get("id"))
   383  	assert.Equal(t, "apple", Get("f"))
   384  	assert.Equal(t, "Cake", Get("name"))
   385  
   386  	AutomaticEnv()
   387  
   388  	assert.Equal(t, "crunk", Get("name"))
   389  
   390  }
   391  
   392  func TestEmptyEnv(t *testing.T) {
   393  	initJSON()
   394  
   395  	BindEnv("type") // Empty environment variable
   396  	BindEnv("name") // Bound, but not set environment variable
   397  
   398  	os.Clearenv()
   399  
   400  	os.Setenv("TYPE", "")
   401  
   402  	assert.Equal(t, "donut", Get("type"))
   403  	assert.Equal(t, "Cake", Get("name"))
   404  }
   405  
   406  func TestEmptyEnv_Allowed(t *testing.T) {
   407  	initJSON()
   408  
   409  	AllowEmptyEnv(true)
   410  
   411  	BindEnv("type") // Empty environment variable
   412  	BindEnv("name") // Bound, but not set environment variable
   413  
   414  	os.Clearenv()
   415  
   416  	os.Setenv("TYPE", "")
   417  
   418  	assert.Equal(t, "", Get("type"))
   419  	assert.Equal(t, "Cake", Get("name"))
   420  }
   421  
   422  func TestEnvPrefix(t *testing.T) {
   423  	initJSON()
   424  
   425  	SetEnvPrefix("foo") // will be uppercased automatically
   426  	BindEnv("id")
   427  	BindEnv("f", "FOOD") // not using prefix
   428  
   429  	os.Setenv("FOO_ID", "13")
   430  	os.Setenv("FOOD", "apple")
   431  	os.Setenv("FOO_NAME", "crunk")
   432  
   433  	assert.Equal(t, "13", Get("id"))
   434  	assert.Equal(t, "apple", Get("f"))
   435  	assert.Equal(t, "Cake", Get("name"))
   436  
   437  	AutomaticEnv()
   438  
   439  	assert.Equal(t, "crunk", Get("name"))
   440  }
   441  
   442  func TestAutoEnv(t *testing.T) {
   443  	Reset()
   444  
   445  	AutomaticEnv()
   446  	os.Setenv("FOO_BAR", "13")
   447  	assert.Equal(t, "13", Get("foo_bar"))
   448  }
   449  
   450  func TestAutoEnvWithPrefix(t *testing.T) {
   451  	Reset()
   452  
   453  	AutomaticEnv()
   454  	SetEnvPrefix("Baz")
   455  	os.Setenv("BAZ_BAR", "13")
   456  	assert.Equal(t, "13", Get("bar"))
   457  }
   458  
   459  func TestSetEnvKeyReplacer(t *testing.T) {
   460  	Reset()
   461  
   462  	AutomaticEnv()
   463  	os.Setenv("REFRESH_INTERVAL", "30s")
   464  
   465  	replacer := strings.NewReplacer("-", "_")
   466  	SetEnvKeyReplacer(replacer)
   467  
   468  	assert.Equal(t, "30s", Get("refresh-interval"))
   469  }
   470  
   471  func TestAllKeys(t *testing.T) {
   472  	initConfigs()
   473  
   474  	ks := sort.StringSlice{"title", "newkey", "owner.organization", "owner.dob", "owner.bio", "name", "beard", "ppu", "batters.batter", "hobbies", "clothing.jacket", "clothing.trousers", "clothing.pants.size", "age", "hacker", "id", "type", "eyes", "p_id", "p_ppu", "p_batters.batter.type", "p_type", "password", "p_name", "foos"}
   475  	dob, _ := time.Parse(time.RFC3339, "1979-05-27T07:32:00Z")
   476  	all := map[string]interface{}{"owner": map[string]interface{}{"organization": "MongoDB", "bio": "MongoDB Chief Developer Advocate & Hacker at Large", "dob": dob}, "title": "TOML Example", "ppu": 0.55, "eyes": "brown", "clothing": map[string]interface{}{"trousers": "denim", "jacket": "leather", "pants": map[string]interface{}{"size": "large"}}, "id": "0001", "batters": map[string]interface{}{"batter": []interface{}{map[string]interface{}{"type": "Regular"}, map[string]interface{}{"type": "Chocolate"}, map[string]interface{}{"type": "Blueberry"}, map[string]interface{}{"type": "Devil's Food"}}}, "hacker": true, "beard": true, "hobbies": []interface{}{"skateboarding", "snowboarding", "go"}, "age": 35, "type": "donut", "password": "p@ss&w<>rd", "newkey": "remote", "name": "Cake", "p_id": "0001", "p_ppu": "0.55", "p_name": "Cake", "p_batters": map[string]interface{}{"batter": map[string]interface{}{"type": "Regular"}}, "p_type": "donut", "foos": []map[string]interface{}{map[string]interface{}{"foo": []map[string]interface{}{map[string]interface{}{"key": 1}, map[string]interface{}{"key": 2}, map[string]interface{}{"key": 3}, map[string]interface{}{"key": 4}}}}}
   477  
   478  	var allkeys sort.StringSlice
   479  	allkeys = AllKeys()
   480  	allkeys.Sort()
   481  	ks.Sort()
   482  
   483  	assert.Equal(t, ks, allkeys)
   484  	assert.Equal(t, all, AllSettings())
   485  }
   486  
   487  func TestAllKeysWithEnv(t *testing.T) {
   488  	v := New()
   489  
   490  	// bind and define environment variables (including a nested one)
   491  	v.BindEnv("id")
   492  	v.BindEnv("foo.bar")
   493  	v.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
   494  	os.Setenv("ID", "13")
   495  	os.Setenv("FOO_BAR", "baz")
   496  
   497  	expectedKeys := sort.StringSlice{"id", "foo.bar"}
   498  	expectedKeys.Sort()
   499  	keys := sort.StringSlice(v.AllKeys())
   500  	keys.Sort()
   501  	assert.Equal(t, expectedKeys, keys)
   502  }
   503  
   504  func TestAliasesOfAliases(t *testing.T) {
   505  	Set("Title", "Checking Case")
   506  	RegisterAlias("Foo", "Bar")
   507  	RegisterAlias("Bar", "Title")
   508  	assert.Equal(t, "Checking Case", Get("FOO"))
   509  }
   510  
   511  func TestRecursiveAliases(t *testing.T) {
   512  	RegisterAlias("Baz", "Roo")
   513  	RegisterAlias("Roo", "baz")
   514  }
   515  
   516  func TestUnmarshal(t *testing.T) {
   517  	SetDefault("port", 1313)
   518  	Set("name", "Steve")
   519  	Set("duration", "1s1ms")
   520  
   521  	type config struct {
   522  		Port     int
   523  		Name     string
   524  		Duration time.Duration
   525  	}
   526  
   527  	var C config
   528  
   529  	err := Unmarshal(&C)
   530  	if err != nil {
   531  		t.Fatalf("unable to decode into struct, %v", err)
   532  	}
   533  
   534  	assert.Equal(t, &config{Name: "Steve", Port: 1313, Duration: time.Second + time.Millisecond}, &C)
   535  
   536  	Set("port", 1234)
   537  	err = Unmarshal(&C)
   538  	if err != nil {
   539  		t.Fatalf("unable to decode into struct, %v", err)
   540  	}
   541  	assert.Equal(t, &config{Name: "Steve", Port: 1234, Duration: time.Second + time.Millisecond}, &C)
   542  }
   543  
   544  func TestUnmarshalWithDecoderOptions(t *testing.T) {
   545  	Set("credentials", "{\"foo\":\"bar\"}")
   546  
   547  	opt := DecodeHook(mapstructure.ComposeDecodeHookFunc(
   548  		mapstructure.StringToTimeDurationHookFunc(),
   549  		mapstructure.StringToSliceHookFunc(","),
   550  		// Custom Decode Hook Function
   551  		func(rf reflect.Kind, rt reflect.Kind, data interface{}) (interface{}, error) {
   552  			if rf != reflect.String || rt != reflect.Map {
   553  				return data, nil
   554  			}
   555  			m := map[string]string{}
   556  			raw := data.(string)
   557  			if raw == "" {
   558  				return m, nil
   559  			}
   560  			return m, json.Unmarshal([]byte(raw), &m)
   561  		},
   562  	))
   563  
   564  	type config struct {
   565  		Credentials map[string]string
   566  	}
   567  
   568  	var C config
   569  
   570  	err := Unmarshal(&C, opt)
   571  	if err != nil {
   572  		t.Fatalf("unable to decode into struct, %v", err)
   573  	}
   574  
   575  	assert.Equal(t, &config{
   576  		Credentials: map[string]string{"foo": "bar"},
   577  	}, &C)
   578  }
   579  
   580  func TestBindPFlags(t *testing.T) {
   581  	v := New() // create independent Viper object
   582  	flagSet := pflag.NewFlagSet("test", pflag.ContinueOnError)
   583  
   584  	var testValues = map[string]*string{
   585  		"host":     nil,
   586  		"port":     nil,
   587  		"endpoint": nil,
   588  	}
   589  
   590  	var mutatedTestValues = map[string]string{
   591  		"host":     "localhost",
   592  		"port":     "6060",
   593  		"endpoint": "/public",
   594  	}
   595  
   596  	for name := range testValues {
   597  		testValues[name] = flagSet.String(name, "", "test")
   598  	}
   599  
   600  	err := v.BindPFlags(flagSet)
   601  	if err != nil {
   602  		t.Fatalf("error binding flag set, %v", err)
   603  	}
   604  
   605  	flagSet.VisitAll(func(flag *pflag.Flag) {
   606  		flag.Value.Set(mutatedTestValues[flag.Name])
   607  		flag.Changed = true
   608  	})
   609  
   610  	for name, expected := range mutatedTestValues {
   611  		assert.Equal(t, expected, v.Get(name))
   612  	}
   613  
   614  }
   615  
   616  func TestBindPFlagsStringSlice(t *testing.T) {
   617  	tests := []struct {
   618  		Expected []string
   619  		Value    string
   620  	}{
   621  		{nil, ""},
   622  		{[]string{"jeden"}, "jeden"},
   623  		{[]string{"dwa", "trzy"}, "dwa,trzy"},
   624  		{[]string{"cztery", "piec , szesc"}, "cztery,\"piec , szesc\""},
   625  	}
   626  
   627  	v := New() // create independent Viper object
   628  	defaultVal := []string{"default"}
   629  	v.SetDefault("stringslice", defaultVal)
   630  
   631  	for _, testValue := range tests {
   632  		flagSet := pflag.NewFlagSet("test", pflag.ContinueOnError)
   633  		flagSet.StringSlice("stringslice", testValue.Expected, "test")
   634  
   635  		for _, changed := range []bool{true, false} {
   636  			flagSet.VisitAll(func(f *pflag.Flag) {
   637  				f.Value.Set(testValue.Value)
   638  				f.Changed = changed
   639  			})
   640  
   641  			err := v.BindPFlags(flagSet)
   642  			if err != nil {
   643  				t.Fatalf("error binding flag set, %v", err)
   644  			}
   645  
   646  			type TestStr struct {
   647  				StringSlice []string
   648  			}
   649  			val := &TestStr{}
   650  			if err := v.Unmarshal(val); err != nil {
   651  				t.Fatalf("%+#v cannot unmarshal: %s", testValue.Value, err)
   652  			}
   653  			if changed {
   654  				assert.Equal(t, testValue.Expected, val.StringSlice)
   655  			} else {
   656  				assert.Equal(t, defaultVal, val.StringSlice)
   657  			}
   658  		}
   659  	}
   660  }
   661  
   662  func TestBindPFlag(t *testing.T) {
   663  	var testString = "testing"
   664  	var testValue = newStringValue(testString, &testString)
   665  
   666  	flag := &pflag.Flag{
   667  		Name:    "testflag",
   668  		Value:   testValue,
   669  		Changed: false,
   670  	}
   671  
   672  	BindPFlag("testvalue", flag)
   673  
   674  	assert.Equal(t, testString, Get("testvalue"))
   675  
   676  	flag.Value.Set("testing_mutate")
   677  	flag.Changed = true //hack for pflag usage
   678  
   679  	assert.Equal(t, "testing_mutate", Get("testvalue"))
   680  
   681  }
   682  
   683  func TestBoundCaseSensitivity(t *testing.T) {
   684  	assert.Equal(t, "brown", Get("eyes"))
   685  
   686  	BindEnv("eYEs", "TURTLE_EYES")
   687  	os.Setenv("TURTLE_EYES", "blue")
   688  
   689  	assert.Equal(t, "blue", Get("eyes"))
   690  
   691  	var testString = "green"
   692  	var testValue = newStringValue(testString, &testString)
   693  
   694  	flag := &pflag.Flag{
   695  		Name:    "eyeballs",
   696  		Value:   testValue,
   697  		Changed: true,
   698  	}
   699  
   700  	BindPFlag("eYEs", flag)
   701  	assert.Equal(t, "green", Get("eyes"))
   702  
   703  }
   704  
   705  func TestSizeInBytes(t *testing.T) {
   706  	input := map[string]uint{
   707  		"":               0,
   708  		"b":              0,
   709  		"12 bytes":       0,
   710  		"200000000000gb": 0,
   711  		"12 b":           12,
   712  		"43 MB":          43 * (1 << 20),
   713  		"10mb":           10 * (1 << 20),
   714  		"1gb":            1 << 30,
   715  	}
   716  
   717  	for str, expected := range input {
   718  		assert.Equal(t, expected, parseSizeInBytes(str), str)
   719  	}
   720  }
   721  
   722  func TestFindsNestedKeys(t *testing.T) {
   723  	initConfigs()
   724  	dob, _ := time.Parse(time.RFC3339, "1979-05-27T07:32:00Z")
   725  
   726  	Set("super", map[string]interface{}{
   727  		"deep": map[string]interface{}{
   728  			"nested": "value",
   729  		},
   730  	})
   731  
   732  	expected := map[string]interface{}{
   733  		"super": map[string]interface{}{
   734  			"deep": map[string]interface{}{
   735  				"nested": "value",
   736  			},
   737  		},
   738  		"super.deep": map[string]interface{}{
   739  			"nested": "value",
   740  		},
   741  		"super.deep.nested":  "value",
   742  		"owner.organization": "MongoDB",
   743  		"batters.batter": []interface{}{
   744  			map[string]interface{}{
   745  				"type": "Regular",
   746  			},
   747  			map[string]interface{}{
   748  				"type": "Chocolate",
   749  			},
   750  			map[string]interface{}{
   751  				"type": "Blueberry",
   752  			},
   753  			map[string]interface{}{
   754  				"type": "Devil's Food",
   755  			},
   756  		},
   757  		"hobbies": []interface{}{
   758  			"skateboarding", "snowboarding", "go",
   759  		},
   760  		"title":  "TOML Example",
   761  		"newkey": "remote",
   762  		"batters": map[string]interface{}{
   763  			"batter": []interface{}{
   764  				map[string]interface{}{
   765  					"type": "Regular",
   766  				},
   767  				map[string]interface{}{
   768  					"type": "Chocolate",
   769  				}, map[string]interface{}{
   770  					"type": "Blueberry",
   771  				}, map[string]interface{}{
   772  					"type": "Devil's Food",
   773  				},
   774  			},
   775  		},
   776  		"eyes": "brown",
   777  		"age":  35,
   778  		"owner": map[string]interface{}{
   779  			"organization": "MongoDB",
   780  			"bio":          "MongoDB Chief Developer Advocate & Hacker at Large",
   781  			"dob":          dob,
   782  		},
   783  		"owner.bio": "MongoDB Chief Developer Advocate & Hacker at Large",
   784  		"type":      "donut",
   785  		"id":        "0001",
   786  		"name":      "Cake",
   787  		"hacker":    true,
   788  		"ppu":       0.55,
   789  		"clothing": map[string]interface{}{
   790  			"jacket":   "leather",
   791  			"trousers": "denim",
   792  			"pants": map[string]interface{}{
   793  				"size": "large",
   794  			},
   795  		},
   796  		"clothing.jacket":     "leather",
   797  		"clothing.pants.size": "large",
   798  		"clothing.trousers":   "denim",
   799  		"owner.dob":           dob,
   800  		"beard":               true,
   801  		"foos": []map[string]interface{}{
   802  			map[string]interface{}{
   803  				"foo": []map[string]interface{}{
   804  					map[string]interface{}{
   805  						"key": 1,
   806  					},
   807  					map[string]interface{}{
   808  						"key": 2,
   809  					},
   810  					map[string]interface{}{
   811  						"key": 3,
   812  					},
   813  					map[string]interface{}{
   814  						"key": 4,
   815  					},
   816  				},
   817  			},
   818  		},
   819  	}
   820  
   821  	for key, expectedValue := range expected {
   822  
   823  		assert.Equal(t, expectedValue, v.Get(key))
   824  	}
   825  
   826  }
   827  
   828  func TestReadBufConfig(t *testing.T) {
   829  	v := New()
   830  	v.SetConfigType("yaml")
   831  	v.ReadConfig(bytes.NewBuffer(yamlExample))
   832  	t.Log(v.AllKeys())
   833  
   834  	assert.True(t, v.InConfig("name"))
   835  	assert.False(t, v.InConfig("state"))
   836  	assert.Equal(t, "steve", v.Get("name"))
   837  	assert.Equal(t, []interface{}{"skateboarding", "snowboarding", "go"}, v.Get("hobbies"))
   838  	assert.Equal(t, map[string]interface{}{"jacket": "leather", "trousers": "denim", "pants": map[string]interface{}{"size": "large"}}, v.Get("clothing"))
   839  	assert.Equal(t, 35, v.Get("age"))
   840  }
   841  
   842  func TestIsSet(t *testing.T) {
   843  	v := New()
   844  	v.SetConfigType("yaml")
   845  	v.ReadConfig(bytes.NewBuffer(yamlExample))
   846  	assert.True(t, v.IsSet("clothing.jacket"))
   847  	assert.False(t, v.IsSet("clothing.jackets"))
   848  	assert.False(t, v.IsSet("helloworld"))
   849  	v.Set("helloworld", "fubar")
   850  	assert.True(t, v.IsSet("helloworld"))
   851  }
   852  
   853  func TestDirsSearch(t *testing.T) {
   854  
   855  	root, config, cleanup := initDirs(t)
   856  	defer cleanup()
   857  
   858  	v := New()
   859  	v.SetConfigName(config)
   860  	v.SetDefault(`key`, `default`)
   861  
   862  	entries, err := ioutil.ReadDir(root)
   863  	for _, e := range entries {
   864  		if e.IsDir() {
   865  			v.AddConfigPath(e.Name())
   866  		}
   867  	}
   868  
   869  	err = v.ReadInConfig()
   870  	assert.Nil(t, err)
   871  
   872  	assert.Equal(t, `value is `+path.Base(v.configPaths[0]), v.GetString(`key`))
   873  }
   874  
   875  func TestWrongDirsSearchNotFound(t *testing.T) {
   876  
   877  	_, config, cleanup := initDirs(t)
   878  	defer cleanup()
   879  
   880  	v := New()
   881  	v.SetConfigName(config)
   882  	v.SetDefault(`key`, `default`)
   883  
   884  	v.AddConfigPath(`whattayoutalkingbout`)
   885  	v.AddConfigPath(`thispathaintthere`)
   886  
   887  	err := v.ReadInConfig()
   888  	assert.Equal(t, reflect.TypeOf(ConfigFileNotFoundError{"", ""}), reflect.TypeOf(err))
   889  
   890  	// Even though config did not load and the error might have
   891  	// been ignored by the client, the default still loads
   892  	assert.Equal(t, `default`, v.GetString(`key`))
   893  }
   894  
   895  func TestWrongDirsSearchNotFoundForMerge(t *testing.T) {
   896  
   897  	_, config, cleanup := initDirs(t)
   898  	defer cleanup()
   899  
   900  	v := New()
   901  	v.SetConfigName(config)
   902  	v.SetDefault(`key`, `default`)
   903  
   904  	v.AddConfigPath(`whattayoutalkingbout`)
   905  	v.AddConfigPath(`thispathaintthere`)
   906  
   907  	err := v.MergeInConfig()
   908  	assert.Equal(t, reflect.TypeOf(ConfigFileNotFoundError{"", ""}), reflect.TypeOf(err))
   909  
   910  	// Even though config did not load and the error might have
   911  	// been ignored by the client, the default still loads
   912  	assert.Equal(t, `default`, v.GetString(`key`))
   913  }
   914  
   915  func TestSub(t *testing.T) {
   916  	v := New()
   917  	v.SetConfigType("yaml")
   918  	v.ReadConfig(bytes.NewBuffer(yamlExample))
   919  
   920  	subv := v.Sub("clothing")
   921  	assert.Equal(t, v.Get("clothing.pants.size"), subv.Get("pants.size"))
   922  
   923  	subv = v.Sub("clothing.pants")
   924  	assert.Equal(t, v.Get("clothing.pants.size"), subv.Get("size"))
   925  
   926  	subv = v.Sub("clothing.pants.size")
   927  	assert.Equal(t, (*Viper)(nil), subv)
   928  
   929  	subv = v.Sub("missing.key")
   930  	assert.Equal(t, (*Viper)(nil), subv)
   931  }
   932  
   933  var hclWriteExpected = []byte(`"foos" = {
   934    "foo" = {
   935      "key" = 1
   936    }
   937  
   938    "foo" = {
   939      "key" = 2
   940    }
   941  
   942    "foo" = {
   943      "key" = 3
   944    }
   945  
   946    "foo" = {
   947      "key" = 4
   948    }
   949  }
   950  
   951  "id" = "0001"
   952  
   953  "name" = "Cake"
   954  
   955  "ppu" = 0.55
   956  
   957  "type" = "donut"`)
   958  
   959  func TestWriteConfigHCL(t *testing.T) {
   960  	v := New()
   961  	fs := afero.NewMemMapFs()
   962  	v.SetFs(fs)
   963  	v.SetConfigName("c")
   964  	v.SetConfigType("hcl")
   965  	err := v.ReadConfig(bytes.NewBuffer(hclExample))
   966  	if err != nil {
   967  		t.Fatal(err)
   968  	}
   969  	if err := v.WriteConfigAs("c.hcl"); err != nil {
   970  		t.Fatal(err)
   971  	}
   972  	read, err := afero.ReadFile(fs, "c.hcl")
   973  	if err != nil {
   974  		t.Fatal(err)
   975  	}
   976  	assert.Equal(t, hclWriteExpected, read)
   977  }
   978  
   979  var jsonWriteExpected = []byte(`{
   980    "batters": {
   981      "batter": [
   982        {
   983          "type": "Regular"
   984        },
   985        {
   986          "type": "Chocolate"
   987        },
   988        {
   989          "type": "Blueberry"
   990        },
   991        {
   992          "type": "Devil's Food"
   993        }
   994      ]
   995    },
   996    "id": "0001",
   997    "name": "Cake",
   998    "password": "p@ss&w<>rd",
   999    "ppu": 0.55,
  1000    "type": "donut"
  1001  }`)
  1002  
  1003  func TestWriteConfigJson(t *testing.T) {
  1004  	v := New()
  1005  	fs := afero.NewMemMapFs()
  1006  	v.SetFs(fs)
  1007  	v.SetConfigName("c")
  1008  	v.SetConfigType("json")
  1009  	err := v.ReadConfig(bytes.NewBuffer(jsonExample))
  1010  	if err != nil {
  1011  		t.Fatal(err)
  1012  	}
  1013  	if err := v.WriteConfigAs("c.json"); err != nil {
  1014  		t.Fatal(err)
  1015  	}
  1016  	read, err := afero.ReadFile(fs, "c.json")
  1017  	if err != nil {
  1018  		t.Fatal(err)
  1019  	}
  1020  	assert.Equal(t, jsonWriteExpected, read)
  1021  }
  1022  
  1023  var propertiesWriteExpected = []byte(`p_id = 0001
  1024  p_type = donut
  1025  p_name = Cake
  1026  p_ppu = 0.55
  1027  p_batters.batter.type = Regular
  1028  `)
  1029  
  1030  func TestWriteConfigProperties(t *testing.T) {
  1031  	v := New()
  1032  	fs := afero.NewMemMapFs()
  1033  	v.SetFs(fs)
  1034  	v.SetConfigName("c")
  1035  	v.SetConfigType("properties")
  1036  	err := v.ReadConfig(bytes.NewBuffer(propertiesExample))
  1037  	if err != nil {
  1038  		t.Fatal(err)
  1039  	}
  1040  	if err := v.WriteConfigAs("c.properties"); err != nil {
  1041  		t.Fatal(err)
  1042  	}
  1043  	read, err := afero.ReadFile(fs, "c.properties")
  1044  	if err != nil {
  1045  		t.Fatal(err)
  1046  	}
  1047  	assert.Equal(t, propertiesWriteExpected, read)
  1048  }
  1049  
  1050  func TestWriteConfigTOML(t *testing.T) {
  1051  	fs := afero.NewMemMapFs()
  1052  	v := New()
  1053  	v.SetFs(fs)
  1054  	v.SetConfigName("c")
  1055  	v.SetConfigType("toml")
  1056  	err := v.ReadConfig(bytes.NewBuffer(tomlExample))
  1057  	if err != nil {
  1058  		t.Fatal(err)
  1059  	}
  1060  	if err := v.WriteConfigAs("c.toml"); err != nil {
  1061  		t.Fatal(err)
  1062  	}
  1063  
  1064  	// The TOML String method does not order the contents.
  1065  	// Therefore, we must read the generated file and compare the data.
  1066  	v2 := New()
  1067  	v2.SetFs(fs)
  1068  	v2.SetConfigName("c")
  1069  	v2.SetConfigType("toml")
  1070  	v2.SetConfigFile("c.toml")
  1071  	err = v2.ReadInConfig()
  1072  	if err != nil {
  1073  		t.Fatal(err)
  1074  	}
  1075  
  1076  	assert.Equal(t, v.GetString("title"), v2.GetString("title"))
  1077  	assert.Equal(t, v.GetString("owner.bio"), v2.GetString("owner.bio"))
  1078  	assert.Equal(t, v.GetString("owner.dob"), v2.GetString("owner.dob"))
  1079  	assert.Equal(t, v.GetString("owner.organization"), v2.GetString("owner.organization"))
  1080  }
  1081  
  1082  var yamlWriteExpected = []byte(`age: 35
  1083  beard: true
  1084  clothing:
  1085    jacket: leather
  1086    pants:
  1087      size: large
  1088    trousers: denim
  1089  eyes: brown
  1090  hacker: true
  1091  hobbies:
  1092  - skateboarding
  1093  - snowboarding
  1094  - go
  1095  name: steve
  1096  `)
  1097  
  1098  func TestWriteConfigYAML(t *testing.T) {
  1099  	v := New()
  1100  	fs := afero.NewMemMapFs()
  1101  	v.SetFs(fs)
  1102  	v.SetConfigName("c")
  1103  	v.SetConfigType("yaml")
  1104  	err := v.ReadConfig(bytes.NewBuffer(yamlExample))
  1105  	if err != nil {
  1106  		t.Fatal(err)
  1107  	}
  1108  	if err := v.WriteConfigAs("c.yaml"); err != nil {
  1109  		t.Fatal(err)
  1110  	}
  1111  	read, err := afero.ReadFile(fs, "c.yaml")
  1112  	if err != nil {
  1113  		t.Fatal(err)
  1114  	}
  1115  	assert.Equal(t, yamlWriteExpected, read)
  1116  }
  1117  
  1118  var yamlMergeExampleTgt = []byte(`
  1119  hello:
  1120      pop: 37890
  1121      largenum: 765432101234567
  1122      num2pow63: 9223372036854775808
  1123      world:
  1124      - us
  1125      - uk
  1126      - fr
  1127      - de
  1128  `)
  1129  
  1130  var yamlMergeExampleSrc = []byte(`
  1131  hello:
  1132      pop: 45000
  1133      largenum: 7654321001234567
  1134      universe:
  1135      - mw
  1136      - ad
  1137  fu: bar
  1138  `)
  1139  
  1140  func TestMergeConfig(t *testing.T) {
  1141  	v := New()
  1142  	v.SetConfigType("yml")
  1143  	if err := v.ReadConfig(bytes.NewBuffer(yamlMergeExampleTgt)); err != nil {
  1144  		t.Fatal(err)
  1145  	}
  1146  
  1147  	if pop := v.GetInt("hello.pop"); pop != 37890 {
  1148  		t.Fatalf("pop != 37890, = %d", pop)
  1149  	}
  1150  
  1151  	if pop := v.GetInt32("hello.pop"); pop != int32(37890) {
  1152  		t.Fatalf("pop != 37890, = %d", pop)
  1153  	}
  1154  
  1155  	if pop := v.GetInt64("hello.largenum"); pop != int64(765432101234567) {
  1156  		t.Fatalf("int64 largenum != 765432101234567, = %d", pop)
  1157  	}
  1158  
  1159  	if pop := v.GetUint("hello.pop"); pop != 37890 {
  1160  		t.Fatalf("uint pop != 37890, = %d", pop)
  1161  	}
  1162  
  1163  	if pop := v.GetUint32("hello.pop"); pop != 37890 {
  1164  		t.Fatalf("uint32 pop != 37890, = %d", pop)
  1165  	}
  1166  
  1167  	if pop := v.GetUint64("hello.num2pow63"); pop != 9223372036854775808 {
  1168  		t.Fatalf("uint64 num2pow63 != 9223372036854775808, = %d", pop)
  1169  	}
  1170  
  1171  	if world := v.GetStringSlice("hello.world"); len(world) != 4 {
  1172  		t.Fatalf("len(world) != 4, = %d", len(world))
  1173  	}
  1174  
  1175  	if fu := v.GetString("fu"); fu != "" {
  1176  		t.Fatalf("fu != \"\", = %s", fu)
  1177  	}
  1178  
  1179  	if err := v.MergeConfig(bytes.NewBuffer(yamlMergeExampleSrc)); err != nil {
  1180  		t.Fatal(err)
  1181  	}
  1182  
  1183  	if pop := v.GetInt("hello.pop"); pop != 45000 {
  1184  		t.Fatalf("pop != 45000, = %d", pop)
  1185  	}
  1186  
  1187  	if pop := v.GetInt32("hello.pop"); pop != int32(45000) {
  1188  		t.Fatalf("pop != 45000, = %d", pop)
  1189  	}
  1190  
  1191  	if pop := v.GetInt64("hello.largenum"); pop != int64(7654321001234567) {
  1192  		t.Fatalf("int64 largenum != 7654321001234567, = %d", pop)
  1193  	}
  1194  
  1195  	if world := v.GetStringSlice("hello.world"); len(world) != 4 {
  1196  		t.Fatalf("len(world) != 4, = %d", len(world))
  1197  	}
  1198  
  1199  	if universe := v.GetStringSlice("hello.universe"); len(universe) != 2 {
  1200  		t.Fatalf("len(universe) != 2, = %d", len(universe))
  1201  	}
  1202  
  1203  	if fu := v.GetString("fu"); fu != "bar" {
  1204  		t.Fatalf("fu != \"bar\", = %s", fu)
  1205  	}
  1206  }
  1207  
  1208  func TestMergeConfigNoMerge(t *testing.T) {
  1209  	v := New()
  1210  	v.SetConfigType("yml")
  1211  	if err := v.ReadConfig(bytes.NewBuffer(yamlMergeExampleTgt)); err != nil {
  1212  		t.Fatal(err)
  1213  	}
  1214  
  1215  	if pop := v.GetInt("hello.pop"); pop != 37890 {
  1216  		t.Fatalf("pop != 37890, = %d", pop)
  1217  	}
  1218  
  1219  	if world := v.GetStringSlice("hello.world"); len(world) != 4 {
  1220  		t.Fatalf("len(world) != 4, = %d", len(world))
  1221  	}
  1222  
  1223  	if fu := v.GetString("fu"); fu != "" {
  1224  		t.Fatalf("fu != \"\", = %s", fu)
  1225  	}
  1226  
  1227  	if err := v.ReadConfig(bytes.NewBuffer(yamlMergeExampleSrc)); err != nil {
  1228  		t.Fatal(err)
  1229  	}
  1230  
  1231  	if pop := v.GetInt("hello.pop"); pop != 45000 {
  1232  		t.Fatalf("pop != 45000, = %d", pop)
  1233  	}
  1234  
  1235  	if world := v.GetStringSlice("hello.world"); len(world) != 0 {
  1236  		t.Fatalf("len(world) != 0, = %d", len(world))
  1237  	}
  1238  
  1239  	if universe := v.GetStringSlice("hello.universe"); len(universe) != 2 {
  1240  		t.Fatalf("len(universe) != 2, = %d", len(universe))
  1241  	}
  1242  
  1243  	if fu := v.GetString("fu"); fu != "bar" {
  1244  		t.Fatalf("fu != \"bar\", = %s", fu)
  1245  	}
  1246  }
  1247  
  1248  func TestMergeConfigMap(t *testing.T) {
  1249  	v := New()
  1250  	v.SetConfigType("yml")
  1251  	if err := v.ReadConfig(bytes.NewBuffer(yamlMergeExampleTgt)); err != nil {
  1252  		t.Fatal(err)
  1253  	}
  1254  
  1255  	assert := func(i int) {
  1256  		large := v.GetInt64("hello.largenum")
  1257  		pop := v.GetInt("hello.pop")
  1258  		if large != 765432101234567 {
  1259  			t.Fatal("Got large num:", large)
  1260  		}
  1261  
  1262  		if pop != i {
  1263  			t.Fatal("Got pop:", pop)
  1264  		}
  1265  	}
  1266  
  1267  	assert(37890)
  1268  
  1269  	update := map[string]interface{}{
  1270  		"Hello": map[string]interface{}{
  1271  			"Pop": 1234,
  1272  		},
  1273  		"World": map[interface{}]interface{}{
  1274  			"Rock": 345,
  1275  		},
  1276  	}
  1277  
  1278  	if err := v.MergeConfigMap(update); err != nil {
  1279  		t.Fatal(err)
  1280  	}
  1281  
  1282  	if rock := v.GetInt("world.rock"); rock != 345 {
  1283  		t.Fatal("Got rock:", rock)
  1284  	}
  1285  
  1286  	assert(1234)
  1287  
  1288  }
  1289  
  1290  func TestUnmarshalingWithAliases(t *testing.T) {
  1291  	v := New()
  1292  	v.SetDefault("ID", 1)
  1293  	v.Set("name", "Steve")
  1294  	v.Set("lastname", "Owen")
  1295  
  1296  	v.RegisterAlias("UserID", "ID")
  1297  	v.RegisterAlias("Firstname", "name")
  1298  	v.RegisterAlias("Surname", "lastname")
  1299  
  1300  	type config struct {
  1301  		ID        int
  1302  		FirstName string
  1303  		Surname   string
  1304  	}
  1305  
  1306  	var C config
  1307  	err := v.Unmarshal(&C)
  1308  	if err != nil {
  1309  		t.Fatalf("unable to decode into struct, %v", err)
  1310  	}
  1311  
  1312  	assert.Equal(t, &config{ID: 1, FirstName: "Steve", Surname: "Owen"}, &C)
  1313  }
  1314  
  1315  func TestSetConfigNameClearsFileCache(t *testing.T) {
  1316  	SetConfigFile("/tmp/config.yaml")
  1317  	SetConfigName("default")
  1318  	f, err := v.getConfigFile()
  1319  	if err == nil {
  1320  		t.Fatalf("config file cache should have been cleared")
  1321  	}
  1322  	assert.Empty(t, f)
  1323  }
  1324  
  1325  func TestShadowedNestedValue(t *testing.T) {
  1326  
  1327  	config := `name: steve
  1328  clothing:
  1329    jacket: leather
  1330    trousers: denim
  1331    pants:
  1332      size: large
  1333  `
  1334  	initConfig("yaml", config)
  1335  
  1336  	assert.Equal(t, "steve", GetString("name"))
  1337  
  1338  	polyester := "polyester"
  1339  	SetDefault("clothing.shirt", polyester)
  1340  	SetDefault("clothing.jacket.price", 100)
  1341  
  1342  	assert.Equal(t, "leather", GetString("clothing.jacket"))
  1343  	assert.Nil(t, Get("clothing.jacket.price"))
  1344  	assert.Equal(t, polyester, GetString("clothing.shirt"))
  1345  
  1346  	clothingSettings := AllSettings()["clothing"].(map[string]interface{})
  1347  	assert.Equal(t, "leather", clothingSettings["jacket"])
  1348  	assert.Equal(t, polyester, clothingSettings["shirt"])
  1349  }
  1350  
  1351  func TestDotParameter(t *testing.T) {
  1352  	initJSON()
  1353  	// shoud take precedence over batters defined in jsonExample
  1354  	r := bytes.NewReader([]byte(`{ "batters.batter": [ { "type": "Small" } ] }`))
  1355  	unmarshalReader(r, v.config)
  1356  
  1357  	actual := Get("batters.batter")
  1358  	expected := []interface{}{map[string]interface{}{"type": "Small"}}
  1359  	assert.Equal(t, expected, actual)
  1360  }
  1361  
  1362  func TestCaseInsensitive(t *testing.T) {
  1363  	for _, config := range []struct {
  1364  		typ     string
  1365  		content string
  1366  	}{
  1367  		{"yaml", `
  1368  aBcD: 1
  1369  eF:
  1370    gH: 2
  1371    iJk: 3
  1372    Lm:
  1373      nO: 4
  1374      P:
  1375        Q: 5
  1376        R: 6
  1377  `},
  1378  		{"json", `{
  1379    "aBcD": 1,
  1380    "eF": {
  1381      "iJk": 3,
  1382      "Lm": {
  1383        "P": {
  1384          "Q": 5,
  1385          "R": 6
  1386        },
  1387        "nO": 4
  1388      },
  1389      "gH": 2
  1390    }
  1391  }`},
  1392  		{"toml", `aBcD = 1
  1393  [eF]
  1394  gH = 2
  1395  iJk = 3
  1396  [eF.Lm]
  1397  nO = 4
  1398  [eF.Lm.P]
  1399  Q = 5
  1400  R = 6
  1401  `},
  1402  	} {
  1403  		doTestCaseInsensitive(t, config.typ, config.content)
  1404  	}
  1405  }
  1406  
  1407  func TestCaseSensitive(t *testing.T) {
  1408  	for _, config := range []struct {
  1409  		typ     string
  1410  		content string
  1411  	}{
  1412  		{"yaml", `
  1413  aBcD: 1
  1414  eF:
  1415    gH: 2
  1416    iJk: 3
  1417    Lm:
  1418      nO: 4
  1419      P:
  1420        Q: 5
  1421        R: 6
  1422  `},
  1423  		{"json", `{
  1424    "aBcD": 1,
  1425    "eF": {
  1426      "iJk": 3,
  1427      "Lm": {
  1428        "P": {
  1429          "Q": 5,
  1430          "R": 6
  1431        },
  1432        "nO": 4
  1433      },
  1434      "gH": 2
  1435    }
  1436  }`},
  1437  		{"toml", `aBcD = 1
  1438  [eF]
  1439  gH = 2
  1440  iJk = 3
  1441  [eF.Lm]
  1442  nO = 4
  1443  [eF.Lm.P]
  1444  Q = 5
  1445  R = 6
  1446  `},
  1447  	} {
  1448  		doTestCaseSensitive(t, config.typ, config.content)
  1449  	}
  1450  }
  1451  
  1452  func TestCaseInsensitiveSet(t *testing.T) {
  1453  	Reset()
  1454  	m1 := map[string]interface{}{
  1455  		"Foo": 32,
  1456  		"Bar": map[interface{}]interface {
  1457  		}{
  1458  			"ABc": "A",
  1459  			"cDE": "B"},
  1460  	}
  1461  
  1462  	m2 := map[string]interface{}{
  1463  		"Foo": 52,
  1464  		"Bar": map[interface{}]interface {
  1465  		}{
  1466  			"bCd": "A",
  1467  			"eFG": "B"},
  1468  	}
  1469  
  1470  	Set("Given1", m1)
  1471  	Set("Number1", 42)
  1472  
  1473  	SetDefault("Given2", m2)
  1474  	SetDefault("Number2", 52)
  1475  
  1476  	// Verify SetDefault
  1477  	if v := Get("number2"); v != 52 {
  1478  		t.Fatalf("Expected 52 got %q", v)
  1479  	}
  1480  
  1481  	if v := Get("given2.foo"); v != 52 {
  1482  		t.Fatalf("Expected 52 got %q", v)
  1483  	}
  1484  
  1485  	if v := Get("given2.bar.bcd"); v != "A" {
  1486  		t.Fatalf("Expected A got %q", v)
  1487  	}
  1488  
  1489  	if _, ok := m2["Foo"]; !ok {
  1490  		t.Fatal("Input map changed")
  1491  	}
  1492  
  1493  	// Verify Set
  1494  	if v := Get("number1"); v != 42 {
  1495  		t.Fatalf("Expected 42 got %q", v)
  1496  	}
  1497  
  1498  	if v := Get("given1.foo"); v != 32 {
  1499  		t.Fatalf("Expected 32 got %q", v)
  1500  	}
  1501  
  1502  	if v := Get("given1.bar.abc"); v != "A" {
  1503  		t.Fatalf("Expected A got %q", v)
  1504  	}
  1505  
  1506  	if _, ok := m1["Foo"]; !ok {
  1507  		t.Fatal("Input map changed")
  1508  	}
  1509  }
  1510  
  1511  func TestParseNested(t *testing.T) {
  1512  	type duration struct {
  1513  		Delay time.Duration
  1514  	}
  1515  
  1516  	type item struct {
  1517  		Name   string
  1518  		Delay  time.Duration
  1519  		Nested duration
  1520  	}
  1521  
  1522  	config := `[[parent]]
  1523  	delay="100ms"
  1524  	[parent.nested]
  1525  	delay="200ms"
  1526  `
  1527  	initConfig("toml", config)
  1528  
  1529  	var items []item
  1530  	err := v.UnmarshalKey("parent", &items)
  1531  	if err != nil {
  1532  		t.Fatalf("unable to decode into struct, %v", err)
  1533  	}
  1534  
  1535  	assert.Equal(t, 1, len(items))
  1536  	assert.Equal(t, 100*time.Millisecond, items[0].Delay)
  1537  	assert.Equal(t, 200*time.Millisecond, items[0].Nested.Delay)
  1538  }
  1539  
  1540  func doTestCaseInsensitive(t *testing.T, typ, config string) {
  1541  	initConfig(typ, config)
  1542  	Set("RfD", true)
  1543  	assert.Equal(t, true, Get("rfd"))
  1544  	assert.Equal(t, true, Get("rFD"))
  1545  	assert.Equal(t, 1, cast.ToInt(Get("abcd")))
  1546  	assert.Equal(t, 1, cast.ToInt(Get("Abcd")))
  1547  	assert.Equal(t, 2, cast.ToInt(Get("ef.gh")))
  1548  	assert.Equal(t, 3, cast.ToInt(Get("ef.ijk")))
  1549  	assert.Equal(t, 4, cast.ToInt(Get("ef.lm.no")))
  1550  	assert.Equal(t, 5, cast.ToInt(Get("ef.lm.p.q")))
  1551  }
  1552  
  1553  func doTestCaseSensitive(t *testing.T, typ, config string) {
  1554  	Reset()
  1555  	SetConfigType(typ)
  1556  
  1557  	// Turn on case sensitivy.
  1558  	SetKeysCaseSensitive(true)
  1559  	r := strings.NewReader(config)
  1560  	if err := unmarshalReader(r, v.config); err != nil {
  1561  		panic(err)
  1562  	}
  1563  
  1564  	Set("RfD", true)
  1565  	assert.Equal(t, nil, Get("rfd"))
  1566  	assert.Equal(t, true, Get("RfD"))
  1567  	assert.Equal(t, 0, cast.ToInt(Get("abcd")))
  1568  	assert.Equal(t, 1, cast.ToInt(Get("aBcD")))
  1569  	assert.Equal(t, 0, cast.ToInt(Get("ef.gh")))
  1570  	assert.Equal(t, 2, cast.ToInt(Get("eF.gH")))
  1571  	assert.Equal(t, 0, cast.ToInt(Get("ef.ijk")))
  1572  	assert.Equal(t, 3, cast.ToInt(Get("eF.iJk")))
  1573  	assert.Equal(t, 0, cast.ToInt(Get("ef.lm.no")))
  1574  	assert.Equal(t, 4, cast.ToInt(Get("eF.Lm.nO")))
  1575  	assert.Equal(t, 0, cast.ToInt(Get("ef.lm.p.q")))
  1576  	assert.Equal(t, 5, cast.ToInt(Get("eF.Lm.P.Q")))
  1577  
  1578  }
  1579  
  1580  func newViperWithConfigFile(t *testing.T) (*Viper, string, func()) {
  1581  	watchDir, err := ioutil.TempDir("", "")
  1582  	require.Nil(t, err)
  1583  	configFile := path.Join(watchDir, "config.yaml")
  1584  	err = ioutil.WriteFile(configFile, []byte("foo: bar\n"), 0640)
  1585  	require.Nil(t, err)
  1586  	cleanup := func() {
  1587  		os.RemoveAll(watchDir)
  1588  	}
  1589  	v := New()
  1590  	v.SetConfigFile(configFile)
  1591  	err = v.ReadInConfig()
  1592  	require.Nil(t, err)
  1593  	require.Equal(t, "bar", v.Get("foo"))
  1594  	return v, configFile, cleanup
  1595  }
  1596  
  1597  func newViperWithSymlinkedConfigFile(t *testing.T) (*Viper, string, string, func()) {
  1598  	watchDir, err := ioutil.TempDir("", "")
  1599  	require.Nil(t, err)
  1600  	dataDir1 := path.Join(watchDir, "data1")
  1601  	err = os.Mkdir(dataDir1, 0777)
  1602  	require.Nil(t, err)
  1603  	realConfigFile := path.Join(dataDir1, "config.yaml")
  1604  	t.Logf("Real config file location: %s\n", realConfigFile)
  1605  	err = ioutil.WriteFile(realConfigFile, []byte("foo: bar\n"), 0640)
  1606  	require.Nil(t, err)
  1607  	cleanup := func() {
  1608  		os.RemoveAll(watchDir)
  1609  	}
  1610  	// now, symlink the tm `data1` dir to `data` in the baseDir
  1611  	os.Symlink(dataDir1, path.Join(watchDir, "data"))
  1612  	// and link the `<watchdir>/datadir1/config.yaml` to `<watchdir>/config.yaml`
  1613  	configFile := path.Join(watchDir, "config.yaml")
  1614  	os.Symlink(path.Join(watchDir, "data", "config.yaml"), configFile)
  1615  	t.Logf("Config file location: %s\n", path.Join(watchDir, "config.yaml"))
  1616  	// init Viper
  1617  	v := New()
  1618  	v.SetConfigFile(configFile)
  1619  	err = v.ReadInConfig()
  1620  	require.Nil(t, err)
  1621  	require.Equal(t, "bar", v.Get("foo"))
  1622  	return v, watchDir, configFile, cleanup
  1623  }
  1624  
  1625  func TestWatchFile(t *testing.T) {
  1626  	if runtime.GOOS == "linux" {
  1627  		// TODO(bep) FIX ME
  1628  		t.Skip("Skip test on Linux ...")
  1629  	}
  1630  
  1631  	t.Run("file content changed", func(t *testing.T) {
  1632  		// given a `config.yaml` file being watched
  1633  		v, configFile, cleanup := newViperWithConfigFile(t)
  1634  		defer cleanup()
  1635  		_, err := os.Stat(configFile)
  1636  		require.NoError(t, err)
  1637  		t.Logf("test config file: %s\n", configFile)
  1638  		wg := sync.WaitGroup{}
  1639  		wg.Add(1)
  1640  		v.OnConfigChange(func(in fsnotify.Event) {
  1641  			t.Logf("config file changed")
  1642  			wg.Done()
  1643  		})
  1644  		v.WatchConfig()
  1645  		// when overwriting the file and waiting for the custom change notification handler to be triggered
  1646  		err = ioutil.WriteFile(configFile, []byte("foo: baz\n"), 0640)
  1647  		wg.Wait()
  1648  		// then the config value should have changed
  1649  		require.Nil(t, err)
  1650  		assert.Equal(t, "baz", v.Get("foo"))
  1651  	})
  1652  
  1653  	t.Run("link to real file changed (à la Kubernetes)", func(t *testing.T) {
  1654  		// skip if not executed on Linux
  1655  		if runtime.GOOS != "linux" {
  1656  			t.Skipf("Skipping test as symlink replacements don't work on non-linux environment...")
  1657  		}
  1658  		v, watchDir, _, _ := newViperWithSymlinkedConfigFile(t)
  1659  		// defer cleanup()
  1660  		wg := sync.WaitGroup{}
  1661  		v.WatchConfig()
  1662  		v.OnConfigChange(func(in fsnotify.Event) {
  1663  			t.Logf("config file changed")
  1664  			wg.Done()
  1665  		})
  1666  		wg.Add(1)
  1667  		// when link to another `config.yaml` file
  1668  		dataDir2 := path.Join(watchDir, "data2")
  1669  		err := os.Mkdir(dataDir2, 0777)
  1670  		require.Nil(t, err)
  1671  		configFile2 := path.Join(dataDir2, "config.yaml")
  1672  		err = ioutil.WriteFile(configFile2, []byte("foo: baz\n"), 0640)
  1673  		require.Nil(t, err)
  1674  		// change the symlink using the `ln -sfn` command
  1675  		err = exec.Command("ln", "-sfn", dataDir2, path.Join(watchDir, "data")).Run()
  1676  		require.Nil(t, err)
  1677  		wg.Wait()
  1678  		// then
  1679  		require.Nil(t, err)
  1680  		assert.Equal(t, "baz", v.Get("foo"))
  1681  	})
  1682  
  1683  }
  1684  
  1685  func BenchmarkGetBool(b *testing.B) {
  1686  	key := "BenchmarkGetBool"
  1687  	v = New()
  1688  	v.Set(key, true)
  1689  
  1690  	for i := 0; i < b.N; i++ {
  1691  		if !v.GetBool(key) {
  1692  			b.Fatal("GetBool returned false")
  1693  		}
  1694  	}
  1695  }
  1696  
  1697  func BenchmarkGet(b *testing.B) {
  1698  	key := "BenchmarkGet"
  1699  	v = New()
  1700  	v.Set(key, true)
  1701  
  1702  	for i := 0; i < b.N; i++ {
  1703  		if !v.Get(key).(bool) {
  1704  			b.Fatal("Get returned false")
  1705  		}
  1706  	}
  1707  }
  1708  
  1709  // This is the "perfect result" for the above.
  1710  func BenchmarkGetBoolFromMap(b *testing.B) {
  1711  	m := make(map[string]bool)
  1712  	key := "BenchmarkGetBool"
  1713  	m[key] = true
  1714  
  1715  	for i := 0; i < b.N; i++ {
  1716  		if !m[key] {
  1717  			b.Fatal("Map value was false")
  1718  		}
  1719  	}
  1720  }