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