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