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