github.com/samt42/viper@v0.0.0-20190213113551-4b317a1ea64b/viper_test.go (about)

     1  // Copyright © 2014 Steve Francia <spf@spf13.com>.
     2  //
     3  // Use of this source code is governed by an MIT-style
     4  // license that can be found in the LICENSE file.
     5  
     6  package viper
     7  
     8  import (
     9  	"bytes"
    10  	"fmt"
    11  	"io"
    12  	"io/ioutil"
    13  	"os"
    14  	"path"
    15  	"reflect"
    16  	"sort"
    17  	"strings"
    18  	"testing"
    19  	"time"
    20  
    21  	"github.com/spf13/cast"
    22  
    23  	"github.com/spf13/pflag"
    24  	"github.com/stretchr/testify/assert"
    25  )
    26  
    27  var iniExample = []byte(`
    28  ;comment one
    29  #comment two
    30  string = testing
    31  string_1 = testing_1
    32  string_1.1 = "testing"
    33  string_2.1 = "testing"
    34  string_3.1.1 = "testing_1"
    35  string_3.1.2 = "testing_2"
    36  int = 8080
    37  float = 3.1415976
    38  boolean = false
    39  boolean_1 = true
    40  switcher= on
    41  switcher_1= off
    42  switcher_2 = OFF
    43  switcher_3 = ON
    44  switcher_4 = Y
    45  switcher_5 = N
    46  flag = 1
    47  [dev]
    48  string_1.1 = "testing_dev"
    49  string_2.2 = "testing_dev"
    50  `)
    51  
    52  var yamlExample = []byte(`Hacker: true
    53  name: steve
    54  hobbies:
    55  - skateboarding
    56  - snowboarding
    57  - go
    58  clothing:
    59    jacket: leather
    60    trousers: denim
    61    pants:
    62      size: large
    63  age: 35
    64  eyes : brown
    65  beard: true
    66  `)
    67  
    68  var yamlExampleWithExtras = []byte(`Existing: true
    69  Bogus: true
    70  `)
    71  
    72  type testUnmarshalExtra struct {
    73  	Existing bool
    74  }
    75  
    76  var tomlExample = []byte(`
    77  title = "TOML Example"
    78  
    79  [owner]
    80  organization = "MongoDB"
    81  Bio = "MongoDB Chief developer Advocate & Hacker at Large"
    82  dob = 1979-05-27T07:32:00Z # First class dates? Why not?`)
    83  
    84  var jsonExample = []byte(`{
    85  "id": "0001",
    86  "type": "donut",
    87  "name": "Cake",
    88  "ppu": 0.55,
    89  "batters": {
    90          "batter": [
    91                  { "type": "Regular" },
    92                  { "type": "Chocolate" },
    93                  { "type": "Blueberry" },
    94                  { "type": "devil's Food" }
    95              ]
    96      }
    97  }`)
    98  
    99  var hclExample = []byte(`
   100  id = "0001"
   101  type = "donut"
   102  name = "Cake"
   103  ppu = 0.55
   104  foos {
   105  	foo {
   106  		key = 1
   107  	}
   108  	foo {
   109  		key = 2
   110  	}
   111  	foo {
   112  		key = 3
   113  	}
   114  	foo {
   115  		key = 4
   116  	}
   117  }`)
   118  
   119  var propertiesExample = []byte(`
   120  p_id: 0001
   121  p_type: donut
   122  p_name: Cake
   123  p_ppu: 0.55
   124  p_batters.batter.type: Regular
   125  `)
   126  
   127  var remoteExample = []byte(`{
   128  "id":"0002",
   129  "type":"cronut",
   130  "newkey":"remote"
   131  }`)
   132  
   133  func initConfigs() {
   134  	Reset()
   135  	var r io.Reader
   136  	SetConfigType("ini")
   137  	r = bytes.NewReader(iniExample)
   138  	unmarshalReader(r, v.config)
   139  
   140  	SetConfigType("yaml")
   141  	r = bytes.NewReader(yamlExample)
   142  	unmarshalReader(r, v.config)
   143  
   144  	SetConfigType("json")
   145  	r = bytes.NewReader(jsonExample)
   146  	unmarshalReader(r, v.config)
   147  
   148  	SetConfigType("hcl")
   149  	r = bytes.NewReader(hclExample)
   150  	unmarshalReader(r, v.config)
   151  
   152  	SetConfigType("properties")
   153  	r = bytes.NewReader(propertiesExample)
   154  	unmarshalReader(r, v.config)
   155  
   156  	SetConfigType("toml")
   157  	r = bytes.NewReader(tomlExample)
   158  	unmarshalReader(r, v.config)
   159  
   160  	SetConfigType("json")
   161  	remote := bytes.NewReader(remoteExample)
   162  	unmarshalReader(remote, v.kvstore)
   163  }
   164  
   165  func initConfig(typ, config string) {
   166  	Reset()
   167  	SetConfigType(typ)
   168  	r := strings.NewReader(config)
   169  
   170  	if err := unmarshalReader(r, v.config); err != nil {
   171  		panic(err)
   172  	}
   173  }
   174  
   175  func initINI() {
   176  	initConfig("ini", string(iniExample))
   177  }
   178  
   179  func initYAML() {
   180  	initConfig("yaml", string(yamlExample))
   181  }
   182  
   183  func initJSON() {
   184  	Reset()
   185  	SetConfigType("json")
   186  	r := bytes.NewReader(jsonExample)
   187  
   188  	unmarshalReader(r, v.config)
   189  }
   190  
   191  func initProperties() {
   192  	Reset()
   193  	SetConfigType("properties")
   194  	r := bytes.NewReader(propertiesExample)
   195  
   196  	unmarshalReader(r, v.config)
   197  }
   198  
   199  func initTOML() {
   200  	Reset()
   201  	SetConfigType("toml")
   202  	r := bytes.NewReader(tomlExample)
   203  
   204  	unmarshalReader(r, v.config)
   205  }
   206  
   207  func initHcl() {
   208  	Reset()
   209  	SetConfigType("hcl")
   210  	r := bytes.NewReader(hclExample)
   211  
   212  	unmarshalReader(r, v.config)
   213  }
   214  
   215  // make directories for testing
   216  func initDirs(t *testing.T) (string, string, func()) {
   217  
   218  	var (
   219  		testDirs = []string{`a a`, `b`, `c\c`, `D_`}
   220  		config   = `improbable`
   221  	)
   222  
   223  	root, err := ioutil.TempDir("", "")
   224  
   225  	cleanup := true
   226  	defer func() {
   227  		if cleanup {
   228  			os.Chdir("..")
   229  			os.RemoveAll(root)
   230  		}
   231  	}()
   232  
   233  	assert.Nil(t, err)
   234  
   235  	err = os.Chdir(root)
   236  	assert.Nil(t, err)
   237  
   238  	for _, dir := range testDirs {
   239  		err = os.Mkdir(dir, 0750)
   240  		assert.Nil(t, err)
   241  
   242  		err = ioutil.WriteFile(
   243  			path.Join(dir, config+".toml"),
   244  			[]byte("key = \"value is "+dir+"\"\n"),
   245  			0640)
   246  		assert.Nil(t, err)
   247  	}
   248  
   249  	cleanup = false
   250  	return root, config, func() {
   251  		os.Chdir("..")
   252  		os.RemoveAll(root)
   253  	}
   254  }
   255  
   256  //stubs for PFlag Values
   257  type stringValue string
   258  
   259  func newStringValue(val string, p *string) *stringValue {
   260  	*p = val
   261  	return (*stringValue)(p)
   262  }
   263  
   264  func (s *stringValue) Set(val string) error {
   265  	*s = stringValue(val)
   266  	return nil
   267  }
   268  
   269  func (s *stringValue) Type() string {
   270  	return "string"
   271  }
   272  
   273  func (s *stringValue) String() string {
   274  	return fmt.Sprintf("%s", *s)
   275  }
   276  
   277  func TestBasics(t *testing.T) {
   278  	SetConfigFile("/tmp/config.yaml")
   279  	filename, err := v.getConfigFile()
   280  	assert.Equal(t, "/tmp/config.yaml", filename)
   281  	assert.NoError(t, err)
   282  }
   283  
   284  func TestDefault(t *testing.T) {
   285  	SetDefault("age", 45)
   286  	assert.Equal(t, 45, Get("age"))
   287  
   288  	SetDefault("clothing.jacket", "slacks")
   289  	assert.Equal(t, "slacks", Get("clothing.jacket"))
   290  
   291  	SetConfigType("yaml")
   292  	err := ReadConfig(bytes.NewBuffer(yamlExample))
   293  
   294  	assert.NoError(t, err)
   295  	assert.Equal(t, "leather", Get("clothing.jacket"))
   296  }
   297  
   298  func TestUnmarshalling(t *testing.T) {
   299  	SetConfigType("yaml")
   300  	r := bytes.NewReader(yamlExample)
   301  
   302  	unmarshalReader(r, v.config)
   303  	assert.True(t, InConfig("name"))
   304  	assert.False(t, InConfig("state"))
   305  	assert.Equal(t, "steve", Get("name"))
   306  	assert.Equal(t, []interface{}{"skateboarding", "snowboarding", "go"}, Get("hobbies"))
   307  	assert.Equal(t, map[string]interface{}{"jacket": "leather", "trousers": "denim", "pants": map[string]interface{}{"size": "large"}}, Get("clothing"))
   308  	assert.Equal(t, 35, Get("age"))
   309  }
   310  
   311  func TestUnmarshalExact(t *testing.T) {
   312  	vip := New()
   313  	target := &testUnmarshalExtra{}
   314  	vip.SetConfigType("yaml")
   315  	r := bytes.NewReader(yamlExampleWithExtras)
   316  	vip.ReadConfig(r)
   317  	err := vip.UnmarshalExact(target)
   318  	if err == nil {
   319  		t.Fatal("UnmarshalExact should error when populating a struct from a conf that contains unused fields")
   320  	}
   321  }
   322  
   323  func TestOverrides(t *testing.T) {
   324  	Set("age", 40)
   325  	assert.Equal(t, 40, Get("age"))
   326  }
   327  
   328  func TestDefaultPost(t *testing.T) {
   329  	assert.NotEqual(t, "NYC", Get("state"))
   330  	SetDefault("state", "NYC")
   331  	assert.Equal(t, "NYC", Get("state"))
   332  }
   333  
   334  func TestAliases(t *testing.T) {
   335  	RegisterAlias("years", "age")
   336  	assert.Equal(t, 40, Get("years"))
   337  	Set("years", 45)
   338  	assert.Equal(t, 45, Get("age"))
   339  }
   340  
   341  func TestAliasInConfigFile(t *testing.T) {
   342  	// the config file specifies "beard".  If we make this an alias for
   343  	// "hasbeard", we still want the old config file to work with beard.
   344  	RegisterAlias("beard", "hasbeard")
   345  	assert.Equal(t, true, Get("hasbeard"))
   346  	Set("hasbeard", false)
   347  	assert.Equal(t, false, Get("beard"))
   348  }
   349  
   350  func TestINI(t *testing.T) {
   351  	initINI()
   352  	assert.Equal(t, "testing", Get("string"))
   353  }
   354  
   355  func TestYML(t *testing.T) {
   356  	initYAML()
   357  	assert.Equal(t, "steve", Get("name"))
   358  }
   359  
   360  func TestJSON(t *testing.T) {
   361  	initJSON()
   362  	assert.Equal(t, "0001", Get("id"))
   363  }
   364  
   365  func TestProperties(t *testing.T) {
   366  	initProperties()
   367  	assert.Equal(t, "0001", Get("p_id"))
   368  }
   369  
   370  func TestTOML(t *testing.T) {
   371  	initTOML()
   372  	assert.Equal(t, "TOML Example", Get("title"))
   373  }
   374  
   375  func TestHCL(t *testing.T) {
   376  	initHcl()
   377  	assert.Equal(t, "0001", Get("id"))
   378  	assert.Equal(t, 0.55, Get("ppu"))
   379  	assert.Equal(t, "donut", Get("type"))
   380  	assert.Equal(t, "Cake", Get("name"))
   381  	Set("id", "0002")
   382  	assert.Equal(t, "0002", Get("id"))
   383  	assert.NotEqual(t, "cronut", Get("type"))
   384  }
   385  
   386  func TestRemotePrecedence(t *testing.T) {
   387  	initJSON()
   388  
   389  	remote := bytes.NewReader(remoteExample)
   390  	assert.Equal(t, "0001", Get("id"))
   391  	unmarshalReader(remote, v.kvstore)
   392  	assert.Equal(t, "0001", Get("id"))
   393  	assert.NotEqual(t, "cronut", Get("type"))
   394  	assert.Equal(t, "remote", Get("newkey"))
   395  	Set("newkey", "newvalue")
   396  	assert.NotEqual(t, "remote", Get("newkey"))
   397  	assert.Equal(t, "newvalue", Get("newkey"))
   398  	Set("newkey", "remote")
   399  }
   400  
   401  func TestEnv(t *testing.T) {
   402  	initJSON()
   403  
   404  	BindEnv("id")
   405  	BindEnv("f", "FOOD")
   406  
   407  	os.Setenv("ID", "13")
   408  	os.Setenv("FOOD", "apple")
   409  	os.Setenv("NAME", "crunk")
   410  
   411  	assert.Equal(t, "13", Get("id"))
   412  	assert.Equal(t, "apple", Get("f"))
   413  	assert.Equal(t, "Cake", Get("name"))
   414  
   415  	AutomaticEnv()
   416  
   417  	assert.Equal(t, "crunk", Get("name"))
   418  
   419  }
   420  
   421  func TestEnvPrefix(t *testing.T) {
   422  	initJSON()
   423  
   424  	SetEnvPrefix("foo") // will be uppercased automatically
   425  	BindEnv("id")
   426  	BindEnv("f", "FOOD") // not using prefix
   427  
   428  	os.Setenv("FOO_ID", "13")
   429  	os.Setenv("FOOD", "apple")
   430  	os.Setenv("FOO_NAME", "crunk")
   431  
   432  	assert.Equal(t, "13", Get("id"))
   433  	assert.Equal(t, "apple", Get("f"))
   434  	assert.Equal(t, "Cake", Get("name"))
   435  
   436  	AutomaticEnv()
   437  
   438  	assert.Equal(t, "crunk", Get("name"))
   439  }
   440  
   441  func TestAutoEnv(t *testing.T) {
   442  	Reset()
   443  
   444  	AutomaticEnv()
   445  	os.Setenv("FOO_BAR", "13")
   446  	assert.Equal(t, "13", Get("foo_bar"))
   447  }
   448  
   449  func TestAutoEnvWithPrefix(t *testing.T) {
   450  	Reset()
   451  
   452  	AutomaticEnv()
   453  	SetEnvPrefix("Baz")
   454  	os.Setenv("BAZ_BAR", "13")
   455  	assert.Equal(t, "13", Get("bar"))
   456  }
   457  
   458  func TestSetEnvReplacer(t *testing.T) {
   459  	Reset()
   460  
   461  	AutomaticEnv()
   462  	os.Setenv("REFRESH_INTERVAL", "30s")
   463  
   464  	replacer := strings.NewReplacer("-", "_")
   465  	SetEnvKeyReplacer(replacer)
   466  
   467  	assert.Equal(t, "30s", Get("refresh-interval"))
   468  }
   469  
   470  func TestAllKeys(t *testing.T) {
   471  	initConfigs()
   472  
   473  	ks := sort.StringSlice{
   474  		"string",
   475  		"string_1.1",
   476  		"string_2.1",
   477  		"string_3.1.1",
   478  		"string_3.1.2",
   479  		"int",
   480  		"float",
   481  		"boolean",
   482  		"boolean_1",
   483  		"switcher",
   484  		"switcher_1",
   485  		"switcher_2",
   486  		"switcher_3",
   487  		"switcher_4",
   488  		"switcher_5",
   489  		"flag",
   490  		"dev.boolean",
   491  		"dev.boolean_1",
   492  		"dev.flag",
   493  		"dev.float",
   494  		"dev.int",
   495  		"dev.string",
   496  		"dev.string_1.1",
   497  		"dev.string_2.1",
   498  		"dev.string_2.2",
   499  		"dev.string_3.1.1",
   500  		"dev.string_3.1.2",
   501  		"dev.switcher",
   502  		"dev.switcher_1",
   503  		"dev.switcher_2",
   504  		"dev.switcher_3",
   505  		"dev.switcher_4",
   506  		"dev.switcher_5",
   507  		"title",
   508  		"newkey",
   509  		"owner.organization",
   510  		"owner.dob",
   511  		"owner.bio",
   512  		"name",
   513  		"beard",
   514  		"ppu",
   515  		"batters.batter",
   516  		"hobbies",
   517  		"clothing.jacket",
   518  		"clothing.trousers",
   519  		"clothing.pants.size",
   520  		"age",
   521  		"hacker",
   522  		"id",
   523  		"type",
   524  		"eyes",
   525  		"p_id",
   526  		"p_ppu",
   527  		"p_batters.batter.type",
   528  		"p_type",
   529  		"p_name",
   530  		"foos",
   531  	}
   532  	dob, _ := time.Parse(time.RFC3339, "1979-05-27T07:32:00Z")
   533  	all := map[string]interface{}{
   534  		"string":     "testing",
   535  		"string_1":   map[string]interface{}{"1": "testing"},
   536  		"string_2":   map[string]interface{}{"1": "testing"},
   537  		"string_3":   map[string]interface{}{"1": map[string]interface{}{"1": "testing_1", "2": "testing_2"}},
   538  		"int":        8080,
   539  		"float":      3.1415976,
   540  		"boolean":    false,
   541  		"boolean_1":  true,
   542  		"switcher":   true,
   543  		"switcher_1": false,
   544  		"switcher_2": false,
   545  		"switcher_3": true,
   546  		"switcher_4": true,
   547  		"switcher_5": false,
   548  		"flag":       1,
   549  		"dev": map[string]interface{}{
   550  			"string":          "testing",
   551  			"string_1":        map[string]interface{}{"1": "testing_dev"},
   552  			"string_2":        map[string]interface{}{"1": "testing", "2": "testing_dev"},
   553  			"string_3":        map[string]interface{}{"1": map[string]interface{}{"1": "testing_1", "2": "testing_2"}},
   554  			"int":             8080,
   555  			"float":           3.1415976,
   556  			"boolean":         false,
   557  			"boolean_1":       true,
   558  			"switcher":        true,
   559  			"switcher_1":      false,
   560  			"switcher_2":      false,
   561  			"switcher_3":      true,
   562  			"switcher_4":      true,
   563  			"switcher_5":      false,
   564  			"flag":            1,
   565  		},
   566  		"owner": map[string]interface{}{
   567  			"organization": "MongoDB",
   568  			"bio":          "MongoDB Chief developer Advocate & Hacker at Large",
   569  			"dob":          dob,
   570  		},
   571  		"title": "TOML Example",
   572  		"ppu":   0.55,
   573  		"eyes":  "brown",
   574  		"clothing": map[string]interface{}{
   575  			"trousers": "denim",
   576  			"jacket":   "leather",
   577  			"pants":    map[string]interface{}{"size": "large"},
   578  		},
   579  		"id": "0001",
   580  		"batters": map[string]interface{}{
   581  			"batter": []interface{}{
   582  				map[string]interface{}{
   583  					"type": "Regular",
   584  				},
   585  				map[string]interface{}{
   586  					"type": "Chocolate",
   587  				},
   588  				map[string]interface{}{
   589  					"type": "Blueberry",
   590  				},
   591  				map[string]interface{}{
   592  					"type": "devil's Food",
   593  				},
   594  			},
   595  		},
   596  		"hacker":  true,
   597  		"beard":   true,
   598  		"hobbies": []interface{}{"skateboarding", "snowboarding", "go"},
   599  		"age":     35,
   600  		"type":    "donut",
   601  		"newkey":  "remote",
   602  		"name":    "Cake",
   603  		"p_id":    "0001",
   604  		"p_ppu":   "0.55",
   605  		"p_name":  "Cake",
   606  		"p_batters": map[string]interface{}{
   607  			"batter": map[string]interface{}{
   608  				"type": "Regular",
   609  			},
   610  		},
   611  		"p_type": "donut",
   612  		"foos": []map[string]interface{}{
   613  			map[string]interface{}{
   614  				"foo": []map[string]interface{}{
   615  					map[string]interface{}{"key": 1},
   616  					map[string]interface{}{"key": 2},
   617  					map[string]interface{}{"key": 3},
   618  					map[string]interface{}{"key": 4},
   619  				},
   620  			},
   621  		},
   622  	}
   623  
   624  	var allkeys sort.StringSlice
   625  	allkeys = AllKeys()
   626  	allkeys.Sort()
   627  	ks.Sort()
   628  
   629  	assert.Equal(t, ks, allkeys)
   630  	assert.Equal(t, all, AllSettings())
   631  }
   632  
   633  func TestAllKeysWithEnv(t *testing.T) {
   634  	v := New()
   635  
   636  	// bind and define environment variables (including a nested one)
   637  	v.BindEnv("id")
   638  	v.BindEnv("foo.bar")
   639  	v.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
   640  	os.Setenv("ID", "13")
   641  	os.Setenv("FOO_BAR", "baz")
   642  
   643  	expectedKeys := sort.StringSlice{"id", "foo.bar"}
   644  	expectedKeys.Sort()
   645  	keys := sort.StringSlice(v.AllKeys())
   646  	keys.Sort()
   647  	assert.Equal(t, expectedKeys, keys)
   648  }
   649  
   650  func TestAliasesOfAliases(t *testing.T) {
   651  	Set("Title", "Checking Case")
   652  	RegisterAlias("Foo", "Bar")
   653  	RegisterAlias("Bar", "Title")
   654  	assert.Equal(t, "Checking Case", Get("FOO"))
   655  }
   656  
   657  func TestRecursiveAliases(t *testing.T) {
   658  	RegisterAlias("Baz", "Roo")
   659  	RegisterAlias("Roo", "baz")
   660  }
   661  
   662  func TestUnmarshal(t *testing.T) {
   663  	SetDefault("port", 1313)
   664  	Set("name", "Steve")
   665  	Set("duration", "1s1ms")
   666  
   667  	type config struct {
   668  		Port     int
   669  		Name     string
   670  		Duration time.Duration
   671  	}
   672  
   673  	var C config
   674  
   675  	err := Unmarshal(&C)
   676  	if err != nil {
   677  		t.Fatalf("unable to decode into struct, %v", err)
   678  	}
   679  
   680  	assert.Equal(t, &config{Name: "Steve", Port: 1313, Duration: time.Second + time.Millisecond}, &C)
   681  
   682  	Set("port", 1234)
   683  	err = Unmarshal(&C)
   684  	if err != nil {
   685  		t.Fatalf("unable to decode into struct, %v", err)
   686  	}
   687  	assert.Equal(t, &config{Name: "Steve", Port: 1234, Duration: time.Second + time.Millisecond}, &C)
   688  }
   689  
   690  func TestBindPFlags(t *testing.T) {
   691  	v := New() // create independent Viper object
   692  	flagSet := pflag.NewFlagSet("test", pflag.ContinueOnError)
   693  
   694  	var testValues = map[string]*string{
   695  		"host":     nil,
   696  		"port":     nil,
   697  		"endpoint": nil,
   698  	}
   699  
   700  	var mutatedTestValues = map[string]string{
   701  		"host":     "localhost",
   702  		"port":     "6060",
   703  		"endpoint": "/public",
   704  	}
   705  
   706  	for name := range testValues {
   707  		testValues[name] = flagSet.String(name, "", "test")
   708  	}
   709  
   710  	err := v.BindPFlags(flagSet)
   711  	if err != nil {
   712  		t.Fatalf("error binding flag set, %v", err)
   713  	}
   714  
   715  	flagSet.VisitAll(func(flag *pflag.Flag) {
   716  		flag.Value.Set(mutatedTestValues[flag.Name])
   717  		flag.Changed = true
   718  	})
   719  
   720  	for name, expected := range mutatedTestValues {
   721  		assert.Equal(t, expected, v.Get(name))
   722  	}
   723  
   724  }
   725  
   726  func TestBindPFlagsStringSlice(t *testing.T) {
   727  	for _, testValue := range []struct {
   728  		Expected []string
   729  		Value    string
   730  	}{
   731  		{[]string{}, ""},
   732  		{[]string{"jeden"}, "jeden"},
   733  		{[]string{"dwa", "trzy"}, "dwa,trzy"},
   734  		{[]string{"cztery", "piec , szesc"}, "cztery,\"piec , szesc\""}} {
   735  
   736  		for _, changed := range []bool{true, false} {
   737  			v := New() // create independent Viper object
   738  			flagSet := pflag.NewFlagSet("test", pflag.ContinueOnError)
   739  			flagSet.StringSlice("stringslice", testValue.Expected, "test")
   740  			flagSet.Visit(func(f *pflag.Flag) {
   741  				if len(testValue.Value) > 0 {
   742  					f.Value.Set(testValue.Value)
   743  					f.Changed = changed
   744  				}
   745  			})
   746  
   747  			err := v.BindPFlags(flagSet)
   748  			if err != nil {
   749  				t.Fatalf("error binding flag set, %v", err)
   750  			}
   751  
   752  			type TestStr struct {
   753  				StringSlice []string
   754  			}
   755  			val := &TestStr{}
   756  			if err := v.Unmarshal(val); err != nil {
   757  				t.Fatalf("%+#v cannot unmarshal: %s", testValue.Value, err)
   758  			}
   759  			assert.Equal(t, testValue.Expected, val.StringSlice)
   760  		}
   761  	}
   762  }
   763  
   764  func TestBindPFlag(t *testing.T) {
   765  	var testString = "testing"
   766  	var testValue = newStringValue(testString, &testString)
   767  
   768  	flag := &pflag.Flag{
   769  		Name:    "testflag",
   770  		Value:   testValue,
   771  		Changed: false,
   772  	}
   773  
   774  	BindPFlag("testvalue", flag)
   775  
   776  	assert.Equal(t, testString, Get("testvalue"))
   777  
   778  	flag.Value.Set("testing_mutate")
   779  	flag.Changed = true //hack for pflag usage
   780  
   781  	assert.Equal(t, "testing_mutate", Get("testvalue"))
   782  
   783  }
   784  
   785  func TestBoundCaseSensitivity(t *testing.T) {
   786  	assert.Equal(t, "brown", Get("eyes"))
   787  
   788  	BindEnv("eYEs", "TURTLE_EYES")
   789  	os.Setenv("TURTLE_EYES", "blue")
   790  
   791  	assert.Equal(t, "blue", Get("eyes"))
   792  
   793  	var testString = "green"
   794  	var testValue = newStringValue(testString, &testString)
   795  
   796  	flag := &pflag.Flag{
   797  		Name:    "eyeballs",
   798  		Value:   testValue,
   799  		Changed: true,
   800  	}
   801  
   802  	BindPFlag("eYEs", flag)
   803  	assert.Equal(t, "green", Get("eyes"))
   804  
   805  }
   806  
   807  func TestSizeInBytes(t *testing.T) {
   808  	input := map[string]uint{
   809  		"":               0,
   810  		"b":              0,
   811  		"12 bytes":       0,
   812  		"200000000000gb": 0,
   813  		"12 b":           12,
   814  		"43 MB":          43 * (1 << 20),
   815  		"10mb":           10 * (1 << 20),
   816  		"1gb":            1 << 30,
   817  	}
   818  
   819  	for str, expected := range input {
   820  		assert.Equal(t, expected, parseSizeInBytes(str), str)
   821  	}
   822  }
   823  
   824  func TestFindsNestedKeys(t *testing.T) {
   825  	initConfigs()
   826  	dob, _ := time.Parse(time.RFC3339, "1979-05-27T07:32:00Z")
   827  
   828  	Set("super", map[string]interface{}{
   829  		"deep": map[string]interface{}{
   830  			"nested": "value",
   831  		},
   832  	})
   833  
   834  	expected := map[string]interface{}{
   835  		"super": map[string]interface{}{
   836  			"deep": map[string]interface{}{
   837  				"nested": "value",
   838  			},
   839  		},
   840  		"super.deep": map[string]interface{}{
   841  			"nested": "value",
   842  		},
   843  		"super.deep.nested":  "value",
   844  		"owner.organization": "MongoDB",
   845  		"batters.batter": []interface{}{
   846  			map[string]interface{}{
   847  				"type": "Regular",
   848  			},
   849  			map[string]interface{}{
   850  				"type": "Chocolate",
   851  			},
   852  			map[string]interface{}{
   853  				"type": "Blueberry",
   854  			},
   855  			map[string]interface{}{
   856  				"type": "devil's Food",
   857  			},
   858  		},
   859  		"hobbies": []interface{}{
   860  			"skateboarding", "snowboarding", "go",
   861  		},
   862  		"title":  "TOML Example",
   863  		"newkey": "remote",
   864  		"batters": map[string]interface{}{
   865  			"batter": []interface{}{
   866  				map[string]interface{}{
   867  					"type": "Regular",
   868  				},
   869  				map[string]interface{}{
   870  					"type": "Chocolate",
   871  				}, map[string]interface{}{
   872  					"type": "Blueberry",
   873  				}, map[string]interface{}{
   874  					"type": "devil's Food",
   875  				},
   876  			},
   877  		},
   878  		"eyes": "brown",
   879  		"age":  35,
   880  		"owner": map[string]interface{}{
   881  			"organization": "MongoDB",
   882  			"bio":          "MongoDB Chief developer Advocate & Hacker at Large",
   883  			"dob":          dob,
   884  		},
   885  		"owner.bio": "MongoDB Chief developer Advocate & Hacker at Large",
   886  		"type":      "donut",
   887  		"id":        "0001",
   888  		"name":      "Cake",
   889  		"hacker":    true,
   890  		"ppu":       0.55,
   891  		"clothing": map[string]interface{}{
   892  			"jacket":   "leather",
   893  			"trousers": "denim",
   894  			"pants": map[string]interface{}{
   895  				"size": "large",
   896  			},
   897  		},
   898  		"clothing.jacket":     "leather",
   899  		"clothing.pants.size": "large",
   900  		"clothing.trousers":   "denim",
   901  		"owner.dob":           dob,
   902  		"beard":               true,
   903  		"foos": []map[string]interface{}{
   904  			map[string]interface{}{
   905  				"foo": []map[string]interface{}{
   906  					map[string]interface{}{
   907  						"key": 1,
   908  					},
   909  					map[string]interface{}{
   910  						"key": 2,
   911  					},
   912  					map[string]interface{}{
   913  						"key": 3,
   914  					},
   915  					map[string]interface{}{
   916  						"key": 4,
   917  					},
   918  				},
   919  			},
   920  		},
   921  	}
   922  
   923  	for key, expectedValue := range expected {
   924  
   925  		assert.Equal(t, expectedValue, v.Get(key))
   926  	}
   927  
   928  }
   929  
   930  func TestReadBufConfig(t *testing.T) {
   931  	v := New()
   932  	v.SetConfigType("yaml")
   933  	v.ReadConfig(bytes.NewBuffer(yamlExample))
   934  	t.Log(v.AllKeys())
   935  
   936  	assert.True(t, v.InConfig("name"))
   937  	assert.False(t, v.InConfig("state"))
   938  	assert.Equal(t, "steve", v.Get("name"))
   939  	assert.Equal(t, []interface{}{"skateboarding", "snowboarding", "go"}, v.Get("hobbies"))
   940  	assert.Equal(t, map[string]interface{}{"jacket": "leather", "trousers": "denim", "pants": map[string]interface{}{"size": "large"}}, v.Get("clothing"))
   941  	assert.Equal(t, 35, v.Get("age"))
   942  }
   943  
   944  func TestIsSet(t *testing.T) {
   945  	v := New()
   946  	v.SetConfigType("yaml")
   947  	v.ReadConfig(bytes.NewBuffer(yamlExample))
   948  	assert.True(t, v.IsSet("clothing.jacket"))
   949  	assert.False(t, v.IsSet("clothing.jackets"))
   950  	assert.False(t, v.IsSet("helloworld"))
   951  	v.Set("helloworld", "fubar")
   952  	assert.True(t, v.IsSet("helloworld"))
   953  }
   954  
   955  func TestDirsSearch(t *testing.T) {
   956  
   957  	root, config, cleanup := initDirs(t)
   958  	defer cleanup()
   959  
   960  	v := New()
   961  	v.SetConfigName(config)
   962  	v.SetDefault(`key`, `default`)
   963  
   964  	entries, err := ioutil.ReadDir(root)
   965  	for _, e := range entries {
   966  		if e.IsDir() {
   967  			v.AddConfigPath(e.Name())
   968  		}
   969  	}
   970  
   971  	err = v.ReadInConfig()
   972  	assert.Nil(t, err)
   973  
   974  	assert.Equal(t, `value is `+path.Base(v.configPaths[0]), v.GetString(`key`))
   975  }
   976  
   977  func TestWrongDirsSearchNotFound(t *testing.T) {
   978  
   979  	_, config, cleanup := initDirs(t)
   980  	defer cleanup()
   981  
   982  	v := New()
   983  	v.SetConfigName(config)
   984  	v.SetDefault(`key`, `default`)
   985  
   986  	v.AddConfigPath(`whattayoutalkingbout`)
   987  	v.AddConfigPath(`thispathaintthere`)
   988  
   989  	err := v.ReadInConfig()
   990  	assert.Equal(t, reflect.TypeOf(ConfigFileNotFoundError{"", ""}), reflect.TypeOf(err))
   991  
   992  	// Even though config did not load and the error might have
   993  	// been ignored by the client, the default still loads
   994  	assert.Equal(t, `default`, v.GetString(`key`))
   995  }
   996  
   997  func TestWrongDirsSearchNotFoundForMerge(t *testing.T) {
   998  
   999  	_, config, cleanup := initDirs(t)
  1000  	defer cleanup()
  1001  
  1002  	v := New()
  1003  	v.SetConfigName(config)
  1004  	v.SetDefault(`key`, `default`)
  1005  
  1006  	v.AddConfigPath(`whattayoutalkingbout`)
  1007  	v.AddConfigPath(`thispathaintthere`)
  1008  
  1009  	err := v.MergeInConfig()
  1010  	assert.Equal(t, reflect.TypeOf(ConfigFileNotFoundError{"", ""}), reflect.TypeOf(err))
  1011  
  1012  	// Even though config did not load and the error might have
  1013  	// been ignored by the client, the default still loads
  1014  	assert.Equal(t, `default`, v.GetString(`key`))
  1015  }
  1016  
  1017  func TestSub(t *testing.T) {
  1018  	v := New()
  1019  	v.SetConfigType("yaml")
  1020  	v.ReadConfig(bytes.NewBuffer(yamlExample))
  1021  
  1022  	subv := v.Sub("clothing")
  1023  	assert.Equal(t, v.Get("clothing.pants.size"), subv.Get("pants.size"))
  1024  
  1025  	subv = v.Sub("clothing.pants")
  1026  	assert.Equal(t, v.Get("clothing.pants.size"), subv.Get("size"))
  1027  
  1028  	subv = v.Sub("clothing.pants.size")
  1029  	assert.Equal(t, (*Viper)(nil), subv)
  1030  
  1031  	subv = v.Sub("missing.key")
  1032  	assert.Equal(t, (*Viper)(nil), subv)
  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          {"ini", `
  1230  aBcD=1
  1231  [eF]
  1232  gH=2
  1233  iJk=3
  1234  Lm.nO=4
  1235  Lm.P.Q=5
  1236  Lm.P.R=6
  1237  `},
  1238  		{"yaml", `
  1239  aBcD: 1
  1240  eF:
  1241    gH: 2
  1242    iJk: 3
  1243    Lm:
  1244      nO: 4
  1245      P:
  1246        Q: 5
  1247        R: 6
  1248  `},
  1249  		{"json", `{
  1250    "aBcD": 1,
  1251    "eF": {
  1252      "iJk": 3,
  1253      "Lm": {
  1254        "P": {
  1255          "Q": 5,
  1256          "R": 6
  1257        },
  1258        "nO": 4
  1259      },
  1260      "gH": 2
  1261    }
  1262  }`},
  1263  		{"toml", `aBcD = 1
  1264  [eF]
  1265  gH = 2
  1266  iJk = 3
  1267  [eF.Lm]
  1268  nO = 4
  1269  [eF.Lm.P]
  1270  Q = 5
  1271  R = 6
  1272  `},
  1273  	} {
  1274  		doTestCaseInsensitive(t, config.typ, config.content)
  1275  	}
  1276  }
  1277  
  1278  func TestCaseInsensitiveSet(t *testing.T) {
  1279  	Reset()
  1280  	m1 := map[string]interface{}{
  1281  		"Foo": 32,
  1282  		"Bar": map[interface{}]interface {
  1283  		}{
  1284  			"ABc": "A",
  1285  			"cDE": "B"},
  1286  	}
  1287  
  1288  	m2 := map[string]interface{}{
  1289  		"Foo": 52,
  1290  		"Bar": map[interface{}]interface {
  1291  		}{
  1292  			"bCd": "A",
  1293  			"eFG": "B"},
  1294  	}
  1295  
  1296  	Set("Given1", m1)
  1297  	Set("Number1", 42)
  1298  
  1299  	SetDefault("Given2", m2)
  1300  	SetDefault("Number2", 52)
  1301  
  1302  	// Verify SetDefault
  1303  	if v := Get("number2"); v != 52 {
  1304  		t.Fatalf("Expected 52 got %q", v)
  1305  	}
  1306  
  1307  	if v := Get("given2.foo"); v != 52 {
  1308  		t.Fatalf("Expected 52 got %q", v)
  1309  	}
  1310  
  1311  	if v := Get("given2.bar.bcd"); v != "A" {
  1312  		t.Fatalf("Expected A got %q", v)
  1313  	}
  1314  
  1315  	if _, ok := m2["Foo"]; !ok {
  1316  		t.Fatal("Input map changed")
  1317  	}
  1318  
  1319  	// Verify Set
  1320  	if v := Get("number1"); v != 42 {
  1321  		t.Fatalf("Expected 42 got %q", v)
  1322  	}
  1323  
  1324  	if v := Get("given1.foo"); v != 32 {
  1325  		t.Fatalf("Expected 32 got %q", v)
  1326  	}
  1327  
  1328  	if v := Get("given1.bar.abc"); v != "A" {
  1329  		t.Fatalf("Expected A got %q", v)
  1330  	}
  1331  
  1332  	if _, ok := m1["Foo"]; !ok {
  1333  		t.Fatal("Input map changed")
  1334  	}
  1335  }
  1336  
  1337  func TestParseNested(t *testing.T) {
  1338  	type duration struct {
  1339  		Delay time.Duration
  1340  	}
  1341  
  1342  	type item struct {
  1343  		Name   string
  1344  		Delay  time.Duration
  1345  		Nested duration
  1346  	}
  1347  
  1348  	config := `[[parent]]
  1349  	delay="100ms"
  1350  	[parent.nested]
  1351  	delay="200ms"
  1352  `
  1353  	initConfig("toml", config)
  1354  
  1355  	var items []item
  1356  	err := v.UnmarshalKey("parent", &items)
  1357  	if err != nil {
  1358  		t.Fatalf("unable to decode into struct, %v", err)
  1359  	}
  1360  
  1361  	assert.Equal(t, 1, len(items))
  1362  	assert.Equal(t, 100*time.Millisecond, items[0].Delay)
  1363  	assert.Equal(t, 200*time.Millisecond, items[0].Nested.Delay)
  1364  }
  1365  
  1366  func doTestCaseInsensitive(t *testing.T, typ, config string) {
  1367  	initConfig(typ, config)
  1368  	Set("RfD", true)
  1369  	assert.Equal(t, true, Get("rfd"))
  1370  	assert.Equal(t, true, Get("rFD"))
  1371  	assert.Equal(t, 1, cast.ToInt(Get("abcd")))
  1372  	assert.Equal(t, 1, cast.ToInt(Get("Abcd")))
  1373  	assert.Equal(t, 2, cast.ToInt(Get("ef.gh")))
  1374  	assert.Equal(t, 3, cast.ToInt(Get("ef.ijk")))
  1375  	assert.Equal(t, 4, cast.ToInt(Get("ef.lm.no")))
  1376  	assert.Equal(t, 5, cast.ToInt(Get("ef.lm.p.q")))
  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  }