gopkg.in/necryin/viper.v1@v1.0.2/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  	"fmt"
    11  	"io"
    12  	"io/ioutil"
    13  	"os"
    14  	"path"
    15  	"reflect"
    16  	"sort"
    17  	"strings"
    18  	"testing"
    19  	"time"
    20  
    21  	"github.com/spf13/cast"
    22  
    23  	"github.com/spf13/pflag"
    24  	"github.com/stretchr/testify/assert"
    25  )
    26  
    27  var yamlExample = []byte(`Hacker: true
    28  name: steve
    29  hobbies:
    30  - skateboarding
    31  - snowboarding
    32  - go
    33  clothing:
    34    jacket: leather
    35    trousers: denim
    36    pants:
    37      size: large
    38  age: 35
    39  eyes : brown
    40  beard: true
    41  `)
    42  
    43  var yamlExampleWithExtras = []byte(`Existing: true
    44  Bogus: true
    45  `)
    46  
    47  type testUnmarshalExtra struct {
    48  	Existing bool
    49  }
    50  
    51  var tomlExample = []byte(`
    52  title = "TOML Example"
    53  
    54  [owner]
    55  organization = "MongoDB"
    56  Bio = "MongoDB Chief Developer Advocate & Hacker at Large"
    57  dob = 1979-05-27T07:32:00Z # First class dates? Why not?`)
    58  
    59  var jsonExample = []byte(`{
    60  "id": "0001",
    61  "type": "donut",
    62  "name": "Cake",
    63  "ppu": 0.55,
    64  "batters": {
    65          "batter": [
    66                  { "type": "Regular" },
    67                  { "type": "Chocolate" },
    68                  { "type": "Blueberry" },
    69                  { "type": "Devil's Food" }
    70              ]
    71      }
    72  }`)
    73  
    74  var hclExample = []byte(`
    75  id = "0001"
    76  type = "donut"
    77  name = "Cake"
    78  ppu = 0.55
    79  foos {
    80  	foo {
    81  		key = 1
    82  	}
    83  	foo {
    84  		key = 2
    85  	}
    86  	foo {
    87  		key = 3
    88  	}
    89  	foo {
    90  		key = 4
    91  	}
    92  }`)
    93  
    94  var propertiesExample = []byte(`
    95  p_id: 0001
    96  p_type: donut
    97  p_name: Cake
    98  p_ppu: 0.55
    99  p_batters.batter.type: Regular
   100  `)
   101  
   102  var remoteExample = []byte(`{
   103  "id":"0002",
   104  "type":"cronut",
   105  "newkey":"remote"
   106  }`)
   107  
   108  func initConfigs() {
   109  	Reset()
   110  	var r io.Reader
   111  	SetConfigType("yaml")
   112  	r = bytes.NewReader(yamlExample)
   113  	unmarshalReader(r, v.config)
   114  
   115  	SetConfigType("json")
   116  	r = bytes.NewReader(jsonExample)
   117  	unmarshalReader(r, v.config)
   118  
   119  	SetConfigType("hcl")
   120  	r = bytes.NewReader(hclExample)
   121  	unmarshalReader(r, v.config)
   122  
   123  	SetConfigType("properties")
   124  	r = bytes.NewReader(propertiesExample)
   125  	unmarshalReader(r, v.config)
   126  
   127  	SetConfigType("toml")
   128  	r = bytes.NewReader(tomlExample)
   129  	unmarshalReader(r, v.config)
   130  
   131  	SetConfigType("json")
   132  	remote := bytes.NewReader(remoteExample)
   133  	unmarshalReader(remote, v.kvstore)
   134  }
   135  
   136  func initConfig(typ, config string) {
   137  	Reset()
   138  	SetConfigType(typ)
   139  	r := strings.NewReader(config)
   140  
   141  	if err := unmarshalReader(r, v.config); err != nil {
   142  		panic(err)
   143  	}
   144  }
   145  
   146  func initYAML() {
   147  	initConfig("yaml", string(yamlExample))
   148  }
   149  
   150  func initJSON() {
   151  	Reset()
   152  	SetConfigType("json")
   153  	r := bytes.NewReader(jsonExample)
   154  
   155  	unmarshalReader(r, v.config)
   156  }
   157  
   158  func initProperties() {
   159  	Reset()
   160  	SetConfigType("properties")
   161  	r := bytes.NewReader(propertiesExample)
   162  
   163  	unmarshalReader(r, v.config)
   164  }
   165  
   166  func initTOML() {
   167  	Reset()
   168  	SetConfigType("toml")
   169  	r := bytes.NewReader(tomlExample)
   170  
   171  	unmarshalReader(r, v.config)
   172  }
   173  
   174  func initHcl() {
   175  	Reset()
   176  	SetConfigType("hcl")
   177  	r := bytes.NewReader(hclExample)
   178  
   179  	unmarshalReader(r, v.config)
   180  }
   181  
   182  // make directories for testing
   183  func initDirs(t *testing.T) (string, string, func()) {
   184  
   185  	var (
   186  		testDirs = []string{`a a`, `b`, `c\c`, `D_`}
   187  		config   = `improbable`
   188  	)
   189  
   190  	root, err := ioutil.TempDir("", "")
   191  
   192  	cleanup := true
   193  	defer func() {
   194  		if cleanup {
   195  			os.Chdir("..")
   196  			os.RemoveAll(root)
   197  		}
   198  	}()
   199  
   200  	assert.Nil(t, err)
   201  
   202  	err = os.Chdir(root)
   203  	assert.Nil(t, err)
   204  
   205  	for _, dir := range testDirs {
   206  		err = os.Mkdir(dir, 0750)
   207  		assert.Nil(t, err)
   208  
   209  		err = ioutil.WriteFile(
   210  			path.Join(dir, config+".toml"),
   211  			[]byte("key = \"value is "+dir+"\"\n"),
   212  			0640)
   213  		assert.Nil(t, err)
   214  	}
   215  
   216  	cleanup = false
   217  	return root, config, func() {
   218  		os.Chdir("..")
   219  		os.RemoveAll(root)
   220  	}
   221  }
   222  
   223  //stubs for PFlag Values
   224  type stringValue string
   225  
   226  func newStringValue(val string, p *string) *stringValue {
   227  	*p = val
   228  	return (*stringValue)(p)
   229  }
   230  
   231  func (s *stringValue) Set(val string) error {
   232  	*s = stringValue(val)
   233  	return nil
   234  }
   235  
   236  func (s *stringValue) Type() string {
   237  	return "string"
   238  }
   239  
   240  func (s *stringValue) String() string {
   241  	return fmt.Sprintf("%s", *s)
   242  }
   243  
   244  func TestBasics(t *testing.T) {
   245  	SetConfigFile("/tmp/config.yaml")
   246  	filename, err := v.getConfigFile()
   247  	assert.Equal(t, "/tmp/config.yaml", filename)
   248  	assert.NoError(t, err)
   249  }
   250  
   251  func TestDefault(t *testing.T) {
   252  	SetDefault("age", 45)
   253  	assert.Equal(t, 45, Get("age"))
   254  
   255  	SetDefault("clothing.jacket", "slacks")
   256  	assert.Equal(t, "slacks", Get("clothing.jacket"))
   257  
   258  	SetConfigType("yaml")
   259  	err := ReadConfig(bytes.NewBuffer(yamlExample))
   260  
   261  	assert.NoError(t, err)
   262  	assert.Equal(t, "leather", Get("clothing.jacket"))
   263  }
   264  
   265  func TestUnmarshalling(t *testing.T) {
   266  	SetConfigType("yaml")
   267  	r := bytes.NewReader(yamlExample)
   268  
   269  	unmarshalReader(r, v.config)
   270  	assert.True(t, InConfig("name"))
   271  	assert.False(t, InConfig("state"))
   272  	assert.Equal(t, "steve", Get("name"))
   273  	assert.Equal(t, []interface{}{"skateboarding", "snowboarding", "go"}, Get("hobbies"))
   274  	assert.Equal(t, map[string]interface{}{"jacket": "leather", "trousers": "denim", "pants": map[string]interface{}{"size": "large"}}, Get("clothing"))
   275  	assert.Equal(t, 35, Get("age"))
   276  }
   277  
   278  func TestUnmarshalExact(t *testing.T) {
   279  	vip := New()
   280  	target := &testUnmarshalExtra{}
   281  	vip.SetConfigType("yaml")
   282  	r := bytes.NewReader(yamlExampleWithExtras)
   283  	vip.ReadConfig(r)
   284  	err := vip.UnmarshalExact(target)
   285  	if err == nil {
   286  		t.Fatal("UnmarshalExact should error when populating a struct from a conf that contains unused fields")
   287  	}
   288  }
   289  
   290  func TestOverrides(t *testing.T) {
   291  	Set("age", 40)
   292  	assert.Equal(t, 40, Get("age"))
   293  }
   294  
   295  func TestDefaultPost(t *testing.T) {
   296  	assert.NotEqual(t, "NYC", Get("state"))
   297  	SetDefault("state", "NYC")
   298  	assert.Equal(t, "NYC", Get("state"))
   299  }
   300  
   301  func TestAliases(t *testing.T) {
   302  	RegisterAlias("years", "age")
   303  	assert.Equal(t, 40, Get("years"))
   304  	Set("years", 45)
   305  	assert.Equal(t, 45, Get("age"))
   306  }
   307  
   308  func TestAliasInConfigFile(t *testing.T) {
   309  	// the config file specifies "beard".  If we make this an alias for
   310  	// "hasbeard", we still want the old config file to work with beard.
   311  	RegisterAlias("beard", "hasbeard")
   312  	assert.Equal(t, true, Get("hasbeard"))
   313  	Set("hasbeard", false)
   314  	assert.Equal(t, false, Get("beard"))
   315  }
   316  
   317  func TestYML(t *testing.T) {
   318  	initYAML()
   319  	assert.Equal(t, "steve", Get("name"))
   320  }
   321  
   322  func TestJSON(t *testing.T) {
   323  	initJSON()
   324  	assert.Equal(t, "0001", Get("id"))
   325  }
   326  
   327  func TestProperties(t *testing.T) {
   328  	initProperties()
   329  	assert.Equal(t, "0001", Get("p_id"))
   330  }
   331  
   332  func TestTOML(t *testing.T) {
   333  	initTOML()
   334  	assert.Equal(t, "TOML Example", Get("title"))
   335  }
   336  
   337  func TestHCL(t *testing.T) {
   338  	initHcl()
   339  	assert.Equal(t, "0001", Get("id"))
   340  	assert.Equal(t, 0.55, Get("ppu"))
   341  	assert.Equal(t, "donut", Get("type"))
   342  	assert.Equal(t, "Cake", Get("name"))
   343  	Set("id", "0002")
   344  	assert.Equal(t, "0002", Get("id"))
   345  	assert.NotEqual(t, "cronut", Get("type"))
   346  }
   347  
   348  func TestRemotePrecedence(t *testing.T) {
   349  	initJSON()
   350  
   351  	remote := bytes.NewReader(remoteExample)
   352  	assert.Equal(t, "0001", Get("id"))
   353  	unmarshalReader(remote, v.kvstore)
   354  	assert.Equal(t, "0001", Get("id"))
   355  	assert.NotEqual(t, "cronut", Get("type"))
   356  	assert.Equal(t, "remote", Get("newkey"))
   357  	Set("newkey", "newvalue")
   358  	assert.NotEqual(t, "remote", Get("newkey"))
   359  	assert.Equal(t, "newvalue", Get("newkey"))
   360  	Set("newkey", "remote")
   361  }
   362  
   363  func TestEnv(t *testing.T) {
   364  	initJSON()
   365  
   366  	BindEnv("id")
   367  	BindEnv("f", "FOOD")
   368  
   369  	os.Setenv("ID", "13")
   370  	os.Setenv("FOOD", "apple")
   371  	os.Setenv("NAME", "crunk")
   372  
   373  	assert.Equal(t, "13", Get("id"))
   374  	assert.Equal(t, "apple", Get("f"))
   375  	assert.Equal(t, "Cake", Get("name"))
   376  
   377  	AutomaticEnv()
   378  
   379  	assert.Equal(t, "crunk", Get("name"))
   380  
   381  }
   382  
   383  func TestEnvPrefix(t *testing.T) {
   384  	initJSON()
   385  
   386  	SetEnvPrefix("foo") // will be uppercased automatically
   387  	BindEnv("id")
   388  	BindEnv("f", "FOOD") // not using prefix
   389  
   390  	os.Setenv("FOO_ID", "13")
   391  	os.Setenv("FOOD", "apple")
   392  	os.Setenv("FOO_NAME", "crunk")
   393  
   394  	assert.Equal(t, "13", Get("id"))
   395  	assert.Equal(t, "apple", Get("f"))
   396  	assert.Equal(t, "Cake", Get("name"))
   397  
   398  	AutomaticEnv()
   399  
   400  	assert.Equal(t, "crunk", Get("name"))
   401  }
   402  
   403  func TestAutoEnv(t *testing.T) {
   404  	Reset()
   405  
   406  	AutomaticEnv()
   407  	os.Setenv("FOO_BAR", "13")
   408  	assert.Equal(t, "13", Get("foo_bar"))
   409  }
   410  
   411  func TestAutoEnvWithPrefix(t *testing.T) {
   412  	Reset()
   413  
   414  	AutomaticEnv()
   415  	SetEnvPrefix("Baz")
   416  	os.Setenv("BAZ_BAR", "13")
   417  	assert.Equal(t, "13", Get("bar"))
   418  }
   419  
   420  func TestSetEnvKeyReplacer(t *testing.T) {
   421  	Reset()
   422  
   423  	AutomaticEnv()
   424  	os.Setenv("REFRESH_INTERVAL", "30s")
   425  
   426  	replacer := strings.NewReplacer("-", "_")
   427  	SetEnvKeyReplacer(replacer)
   428  
   429  	assert.Equal(t, "30s", Get("refresh-interval"))
   430  }
   431  
   432  func TestAllKeys(t *testing.T) {
   433  	initConfigs()
   434  
   435  	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"}
   436  	dob, _ := time.Parse(time.RFC3339, "1979-05-27T07:32:00Z")
   437  	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}}}}}
   438  
   439  	var allkeys sort.StringSlice
   440  	allkeys = AllKeys()
   441  	allkeys.Sort()
   442  	ks.Sort()
   443  
   444  	assert.Equal(t, ks, allkeys)
   445  	assert.Equal(t, all, AllSettings())
   446  }
   447  
   448  func TestAllKeysWithEnv(t *testing.T) {
   449  	v := New()
   450  
   451  	// bind and define environment variables (including a nested one)
   452  	v.BindEnv("id")
   453  	v.BindEnv("foo.bar")
   454  	v.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
   455  	os.Setenv("ID", "13")
   456  	os.Setenv("FOO_BAR", "baz")
   457  
   458  	expectedKeys := sort.StringSlice{"id", "foo.bar"}
   459  	expectedKeys.Sort()
   460  	keys := sort.StringSlice(v.AllKeys())
   461  	keys.Sort()
   462  	assert.Equal(t, expectedKeys, keys)
   463  }
   464  
   465  func TestAliasesOfAliases(t *testing.T) {
   466  	Set("Title", "Checking Case")
   467  	RegisterAlias("Foo", "Bar")
   468  	RegisterAlias("Bar", "Title")
   469  	assert.Equal(t, "Checking Case", Get("FOO"))
   470  }
   471  
   472  func TestRecursiveAliases(t *testing.T) {
   473  	RegisterAlias("Baz", "Roo")
   474  	RegisterAlias("Roo", "baz")
   475  }
   476  
   477  func TestUnmarshal(t *testing.T) {
   478  	SetDefault("port", 1313)
   479  	Set("name", "Steve")
   480  	Set("duration", "1s1ms")
   481  
   482  	type config struct {
   483  		Port     int
   484  		Name     string
   485  		Duration time.Duration
   486  	}
   487  
   488  	var C config
   489  
   490  	err := Unmarshal(&C)
   491  	if err != nil {
   492  		t.Fatalf("unable to decode into struct, %v", err)
   493  	}
   494  
   495  	assert.Equal(t, &config{Name: "Steve", Port: 1313, Duration: time.Second + time.Millisecond}, &C)
   496  
   497  	Set("port", 1234)
   498  	err = Unmarshal(&C)
   499  	if err != nil {
   500  		t.Fatalf("unable to decode into struct, %v", err)
   501  	}
   502  	assert.Equal(t, &config{Name: "Steve", Port: 1234, Duration: time.Second + time.Millisecond}, &C)
   503  }
   504  
   505  func TestBindPFlags(t *testing.T) {
   506  	v := New() // create independent Viper object
   507  	flagSet := pflag.NewFlagSet("test", pflag.ContinueOnError)
   508  
   509  	var testValues = map[string]*string{
   510  		"host":     nil,
   511  		"port":     nil,
   512  		"endpoint": nil,
   513  	}
   514  
   515  	var mutatedTestValues = map[string]string{
   516  		"host":     "localhost",
   517  		"port":     "6060",
   518  		"endpoint": "/public",
   519  	}
   520  
   521  	for name := range testValues {
   522  		testValues[name] = flagSet.String(name, "", "test")
   523  	}
   524  
   525  	err := v.BindPFlags(flagSet)
   526  	if err != nil {
   527  		t.Fatalf("error binding flag set, %v", err)
   528  	}
   529  
   530  	flagSet.VisitAll(func(flag *pflag.Flag) {
   531  		flag.Value.Set(mutatedTestValues[flag.Name])
   532  		flag.Changed = true
   533  	})
   534  
   535  	for name, expected := range mutatedTestValues {
   536  		assert.Equal(t, expected, v.Get(name))
   537  	}
   538  
   539  }
   540  
   541  func TestBindPFlagsStringSlice(t *testing.T) {
   542  	for _, testValue := range []struct {
   543  		Expected []string
   544  		Value    string
   545  	}{
   546  		{[]string{}, ""},
   547  		{[]string{"jeden"}, "jeden"},
   548  		{[]string{"dwa", "trzy"}, "dwa,trzy"},
   549  		{[]string{"cztery", "piec , szesc"}, "cztery,\"piec , szesc\""}} {
   550  
   551  		for _, changed := range []bool{true, false} {
   552  			v := New() // create independent Viper object
   553  			flagSet := pflag.NewFlagSet("test", pflag.ContinueOnError)
   554  			flagSet.StringSlice("stringslice", testValue.Expected, "test")
   555  			flagSet.Visit(func(f *pflag.Flag) {
   556  				if len(testValue.Value) > 0 {
   557  					f.Value.Set(testValue.Value)
   558  					f.Changed = changed
   559  				}
   560  			})
   561  
   562  			err := v.BindPFlags(flagSet)
   563  			if err != nil {
   564  				t.Fatalf("error binding flag set, %v", err)
   565  			}
   566  
   567  			type TestStr struct {
   568  				StringSlice []string
   569  			}
   570  			val := &TestStr{}
   571  			if err := v.Unmarshal(val); err != nil {
   572  				t.Fatalf("%+#v cannot unmarshal: %s", testValue.Value, err)
   573  			}
   574  			assert.Equal(t, testValue.Expected, val.StringSlice)
   575  		}
   576  	}
   577  }
   578  
   579  func TestBindPFlag(t *testing.T) {
   580  	var testString = "testing"
   581  	var testValue = newStringValue(testString, &testString)
   582  
   583  	flag := &pflag.Flag{
   584  		Name:    "testflag",
   585  		Value:   testValue,
   586  		Changed: false,
   587  	}
   588  
   589  	BindPFlag("testvalue", flag)
   590  
   591  	assert.Equal(t, testString, Get("testvalue"))
   592  
   593  	flag.Value.Set("testing_mutate")
   594  	flag.Changed = true //hack for pflag usage
   595  
   596  	assert.Equal(t, "testing_mutate", Get("testvalue"))
   597  
   598  }
   599  
   600  func TestBoundCaseSensitivity(t *testing.T) {
   601  	assert.Equal(t, "brown", Get("eyes"))
   602  
   603  	BindEnv("eYEs", "TURTLE_EYES")
   604  	os.Setenv("TURTLE_EYES", "blue")
   605  
   606  	assert.Equal(t, "blue", Get("eyes"))
   607  
   608  	var testString = "green"
   609  	var testValue = newStringValue(testString, &testString)
   610  
   611  	flag := &pflag.Flag{
   612  		Name:    "eyeballs",
   613  		Value:   testValue,
   614  		Changed: true,
   615  	}
   616  
   617  	BindPFlag("eYEs", flag)
   618  	assert.Equal(t, "green", Get("eyes"))
   619  
   620  }
   621  
   622  func TestSizeInBytes(t *testing.T) {
   623  	input := map[string]uint{
   624  		"":               0,
   625  		"b":              0,
   626  		"12 bytes":       0,
   627  		"200000000000gb": 0,
   628  		"12 b":           12,
   629  		"43 MB":          43 * (1 << 20),
   630  		"10mb":           10 * (1 << 20),
   631  		"1gb":            1 << 30,
   632  	}
   633  
   634  	for str, expected := range input {
   635  		assert.Equal(t, expected, parseSizeInBytes(str), str)
   636  	}
   637  }
   638  
   639  func TestFindsNestedKeys(t *testing.T) {
   640  	initConfigs()
   641  	dob, _ := time.Parse(time.RFC3339, "1979-05-27T07:32:00Z")
   642  
   643  	Set("super", map[string]interface{}{
   644  		"deep": map[string]interface{}{
   645  			"nested": "value",
   646  		},
   647  	})
   648  
   649  	expected := map[string]interface{}{
   650  		"super": map[string]interface{}{
   651  			"deep": map[string]interface{}{
   652  				"nested": "value",
   653  			},
   654  		},
   655  		"super.deep": map[string]interface{}{
   656  			"nested": "value",
   657  		},
   658  		"super.deep.nested":  "value",
   659  		"owner.organization": "MongoDB",
   660  		"batters.batter": []interface{}{
   661  			map[string]interface{}{
   662  				"type": "Regular",
   663  			},
   664  			map[string]interface{}{
   665  				"type": "Chocolate",
   666  			},
   667  			map[string]interface{}{
   668  				"type": "Blueberry",
   669  			},
   670  			map[string]interface{}{
   671  				"type": "Devil's Food",
   672  			},
   673  		},
   674  		"hobbies": []interface{}{
   675  			"skateboarding", "snowboarding", "go",
   676  		},
   677  		"title":  "TOML Example",
   678  		"newkey": "remote",
   679  		"batters": map[string]interface{}{
   680  			"batter": []interface{}{
   681  				map[string]interface{}{
   682  					"type": "Regular",
   683  				},
   684  				map[string]interface{}{
   685  					"type": "Chocolate",
   686  				}, map[string]interface{}{
   687  					"type": "Blueberry",
   688  				}, map[string]interface{}{
   689  					"type": "Devil's Food",
   690  				},
   691  			},
   692  		},
   693  		"eyes": "brown",
   694  		"age":  35,
   695  		"owner": map[string]interface{}{
   696  			"organization": "MongoDB",
   697  			"bio":          "MongoDB Chief Developer Advocate & Hacker at Large",
   698  			"dob":          dob,
   699  		},
   700  		"owner.bio": "MongoDB Chief Developer Advocate & Hacker at Large",
   701  		"type":      "donut",
   702  		"id":        "0001",
   703  		"name":      "Cake",
   704  		"hacker":    true,
   705  		"ppu":       0.55,
   706  		"clothing": map[string]interface{}{
   707  			"jacket":   "leather",
   708  			"trousers": "denim",
   709  			"pants": map[string]interface{}{
   710  				"size": "large",
   711  			},
   712  		},
   713  		"clothing.jacket":     "leather",
   714  		"clothing.pants.size": "large",
   715  		"clothing.trousers":   "denim",
   716  		"owner.dob":           dob,
   717  		"beard":               true,
   718  		"foos": []map[string]interface{}{
   719  			map[string]interface{}{
   720  				"foo": []map[string]interface{}{
   721  					map[string]interface{}{
   722  						"key": 1,
   723  					},
   724  					map[string]interface{}{
   725  						"key": 2,
   726  					},
   727  					map[string]interface{}{
   728  						"key": 3,
   729  					},
   730  					map[string]interface{}{
   731  						"key": 4,
   732  					},
   733  				},
   734  			},
   735  		},
   736  	}
   737  
   738  	for key, expectedValue := range expected {
   739  
   740  		assert.Equal(t, expectedValue, v.Get(key))
   741  	}
   742  
   743  }
   744  
   745  func TestReadBufConfig(t *testing.T) {
   746  	v := New()
   747  	v.SetConfigType("yaml")
   748  	v.ReadConfig(bytes.NewBuffer(yamlExample))
   749  	t.Log(v.AllKeys())
   750  
   751  	assert.True(t, v.InConfig("name"))
   752  	assert.False(t, v.InConfig("state"))
   753  	assert.Equal(t, "steve", v.Get("name"))
   754  	assert.Equal(t, []interface{}{"skateboarding", "snowboarding", "go"}, v.Get("hobbies"))
   755  	assert.Equal(t, map[string]interface{}{"jacket": "leather", "trousers": "denim", "pants": map[string]interface{}{"size": "large"}}, v.Get("clothing"))
   756  	assert.Equal(t, 35, v.Get("age"))
   757  }
   758  
   759  func TestIsSet(t *testing.T) {
   760  	v := New()
   761  	v.SetConfigType("yaml")
   762  	v.ReadConfig(bytes.NewBuffer(yamlExample))
   763  	assert.True(t, v.IsSet("clothing.jacket"))
   764  	assert.False(t, v.IsSet("clothing.jackets"))
   765  	assert.False(t, v.IsSet("helloworld"))
   766  	v.Set("helloworld", "fubar")
   767  	assert.True(t, v.IsSet("helloworld"))
   768  }
   769  
   770  func TestDirsSearch(t *testing.T) {
   771  
   772  	root, config, cleanup := initDirs(t)
   773  	defer cleanup()
   774  
   775  	v := New()
   776  	v.SetConfigName(config)
   777  	v.SetDefault(`key`, `default`)
   778  
   779  	entries, err := ioutil.ReadDir(root)
   780  	for _, e := range entries {
   781  		if e.IsDir() {
   782  			v.AddConfigPath(e.Name())
   783  		}
   784  	}
   785  
   786  	err = v.ReadInConfig()
   787  	assert.Nil(t, err)
   788  
   789  	assert.Equal(t, `value is `+path.Base(v.configPaths[0]), v.GetString(`key`))
   790  }
   791  
   792  func TestWrongDirsSearchNotFound(t *testing.T) {
   793  
   794  	_, config, cleanup := initDirs(t)
   795  	defer cleanup()
   796  
   797  	v := New()
   798  	v.SetConfigName(config)
   799  	v.SetDefault(`key`, `default`)
   800  
   801  	v.AddConfigPath(`whattayoutalkingbout`)
   802  	v.AddConfigPath(`thispathaintthere`)
   803  
   804  	err := v.ReadInConfig()
   805  	assert.Equal(t, reflect.TypeOf(ConfigFileNotFoundError{"", ""}), reflect.TypeOf(err))
   806  
   807  	// Even though config did not load and the error might have
   808  	// been ignored by the client, the default still loads
   809  	assert.Equal(t, `default`, v.GetString(`key`))
   810  }
   811  
   812  func TestWrongDirsSearchNotFoundForMerge(t *testing.T) {
   813  
   814  	_, config, cleanup := initDirs(t)
   815  	defer cleanup()
   816  
   817  	v := New()
   818  	v.SetConfigName(config)
   819  	v.SetDefault(`key`, `default`)
   820  
   821  	v.AddConfigPath(`whattayoutalkingbout`)
   822  	v.AddConfigPath(`thispathaintthere`)
   823  
   824  	err := v.MergeInConfig()
   825  	assert.Equal(t, reflect.TypeOf(ConfigFileNotFoundError{"", ""}), reflect.TypeOf(err))
   826  
   827  	// Even though config did not load and the error might have
   828  	// been ignored by the client, the default still loads
   829  	assert.Equal(t, `default`, v.GetString(`key`))
   830  }
   831  
   832  func TestSub(t *testing.T) {
   833  	v := New()
   834  	v.SetConfigType("yaml")
   835  	v.ReadConfig(bytes.NewBuffer(yamlExample))
   836  
   837  	subv := v.Sub("clothing")
   838  	assert.Equal(t, v.Get("clothing.pants.size"), subv.Get("pants.size"))
   839  
   840  	subv = v.Sub("clothing.pants")
   841  	assert.Equal(t, v.Get("clothing.pants.size"), subv.Get("size"))
   842  
   843  	subv = v.Sub("clothing.pants.size")
   844  	assert.Equal(t, (*Viper)(nil), subv)
   845  
   846  	subv = v.Sub("missing.key")
   847  	assert.Equal(t, (*Viper)(nil), subv)
   848  }
   849  
   850  var yamlMergeExampleTgt = []byte(`
   851  hello:
   852      pop: 37890
   853      lagrenum: 765432101234567
   854      world:
   855      - us
   856      - uk
   857      - fr
   858      - de
   859  `)
   860  
   861  var yamlMergeExampleSrc = []byte(`
   862  hello:
   863      pop: 45000
   864      lagrenum: 7654321001234567
   865      universe:
   866      - mw
   867      - ad
   868  fu: bar
   869  `)
   870  
   871  func TestMergeConfig(t *testing.T) {
   872  	v := New()
   873  	v.SetConfigType("yml")
   874  	if err := v.ReadConfig(bytes.NewBuffer(yamlMergeExampleTgt)); err != nil {
   875  		t.Fatal(err)
   876  	}
   877  
   878  	if pop := v.GetInt("hello.pop"); pop != 37890 {
   879  		t.Fatalf("pop != 37890, = %d", pop)
   880  	}
   881  
   882  	if pop := v.GetInt("hello.lagrenum"); pop != 765432101234567 {
   883  		t.Fatalf("lagrenum != 765432101234567, = %d", pop)
   884  	}
   885  
   886  	if pop := v.GetInt64("hello.lagrenum"); pop != int64(765432101234567) {
   887  		t.Fatalf("int64 lagrenum != 765432101234567, = %d", pop)
   888  	}
   889  
   890  	if world := v.GetStringSlice("hello.world"); len(world) != 4 {
   891  		t.Fatalf("len(world) != 4, = %d", len(world))
   892  	}
   893  
   894  	if fu := v.GetString("fu"); fu != "" {
   895  		t.Fatalf("fu != \"\", = %s", fu)
   896  	}
   897  
   898  	if err := v.MergeConfig(bytes.NewBuffer(yamlMergeExampleSrc)); err != nil {
   899  		t.Fatal(err)
   900  	}
   901  
   902  	if pop := v.GetInt("hello.pop"); pop != 45000 {
   903  		t.Fatalf("pop != 45000, = %d", pop)
   904  	}
   905  
   906  	if pop := v.GetInt("hello.lagrenum"); pop != 7654321001234567 {
   907  		t.Fatalf("lagrenum != 7654321001234567, = %d", pop)
   908  	}
   909  
   910  	if pop := v.GetInt64("hello.lagrenum"); pop != int64(7654321001234567) {
   911  		t.Fatalf("int64 lagrenum != 7654321001234567, = %d", pop)
   912  	}
   913  
   914  	if world := v.GetStringSlice("hello.world"); len(world) != 4 {
   915  		t.Fatalf("len(world) != 4, = %d", len(world))
   916  	}
   917  
   918  	if universe := v.GetStringSlice("hello.universe"); len(universe) != 2 {
   919  		t.Fatalf("len(universe) != 2, = %d", len(universe))
   920  	}
   921  
   922  	if fu := v.GetString("fu"); fu != "bar" {
   923  		t.Fatalf("fu != \"bar\", = %s", fu)
   924  	}
   925  }
   926  
   927  func TestMergeConfigNoMerge(t *testing.T) {
   928  	v := New()
   929  	v.SetConfigType("yml")
   930  	if err := v.ReadConfig(bytes.NewBuffer(yamlMergeExampleTgt)); err != nil {
   931  		t.Fatal(err)
   932  	}
   933  
   934  	if pop := v.GetInt("hello.pop"); pop != 37890 {
   935  		t.Fatalf("pop != 37890, = %d", pop)
   936  	}
   937  
   938  	if world := v.GetStringSlice("hello.world"); len(world) != 4 {
   939  		t.Fatalf("len(world) != 4, = %d", len(world))
   940  	}
   941  
   942  	if fu := v.GetString("fu"); fu != "" {
   943  		t.Fatalf("fu != \"\", = %s", fu)
   944  	}
   945  
   946  	if err := v.ReadConfig(bytes.NewBuffer(yamlMergeExampleSrc)); err != nil {
   947  		t.Fatal(err)
   948  	}
   949  
   950  	if pop := v.GetInt("hello.pop"); pop != 45000 {
   951  		t.Fatalf("pop != 45000, = %d", pop)
   952  	}
   953  
   954  	if world := v.GetStringSlice("hello.world"); len(world) != 0 {
   955  		t.Fatalf("len(world) != 0, = %d", len(world))
   956  	}
   957  
   958  	if universe := v.GetStringSlice("hello.universe"); len(universe) != 2 {
   959  		t.Fatalf("len(universe) != 2, = %d", len(universe))
   960  	}
   961  
   962  	if fu := v.GetString("fu"); fu != "bar" {
   963  		t.Fatalf("fu != \"bar\", = %s", fu)
   964  	}
   965  }
   966  
   967  func TestUnmarshalingWithAliases(t *testing.T) {
   968  	v := New()
   969  	v.SetDefault("ID", 1)
   970  	v.Set("name", "Steve")
   971  	v.Set("lastname", "Owen")
   972  
   973  	v.RegisterAlias("UserID", "ID")
   974  	v.RegisterAlias("Firstname", "name")
   975  	v.RegisterAlias("Surname", "lastname")
   976  
   977  	type config struct {
   978  		ID        int
   979  		FirstName string
   980  		Surname   string
   981  	}
   982  
   983  	var C config
   984  	err := v.Unmarshal(&C)
   985  	if err != nil {
   986  		t.Fatalf("unable to decode into struct, %v", err)
   987  	}
   988  
   989  	assert.Equal(t, &config{ID: 1, FirstName: "Steve", Surname: "Owen"}, &C)
   990  }
   991  
   992  func TestSetConfigNameClearsFileCache(t *testing.T) {
   993  	SetConfigFile("/tmp/config.yaml")
   994  	SetConfigName("default")
   995  	f, err := v.getConfigFile()
   996  	if err == nil {
   997  		t.Fatalf("config file cache should have been cleared")
   998  	}
   999  	assert.Empty(t, f)
  1000  }
  1001  
  1002  func TestShadowedNestedValue(t *testing.T) {
  1003  
  1004  	config := `name: steve
  1005  clothing:
  1006    jacket: leather
  1007    trousers: denim
  1008    pants:
  1009      size: large
  1010  `
  1011  	initConfig("yaml", config)
  1012  
  1013  	assert.Equal(t, "steve", GetString("name"))
  1014  
  1015  	polyester := "polyester"
  1016  	SetDefault("clothing.shirt", polyester)
  1017  	SetDefault("clothing.jacket.price", 100)
  1018  
  1019  	assert.Equal(t, "leather", GetString("clothing.jacket"))
  1020  	assert.Nil(t, Get("clothing.jacket.price"))
  1021  	assert.Equal(t, polyester, GetString("clothing.shirt"))
  1022  
  1023  	clothingSettings := AllSettings()["clothing"].(map[string]interface{})
  1024  	assert.Equal(t, "leather", clothingSettings["jacket"])
  1025  	assert.Equal(t, polyester, clothingSettings["shirt"])
  1026  }
  1027  
  1028  func TestDotParameter(t *testing.T) {
  1029  	initJSON()
  1030  	// shoud take precedence over batters defined in jsonExample
  1031  	r := bytes.NewReader([]byte(`{ "batters.batter": [ { "type": "Small" } ] }`))
  1032  	unmarshalReader(r, v.config)
  1033  
  1034  	actual := Get("batters.batter")
  1035  	expected := []interface{}{map[string]interface{}{"type": "Small"}}
  1036  	assert.Equal(t, expected, actual)
  1037  }
  1038  
  1039  func TestCaseInsensitive(t *testing.T) {
  1040  	for _, config := range []struct {
  1041  		typ     string
  1042  		content string
  1043  	}{
  1044  		{"yaml", `
  1045  aBcD: 1
  1046  eF:
  1047    gH: 2
  1048    iJk: 3
  1049    Lm:
  1050      nO: 4
  1051      P:
  1052        Q: 5
  1053        R: 6
  1054  `},
  1055  		{"json", `{
  1056    "aBcD": 1,
  1057    "eF": {
  1058      "iJk": 3,
  1059      "Lm": {
  1060        "P": {
  1061          "Q": 5,
  1062          "R": 6
  1063        },
  1064        "nO": 4
  1065      },
  1066      "gH": 2
  1067    }
  1068  }`},
  1069  		{"toml", `aBcD = 1
  1070  [eF]
  1071  gH = 2
  1072  iJk = 3
  1073  [eF.Lm]
  1074  nO = 4
  1075  [eF.Lm.P]
  1076  Q = 5
  1077  R = 6
  1078  `},
  1079  	} {
  1080  		doTestCaseInsensitive(t, config.typ, config.content)
  1081  	}
  1082  }
  1083  
  1084  func TestCaseInsensitiveSet(t *testing.T) {
  1085  	Reset()
  1086  	m1 := map[string]interface{}{
  1087  		"Foo": 32,
  1088  		"Bar": map[interface{}]interface {
  1089  		}{
  1090  			"ABc": "A",
  1091  			"cDE": "B"},
  1092  	}
  1093  
  1094  	m2 := map[string]interface{}{
  1095  		"Foo": 52,
  1096  		"Bar": map[interface{}]interface {
  1097  		}{
  1098  			"bCd": "A",
  1099  			"eFG": "B"},
  1100  	}
  1101  
  1102  	Set("Given1", m1)
  1103  	Set("Number1", 42)
  1104  
  1105  	SetDefault("Given2", m2)
  1106  	SetDefault("Number2", 52)
  1107  
  1108  	// Verify SetDefault
  1109  	if v := Get("number2"); v != 52 {
  1110  		t.Fatalf("Expected 52 got %q", v)
  1111  	}
  1112  
  1113  	if v := Get("given2.foo"); v != 52 {
  1114  		t.Fatalf("Expected 52 got %q", v)
  1115  	}
  1116  
  1117  	if v := Get("given2.bar.bcd"); v != "A" {
  1118  		t.Fatalf("Expected A got %q", v)
  1119  	}
  1120  
  1121  	if _, ok := m2["Foo"]; !ok {
  1122  		t.Fatal("Input map changed")
  1123  	}
  1124  
  1125  	// Verify Set
  1126  	if v := Get("number1"); v != 42 {
  1127  		t.Fatalf("Expected 42 got %q", v)
  1128  	}
  1129  
  1130  	if v := Get("given1.foo"); v != 32 {
  1131  		t.Fatalf("Expected 32 got %q", v)
  1132  	}
  1133  
  1134  	if v := Get("given1.bar.abc"); v != "A" {
  1135  		t.Fatalf("Expected A got %q", v)
  1136  	}
  1137  
  1138  	if _, ok := m1["Foo"]; !ok {
  1139  		t.Fatal("Input map changed")
  1140  	}
  1141  }
  1142  
  1143  func TestParseNested(t *testing.T) {
  1144  	type duration struct {
  1145  		Delay time.Duration
  1146  	}
  1147  
  1148  	type item struct {
  1149  		Name   string
  1150  		Delay  time.Duration
  1151  		Nested duration
  1152  	}
  1153  
  1154  	config := `[[parent]]
  1155  	delay="100ms"
  1156  	[parent.nested]
  1157  	delay="200ms"
  1158  `
  1159  	initConfig("toml", config)
  1160  
  1161  	var items []item
  1162  	err := v.UnmarshalKey("parent", &items)
  1163  	if err != nil {
  1164  		t.Fatalf("unable to decode into struct, %v", err)
  1165  	}
  1166  
  1167  	assert.Equal(t, 1, len(items))
  1168  	assert.Equal(t, 100*time.Millisecond, items[0].Delay)
  1169  	assert.Equal(t, 200*time.Millisecond, items[0].Nested.Delay)
  1170  }
  1171  
  1172  func doTestCaseInsensitive(t *testing.T, typ, config string) {
  1173  	initConfig(typ, config)
  1174  	Set("RfD", true)
  1175  	assert.Equal(t, true, Get("rfd"))
  1176  	assert.Equal(t, true, Get("rFD"))
  1177  	assert.Equal(t, 1, cast.ToInt(Get("abcd")))
  1178  	assert.Equal(t, 1, cast.ToInt(Get("Abcd")))
  1179  	assert.Equal(t, 2, cast.ToInt(Get("ef.gh")))
  1180  	assert.Equal(t, 3, cast.ToInt(Get("ef.ijk")))
  1181  	assert.Equal(t, 4, cast.ToInt(Get("ef.lm.no")))
  1182  	assert.Equal(t, 5, cast.ToInt(Get("ef.lm.p.q")))
  1183  
  1184  }
  1185  
  1186  func BenchmarkGetBool(b *testing.B) {
  1187  	key := "BenchmarkGetBool"
  1188  	v = New()
  1189  	v.Set(key, true)
  1190  
  1191  	for i := 0; i < b.N; i++ {
  1192  		if !v.GetBool(key) {
  1193  			b.Fatal("GetBool returned false")
  1194  		}
  1195  	}
  1196  }
  1197  
  1198  func BenchmarkGet(b *testing.B) {
  1199  	key := "BenchmarkGet"
  1200  	v = New()
  1201  	v.Set(key, true)
  1202  
  1203  	for i := 0; i < b.N; i++ {
  1204  		if !v.Get(key).(bool) {
  1205  			b.Fatal("Get returned false")
  1206  		}
  1207  	}
  1208  }
  1209  
  1210  // This is the "perfect result" for the above.
  1211  func BenchmarkGetBoolFromMap(b *testing.B) {
  1212  	m := make(map[string]bool)
  1213  	key := "BenchmarkGetBool"
  1214  	m[key] = true
  1215  
  1216  	for i := 0; i < b.N; i++ {
  1217  		if !m[key] {
  1218  			b.Fatal("Map value was false")
  1219  		}
  1220  	}
  1221  }