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