github.com/nhoya/viper@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/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.GetInt64("hello.lagrenum"); pop != int64(765432101234567) {
  1072  		t.Fatalf("int64 lagrenum != 765432101234567, = %d", pop)
  1073  	}
  1074  
  1075  	if world := v.GetStringSlice("hello.world"); len(world) != 4 {
  1076  		t.Fatalf("len(world) != 4, = %d", len(world))
  1077  	}
  1078  
  1079  	if fu := v.GetString("fu"); fu != "" {
  1080  		t.Fatalf("fu != \"\", = %s", fu)
  1081  	}
  1082  
  1083  	if err := v.MergeConfig(bytes.NewBuffer(yamlMergeExampleSrc)); err != nil {
  1084  		t.Fatal(err)
  1085  	}
  1086  
  1087  	if pop := v.GetInt("hello.pop"); pop != 45000 {
  1088  		t.Fatalf("pop != 45000, = %d", pop)
  1089  	}
  1090  
  1091  	if pop := v.GetInt("hello.lagrenum"); pop != 7654321001234567 {
  1092  		t.Fatalf("lagrenum != 7654321001234567, = %d", pop)
  1093  	}
  1094  
  1095  	if pop := v.GetInt64("hello.lagrenum"); pop != int64(7654321001234567) {
  1096  		t.Fatalf("int64 lagrenum != 7654321001234567, = %d", pop)
  1097  	}
  1098  
  1099  	if world := v.GetStringSlice("hello.world"); len(world) != 4 {
  1100  		t.Fatalf("len(world) != 4, = %d", len(world))
  1101  	}
  1102  
  1103  	if universe := v.GetStringSlice("hello.universe"); len(universe) != 2 {
  1104  		t.Fatalf("len(universe) != 2, = %d", len(universe))
  1105  	}
  1106  
  1107  	if fu := v.GetString("fu"); fu != "bar" {
  1108  		t.Fatalf("fu != \"bar\", = %s", fu)
  1109  	}
  1110  }
  1111  
  1112  func TestMergeConfigNoMerge(t *testing.T) {
  1113  	v := New()
  1114  	v.SetConfigType("yml")
  1115  	if err := v.ReadConfig(bytes.NewBuffer(yamlMergeExampleTgt)); err != nil {
  1116  		t.Fatal(err)
  1117  	}
  1118  
  1119  	if pop := v.GetInt("hello.pop"); pop != 37890 {
  1120  		t.Fatalf("pop != 37890, = %d", pop)
  1121  	}
  1122  
  1123  	if world := v.GetStringSlice("hello.world"); len(world) != 4 {
  1124  		t.Fatalf("len(world) != 4, = %d", len(world))
  1125  	}
  1126  
  1127  	if fu := v.GetString("fu"); fu != "" {
  1128  		t.Fatalf("fu != \"\", = %s", fu)
  1129  	}
  1130  
  1131  	if err := v.ReadConfig(bytes.NewBuffer(yamlMergeExampleSrc)); err != nil {
  1132  		t.Fatal(err)
  1133  	}
  1134  
  1135  	if pop := v.GetInt("hello.pop"); pop != 45000 {
  1136  		t.Fatalf("pop != 45000, = %d", pop)
  1137  	}
  1138  
  1139  	if world := v.GetStringSlice("hello.world"); len(world) != 0 {
  1140  		t.Fatalf("len(world) != 0, = %d", len(world))
  1141  	}
  1142  
  1143  	if universe := v.GetStringSlice("hello.universe"); len(universe) != 2 {
  1144  		t.Fatalf("len(universe) != 2, = %d", len(universe))
  1145  	}
  1146  
  1147  	if fu := v.GetString("fu"); fu != "bar" {
  1148  		t.Fatalf("fu != \"bar\", = %s", fu)
  1149  	}
  1150  }
  1151  
  1152  func TestUnmarshalingWithAliases(t *testing.T) {
  1153  	v := New()
  1154  	v.SetDefault("ID", 1)
  1155  	v.Set("name", "Steve")
  1156  	v.Set("lastname", "Owen")
  1157  
  1158  	v.RegisterAlias("UserID", "ID")
  1159  	v.RegisterAlias("Firstname", "name")
  1160  	v.RegisterAlias("Surname", "lastname")
  1161  
  1162  	type config struct {
  1163  		ID        int
  1164  		FirstName string
  1165  		Surname   string
  1166  	}
  1167  
  1168  	var C config
  1169  	err := v.Unmarshal(&C)
  1170  	if err != nil {
  1171  		t.Fatalf("unable to decode into struct, %v", err)
  1172  	}
  1173  
  1174  	assert.Equal(t, &config{ID: 1, FirstName: "Steve", Surname: "Owen"}, &C)
  1175  }
  1176  
  1177  func TestSetConfigNameClearsFileCache(t *testing.T) {
  1178  	SetConfigFile("/tmp/config.yaml")
  1179  	SetConfigName("default")
  1180  	f, err := v.getConfigFile()
  1181  	if err == nil {
  1182  		t.Fatalf("config file cache should have been cleared")
  1183  	}
  1184  	assert.Empty(t, f)
  1185  }
  1186  
  1187  func TestShadowedNestedValue(t *testing.T) {
  1188  
  1189  	config := `name: steve
  1190  clothing:
  1191    jacket: leather
  1192    trousers: denim
  1193    pants:
  1194      size: large
  1195  `
  1196  	initConfig("yaml", config)
  1197  
  1198  	assert.Equal(t, "steve", GetString("name"))
  1199  
  1200  	polyester := "polyester"
  1201  	SetDefault("clothing.shirt", polyester)
  1202  	SetDefault("clothing.jacket.price", 100)
  1203  
  1204  	assert.Equal(t, "leather", GetString("clothing.jacket"))
  1205  	assert.Nil(t, Get("clothing.jacket.price"))
  1206  	assert.Equal(t, polyester, GetString("clothing.shirt"))
  1207  
  1208  	clothingSettings := AllSettings()["clothing"].(map[string]interface{})
  1209  	assert.Equal(t, "leather", clothingSettings["jacket"])
  1210  	assert.Equal(t, polyester, clothingSettings["shirt"])
  1211  }
  1212  
  1213  func TestDotParameter(t *testing.T) {
  1214  	initJSON()
  1215  	// shoud take precedence over batters defined in jsonExample
  1216  	r := bytes.NewReader([]byte(`{ "batters.batter": [ { "type": "Small" } ] }`))
  1217  	unmarshalReader(r, v.config)
  1218  
  1219  	actual := Get("batters.batter")
  1220  	expected := []interface{}{map[string]interface{}{"type": "Small"}}
  1221  	assert.Equal(t, expected, actual)
  1222  }
  1223  
  1224  func TestCaseInsensitive(t *testing.T) {
  1225  	for _, config := range []struct {
  1226  		typ     string
  1227  		content string
  1228  	}{
  1229  		{"yaml", `
  1230  aBcD: 1
  1231  eF:
  1232    gH: 2
  1233    iJk: 3
  1234    Lm:
  1235      nO: 4
  1236      P:
  1237        Q: 5
  1238        R: 6
  1239  `},
  1240  		{"json", `{
  1241    "aBcD": 1,
  1242    "eF": {
  1243      "iJk": 3,
  1244      "Lm": {
  1245        "P": {
  1246          "Q": 5,
  1247          "R": 6
  1248        },
  1249        "nO": 4
  1250      },
  1251      "gH": 2
  1252    }
  1253  }`},
  1254  		{"toml", `aBcD = 1
  1255  [eF]
  1256  gH = 2
  1257  iJk = 3
  1258  [eF.Lm]
  1259  nO = 4
  1260  [eF.Lm.P]
  1261  Q = 5
  1262  R = 6
  1263  `},
  1264  	} {
  1265  		doTestCaseInsensitive(t, config.typ, config.content)
  1266  	}
  1267  }
  1268  
  1269  func TestCaseInsensitiveSet(t *testing.T) {
  1270  	Reset()
  1271  	m1 := map[string]interface{}{
  1272  		"Foo": 32,
  1273  		"Bar": map[interface{}]interface {
  1274  		}{
  1275  			"ABc": "A",
  1276  			"cDE": "B"},
  1277  	}
  1278  
  1279  	m2 := map[string]interface{}{
  1280  		"Foo": 52,
  1281  		"Bar": map[interface{}]interface {
  1282  		}{
  1283  			"bCd": "A",
  1284  			"eFG": "B"},
  1285  	}
  1286  
  1287  	Set("Given1", m1)
  1288  	Set("Number1", 42)
  1289  
  1290  	SetDefault("Given2", m2)
  1291  	SetDefault("Number2", 52)
  1292  
  1293  	// Verify SetDefault
  1294  	if v := Get("number2"); v != 52 {
  1295  		t.Fatalf("Expected 52 got %q", v)
  1296  	}
  1297  
  1298  	if v := Get("given2.foo"); v != 52 {
  1299  		t.Fatalf("Expected 52 got %q", v)
  1300  	}
  1301  
  1302  	if v := Get("given2.bar.bcd"); v != "A" {
  1303  		t.Fatalf("Expected A got %q", v)
  1304  	}
  1305  
  1306  	if _, ok := m2["Foo"]; !ok {
  1307  		t.Fatal("Input map changed")
  1308  	}
  1309  
  1310  	// Verify Set
  1311  	if v := Get("number1"); v != 42 {
  1312  		t.Fatalf("Expected 42 got %q", v)
  1313  	}
  1314  
  1315  	if v := Get("given1.foo"); v != 32 {
  1316  		t.Fatalf("Expected 32 got %q", v)
  1317  	}
  1318  
  1319  	if v := Get("given1.bar.abc"); v != "A" {
  1320  		t.Fatalf("Expected A got %q", v)
  1321  	}
  1322  
  1323  	if _, ok := m1["Foo"]; !ok {
  1324  		t.Fatal("Input map changed")
  1325  	}
  1326  }
  1327  
  1328  func TestParseNested(t *testing.T) {
  1329  	type duration struct {
  1330  		Delay time.Duration
  1331  	}
  1332  
  1333  	type item struct {
  1334  		Name   string
  1335  		Delay  time.Duration
  1336  		Nested duration
  1337  	}
  1338  
  1339  	config := `[[parent]]
  1340  	delay="100ms"
  1341  	[parent.nested]
  1342  	delay="200ms"
  1343  `
  1344  	initConfig("toml", config)
  1345  
  1346  	var items []item
  1347  	err := v.UnmarshalKey("parent", &items)
  1348  	if err != nil {
  1349  		t.Fatalf("unable to decode into struct, %v", err)
  1350  	}
  1351  
  1352  	assert.Equal(t, 1, len(items))
  1353  	assert.Equal(t, 100*time.Millisecond, items[0].Delay)
  1354  	assert.Equal(t, 200*time.Millisecond, items[0].Nested.Delay)
  1355  }
  1356  
  1357  func doTestCaseInsensitive(t *testing.T, typ, config string) {
  1358  	initConfig(typ, config)
  1359  	Set("RfD", true)
  1360  	assert.Equal(t, true, Get("rfd"))
  1361  	assert.Equal(t, true, Get("rFD"))
  1362  	assert.Equal(t, 1, cast.ToInt(Get("abcd")))
  1363  	assert.Equal(t, 1, cast.ToInt(Get("Abcd")))
  1364  	assert.Equal(t, 2, cast.ToInt(Get("ef.gh")))
  1365  	assert.Equal(t, 3, cast.ToInt(Get("ef.ijk")))
  1366  	assert.Equal(t, 4, cast.ToInt(Get("ef.lm.no")))
  1367  	assert.Equal(t, 5, cast.ToInt(Get("ef.lm.p.q")))
  1368  
  1369  }
  1370  
  1371  func BenchmarkGetBool(b *testing.B) {
  1372  	key := "BenchmarkGetBool"
  1373  	v = New()
  1374  	v.Set(key, true)
  1375  
  1376  	for i := 0; i < b.N; i++ {
  1377  		if !v.GetBool(key) {
  1378  			b.Fatal("GetBool returned false")
  1379  		}
  1380  	}
  1381  }
  1382  
  1383  func BenchmarkGet(b *testing.B) {
  1384  	key := "BenchmarkGet"
  1385  	v = New()
  1386  	v.Set(key, true)
  1387  
  1388  	for i := 0; i < b.N; i++ {
  1389  		if !v.Get(key).(bool) {
  1390  			b.Fatal("Get returned false")
  1391  		}
  1392  	}
  1393  }
  1394  
  1395  // This is the "perfect result" for the above.
  1396  func BenchmarkGetBoolFromMap(b *testing.B) {
  1397  	m := make(map[string]bool)
  1398  	key := "BenchmarkGetBool"
  1399  	m[key] = true
  1400  
  1401  	for i := 0; i < b.N; i++ {
  1402  		if !m[key] {
  1403  			b.Fatal("Map value was false")
  1404  		}
  1405  	}
  1406  }