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