github.com/tomarron/viper@v0.0.0-20160605220307-c1ccc378a054/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/ioutil"
    12  	"os"
    13  	"path"
    14  	"reflect"
    15  	"sort"
    16  	"strings"
    17  	"testing"
    18  	"time"
    19  
    20  	"github.com/spf13/pflag"
    21  	"github.com/stretchr/testify/assert"
    22  )
    23  
    24  var yamlExample = []byte(`Hacker: true
    25  name: steve
    26  hobbies:
    27  - skateboarding
    28  - snowboarding
    29  - go
    30  clothing:
    31    jacket: leather
    32    trousers: denim
    33    pants:
    34      size: large
    35  age: 35
    36  eyes : brown
    37  beard: true
    38  `)
    39  
    40  var yamlExampleWithExtras = []byte(`Existing: true
    41  Bogus: true
    42  `)
    43  
    44  type testUnmarshalExtra struct {
    45  	Existing bool
    46  }
    47  
    48  var tomlExample = []byte(`
    49  title = "TOML Example"
    50  
    51  [owner]
    52  organization = "MongoDB"
    53  Bio = "MongoDB Chief Developer Advocate & Hacker at Large"
    54  dob = 1979-05-27T07:32:00Z # First class dates? Why not?`)
    55  
    56  var jsonExample = []byte(`{
    57  "id": "0001",
    58  "type": "donut",
    59  "name": "Cake",
    60  "ppu": 0.55,
    61  "batters": {
    62          "batter": [
    63                  { "type": "Regular" },
    64                  { "type": "Chocolate" },
    65                  { "type": "Blueberry" },
    66                  { "type": "Devil's Food" }
    67              ]
    68      }
    69  }`)
    70  
    71  var hclExample = []byte(`
    72  id = "0001"
    73  type = "donut"
    74  name = "Cake"
    75  ppu = 0.55
    76  foos {
    77  	foo {
    78  		key = 1
    79  	}
    80  	foo {
    81  		key = 2
    82  	}
    83  	foo {
    84  		key = 3
    85  	}
    86  	foo {
    87  		key = 4
    88  	}
    89  }`)
    90  
    91  var propertiesExample = []byte(`
    92  p_id: 0001
    93  p_type: donut
    94  p_name: Cake
    95  p_ppu: 0.55
    96  p_batters.batter.type: Regular
    97  `)
    98  
    99  var remoteExample = []byte(`{
   100  "id":"0002",
   101  "type":"cronut",
   102  "newkey":"remote"
   103  }`)
   104  
   105  func initConfigs() {
   106  	Reset()
   107  	SetConfigType("yaml")
   108  	r := bytes.NewReader(yamlExample)
   109  	unmarshalReader(r, v.config)
   110  
   111  	SetConfigType("json")
   112  	r = bytes.NewReader(jsonExample)
   113  	unmarshalReader(r, v.config)
   114  
   115  	SetConfigType("hcl")
   116  	r = bytes.NewReader(hclExample)
   117  	unmarshalReader(r, v.config)
   118  
   119  	SetConfigType("properties")
   120  	r = bytes.NewReader(propertiesExample)
   121  	unmarshalReader(r, v.config)
   122  
   123  	SetConfigType("toml")
   124  	r = bytes.NewReader(tomlExample)
   125  	unmarshalReader(r, v.config)
   126  
   127  	SetConfigType("json")
   128  	remote := bytes.NewReader(remoteExample)
   129  	unmarshalReader(remote, v.kvstore)
   130  }
   131  
   132  func initYAML() {
   133  	Reset()
   134  	SetConfigType("yaml")
   135  	r := bytes.NewReader(yamlExample)
   136  
   137  	unmarshalReader(r, v.config)
   138  }
   139  
   140  func initJSON() {
   141  	Reset()
   142  	SetConfigType("json")
   143  	r := bytes.NewReader(jsonExample)
   144  
   145  	unmarshalReader(r, v.config)
   146  }
   147  
   148  func initProperties() {
   149  	Reset()
   150  	SetConfigType("properties")
   151  	r := bytes.NewReader(propertiesExample)
   152  
   153  	unmarshalReader(r, v.config)
   154  }
   155  
   156  func initTOML() {
   157  	Reset()
   158  	SetConfigType("toml")
   159  	r := bytes.NewReader(tomlExample)
   160  
   161  	unmarshalReader(r, v.config)
   162  }
   163  
   164  func initHcl() {
   165  	Reset()
   166  	SetConfigType("hcl")
   167  	r := bytes.NewReader(hclExample)
   168  
   169  	unmarshalReader(r, v.config)
   170  }
   171  
   172  // make directories for testing
   173  func initDirs(t *testing.T) (string, string, func()) {
   174  
   175  	var (
   176  		testDirs = []string{`a a`, `b`, `c\c`, `D_`}
   177  		config   = `improbable`
   178  	)
   179  
   180  	root, err := ioutil.TempDir("", "")
   181  
   182  	cleanup := true
   183  	defer func() {
   184  		if cleanup {
   185  			os.Chdir("..")
   186  			os.RemoveAll(root)
   187  		}
   188  	}()
   189  
   190  	assert.Nil(t, err)
   191  
   192  	err = os.Chdir(root)
   193  	assert.Nil(t, err)
   194  
   195  	for _, dir := range testDirs {
   196  		err = os.Mkdir(dir, 0750)
   197  		assert.Nil(t, err)
   198  
   199  		err = ioutil.WriteFile(
   200  			path.Join(dir, config+".toml"),
   201  			[]byte("key = \"value is "+dir+"\"\n"),
   202  			0640)
   203  		assert.Nil(t, err)
   204  	}
   205  
   206  	cleanup = false
   207  	return root, config, func() {
   208  		os.Chdir("..")
   209  		os.RemoveAll(root)
   210  	}
   211  }
   212  
   213  //stubs for PFlag Values
   214  type stringValue string
   215  
   216  func newStringValue(val string, p *string) *stringValue {
   217  	*p = val
   218  	return (*stringValue)(p)
   219  }
   220  
   221  func (s *stringValue) Set(val string) error {
   222  	*s = stringValue(val)
   223  	return nil
   224  }
   225  
   226  func (s *stringValue) Type() string {
   227  	return "string"
   228  }
   229  
   230  func (s *stringValue) String() string {
   231  	return fmt.Sprintf("%s", *s)
   232  }
   233  
   234  func TestBasics(t *testing.T) {
   235  	SetConfigFile("/tmp/config.yaml")
   236  	assert.Equal(t, "/tmp/config.yaml", v.getConfigFile())
   237  }
   238  
   239  func TestDefault(t *testing.T) {
   240  	SetDefault("age", 45)
   241  	assert.Equal(t, 45, Get("age"))
   242  
   243  	SetDefault("clothing.jacket", "slacks")
   244  	assert.Equal(t, "slacks", Get("clothing.jacket"))
   245  
   246  	SetConfigType("yaml")
   247  	err := ReadConfig(bytes.NewBuffer(yamlExample))
   248  
   249  	assert.NoError(t, err)
   250  	assert.Equal(t, "leather", Get("clothing.jacket"))
   251  }
   252  
   253  func TestUnmarshalling(t *testing.T) {
   254  	SetConfigType("yaml")
   255  	r := bytes.NewReader(yamlExample)
   256  
   257  	unmarshalReader(r, v.config)
   258  	assert.True(t, InConfig("name"))
   259  	assert.False(t, InConfig("state"))
   260  	assert.Equal(t, "steve", Get("name"))
   261  	assert.Equal(t, []interface{}{"skateboarding", "snowboarding", "go"}, Get("hobbies"))
   262  	assert.Equal(t, map[interface{}]interface{}{"jacket": "leather", "trousers": "denim", "pants": map[interface{}]interface{}{"size": "large"}}, Get("clothing"))
   263  	assert.Equal(t, 35, Get("age"))
   264  }
   265  
   266  func TestUnmarshalExact(t *testing.T) {
   267  	vip := New()
   268  	target := &testUnmarshalExtra{}
   269  	vip.SetConfigType("yaml")
   270  	r := bytes.NewReader(yamlExampleWithExtras)
   271  	vip.ReadConfig(r)
   272  	err := vip.UnmarshalExact(target)
   273  	if err == nil {
   274  		t.Fatal("UnmarshalExact should error when populating a struct from a conf that contains unused fields")
   275  	}
   276  }
   277  
   278  func TestOverrides(t *testing.T) {
   279  	Set("age", 40)
   280  	assert.Equal(t, 40, Get("age"))
   281  }
   282  
   283  func TestDefaultPost(t *testing.T) {
   284  	assert.NotEqual(t, "NYC", Get("state"))
   285  	SetDefault("state", "NYC")
   286  	assert.Equal(t, "NYC", Get("state"))
   287  }
   288  
   289  func TestAliases(t *testing.T) {
   290  	RegisterAlias("years", "age")
   291  	assert.Equal(t, 40, Get("years"))
   292  	Set("years", 45)
   293  	assert.Equal(t, 45, Get("age"))
   294  }
   295  
   296  func TestAliasInConfigFile(t *testing.T) {
   297  	// the config file specifies "beard".  If we make this an alias for
   298  	// "hasbeard", we still want the old config file to work with beard.
   299  	RegisterAlias("beard", "hasbeard")
   300  	assert.Equal(t, true, Get("hasbeard"))
   301  	Set("hasbeard", false)
   302  	assert.Equal(t, false, Get("beard"))
   303  }
   304  
   305  func TestYML(t *testing.T) {
   306  	initYAML()
   307  	assert.Equal(t, "steve", Get("name"))
   308  }
   309  
   310  func TestJSON(t *testing.T) {
   311  	initJSON()
   312  	assert.Equal(t, "0001", Get("id"))
   313  }
   314  
   315  func TestProperties(t *testing.T) {
   316  	initProperties()
   317  	assert.Equal(t, "0001", Get("p_id"))
   318  }
   319  
   320  func TestTOML(t *testing.T) {
   321  	initTOML()
   322  	assert.Equal(t, "TOML Example", Get("title"))
   323  }
   324  
   325  func TestHCL(t *testing.T) {
   326  	initHcl()
   327  	assert.Equal(t, "0001", Get("id"))
   328  	assert.Equal(t, 0.55, Get("ppu"))
   329  	assert.Equal(t, "donut", Get("type"))
   330  	assert.Equal(t, "Cake", Get("name"))
   331  	Set("id", "0002")
   332  	assert.Equal(t, "0002", Get("id"))
   333  	assert.NotEqual(t, "cronut", Get("type"))
   334  }
   335  
   336  func TestRemotePrecedence(t *testing.T) {
   337  	initJSON()
   338  
   339  	remote := bytes.NewReader(remoteExample)
   340  	assert.Equal(t, "0001", Get("id"))
   341  	unmarshalReader(remote, v.kvstore)
   342  	assert.Equal(t, "0001", Get("id"))
   343  	assert.NotEqual(t, "cronut", Get("type"))
   344  	assert.Equal(t, "remote", Get("newkey"))
   345  	Set("newkey", "newvalue")
   346  	assert.NotEqual(t, "remote", Get("newkey"))
   347  	assert.Equal(t, "newvalue", Get("newkey"))
   348  	Set("newkey", "remote")
   349  }
   350  
   351  func TestEnv(t *testing.T) {
   352  	initJSON()
   353  
   354  	BindEnv("id")
   355  	BindEnv("f", "FOOD")
   356  
   357  	os.Setenv("ID", "13")
   358  	os.Setenv("FOOD", "apple")
   359  	os.Setenv("NAME", "crunk")
   360  
   361  	assert.Equal(t, "13", Get("id"))
   362  	assert.Equal(t, "apple", Get("f"))
   363  	assert.Equal(t, "Cake", Get("name"))
   364  
   365  	AutomaticEnv()
   366  
   367  	assert.Equal(t, "crunk", Get("name"))
   368  
   369  }
   370  
   371  func TestEnvPrefix(t *testing.T) {
   372  	initJSON()
   373  
   374  	SetEnvPrefix("foo") // will be uppercased automatically
   375  	BindEnv("id")
   376  	BindEnv("f", "FOOD") // not using prefix
   377  
   378  	os.Setenv("FOO_ID", "13")
   379  	os.Setenv("FOOD", "apple")
   380  	os.Setenv("FOO_NAME", "crunk")
   381  
   382  	assert.Equal(t, "13", Get("id"))
   383  	assert.Equal(t, "apple", Get("f"))
   384  	assert.Equal(t, "Cake", Get("name"))
   385  
   386  	AutomaticEnv()
   387  
   388  	assert.Equal(t, "crunk", Get("name"))
   389  }
   390  
   391  func TestAutoEnv(t *testing.T) {
   392  	Reset()
   393  
   394  	AutomaticEnv()
   395  	os.Setenv("FOO_BAR", "13")
   396  	assert.Equal(t, "13", Get("foo_bar"))
   397  }
   398  
   399  func TestAutoEnvWithPrefix(t *testing.T) {
   400  	Reset()
   401  
   402  	AutomaticEnv()
   403  	SetEnvPrefix("Baz")
   404  	os.Setenv("BAZ_BAR", "13")
   405  	assert.Equal(t, "13", Get("bar"))
   406  }
   407  
   408  func TestSetEnvReplacer(t *testing.T) {
   409  	Reset()
   410  
   411  	AutomaticEnv()
   412  	os.Setenv("REFRESH_INTERVAL", "30s")
   413  
   414  	replacer := strings.NewReplacer("-", "_")
   415  	SetEnvKeyReplacer(replacer)
   416  
   417  	assert.Equal(t, "30s", Get("refresh-interval"))
   418  }
   419  
   420  func TestAllKeys(t *testing.T) {
   421  	initConfigs()
   422  
   423  	ks := sort.StringSlice{"title", "newkey", "owner", "name", "beard", "ppu", "batters", "hobbies", "clothing", "age", "hacker", "id", "type", "eyes", "p_id", "p_ppu", "p_batters.batter.type", "p_type", "p_name", "foos"}
   424  	dob, _ := time.Parse(time.RFC3339, "1979-05-27T07:32:00Z")
   425  	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[interface{}]interface{}{"trousers": "denim", "jacket": "leather", "pants": map[interface{}]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.batter.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}}}}}
   426  
   427  	var allkeys sort.StringSlice
   428  	allkeys = AllKeys()
   429  	allkeys.Sort()
   430  	ks.Sort()
   431  
   432  	assert.Equal(t, ks, allkeys)
   433  	assert.Equal(t, all, AllSettings())
   434  }
   435  
   436  func TestCaseInSensitive(t *testing.T) {
   437  	assert.Equal(t, true, Get("hacker"))
   438  	Set("Title", "Checking Case")
   439  	assert.Equal(t, "Checking Case", Get("tItle"))
   440  }
   441  
   442  func TestAliasesOfAliases(t *testing.T) {
   443  	RegisterAlias("Foo", "Bar")
   444  	RegisterAlias("Bar", "Title")
   445  	assert.Equal(t, "Checking Case", Get("FOO"))
   446  }
   447  
   448  func TestRecursiveAliases(t *testing.T) {
   449  	RegisterAlias("Baz", "Roo")
   450  	RegisterAlias("Roo", "baz")
   451  }
   452  
   453  func TestUnmarshal(t *testing.T) {
   454  	SetDefault("port", 1313)
   455  	Set("name", "Steve")
   456  
   457  	type config struct {
   458  		Port int
   459  		Name string
   460  	}
   461  
   462  	var C config
   463  
   464  	err := Unmarshal(&C)
   465  	if err != nil {
   466  		t.Fatalf("unable to decode into struct, %v", err)
   467  	}
   468  
   469  	assert.Equal(t, &C, &config{Name: "Steve", Port: 1313})
   470  
   471  	Set("port", 1234)
   472  	err = Unmarshal(&C)
   473  	if err != nil {
   474  		t.Fatalf("unable to decode into struct, %v", err)
   475  	}
   476  	assert.Equal(t, &C, &config{Name: "Steve", Port: 1234})
   477  }
   478  
   479  func TestBindPFlags(t *testing.T) {
   480  	flagSet := pflag.NewFlagSet("test", pflag.ContinueOnError)
   481  
   482  	var testValues = map[string]*string{
   483  		"host":     nil,
   484  		"port":     nil,
   485  		"endpoint": nil,
   486  	}
   487  
   488  	var mutatedTestValues = map[string]string{
   489  		"host":     "localhost",
   490  		"port":     "6060",
   491  		"endpoint": "/public",
   492  	}
   493  
   494  	for name, _ := range testValues {
   495  		testValues[name] = flagSet.String(name, "", "test")
   496  	}
   497  
   498  	err := BindPFlags(flagSet)
   499  	if err != nil {
   500  		t.Fatalf("error binding flag set, %v", err)
   501  	}
   502  
   503  	flagSet.VisitAll(func(flag *pflag.Flag) {
   504  		flag.Value.Set(mutatedTestValues[flag.Name])
   505  		flag.Changed = true
   506  	})
   507  
   508  	for name, expected := range mutatedTestValues {
   509  		assert.Equal(t, Get(name), expected)
   510  	}
   511  
   512  }
   513  
   514  func TestBindPFlag(t *testing.T) {
   515  	var testString = "testing"
   516  	var testValue = newStringValue(testString, &testString)
   517  
   518  	flag := &pflag.Flag{
   519  		Name:    "testflag",
   520  		Value:   testValue,
   521  		Changed: false,
   522  	}
   523  
   524  	BindPFlag("testvalue", flag)
   525  
   526  	assert.Equal(t, testString, Get("testvalue"))
   527  
   528  	flag.Value.Set("testing_mutate")
   529  	flag.Changed = true //hack for pflag usage
   530  
   531  	assert.Equal(t, "testing_mutate", Get("testvalue"))
   532  
   533  }
   534  
   535  func TestBoundCaseSensitivity(t *testing.T) {
   536  
   537  	assert.Equal(t, "brown", Get("eyes"))
   538  
   539  	BindEnv("eYEs", "TURTLE_EYES")
   540  	os.Setenv("TURTLE_EYES", "blue")
   541  
   542  	assert.Equal(t, "blue", Get("eyes"))
   543  
   544  	var testString = "green"
   545  	var testValue = newStringValue(testString, &testString)
   546  
   547  	flag := &pflag.Flag{
   548  		Name:    "eyeballs",
   549  		Value:   testValue,
   550  		Changed: true,
   551  	}
   552  
   553  	BindPFlag("eYEs", flag)
   554  	assert.Equal(t, "green", Get("eyes"))
   555  
   556  }
   557  
   558  func TestSizeInBytes(t *testing.T) {
   559  	input := map[string]uint{
   560  		"":               0,
   561  		"b":              0,
   562  		"12 bytes":       0,
   563  		"200000000000gb": 0,
   564  		"12 b":           12,
   565  		"43 MB":          43 * (1 << 20),
   566  		"10mb":           10 * (1 << 20),
   567  		"1gb":            1 << 30,
   568  	}
   569  
   570  	for str, expected := range input {
   571  		assert.Equal(t, expected, parseSizeInBytes(str), str)
   572  	}
   573  }
   574  
   575  func TestFindsNestedKeys(t *testing.T) {
   576  	initConfigs()
   577  	dob, _ := time.Parse(time.RFC3339, "1979-05-27T07:32:00Z")
   578  
   579  	Set("super", map[string]interface{}{
   580  		"deep": map[string]interface{}{
   581  			"nested": "value",
   582  		},
   583  	})
   584  
   585  	expected := map[string]interface{}{
   586  		"super": map[string]interface{}{
   587  			"deep": map[string]interface{}{
   588  				"nested": "value",
   589  			},
   590  		},
   591  		"super.deep": map[string]interface{}{
   592  			"nested": "value",
   593  		},
   594  		"super.deep.nested":  "value",
   595  		"owner.organization": "MongoDB",
   596  		"batters.batter": []interface{}{
   597  			map[string]interface{}{
   598  				"type": "Regular",
   599  			},
   600  			map[string]interface{}{
   601  				"type": "Chocolate",
   602  			},
   603  			map[string]interface{}{
   604  				"type": "Blueberry",
   605  			},
   606  			map[string]interface{}{
   607  				"type": "Devil's Food",
   608  			},
   609  		},
   610  		"hobbies": []interface{}{
   611  			"skateboarding", "snowboarding", "go",
   612  		},
   613  		"title":  "TOML Example",
   614  		"newkey": "remote",
   615  		"batters": map[string]interface{}{
   616  			"batter": []interface{}{
   617  				map[string]interface{}{
   618  					"type": "Regular",
   619  				},
   620  				map[string]interface{}{
   621  					"type": "Chocolate",
   622  				}, map[string]interface{}{
   623  					"type": "Blueberry",
   624  				}, map[string]interface{}{
   625  					"type": "Devil's Food",
   626  				},
   627  			},
   628  		},
   629  		"eyes": "brown",
   630  		"age":  35,
   631  		"owner": map[string]interface{}{
   632  			"organization": "MongoDB",
   633  			"Bio":          "MongoDB Chief Developer Advocate & Hacker at Large",
   634  			"dob":          dob,
   635  		},
   636  		"owner.Bio": "MongoDB Chief Developer Advocate & Hacker at Large",
   637  		"type":      "donut",
   638  		"id":        "0001",
   639  		"name":      "Cake",
   640  		"hacker":    true,
   641  		"ppu":       0.55,
   642  		"clothing": map[interface{}]interface{}{
   643  			"jacket":   "leather",
   644  			"trousers": "denim",
   645  			"pants": map[interface{}]interface{}{
   646  				"size": "large",
   647  			},
   648  		},
   649  		"clothing.jacket":     "leather",
   650  		"clothing.pants.size": "large",
   651  		"clothing.trousers":   "denim",
   652  		"owner.dob":           dob,
   653  		"beard":               true,
   654  		"foos": []map[string]interface{}{
   655  			map[string]interface{}{
   656  				"foo": []map[string]interface{}{
   657  					map[string]interface{}{
   658  						"key": 1,
   659  					},
   660  					map[string]interface{}{
   661  						"key": 2,
   662  					},
   663  					map[string]interface{}{
   664  						"key": 3,
   665  					},
   666  					map[string]interface{}{
   667  						"key": 4,
   668  					},
   669  				},
   670  			},
   671  		},
   672  	}
   673  
   674  	for key, expectedValue := range expected {
   675  
   676  		assert.Equal(t, expectedValue, v.Get(key))
   677  	}
   678  
   679  }
   680  
   681  func TestReadBufConfig(t *testing.T) {
   682  	v := New()
   683  	v.SetConfigType("yaml")
   684  	v.ReadConfig(bytes.NewBuffer(yamlExample))
   685  	t.Log(v.AllKeys())
   686  
   687  	assert.True(t, v.InConfig("name"))
   688  	assert.False(t, v.InConfig("state"))
   689  	assert.Equal(t, "steve", v.Get("name"))
   690  	assert.Equal(t, []interface{}{"skateboarding", "snowboarding", "go"}, v.Get("hobbies"))
   691  	assert.Equal(t, map[interface{}]interface{}{"jacket": "leather", "trousers": "denim", "pants": map[interface{}]interface{}{"size": "large"}}, v.Get("clothing"))
   692  	assert.Equal(t, 35, v.Get("age"))
   693  }
   694  
   695  func TestIsSet(t *testing.T) {
   696  	v := New()
   697  	v.SetConfigType("yaml")
   698  	v.ReadConfig(bytes.NewBuffer(yamlExample))
   699  	assert.True(t, v.IsSet("clothing.jacket"))
   700  	assert.False(t, v.IsSet("clothing.jackets"))
   701  	assert.False(t, v.IsSet("helloworld"))
   702  	v.Set("helloworld", "fubar")
   703  	assert.True(t, v.IsSet("helloworld"))
   704  }
   705  
   706  func TestDirsSearch(t *testing.T) {
   707  
   708  	root, config, cleanup := initDirs(t)
   709  	defer cleanup()
   710  
   711  	v := New()
   712  	v.SetConfigName(config)
   713  	v.SetDefault(`key`, `default`)
   714  
   715  	entries, err := ioutil.ReadDir(root)
   716  	for _, e := range entries {
   717  		if e.IsDir() {
   718  			v.AddConfigPath(e.Name())
   719  		}
   720  	}
   721  
   722  	err = v.ReadInConfig()
   723  	assert.Nil(t, err)
   724  
   725  	assert.Equal(t, `value is `+path.Base(v.configPaths[0]), v.GetString(`key`))
   726  }
   727  
   728  func TestWrongDirsSearchNotFound(t *testing.T) {
   729  
   730  	_, config, cleanup := initDirs(t)
   731  	defer cleanup()
   732  
   733  	v := New()
   734  	v.SetConfigName(config)
   735  	v.SetDefault(`key`, `default`)
   736  
   737  	v.AddConfigPath(`whattayoutalkingbout`)
   738  	v.AddConfigPath(`thispathaintthere`)
   739  
   740  	err := v.ReadInConfig()
   741  	assert.Equal(t, reflect.TypeOf(UnsupportedConfigError("")), reflect.TypeOf(err))
   742  
   743  	// Even though config did not load and the error might have
   744  	// been ignored by the client, the default still loads
   745  	assert.Equal(t, `default`, v.GetString(`key`))
   746  }
   747  
   748  func TestSub(t *testing.T) {
   749  	v := New()
   750  	v.SetConfigType("yaml")
   751  	v.ReadConfig(bytes.NewBuffer(yamlExample))
   752  
   753  	subv := v.Sub("clothing")
   754  	assert.Equal(t, v.Get("clothing.pants.size"), subv.Get("pants.size"))
   755  
   756  	subv = v.Sub("clothing.pants")
   757  	assert.Equal(t, v.Get("clothing.pants.size"), subv.Get("size"))
   758  
   759  	subv = v.Sub("clothing.pants.size")
   760  	assert.Equal(t, subv, (*Viper)(nil))
   761  }
   762  
   763  var yamlMergeExampleTgt = []byte(`
   764  hello:
   765      pop: 37890
   766      world:
   767      - us
   768      - uk
   769      - fr
   770      - de
   771  `)
   772  
   773  var yamlMergeExampleSrc = []byte(`
   774  hello:
   775      pop: 45000
   776      universe:
   777      - mw
   778      - ad
   779  fu: bar
   780  `)
   781  
   782  func TestMergeConfig(t *testing.T) {
   783  	v := New()
   784  	v.SetConfigType("yml")
   785  	if err := v.ReadConfig(bytes.NewBuffer(yamlMergeExampleTgt)); err != nil {
   786  		t.Fatal(err)
   787  	}
   788  
   789  	if pop := v.GetInt("hello.pop"); pop != 37890 {
   790  		t.Fatalf("pop != 37890, = %d", pop)
   791  	}
   792  
   793  	if world := v.GetStringSlice("hello.world"); len(world) != 4 {
   794  		t.Fatalf("len(world) != 4, = %d", len(world))
   795  	}
   796  
   797  	if fu := v.GetString("fu"); fu != "" {
   798  		t.Fatalf("fu != \"\", = %s", fu)
   799  	}
   800  
   801  	if err := v.MergeConfig(bytes.NewBuffer(yamlMergeExampleSrc)); err != nil {
   802  		t.Fatal(err)
   803  	}
   804  
   805  	if pop := v.GetInt("hello.pop"); pop != 45000 {
   806  		t.Fatalf("pop != 45000, = %d", pop)
   807  	}
   808  
   809  	if world := v.GetStringSlice("hello.world"); len(world) != 4 {
   810  		t.Fatalf("len(world) != 4, = %d", len(world))
   811  	}
   812  
   813  	if universe := v.GetStringSlice("hello.universe"); len(universe) != 2 {
   814  		t.Fatalf("len(universe) != 2, = %d", len(universe))
   815  	}
   816  
   817  	if fu := v.GetString("fu"); fu != "bar" {
   818  		t.Fatalf("fu != \"bar\", = %s", fu)
   819  	}
   820  }
   821  
   822  func TestMergeConfigNoMerge(t *testing.T) {
   823  	v := New()
   824  	v.SetConfigType("yml")
   825  	if err := v.ReadConfig(bytes.NewBuffer(yamlMergeExampleTgt)); err != nil {
   826  		t.Fatal(err)
   827  	}
   828  
   829  	if pop := v.GetInt("hello.pop"); pop != 37890 {
   830  		t.Fatalf("pop != 37890, = %d", pop)
   831  	}
   832  
   833  	if world := v.GetStringSlice("hello.world"); len(world) != 4 {
   834  		t.Fatalf("len(world) != 4, = %d", len(world))
   835  	}
   836  
   837  	if fu := v.GetString("fu"); fu != "" {
   838  		t.Fatalf("fu != \"\", = %s", fu)
   839  	}
   840  
   841  	if err := v.ReadConfig(bytes.NewBuffer(yamlMergeExampleSrc)); err != nil {
   842  		t.Fatal(err)
   843  	}
   844  
   845  	if pop := v.GetInt("hello.pop"); pop != 45000 {
   846  		t.Fatalf("pop != 45000, = %d", pop)
   847  	}
   848  
   849  	if world := v.GetStringSlice("hello.world"); len(world) != 0 {
   850  		t.Fatalf("len(world) != 0, = %d", len(world))
   851  	}
   852  
   853  	if universe := v.GetStringSlice("hello.universe"); len(universe) != 2 {
   854  		t.Fatalf("len(universe) != 2, = %d", len(universe))
   855  	}
   856  
   857  	if fu := v.GetString("fu"); fu != "bar" {
   858  		t.Fatalf("fu != \"bar\", = %s", fu)
   859  	}
   860  }
   861  
   862  func TestUnmarshalingWithAliases(t *testing.T) {
   863  	SetDefault("Id", 1)
   864  	Set("name", "Steve")
   865  	Set("lastname", "Owen")
   866  
   867  	RegisterAlias("UserID", "Id")
   868  	RegisterAlias("Firstname", "name")
   869  	RegisterAlias("Surname", "lastname")
   870  
   871  	type config struct {
   872  		Id        int
   873  		FirstName string
   874  		Surname   string
   875  	}
   876  
   877  	var C config
   878  
   879  	err := Unmarshal(&C)
   880  	if err != nil {
   881  		t.Fatalf("unable to decode into struct, %v", err)
   882  	}
   883  
   884  	assert.Equal(t, &C, &config{Id: 1, FirstName: "Steve", Surname: "Owen"})
   885  }