github.com/DataDog/viper@v1.13.3/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  	"encoding/json"
    11  	"errors"
    12  	"fmt"
    13  	"io"
    14  	"io/ioutil"
    15  	"os"
    16  	"os/exec"
    17  	"path"
    18  	"reflect"
    19  	"runtime"
    20  	"sort"
    21  	"strings"
    22  	"sync"
    23  	"testing"
    24  	"time"
    25  
    26  	"github.com/fsnotify/fsnotify"
    27  	"github.com/mitchellh/mapstructure"
    28  	"github.com/spf13/afero"
    29  	"github.com/spf13/cast"
    30  
    31  	"github.com/spf13/pflag"
    32  	"github.com/stretchr/testify/assert"
    33  	"github.com/stretchr/testify/require"
    34  )
    35  
    36  var yamlExample = []byte(`Hacker: true
    37  name: steve
    38  hobbies:
    39  - skateboarding
    40  - snowboarding
    41  - go
    42  clothing:
    43    jacket: leather
    44    trousers: denim
    45    pants:
    46      size: large
    47  age: 35
    48  eyes : brown
    49  beard: true
    50  `)
    51  
    52  var yamlExampleWithExtras = []byte(`Existing: true
    53  Bogus: true
    54  `)
    55  
    56  type testUnmarshalExtra struct {
    57  	Existing bool
    58  }
    59  
    60  var tomlExample = []byte(`
    61  title = "TOML Example"
    62  
    63  [owner]
    64  organization = "MongoDB"
    65  Bio = "MongoDB Chief Developer Advocate & Hacker at Large"
    66  dob = 1979-05-27T07:32:00Z # First class dates? Why not?`)
    67  
    68  var jsonExample = []byte(`{
    69  "id": "0001",
    70  "type": "donut",
    71  "name": "Cake",
    72  "ppu": 0.55,
    73  "batters": {
    74          "batter": [
    75                  { "type": "Regular" },
    76                  { "type": "Chocolate" },
    77                  { "type": "Blueberry" },
    78                  { "type": "Devil's Food" }
    79              ]
    80      }
    81  }`)
    82  
    83  var hclExample = []byte(`
    84  id = "0001"
    85  type = "donut"
    86  name = "Cake"
    87  ppu = 0.55
    88  foos {
    89  	foo {
    90  		key = 1
    91  	}
    92  	foo {
    93  		key = 2
    94  	}
    95  	foo {
    96  		key = 3
    97  	}
    98  	foo {
    99  		key = 4
   100  	}
   101  }`)
   102  
   103  var propertiesExample = []byte(`
   104  p_id: 0001
   105  p_type: donut
   106  p_name: Cake
   107  p_ppu: 0.55
   108  p_batters.batter.type: Regular
   109  `)
   110  
   111  var remoteExample = []byte(`{
   112  "id":"0002",
   113  "type":"cronut",
   114  "newkey":"remote"
   115  }`)
   116  
   117  func initConfigs(v *Viper) {
   118  	var r io.Reader
   119  	v.SetConfigType("yaml")
   120  	r = bytes.NewReader(yamlExample)
   121  	v.unmarshalReader(r, v.config)
   122  
   123  	v.SetConfigType("json")
   124  	r = bytes.NewReader(jsonExample)
   125  	v.unmarshalReader(r, v.config)
   126  
   127  	v.SetConfigType("hcl")
   128  	r = bytes.NewReader(hclExample)
   129  	v.unmarshalReader(r, v.config)
   130  
   131  	v.SetConfigType("properties")
   132  	r = bytes.NewReader(propertiesExample)
   133  	v.unmarshalReader(r, v.config)
   134  
   135  	v.SetConfigType("toml")
   136  	r = bytes.NewReader(tomlExample)
   137  	v.unmarshalReader(r, v.config)
   138  
   139  	v.SetConfigType("json")
   140  	remote := bytes.NewReader(remoteExample)
   141  	v.unmarshalReader(remote, v.kvstore)
   142  }
   143  
   144  func initConfig(v *Viper, typ, config string) {
   145  	v.SetConfigType(typ)
   146  	r := strings.NewReader(config)
   147  
   148  	if err := v.unmarshalReader(r, v.config); err != nil {
   149  		panic(err)
   150  	}
   151  }
   152  
   153  func initYAML(v *Viper) {
   154  	initConfig(v, "yaml", string(yamlExample))
   155  }
   156  
   157  func initJSON(v *Viper) {
   158  	v.SetConfigType("json")
   159  	r := bytes.NewReader(jsonExample)
   160  
   161  	v.unmarshalReader(r, v.config)
   162  }
   163  
   164  func initProperties(v *Viper) {
   165  	v.SetConfigType("properties")
   166  	r := bytes.NewReader(propertiesExample)
   167  
   168  	v.unmarshalReader(r, v.config)
   169  }
   170  
   171  func initTOML(v *Viper) {
   172  	v.SetConfigType("toml")
   173  	r := bytes.NewReader(tomlExample)
   174  
   175  	v.unmarshalReader(r, v.config)
   176  }
   177  
   178  func initHcl(v *Viper) {
   179  	v.SetConfigType("hcl")
   180  	r := bytes.NewReader(hclExample)
   181  
   182  	v.unmarshalReader(r, v.config)
   183  }
   184  
   185  // make directories for testing
   186  func initDirs(t *testing.T) (string, string, func()) {
   187  
   188  	var (
   189  		testDirs = []string{`a a`, `b`, `c\c`, `D_`}
   190  		config   = `improbable`
   191  	)
   192  
   193  	root, err := ioutil.TempDir("", "")
   194  
   195  	cleanup := true
   196  	defer func() {
   197  		if cleanup {
   198  			os.Chdir("..")
   199  			os.RemoveAll(root)
   200  		}
   201  	}()
   202  
   203  	assert.Nil(t, err)
   204  
   205  	err = os.Chdir(root)
   206  	assert.Nil(t, err)
   207  
   208  	for _, dir := range testDirs {
   209  		err = os.Mkdir(dir, 0750)
   210  		assert.Nil(t, err)
   211  
   212  		err = ioutil.WriteFile(
   213  			path.Join(dir, config+".toml"),
   214  			[]byte("key = \"value is "+dir+"\"\n"),
   215  			0640)
   216  		assert.Nil(t, err)
   217  	}
   218  
   219  	cleanup = false
   220  	return root, config, func() {
   221  		os.Chdir("..")
   222  		os.RemoveAll(root)
   223  	}
   224  }
   225  
   226  //stubs for PFlag Values
   227  type stringValue string
   228  
   229  func newStringValue(val string, p *string) *stringValue {
   230  	*p = val
   231  	return (*stringValue)(p)
   232  }
   233  
   234  func (s *stringValue) Set(val string) error {
   235  	*s = stringValue(val)
   236  	return nil
   237  }
   238  
   239  func (s *stringValue) Type() string {
   240  	return "string"
   241  }
   242  
   243  func (s *stringValue) String() string {
   244  	return fmt.Sprintf("%s", *s)
   245  }
   246  
   247  func TestBasics(t *testing.T) {
   248  	v := New()
   249  	v.SetConfigFile("/tmp/config.yaml")
   250  	filename, err := v.getConfigFile()
   251  	assert.Equal(t, "/tmp/config.yaml", filename)
   252  	assert.NoError(t, err)
   253  }
   254  
   255  func TestDefault(t *testing.T) {
   256  	v := New()
   257  
   258  	v.SetDefault("age", 45)
   259  	assert.Equal(t, 45, v.Get("age"))
   260  
   261  	v.SetDefault("clothing.jacket", "slacks")
   262  	assert.Equal(t, "slacks", v.Get("clothing.jacket"))
   263  
   264  	v.SetConfigType("yaml")
   265  	err := v.ReadConfig(bytes.NewBuffer(yamlExample))
   266  
   267  	assert.NoError(t, err)
   268  	assert.Equal(t, "leather", v.Get("clothing.jacket"))
   269  }
   270  
   271  func TestUnmarshaling(t *testing.T) {
   272  	v := New()
   273  
   274  	v.SetConfigType("yaml")
   275  	r := bytes.NewReader(yamlExample)
   276  
   277  	v.unmarshalReader(r, v.config)
   278  	assert.True(t, v.InConfig("name"))
   279  	assert.False(t, v.InConfig("state"))
   280  	assert.Equal(t, "steve", v.Get("name"))
   281  	assert.Equal(t, []interface{}{"skateboarding", "snowboarding", "go"}, v.Get("hobbies"))
   282  	assert.Equal(t, map[string]interface{}{"jacket": "leather", "trousers": "denim", "pants": map[string]interface{}{"size": "large"}}, v.Get("clothing"))
   283  	assert.Equal(t, 35, v.Get("age"))
   284  }
   285  
   286  func TestUnmarshalExact(t *testing.T) {
   287  	vip := New()
   288  	target := &testUnmarshalExtra{}
   289  	vip.SetConfigType("yaml")
   290  	r := bytes.NewReader(yamlExampleWithExtras)
   291  	vip.ReadConfig(r)
   292  	err := vip.UnmarshalExact(target)
   293  	if err == nil {
   294  		t.Fatal("UnmarshalExact should error when populating a struct from a conf that contains unused fields")
   295  	}
   296  }
   297  
   298  func TestOverrides(t *testing.T) {
   299  	v := New()
   300  	v.Set("age", 40)
   301  	assert.Equal(t, 40, v.Get("age"))
   302  }
   303  
   304  func TestDefaultPost(t *testing.T) {
   305  	v := New()
   306  	assert.NotEqual(t, "NYC", v.Get("state"))
   307  	v.SetDefault("state", "NYC")
   308  	assert.Equal(t, "NYC", v.Get("state"))
   309  }
   310  
   311  func TestAliases(t *testing.T) {
   312  	v := New()
   313  	initYAML(v)
   314  	v.RegisterAlias("years", "age")
   315  	assert.Equal(t, 35, v.Get("years"))
   316  	v.Set("years", 45)
   317  	assert.Equal(t, 45, v.Get("age"))
   318  }
   319  
   320  func TestAliasInConfigFile(t *testing.T) {
   321  	v := New()
   322  	initYAML(v)
   323  	// the config file specifies "beard".  If we make this an alias for
   324  	// "hasbeard", we still want the old config file to work with beard.
   325  	v.RegisterAlias("beard", "hasbeard")
   326  	assert.Equal(t, true, v.Get("hasbeard"))
   327  	v.Set("hasbeard", false)
   328  	assert.Equal(t, false, v.Get("beard"))
   329  }
   330  
   331  func TestYML(t *testing.T) {
   332  	v := New()
   333  	initYAML(v)
   334  	assert.Equal(t, "steve", v.Get("name"))
   335  }
   336  
   337  func TestJSON(t *testing.T) {
   338  	v := New()
   339  	initJSON(v)
   340  	assert.Equal(t, "0001", v.Get("id"))
   341  }
   342  
   343  func TestProperties(t *testing.T) {
   344  	v := New()
   345  	initProperties(v)
   346  	assert.Equal(t, "0001", v.Get("p_id"))
   347  }
   348  
   349  func TestTOML(t *testing.T) {
   350  	v := New()
   351  	initTOML(v)
   352  	assert.Equal(t, "TOML Example", v.Get("title"))
   353  }
   354  
   355  func TestHCL(t *testing.T) {
   356  	v := New()
   357  	initHcl(v)
   358  	assert.Equal(t, "0001", v.Get("id"))
   359  	assert.Equal(t, 0.55, v.Get("ppu"))
   360  	assert.Equal(t, "donut", v.Get("type"))
   361  	assert.Equal(t, "Cake", v.Get("name"))
   362  	v.Set("id", "0002")
   363  	assert.Equal(t, "0002", v.Get("id"))
   364  	assert.NotEqual(t, "cronut", v.Get("type"))
   365  }
   366  
   367  func TestRemotePrecedence(t *testing.T) {
   368  	v := New()
   369  	initJSON(v)
   370  	remote := bytes.NewReader(remoteExample)
   371  	assert.Equal(t, "0001", v.Get("id"))
   372  	v.unmarshalReader(remote, v.kvstore)
   373  	assert.Equal(t, "0001", v.Get("id"))
   374  	assert.NotEqual(t, "cronut", v.Get("type"))
   375  	assert.Equal(t, "remote", v.Get("newkey"))
   376  	v.Set("newkey", "newvalue")
   377  	assert.NotEqual(t, "remote", v.Get("newkey"))
   378  	assert.Equal(t, "newvalue", v.Get("newkey"))
   379  	v.Set("newkey", "remote")
   380  }
   381  
   382  func TestEnv(t *testing.T) {
   383  	v := New()
   384  	initJSON(v)
   385  
   386  	v.BindEnv("id")
   387  	v.BindEnv("f", "FOOD", "DEPRECATED_FOOD")
   388  
   389  	os.Setenv("ID", "13")
   390  	os.Setenv("FOOD", "apple")
   391  	os.Setenv("DEPRECATED_FOOD", "banana")
   392  	os.Setenv("NAME", "crunk")
   393  
   394  	assert.Equal(t, "13", v.Get("id"))
   395  	assert.Equal(t, "apple", v.Get("f"))
   396  	assert.Equal(t, "Cake", v.Get("name"))
   397  
   398  	v.AutomaticEnv()
   399  
   400  	assert.Equal(t, "crunk", v.Get("name"))
   401  }
   402  
   403  func TestEnvTransformer(t *testing.T) {
   404  	v := New()
   405  	initJSON(v)
   406  
   407  	v.BindEnv("id", "MY_ID")
   408  	v.SetEnvKeyTransformer("id", func(in string) interface{} { return "transformed" })
   409  	os.Setenv("MY_ID", "14")
   410  
   411  	assert.Equal(t, "transformed", v.Get("id"))
   412  }
   413  
   414  func TestMultipleEnv(t *testing.T) {
   415  	v := New()
   416  	initJSON(v)
   417  
   418  	v.BindEnv("id")
   419  	v.BindEnv("f", "FOOD", "DEPRECATED_FOOD")
   420  
   421  	os.Setenv("ID", "13")
   422  	os.Unsetenv("FOOD")
   423  	os.Setenv("DEPRECATED_FOOD", "banana")
   424  	os.Setenv("NAME", "crunk")
   425  
   426  	assert.Equal(t, "13", v.Get("id"))
   427  	assert.Equal(t, "banana", v.Get("f"))
   428  	assert.Equal(t, "Cake", v.Get("name"))
   429  
   430  	v.AutomaticEnv()
   431  
   432  	assert.Equal(t, "crunk", v.Get("name"))
   433  }
   434  
   435  func TestEmptyEnv(t *testing.T) {
   436  	v := New()
   437  	initJSON(v)
   438  
   439  	v.BindEnv("type") // Empty environment variable
   440  	v.BindEnv("name") // Bound, but not set environment variable
   441  
   442  	os.Clearenv()
   443  
   444  	os.Setenv("TYPE", "")
   445  
   446  	assert.Equal(t, "donut", v.Get("type"))
   447  	assert.Equal(t, "Cake", v.Get("name"))
   448  }
   449  
   450  func TestEmptyEnv_Allowed(t *testing.T) {
   451  	v := New()
   452  	initJSON(v)
   453  
   454  	v.AllowEmptyEnv(true)
   455  
   456  	v.BindEnv("type") // Empty environment variable
   457  	v.BindEnv("name") // Bound, but not set environment variable
   458  
   459  	os.Clearenv()
   460  
   461  	os.Setenv("TYPE", "")
   462  
   463  	assert.Equal(t, "", v.Get("type"))
   464  	assert.Equal(t, "Cake", v.Get("name"))
   465  }
   466  
   467  func TestEnvPrefix(t *testing.T) {
   468  	v := New()
   469  	initJSON(v)
   470  
   471  	v.SetEnvPrefix("foo") // will be uppercased automatically
   472  	v.BindEnv("id")
   473  	v.BindEnv("f", "FOOD") // not using prefix
   474  
   475  	os.Setenv("FOO_ID", "13")
   476  	os.Setenv("FOOD", "apple")
   477  	os.Setenv("FOO_NAME", "crunk")
   478  
   479  	assert.Equal(t, "13", v.Get("id"))
   480  	assert.Equal(t, "apple", v.Get("f"))
   481  	assert.Equal(t, "Cake", v.Get("name"))
   482  
   483  	v.AutomaticEnv()
   484  
   485  	assert.Equal(t, "crunk", v.Get("name"))
   486  }
   487  
   488  func TestAutoEnv(t *testing.T) {
   489  	v := New()
   490  	v.AutomaticEnv()
   491  	os.Setenv("FOO_BAR", "13")
   492  	assert.Equal(t, "13", v.Get("foo_bar"))
   493  }
   494  
   495  func TestAutoEnvWithPrefix(t *testing.T) {
   496  	v := New()
   497  	v.AutomaticEnv()
   498  	v.SetEnvPrefix("Baz")
   499  	os.Setenv("BAZ_BAR", "13")
   500  	assert.Equal(t, "13", v.Get("bar"))
   501  }
   502  
   503  func TestSetEnvKeyReplacer(t *testing.T) {
   504  	v := New()
   505  	v.AutomaticEnv()
   506  	os.Setenv("REFRESH_INTERVAL", "30s")
   507  
   508  	replacer := strings.NewReplacer("-", "_")
   509  	v.SetEnvKeyReplacer(replacer)
   510  
   511  	assert.Equal(t, "30s", v.Get("refresh-interval"))
   512  }
   513  
   514  func TestAllKeys(t *testing.T) {
   515  	v := New()
   516  	initConfigs(v)
   517  
   518  	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"}
   519  	dob, _ := time.Parse(time.RFC3339, "1979-05-27T07:32:00Z")
   520  	all := map[string]interface{}{"owner": map[string]interface{}{"organization": "MongoDB", "bio": "MongoDB Chief Developer Advocate & Hacker at Large", "dob": dob}, "title": "TOML Example", "ppu": 0.55, "eyes": "brown", "clothing": map[string]interface{}{"trousers": "denim", "jacket": "leather", "pants": map[string]interface{}{"size": "large"}}, "id": "0001", "batters": map[string]interface{}{"batter": []interface{}{map[string]interface{}{"type": "Regular"}, map[string]interface{}{"type": "Chocolate"}, map[string]interface{}{"type": "Blueberry"}, map[string]interface{}{"type": "Devil's Food"}}}, "hacker": true, "beard": true, "hobbies": []interface{}{"skateboarding", "snowboarding", "go"}, "age": 35, "type": "donut", "newkey": "remote", "name": "Cake", "p_id": "0001", "p_ppu": "0.55", "p_name": "Cake", "p_batters": map[string]interface{}{"batter": map[string]interface{}{"type": "Regular"}}, "p_type": "donut", "foos": []map[string]interface{}{map[string]interface{}{"foo": []map[string]interface{}{map[string]interface{}{"key": 1}, map[string]interface{}{"key": 2}, map[string]interface{}{"key": 3}, map[string]interface{}{"key": 4}}}}}
   521  
   522  	var allkeys sort.StringSlice
   523  	allkeys = v.AllKeys()
   524  	allkeys.Sort()
   525  	ks.Sort()
   526  
   527  	assert.Equal(t, ks, allkeys)
   528  	assert.Equal(t, all, v.AllSettings())
   529  }
   530  
   531  func TestAllKeysWithEnv(t *testing.T) {
   532  	v := New()
   533  
   534  	// bind and define environment variables (including a nested one)
   535  	v.BindEnv("id")
   536  	v.BindEnv("foo.bar")
   537  	v.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
   538  	os.Setenv("ID", "13")
   539  	os.Setenv("FOO_BAR", "baz")
   540  
   541  	expectedKeys := sort.StringSlice{"id", "foo.bar"}
   542  	expectedKeys.Sort()
   543  	keys := sort.StringSlice(v.AllKeys())
   544  	keys.Sort()
   545  	assert.Equal(t, expectedKeys, keys)
   546  }
   547  
   548  func TestAllSettingsWithDelimiterInKeys(t *testing.T) {
   549  	exampleYaml := `Hacker: true
   550  name: steve
   551  hobbies:
   552  - skate.boarding
   553  - snowboarding
   554  clothing.summer:
   555    jacket: leather
   556    pants:
   557      size: large
   558  clothing.winter:
   559    jacket: wool
   560    pants:
   561      size: medium
   562  `
   563  	v := New()
   564  	v.SetConfigType("yaml")
   565  	v.SetDefault("test", "example")
   566  	r := strings.NewReader(exampleYaml)
   567  
   568  	if err := v.unmarshalReader(r, v.config); err != nil {
   569  		panic(err)
   570  	}
   571  
   572  	expectedAll := map[string]interface{}{"hacker": true, "name": "steve", "test": "example", "hobbies": []interface{}{"skate.boarding", "snowboarding"}, "clothing.summer": map[string]interface{}{"jacket": "leather", "pants": map[string]interface{}{"size": "large"}}, "clothing.winter": map[string]interface{}{"jacket": "wool", "pants": map[string]interface{}{"size": "medium"}}}
   573  	expectedKeys := sort.StringSlice{"hacker", "name", "test", "hobbies", "clothing.summer.jacket", "clothing.summer.pants.size", "clothing.winter.jacket", "clothing.winter.pants.size"}
   574  	expectedKeys.Sort()
   575  	keys := sort.StringSlice(v.AllKeys())
   576  	keys.Sort()
   577  
   578  	assert.Equal(t, expectedKeys, keys)
   579  	assert.Equal(t, expectedAll, v.AllSettings())
   580  }
   581  
   582  func TestAllSettingsWithDelimiterInKeysWithoutDefault(t *testing.T) {
   583  	exampleYaml := `Hacker: true
   584  name: steve
   585  hobbies:
   586  - skate.boarding
   587  - snowboarding
   588  clothing.summer:
   589    jacket: leather
   590    pants:
   591      size: large
   592  clothing.winter:
   593    jacket: wool
   594    pants:
   595      size: medium
   596  `
   597  	v := New()
   598  	v.SetConfigType("yaml")
   599  	v.SetDefault("test", "example")
   600  	r := strings.NewReader(exampleYaml)
   601  
   602  	if err := v.unmarshalReader(r, v.config); err != nil {
   603  		panic(err)
   604  	}
   605  
   606  	expectedAll := map[string]interface{}{"hacker": true, "name": "steve", "hobbies": []interface{}{"skate.boarding", "snowboarding"}, "clothing.summer": map[string]interface{}{"jacket": "leather", "pants": map[string]interface{}{"size": "large"}}, "clothing.winter": map[string]interface{}{"jacket": "wool", "pants": map[string]interface{}{"size": "medium"}}}
   607  	expectedKeys := sort.StringSlice{"hacker", "name", "test", "hobbies", "clothing.summer.jacket", "clothing.summer.pants.size", "clothing.winter.jacket", "clothing.winter.pants.size"}
   608  	expectedKeys.Sort()
   609  	keys := sort.StringSlice(v.AllKeys())
   610  	keys.Sort()
   611  
   612  	assert.Equal(t, expectedKeys, keys)
   613  	assert.Equal(t, expectedAll, v.AllSettingsWithoutDefault())
   614  }
   615  
   616  func TestAliasesOfAliases(t *testing.T) {
   617  	v := New()
   618  	v.Set("Title", "Checking Case")
   619  	v.RegisterAlias("Foo", "Bar")
   620  	v.RegisterAlias("Bar", "Title")
   621  	assert.Equal(t, "Checking Case", v.Get("FOO"))
   622  }
   623  
   624  func TestRecursiveAliases(t *testing.T) {
   625  	v := New()
   626  	v.RegisterAlias("Baz", "Roo")
   627  	v.RegisterAlias("Roo", "baz")
   628  }
   629  
   630  func TestUnmarshal(t *testing.T) {
   631  	v := New()
   632  	v.SetDefault("port", 1313)
   633  	v.Set("name", "Steve")
   634  	v.Set("duration", "1s1ms")
   635  
   636  	type config struct {
   637  		Port     int
   638  		Name     string
   639  		Duration time.Duration
   640  	}
   641  
   642  	var C config
   643  
   644  	err := v.Unmarshal(&C)
   645  	if err != nil {
   646  		t.Fatalf("unable to decode into struct, %v", err)
   647  	}
   648  
   649  	assert.Equal(t, &config{Name: "Steve", Port: 1313, Duration: time.Second + time.Millisecond}, &C)
   650  
   651  	v.Set("port", 1234)
   652  	err = v.Unmarshal(&C)
   653  	if err != nil {
   654  		t.Fatalf("unable to decode into struct, %v", err)
   655  	}
   656  	assert.Equal(t, &config{Name: "Steve", Port: 1234, Duration: time.Second + time.Millisecond}, &C)
   657  }
   658  
   659  func TestUnmarshalWithDecoderOptions(t *testing.T) {
   660  	v := New()
   661  	v.Set("credentials", "{\"foo\":\"bar\"}")
   662  
   663  	opt := DecodeHook(mapstructure.ComposeDecodeHookFunc(
   664  		mapstructure.StringToTimeDurationHookFunc(),
   665  		mapstructure.StringToSliceHookFunc(","),
   666  		// Custom Decode Hook Function
   667  		func(rf reflect.Kind, rt reflect.Kind, data interface{}) (interface{}, error) {
   668  			if rf != reflect.String || rt != reflect.Map {
   669  				return data, nil
   670  			}
   671  			m := map[string]string{}
   672  			raw := data.(string)
   673  			if raw == "" {
   674  				return m, nil
   675  			}
   676  			return m, json.Unmarshal([]byte(raw), &m)
   677  		},
   678  	))
   679  
   680  	type config struct {
   681  		Credentials map[string]string
   682  	}
   683  
   684  	var C config
   685  
   686  	err := v.Unmarshal(&C, opt)
   687  	if err != nil {
   688  		t.Fatalf("unable to decode into struct, %v", err)
   689  	}
   690  
   691  	assert.Equal(t, &config{
   692  		Credentials: map[string]string{"foo": "bar"},
   693  	}, &C)
   694  }
   695  
   696  func TestBindPFlags(t *testing.T) {
   697  	v := New() // create independent Viper object
   698  	flagSet := pflag.NewFlagSet("test", pflag.ContinueOnError)
   699  
   700  	var testValues = map[string]*string{
   701  		"host":     nil,
   702  		"port":     nil,
   703  		"endpoint": nil,
   704  	}
   705  
   706  	var mutatedTestValues = map[string]string{
   707  		"host":     "localhost",
   708  		"port":     "6060",
   709  		"endpoint": "/public",
   710  	}
   711  
   712  	for name := range testValues {
   713  		testValues[name] = flagSet.String(name, "", "test")
   714  	}
   715  
   716  	err := v.BindPFlags(flagSet)
   717  	if err != nil {
   718  		t.Fatalf("error binding flag set, %v", err)
   719  	}
   720  
   721  	flagSet.VisitAll(func(flag *pflag.Flag) {
   722  		flag.Value.Set(mutatedTestValues[flag.Name])
   723  		flag.Changed = true
   724  	})
   725  
   726  	for name, expected := range mutatedTestValues {
   727  		assert.Equal(t, expected, v.Get(name))
   728  	}
   729  
   730  }
   731  
   732  func TestBindPFlagsStringSlice(t *testing.T) {
   733  	tests := []struct {
   734  		Expected []string
   735  		Value    string
   736  	}{
   737  		{nil, ""},
   738  		{[]string{"jeden"}, "jeden"},
   739  		{[]string{"dwa", "trzy"}, "dwa,trzy"},
   740  		{[]string{"cztery", "piec , szesc"}, "cztery,\"piec , szesc\""},
   741  	}
   742  
   743  	v := New()
   744  	defaultVal := []string{"default"}
   745  	v.SetDefault("stringslice", defaultVal)
   746  
   747  	for _, testValue := range tests {
   748  		flagSet := pflag.NewFlagSet("test", pflag.ContinueOnError)
   749  		flagSet.StringSlice("stringslice", testValue.Expected, "test")
   750  
   751  		for _, changed := range []bool{true, false} {
   752  			flagSet.VisitAll(func(f *pflag.Flag) {
   753  				f.Value.Set(testValue.Value)
   754  				f.Changed = changed
   755  			})
   756  
   757  			err := v.BindPFlags(flagSet)
   758  			if err != nil {
   759  				t.Fatalf("error binding flag set, %v", err)
   760  			}
   761  
   762  			type TestStr struct {
   763  				StringSlice []string
   764  			}
   765  			val := &TestStr{}
   766  			if err := v.Unmarshal(val); err != nil {
   767  				t.Fatalf("%+#v cannot unmarshal: %s", testValue.Value, err)
   768  			}
   769  			if changed {
   770  				assert.Equal(t, testValue.Expected, val.StringSlice)
   771  			} else {
   772  				assert.Equal(t, defaultVal, val.StringSlice)
   773  			}
   774  		}
   775  	}
   776  }
   777  
   778  func TestBindPFlag(t *testing.T) {
   779  	v := New()
   780  
   781  	var testString = "testing"
   782  	var testValue = newStringValue(testString, &testString)
   783  
   784  	flag := &pflag.Flag{
   785  		Name:    "testflag",
   786  		Value:   testValue,
   787  		Changed: false,
   788  	}
   789  
   790  	v.BindPFlag("testvalue", flag)
   791  
   792  	assert.Equal(t, testString, v.Get("testvalue"))
   793  
   794  	flag.Value.Set("testing_mutate")
   795  	flag.Changed = true //hack for pflag usage
   796  
   797  	assert.Equal(t, "testing_mutate", v.Get("testvalue"))
   798  
   799  }
   800  
   801  func TestBoundCaseSensitivity(t *testing.T) {
   802  	v := New()
   803  	initYAML(v)
   804  
   805  	assert.Equal(t, "brown", v.Get("eyes"))
   806  
   807  	v.BindEnv("eYEs", "TURTLE_EYES")
   808  	os.Setenv("TURTLE_EYES", "blue")
   809  
   810  	assert.Equal(t, "blue", v.Get("eyes"))
   811  
   812  	var testString = "green"
   813  	var testValue = newStringValue(testString, &testString)
   814  
   815  	flag := &pflag.Flag{
   816  		Name:    "eyeballs",
   817  		Value:   testValue,
   818  		Changed: true,
   819  	}
   820  
   821  	v.BindPFlag("eYEs", flag)
   822  	assert.Equal(t, "green", v.Get("eyes"))
   823  
   824  }
   825  
   826  func TestSizeInBytes(t *testing.T) {
   827  	input := map[string]struct {
   828  		Size  uint
   829  		Error bool
   830  	}{
   831  		"":               {0, true},
   832  		"b":              {0, true},
   833  		"12 bytes":       {0, true},
   834  		"200000000000gb": {0, true},
   835  		"12 b":           {12, false},
   836  		"43 MB":          {43 * (1 << 20), false},
   837  		"10mb":           {10 * (1 << 20), false},
   838  		"1gb":            {1 << 30, false},
   839  	}
   840  
   841  	for str, expected := range input {
   842  		size, err := parseSizeInBytes(str)
   843  		assert.Equal(t, expected.Size, size, str)
   844  		assert.Equal(t, expected.Error, err != nil, str)
   845  	}
   846  }
   847  
   848  func TestFindsNestedKeys(t *testing.T) {
   849  	v := New()
   850  	initConfigs(v)
   851  	dob, _ := time.Parse(time.RFC3339, "1979-05-27T07:32:00Z")
   852  
   853  	v.Set("super", map[string]interface{}{
   854  		"deep": map[string]interface{}{
   855  			"nested": "value",
   856  		},
   857  	})
   858  
   859  	expected := map[string]interface{}{
   860  		"super": map[string]interface{}{
   861  			"deep": map[string]interface{}{
   862  				"nested": "value",
   863  			},
   864  		},
   865  		"super.deep": map[string]interface{}{
   866  			"nested": "value",
   867  		},
   868  		"super.deep.nested":  "value",
   869  		"owner.organization": "MongoDB",
   870  		"batters.batter": []interface{}{
   871  			map[string]interface{}{
   872  				"type": "Regular",
   873  			},
   874  			map[string]interface{}{
   875  				"type": "Chocolate",
   876  			},
   877  			map[string]interface{}{
   878  				"type": "Blueberry",
   879  			},
   880  			map[string]interface{}{
   881  				"type": "Devil's Food",
   882  			},
   883  		},
   884  		"hobbies": []interface{}{
   885  			"skateboarding", "snowboarding", "go",
   886  		},
   887  		"title":  "TOML Example",
   888  		"newkey": "remote",
   889  		"batters": map[string]interface{}{
   890  			"batter": []interface{}{
   891  				map[string]interface{}{
   892  					"type": "Regular",
   893  				},
   894  				map[string]interface{}{
   895  					"type": "Chocolate",
   896  				}, map[string]interface{}{
   897  					"type": "Blueberry",
   898  				}, map[string]interface{}{
   899  					"type": "Devil's Food",
   900  				},
   901  			},
   902  		},
   903  		"eyes": "brown",
   904  		"age":  35,
   905  		"owner": map[string]interface{}{
   906  			"organization": "MongoDB",
   907  			"bio":          "MongoDB Chief Developer Advocate & Hacker at Large",
   908  			"dob":          dob,
   909  		},
   910  		"owner.bio": "MongoDB Chief Developer Advocate & Hacker at Large",
   911  		"type":      "donut",
   912  		"id":        "0001",
   913  		"name":      "Cake",
   914  		"hacker":    true,
   915  		"ppu":       0.55,
   916  		"clothing": map[string]interface{}{
   917  			"jacket":   "leather",
   918  			"trousers": "denim",
   919  			"pants": map[string]interface{}{
   920  				"size": "large",
   921  			},
   922  		},
   923  		"clothing.jacket":     "leather",
   924  		"clothing.pants.size": "large",
   925  		"clothing.trousers":   "denim",
   926  		"owner.dob":           dob,
   927  		"beard":               true,
   928  		"foos": []map[string]interface{}{
   929  			map[string]interface{}{
   930  				"foo": []map[string]interface{}{
   931  					map[string]interface{}{
   932  						"key": 1,
   933  					},
   934  					map[string]interface{}{
   935  						"key": 2,
   936  					},
   937  					map[string]interface{}{
   938  						"key": 3,
   939  					},
   940  					map[string]interface{}{
   941  						"key": 4,
   942  					},
   943  				},
   944  			},
   945  		},
   946  	}
   947  
   948  	for key, expectedValue := range expected {
   949  
   950  		assert.Equal(t, expectedValue, v.Get(key))
   951  	}
   952  
   953  }
   954  
   955  func TestReadBufConfig(t *testing.T) {
   956  	v := New()
   957  	v.SetConfigType("yaml")
   958  	v.ReadConfig(bytes.NewBuffer(yamlExample))
   959  	t.Log(v.AllKeys())
   960  
   961  	assert.True(t, v.InConfig("name"))
   962  	assert.False(t, v.InConfig("state"))
   963  	assert.Equal(t, "steve", v.Get("name"))
   964  	assert.Equal(t, []interface{}{"skateboarding", "snowboarding", "go"}, v.Get("hobbies"))
   965  	assert.Equal(t, map[string]interface{}{"jacket": "leather", "trousers": "denim", "pants": map[string]interface{}{"size": "large"}}, v.Get("clothing"))
   966  	assert.Equal(t, 35, v.Get("age"))
   967  }
   968  
   969  func TestIsSet(t *testing.T) {
   970  	v := New()
   971  	v.SetConfigType("yaml")
   972  	v.ReadConfig(bytes.NewBuffer(yamlExample))
   973  	assert.True(t, v.IsSet("clothing.jacket"))
   974  	assert.False(t, v.IsSet("clothing.jackets"))
   975  	assert.False(t, v.IsSet("helloworld"))
   976  	v.Set("helloworld", "fubar")
   977  	assert.True(t, v.IsSet("helloworld"))
   978  }
   979  
   980  func TestDirsSearch(t *testing.T) {
   981  
   982  	root, config, cleanup := initDirs(t)
   983  	defer cleanup()
   984  
   985  	v := New()
   986  	v.SetConfigName(config)
   987  	v.SetDefault(`key`, `default`)
   988  
   989  	entries, err := ioutil.ReadDir(root)
   990  	for _, e := range entries {
   991  		if e.IsDir() {
   992  			v.AddConfigPath(e.Name())
   993  		}
   994  	}
   995  
   996  	err = v.ReadInConfig()
   997  	assert.Nil(t, err)
   998  
   999  	assert.Equal(t, `value is `+path.Base(v.configPaths[0]), v.GetString(`key`))
  1000  }
  1001  
  1002  func TestWrongDirsSearchNotFound(t *testing.T) {
  1003  
  1004  	_, config, cleanup := initDirs(t)
  1005  	defer cleanup()
  1006  
  1007  	v := New()
  1008  	v.SetConfigName(config)
  1009  	v.SetDefault(`key`, `default`)
  1010  
  1011  	v.AddConfigPath(`whattayoutalkingbout`)
  1012  	v.AddConfigPath(`thispathaintthere`)
  1013  
  1014  	err := v.ReadInConfig()
  1015  	assert.Equal(t, reflect.TypeOf(ConfigFileNotFoundError{"", ""}), reflect.TypeOf(err))
  1016  
  1017  	// Even though config did not load and the error might have
  1018  	// been ignored by the client, the default still loads
  1019  	assert.Equal(t, `default`, v.GetString(`key`))
  1020  }
  1021  
  1022  func TestNoPermissionDirs(t *testing.T) {
  1023  	tmpdir := t.TempDir()
  1024  
  1025  	v := New()
  1026  	v.SetDefault(`key`, `default`)
  1027  
  1028  	// Make an fs with an un-readable /directory
  1029  	v.fs = afero.NewBasePathFs(afero.NewOsFs(), tmpdir)
  1030  	err := v.fs.Mkdir("/directory", 000)
  1031  	if err != nil {
  1032  		t.Fatalf("Error from fs.Mkdir: %v", err)
  1033  	}
  1034  
  1035  	v.AddConfigPath("/directory")
  1036  	err = v.ReadInConfig()
  1037  
  1038  	if !errors.Is(err, os.ErrPermission) {
  1039  		t.Fatalf("error should have been a permissions error")
  1040  	}
  1041  
  1042  	// Even though config did not load and the error might have
  1043  	// been ignored by the client, the default still loads
  1044  	assert.Equal(t, `default`, v.GetString(`key`))
  1045  }
  1046  
  1047  func TestWrongDirsSearchNotFoundForMerge(t *testing.T) {
  1048  
  1049  	_, config, cleanup := initDirs(t)
  1050  	defer cleanup()
  1051  
  1052  	v := New()
  1053  	v.SetConfigName(config)
  1054  	v.SetDefault(`key`, `default`)
  1055  
  1056  	v.AddConfigPath(`whattayoutalkingbout`)
  1057  	v.AddConfigPath(`thispathaintthere`)
  1058  
  1059  	err := v.MergeInConfig()
  1060  	assert.Equal(t, reflect.TypeOf(ConfigFileNotFoundError{"", ""}), reflect.TypeOf(err))
  1061  
  1062  	// Even though config did not load and the error might have
  1063  	// been ignored by the client, the default still loads
  1064  	assert.Equal(t, `default`, v.GetString(`key`))
  1065  }
  1066  
  1067  func TestSub(t *testing.T) {
  1068  	v := New()
  1069  	v.SetConfigType("yaml")
  1070  	v.ReadConfig(bytes.NewBuffer(yamlExample))
  1071  
  1072  	subv := v.Sub("clothing")
  1073  	assert.Equal(t, v.Get("clothing.pants.size"), subv.Get("pants.size"))
  1074  
  1075  	subv = v.Sub("clothing.pants")
  1076  	assert.Equal(t, v.Get("clothing.pants.size"), subv.Get("size"))
  1077  
  1078  	subv = v.Sub("clothing.pants.size")
  1079  	assert.Equal(t, (*Viper)(nil), subv)
  1080  
  1081  	subv = v.Sub("missing.key")
  1082  	assert.Equal(t, (*Viper)(nil), subv)
  1083  }
  1084  
  1085  var hclWriteExpected = []byte(`"foos" = {
  1086    "foo" = {
  1087      "key" = 1
  1088    }
  1089  
  1090    "foo" = {
  1091      "key" = 2
  1092    }
  1093  
  1094    "foo" = {
  1095      "key" = 3
  1096    }
  1097  
  1098    "foo" = {
  1099      "key" = 4
  1100    }
  1101  }
  1102  
  1103  "id" = "0001"
  1104  
  1105  "name" = "Cake"
  1106  
  1107  "ppu" = 0.55
  1108  
  1109  "type" = "donut"`)
  1110  
  1111  func TestWriteConfigHCL(t *testing.T) {
  1112  	v := New()
  1113  	fs := afero.NewMemMapFs()
  1114  	v.SetFs(fs)
  1115  	v.SetConfigName("c")
  1116  	v.SetConfigType("hcl")
  1117  	err := v.ReadConfig(bytes.NewBuffer(hclExample))
  1118  	if err != nil {
  1119  		t.Fatal(err)
  1120  	}
  1121  	if err := v.WriteConfigAs("c.hcl"); err != nil {
  1122  		t.Fatal(err)
  1123  	}
  1124  	read, err := afero.ReadFile(fs, "c.hcl")
  1125  	if err != nil {
  1126  		t.Fatal(err)
  1127  	}
  1128  	assert.Equal(t, hclWriteExpected, read)
  1129  }
  1130  
  1131  var jsonWriteExpected = []byte(`{
  1132    "batters": {
  1133      "batter": [
  1134        {
  1135          "type": "Regular"
  1136        },
  1137        {
  1138          "type": "Chocolate"
  1139        },
  1140        {
  1141          "type": "Blueberry"
  1142        },
  1143        {
  1144          "type": "Devil's Food"
  1145        }
  1146      ]
  1147    },
  1148    "id": "0001",
  1149    "name": "Cake",
  1150    "ppu": 0.55,
  1151    "type": "donut"
  1152  }`)
  1153  
  1154  func TestWriteConfigJson(t *testing.T) {
  1155  	v := New()
  1156  	fs := afero.NewMemMapFs()
  1157  	v.SetFs(fs)
  1158  	v.SetConfigName("c")
  1159  	v.SetConfigType("json")
  1160  	err := v.ReadConfig(bytes.NewBuffer(jsonExample))
  1161  	if err != nil {
  1162  		t.Fatal(err)
  1163  	}
  1164  	if err := v.WriteConfigAs("c.json"); err != nil {
  1165  		t.Fatal(err)
  1166  	}
  1167  	read, err := afero.ReadFile(fs, "c.json")
  1168  	if err != nil {
  1169  		t.Fatal(err)
  1170  	}
  1171  	assert.Equal(t, jsonWriteExpected, read)
  1172  }
  1173  
  1174  var propertiesWriteExpected = []byte(`p_id = 0001
  1175  p_type = donut
  1176  p_name = Cake
  1177  p_ppu = 0.55
  1178  p_batters.batter.type = Regular
  1179  `)
  1180  
  1181  func TestWriteConfigProperties(t *testing.T) {
  1182  	v := New()
  1183  	fs := afero.NewMemMapFs()
  1184  	v.SetFs(fs)
  1185  	v.SetConfigName("c")
  1186  	v.SetConfigType("properties")
  1187  	err := v.ReadConfig(bytes.NewBuffer(propertiesExample))
  1188  	if err != nil {
  1189  		t.Fatal(err)
  1190  	}
  1191  	if err := v.WriteConfigAs("c.properties"); err != nil {
  1192  		t.Fatal(err)
  1193  	}
  1194  	read, err := afero.ReadFile(fs, "c.properties")
  1195  	if err != nil {
  1196  		t.Fatal(err)
  1197  	}
  1198  	assert.Equal(t, propertiesWriteExpected, read)
  1199  }
  1200  
  1201  func TestWriteConfigTOML(t *testing.T) {
  1202  	fs := afero.NewMemMapFs()
  1203  	v := New()
  1204  	v.SetFs(fs)
  1205  	v.SetConfigName("c")
  1206  	v.SetConfigType("toml")
  1207  	err := v.ReadConfig(bytes.NewBuffer(tomlExample))
  1208  	if err != nil {
  1209  		t.Fatal(err)
  1210  	}
  1211  	if err := v.WriteConfigAs("c.toml"); err != nil {
  1212  		t.Fatal(err)
  1213  	}
  1214  
  1215  	// The TOML String method does not order the contents.
  1216  	// Therefore, we must read the generated file and compare the data.
  1217  	v2 := New()
  1218  	v2.SetFs(fs)
  1219  	v2.SetConfigName("c")
  1220  	v2.SetConfigType("toml")
  1221  	v2.SetConfigFile("c.toml")
  1222  	err = v2.ReadInConfig()
  1223  	if err != nil {
  1224  		t.Fatal(err)
  1225  	}
  1226  
  1227  	assert.Equal(t, v.GetString("title"), v2.GetString("title"))
  1228  	assert.Equal(t, v.GetString("owner.bio"), v2.GetString("owner.bio"))
  1229  	assert.Equal(t, v.GetString("owner.dob"), v2.GetString("owner.dob"))
  1230  	assert.Equal(t, v.GetString("owner.organization"), v2.GetString("owner.organization"))
  1231  }
  1232  
  1233  var yamlWriteExpected = []byte(`age: 35
  1234  beard: true
  1235  clothing:
  1236    jacket: leather
  1237    pants:
  1238      size: large
  1239    trousers: denim
  1240  eyes: brown
  1241  hacker: true
  1242  hobbies:
  1243  - skateboarding
  1244  - snowboarding
  1245  - go
  1246  name: steve
  1247  `)
  1248  
  1249  func TestWriteConfigYAML(t *testing.T) {
  1250  	v := New()
  1251  	fs := afero.NewMemMapFs()
  1252  	v.SetFs(fs)
  1253  	v.SetConfigName("c")
  1254  	v.SetConfigType("yaml")
  1255  	err := v.ReadConfig(bytes.NewBuffer(yamlExample))
  1256  	if err != nil {
  1257  		t.Fatal(err)
  1258  	}
  1259  	if err := v.WriteConfigAs("c.yaml"); err != nil {
  1260  		t.Fatal(err)
  1261  	}
  1262  	read, err := afero.ReadFile(fs, "c.yaml")
  1263  	if err != nil {
  1264  		t.Fatal(err)
  1265  	}
  1266  	assert.Equal(t, yamlWriteExpected, read)
  1267  }
  1268  
  1269  var yamlMergeExampleTgt = []byte(`
  1270  hello:
  1271      pop: 37890
  1272      lagrenum: 765432101234567
  1273      world:
  1274      - us
  1275      - uk
  1276      - fr
  1277      - de
  1278  `)
  1279  
  1280  var yamlMergeExampleSrc = []byte(`
  1281  hello:
  1282      pop: 45000
  1283      lagrenum: 7654321001234567
  1284      universe:
  1285      - mw
  1286      - ad
  1287  fu: bar
  1288  `)
  1289  
  1290  func TestMergeConfig(t *testing.T) {
  1291  	v := New()
  1292  	v.SetConfigType("yml")
  1293  	if err := v.ReadConfig(bytes.NewBuffer(yamlMergeExampleTgt)); err != nil {
  1294  		t.Fatal(err)
  1295  	}
  1296  
  1297  	if pop := v.GetInt("hello.pop"); pop != 37890 {
  1298  		t.Fatalf("pop != 37890, = %d", pop)
  1299  	}
  1300  
  1301  	if pop := v.GetInt32("hello.pop"); pop != int32(37890) {
  1302  		t.Fatalf("pop != 37890, = %d", pop)
  1303  	}
  1304  
  1305  	if pop := v.GetInt64("hello.lagrenum"); pop != int64(765432101234567) {
  1306  		t.Fatalf("int64 lagrenum != 765432101234567, = %d", pop)
  1307  	}
  1308  
  1309  	if world := v.GetStringSlice("hello.world"); len(world) != 4 {
  1310  		t.Fatalf("len(world) != 4, = %d", len(world))
  1311  	}
  1312  
  1313  	if fu := v.GetString("fu"); fu != "" {
  1314  		t.Fatalf("fu != \"\", = %s", fu)
  1315  	}
  1316  
  1317  	if err := v.MergeConfig(bytes.NewBuffer(yamlMergeExampleSrc)); err != nil {
  1318  		t.Fatal(err)
  1319  	}
  1320  
  1321  	if pop := v.GetInt("hello.pop"); pop != 45000 {
  1322  		t.Fatalf("pop != 45000, = %d", pop)
  1323  	}
  1324  
  1325  	if pop := v.GetInt32("hello.pop"); pop != int32(45000) {
  1326  		t.Fatalf("pop != 45000, = %d", pop)
  1327  	}
  1328  
  1329  	if pop := v.GetInt64("hello.lagrenum"); pop != int64(7654321001234567) {
  1330  		t.Fatalf("int64 lagrenum != 7654321001234567, = %d", pop)
  1331  	}
  1332  
  1333  	if world := v.GetStringSlice("hello.world"); len(world) != 4 {
  1334  		t.Fatalf("len(world) != 4, = %d", len(world))
  1335  	}
  1336  
  1337  	if universe := v.GetStringSlice("hello.universe"); len(universe) != 2 {
  1338  		t.Fatalf("len(universe) != 2, = %d", len(universe))
  1339  	}
  1340  
  1341  	if fu := v.GetString("fu"); fu != "bar" {
  1342  		t.Fatalf("fu != \"bar\", = %s", fu)
  1343  	}
  1344  }
  1345  
  1346  func TestMergeConfigOverride(t *testing.T) {
  1347  	v := New()
  1348  	v.SetConfigType("yml")
  1349  
  1350  	v.SetEnvPrefix("Baz")
  1351  	v.BindEnv("fu")
  1352  	os.Setenv("BAZ_FU", "test")
  1353  
  1354  	if err := v.ReadConfig(bytes.NewBuffer(yamlMergeExampleTgt)); err != nil {
  1355  		t.Fatal(err)
  1356  	}
  1357  
  1358  	if pop := v.GetInt("hello.pop"); pop != 37890 {
  1359  		t.Fatalf("pop != 37890, = %d", pop)
  1360  	}
  1361  
  1362  	if pop := v.GetInt("hello.lagrenum"); pop != 765432101234567 {
  1363  		t.Fatalf("lagrenum != 765432101234567, = %d", pop)
  1364  	}
  1365  
  1366  	if pop := v.GetInt32("hello.pop"); pop != int32(37890) {
  1367  		t.Fatalf("pop != 37890, = %d", pop)
  1368  	}
  1369  
  1370  	if pop := v.GetInt64("hello.lagrenum"); pop != int64(765432101234567) {
  1371  		t.Fatalf("int64 lagrenum != 765432101234567, = %d", pop)
  1372  	}
  1373  
  1374  	if world := v.GetStringSlice("hello.world"); len(world) != 4 {
  1375  		t.Fatalf("len(world) != 4, = %d", len(world))
  1376  	}
  1377  
  1378  	if fu := v.GetString("fu"); fu != "test" {
  1379  		t.Fatalf("fu != \"test\", = %s", fu)
  1380  	}
  1381  
  1382  	if err := v.MergeConfigOverride(bytes.NewBuffer(yamlMergeExampleSrc)); err != nil {
  1383  		t.Fatal(err)
  1384  	}
  1385  
  1386  	if pop := v.GetInt("hello.pop"); pop != 45000 {
  1387  		t.Fatalf("pop != 45000, = %d", pop)
  1388  	}
  1389  
  1390  	if pop := v.GetInt("hello.lagrenum"); pop != 7654321001234567 {
  1391  		t.Fatalf("lagrenum != 7654321001234567, = %d", pop)
  1392  	}
  1393  
  1394  	if pop := v.GetInt32("hello.pop"); pop != int32(45000) {
  1395  		t.Fatalf("pop != 45000, = %d", pop)
  1396  	}
  1397  
  1398  	if pop := v.GetInt64("hello.lagrenum"); pop != int64(7654321001234567) {
  1399  		t.Fatalf("int64 lagrenum != 7654321001234567, = %d", pop)
  1400  	}
  1401  
  1402  	if world := v.GetStringSlice("hello.world"); len(world) != 4 {
  1403  		t.Fatalf("len(world) != 4, = %d", len(world))
  1404  	}
  1405  
  1406  	if universe := v.GetStringSlice("hello.universe"); len(universe) != 2 {
  1407  		t.Fatalf("len(universe) != 2, = %d", len(universe))
  1408  	}
  1409  
  1410  	if fu := v.GetString("fu"); fu != "bar" {
  1411  		t.Fatalf("fu != \"bar\", = %s", fu)
  1412  	}
  1413  }
  1414  
  1415  func TestMergeConfigNoMerge(t *testing.T) {
  1416  	v := New()
  1417  	v.SetConfigType("yml")
  1418  	if err := v.ReadConfig(bytes.NewBuffer(yamlMergeExampleTgt)); err != nil {
  1419  		t.Fatal(err)
  1420  	}
  1421  
  1422  	if pop := v.GetInt("hello.pop"); pop != 37890 {
  1423  		t.Fatalf("pop != 37890, = %d", pop)
  1424  	}
  1425  
  1426  	if world := v.GetStringSlice("hello.world"); len(world) != 4 {
  1427  		t.Fatalf("len(world) != 4, = %d", len(world))
  1428  	}
  1429  
  1430  	if fu := v.GetString("fu"); fu != "" {
  1431  		t.Fatalf("fu != \"\", = %s", fu)
  1432  	}
  1433  
  1434  	if err := v.ReadConfig(bytes.NewBuffer(yamlMergeExampleSrc)); err != nil {
  1435  		t.Fatal(err)
  1436  	}
  1437  
  1438  	if pop := v.GetInt("hello.pop"); pop != 45000 {
  1439  		t.Fatalf("pop != 45000, = %d", pop)
  1440  	}
  1441  
  1442  	if world := v.GetStringSlice("hello.world"); len(world) != 0 {
  1443  		t.Fatalf("len(world) != 0, = %d", len(world))
  1444  	}
  1445  
  1446  	if universe := v.GetStringSlice("hello.universe"); len(universe) != 2 {
  1447  		t.Fatalf("len(universe) != 2, = %d", len(universe))
  1448  	}
  1449  
  1450  	if fu := v.GetString("fu"); fu != "bar" {
  1451  		t.Fatalf("fu != \"bar\", = %s", fu)
  1452  	}
  1453  }
  1454  
  1455  func TestMergeConfigMap(t *testing.T) {
  1456  	v := New()
  1457  	v.SetConfigType("yml")
  1458  	if err := v.ReadConfig(bytes.NewBuffer(yamlMergeExampleTgt)); err != nil {
  1459  		t.Fatal(err)
  1460  	}
  1461  
  1462  	assert := func(i int) {
  1463  		large := v.GetInt("hello.lagrenum")
  1464  		pop := v.GetInt("hello.pop")
  1465  		if large != 765432101234567 {
  1466  			t.Fatal("Got large num:", large)
  1467  		}
  1468  
  1469  		if pop != i {
  1470  			t.Fatal("Got pop:", pop)
  1471  		}
  1472  	}
  1473  
  1474  	assert(37890)
  1475  
  1476  	update := map[string]interface{}{
  1477  		"Hello": map[string]interface{}{
  1478  			"Pop": 1234,
  1479  		},
  1480  		"World": map[interface{}]interface{}{
  1481  			"Rock": 345,
  1482  		},
  1483  	}
  1484  
  1485  	if err := v.MergeConfigMap(update); err != nil {
  1486  		t.Fatal(err)
  1487  	}
  1488  
  1489  	if rock := v.GetInt("world.rock"); rock != 345 {
  1490  		t.Fatal("Got rock:", rock)
  1491  	}
  1492  
  1493  	assert(1234)
  1494  
  1495  }
  1496  
  1497  func TestUnmarshalingWithAliases(t *testing.T) {
  1498  	v := New()
  1499  	v.SetDefault("ID", 1)
  1500  	v.Set("name", "Steve")
  1501  	v.Set("lastname", "Owen")
  1502  
  1503  	v.RegisterAlias("UserID", "ID")
  1504  	v.RegisterAlias("Firstname", "name")
  1505  	v.RegisterAlias("Surname", "lastname")
  1506  
  1507  	type config struct {
  1508  		ID        int
  1509  		FirstName string
  1510  		Surname   string
  1511  	}
  1512  
  1513  	var C config
  1514  	err := v.Unmarshal(&C)
  1515  	if err != nil {
  1516  		t.Fatalf("unable to decode into struct, %v", err)
  1517  	}
  1518  
  1519  	assert.Equal(t, &config{ID: 1, FirstName: "Steve", Surname: "Owen"}, &C)
  1520  }
  1521  
  1522  func TestSetConfigNameClearsFileCache(t *testing.T) {
  1523  	v := New()
  1524  	v.SetConfigFile("/tmp/config.yaml")
  1525  	v.SetConfigName("default")
  1526  	f, err := v.getConfigFile()
  1527  	if err == nil {
  1528  		t.Fatalf("config file cache should have been cleared")
  1529  	}
  1530  	assert.Empty(t, f)
  1531  }
  1532  
  1533  func TestShadowedNestedValue(t *testing.T) {
  1534  
  1535  	config := `name: steve
  1536  clothing:
  1537    jacket: leather
  1538    trousers: denim
  1539    pants:
  1540      size: large
  1541  `
  1542  	v := New()
  1543  	initConfig(v, "yaml", config)
  1544  
  1545  	assert.Equal(t, "steve", v.GetString("name"))
  1546  
  1547  	polyester := "polyester"
  1548  	v.SetDefault("clothing.shirt", polyester)
  1549  	v.SetDefault("clothing.jacket.price", 100)
  1550  
  1551  	assert.Equal(t, "leather", v.GetString("clothing.jacket"))
  1552  	assert.Nil(t, v.Get("clothing.jacket.price"))
  1553  	assert.Equal(t, polyester, v.GetString("clothing.shirt"))
  1554  
  1555  	clothingSettings := v.AllSettings()["clothing"].(map[string]interface{})
  1556  	assert.Equal(t, "leather", clothingSettings["jacket"])
  1557  	assert.Equal(t, polyester, clothingSettings["shirt"])
  1558  }
  1559  
  1560  func TestDotParameter(t *testing.T) {
  1561  	v := New()
  1562  	initJSON(v)
  1563  	// shoud take precedence over batters defined in jsonExample
  1564  	r := bytes.NewReader([]byte(`{ "batters.batter": [ { "type": "Small" } ] }`))
  1565  	v.unmarshalReader(r, v.config)
  1566  
  1567  	actual := v.Get("batters.batter")
  1568  	expected := []interface{}{map[string]interface{}{"type": "Small"}}
  1569  	assert.Equal(t, expected, actual)
  1570  }
  1571  
  1572  func TestCaseInsensitive(t *testing.T) {
  1573  	for _, config := range []struct {
  1574  		typ     string
  1575  		content string
  1576  	}{
  1577  		{"yaml", `
  1578  aBcD: 1
  1579  eF:
  1580    gH: 2
  1581    iJk: 3
  1582    Lm:
  1583      nO: 4
  1584      P:
  1585        Q: 5
  1586        R: 6
  1587  `},
  1588  		{"json", `{
  1589    "aBcD": 1,
  1590    "eF": {
  1591      "iJk": 3,
  1592      "Lm": {
  1593        "P": {
  1594          "Q": 5,
  1595          "R": 6
  1596        },
  1597        "nO": 4
  1598      },
  1599      "gH": 2
  1600    }
  1601  }`},
  1602  		{"toml", `aBcD = 1
  1603  [eF]
  1604  gH = 2
  1605  iJk = 3
  1606  [eF.Lm]
  1607  nO = 4
  1608  [eF.Lm.P]
  1609  Q = 5
  1610  R = 6
  1611  `},
  1612  	} {
  1613  		doTestCaseInsensitive(t, config.typ, config.content)
  1614  	}
  1615  }
  1616  
  1617  func TestCaseInsensitiveSet(t *testing.T) {
  1618  	v := New()
  1619  	m1 := map[string]interface{}{
  1620  		"Foo": 32,
  1621  		"Bar": map[interface{}]interface {
  1622  		}{
  1623  			"ABc": "A",
  1624  			"cDE": "B"},
  1625  	}
  1626  
  1627  	m2 := map[string]interface{}{
  1628  		"Foo": 52,
  1629  		"Bar": map[interface{}]interface {
  1630  		}{
  1631  			"bCd": "A",
  1632  			"eFG": "B"},
  1633  	}
  1634  
  1635  	v.Set("Given1", m1)
  1636  	v.Set("Number1", 42)
  1637  
  1638  	v.SetDefault("Given2", m2)
  1639  	v.SetDefault("Number2", 52)
  1640  
  1641  	// Verify SetDefault
  1642  	if v := v.Get("number2"); v != 52 {
  1643  		t.Fatalf("Expected 52 got %q", v)
  1644  	}
  1645  
  1646  	if v := v.Get("given2.foo"); v != 52 {
  1647  		t.Fatalf("Expected 52 got %q", v)
  1648  	}
  1649  
  1650  	if v := v.Get("given2.bar.bcd"); v != "A" {
  1651  		t.Fatalf("Expected A got %q", v)
  1652  	}
  1653  
  1654  	if _, ok := m2["Foo"]; !ok {
  1655  		t.Fatal("Input map changed")
  1656  	}
  1657  
  1658  	// Verify Set
  1659  	if v := v.Get("number1"); v != 42 {
  1660  		t.Fatalf("Expected 42 got %q", v)
  1661  	}
  1662  
  1663  	if v := v.Get("given1.foo"); v != 32 {
  1664  		t.Fatalf("Expected 32 got %q", v)
  1665  	}
  1666  
  1667  	if v := v.Get("given1.bar.abc"); v != "A" {
  1668  		t.Fatalf("Expected A got %q", v)
  1669  	}
  1670  
  1671  	if _, ok := m1["Foo"]; !ok {
  1672  		t.Fatal("Input map changed")
  1673  	}
  1674  }
  1675  
  1676  func TestParseNested(t *testing.T) {
  1677  	type duration struct {
  1678  		Delay time.Duration
  1679  	}
  1680  
  1681  	type item struct {
  1682  		Name   string
  1683  		Delay  time.Duration
  1684  		Nested duration
  1685  	}
  1686  
  1687  	config := `[[parent]]
  1688  	delay="100ms"
  1689  	[parent.nested]
  1690  	delay="200ms"
  1691  `
  1692  	v := New()
  1693  	initConfig(v, "toml", config)
  1694  
  1695  	var items []item
  1696  	err := v.UnmarshalKey("parent", &items)
  1697  	if err != nil {
  1698  		t.Fatalf("unable to decode into struct, %v", err)
  1699  	}
  1700  
  1701  	assert.Equal(t, 1, len(items))
  1702  	assert.Equal(t, 100*time.Millisecond, items[0].Delay)
  1703  	assert.Equal(t, 200*time.Millisecond, items[0].Nested.Delay)
  1704  }
  1705  
  1706  func doTestCaseInsensitive(t *testing.T, typ, config string) {
  1707  	v := New()
  1708  	initConfig(v, typ, config)
  1709  	v.Set("RfD", true)
  1710  	assert.Equal(t, true, v.Get("rfd"))
  1711  	assert.Equal(t, true, v.Get("rFD"))
  1712  	assert.Equal(t, 1, cast.ToInt(v.Get("abcd")))
  1713  	assert.Equal(t, 1, cast.ToInt(v.Get("Abcd")))
  1714  	assert.Equal(t, 2, cast.ToInt(v.Get("ef.gh")))
  1715  	assert.Equal(t, 3, cast.ToInt(v.Get("ef.ijk")))
  1716  	assert.Equal(t, 4, cast.ToInt(v.Get("ef.lm.no")))
  1717  	assert.Equal(t, 5, cast.ToInt(v.Get("ef.lm.p.q")))
  1718  
  1719  }
  1720  
  1721  func newViperWithConfigFile(t *testing.T) (*Viper, string, func()) {
  1722  	watchDir, err := ioutil.TempDir("", "")
  1723  	require.Nil(t, err)
  1724  	configFile := path.Join(watchDir, "config.yaml")
  1725  	err = ioutil.WriteFile(configFile, []byte("foo: bar\n"), 0640)
  1726  	require.Nil(t, err)
  1727  	cleanup := func() {
  1728  		os.RemoveAll(watchDir)
  1729  	}
  1730  	v := New()
  1731  	v.SetConfigFile(configFile)
  1732  	err = v.ReadInConfig()
  1733  	require.Nil(t, err)
  1734  	require.Equal(t, "bar", v.Get("foo"))
  1735  	return v, configFile, cleanup
  1736  }
  1737  
  1738  func newViperWithSymlinkedConfigFile(t *testing.T) (*Viper, string, string, func()) {
  1739  	watchDir, err := ioutil.TempDir("", "")
  1740  	require.Nil(t, err)
  1741  	dataDir1 := path.Join(watchDir, "data1")
  1742  	err = os.Mkdir(dataDir1, 0777)
  1743  	require.Nil(t, err)
  1744  	realConfigFile := path.Join(dataDir1, "config.yaml")
  1745  	t.Logf("Real config file location: %s\n", realConfigFile)
  1746  	err = ioutil.WriteFile(realConfigFile, []byte("foo: bar\n"), 0640)
  1747  	require.Nil(t, err)
  1748  	cleanup := func() {
  1749  		os.RemoveAll(watchDir)
  1750  	}
  1751  	// now, symlink the tm `data1` dir to `data` in the baseDir
  1752  	os.Symlink(dataDir1, path.Join(watchDir, "data"))
  1753  	// and link the `<watchdir>/datadir1/config.yaml` to `<watchdir>/config.yaml`
  1754  	configFile := path.Join(watchDir, "config.yaml")
  1755  	os.Symlink(path.Join(watchDir, "data", "config.yaml"), configFile)
  1756  	t.Logf("Config file location: %s\n", path.Join(watchDir, "config.yaml"))
  1757  	// init Viper
  1758  	v := New()
  1759  	v.SetConfigFile(configFile)
  1760  	err = v.ReadInConfig()
  1761  	require.Nil(t, err)
  1762  	require.Equal(t, "bar", v.Get("foo"))
  1763  	return v, watchDir, configFile, cleanup
  1764  }
  1765  
  1766  func TestWatchFile(t *testing.T) {
  1767  	if runtime.GOOS == "linux" {
  1768  		// TODO(bep) FIX ME
  1769  		t.Skip("Skip test on Linux ...")
  1770  	}
  1771  
  1772  	t.Run("file content changed", func(t *testing.T) {
  1773  		// given a `config.yaml` file being watched
  1774  		v, configFile, cleanup := newViperWithConfigFile(t)
  1775  		defer cleanup()
  1776  		_, err := os.Stat(configFile)
  1777  		require.NoError(t, err)
  1778  		t.Logf("test config file: %s\n", configFile)
  1779  		wg := sync.WaitGroup{}
  1780  		wg.Add(1)
  1781  		v.OnConfigChange(func(in fsnotify.Event) {
  1782  			t.Logf("config file changed")
  1783  			wg.Done()
  1784  		})
  1785  		v.WatchConfig()
  1786  		// when overwriting the file and waiting for the custom change notification handler to be triggered
  1787  		err = ioutil.WriteFile(configFile, []byte("foo: baz\n"), 0640)
  1788  		wg.Wait()
  1789  		// then the config value should have changed
  1790  		require.Nil(t, err)
  1791  		assert.Equal(t, "baz", v.Get("foo"))
  1792  	})
  1793  
  1794  	t.Run("link to real file changed (à la Kubernetes)", func(t *testing.T) {
  1795  		// skip if not executed on Linux
  1796  		if runtime.GOOS != "linux" {
  1797  			t.Skipf("Skipping test as symlink replacements don't work on non-linux environment...")
  1798  		}
  1799  		v, watchDir, _, _ := newViperWithSymlinkedConfigFile(t)
  1800  		// defer cleanup()
  1801  		wg := sync.WaitGroup{}
  1802  		v.WatchConfig()
  1803  		v.OnConfigChange(func(in fsnotify.Event) {
  1804  			t.Logf("config file changed")
  1805  			wg.Done()
  1806  		})
  1807  		wg.Add(1)
  1808  		// when link to another `config.yaml` file
  1809  		dataDir2 := path.Join(watchDir, "data2")
  1810  		err := os.Mkdir(dataDir2, 0777)
  1811  		require.Nil(t, err)
  1812  		configFile2 := path.Join(dataDir2, "config.yaml")
  1813  		err = ioutil.WriteFile(configFile2, []byte("foo: baz\n"), 0640)
  1814  		require.Nil(t, err)
  1815  		// change the symlink using the `ln -sfn` command
  1816  		err = exec.Command("ln", "-sfn", dataDir2, path.Join(watchDir, "data")).Run()
  1817  		require.Nil(t, err)
  1818  		wg.Wait()
  1819  		// then
  1820  		require.Nil(t, err)
  1821  		assert.Equal(t, "baz", v.Get("foo"))
  1822  	})
  1823  
  1824  }
  1825  
  1826  func BenchmarkGetBool(b *testing.B) {
  1827  	key := "BenchmarkGetBool"
  1828  	v := New()
  1829  	v.Set(key, true)
  1830  
  1831  	for i := 0; i < b.N; i++ {
  1832  		if !v.GetBool(key) {
  1833  			b.Fatal("GetBool returned false")
  1834  		}
  1835  	}
  1836  }
  1837  
  1838  func BenchmarkGet(b *testing.B) {
  1839  	key := "BenchmarkGet"
  1840  	v := New()
  1841  	v.Set(key, true)
  1842  
  1843  	for i := 0; i < b.N; i++ {
  1844  		if !v.Get(key).(bool) {
  1845  			b.Fatal("Get returned false")
  1846  		}
  1847  	}
  1848  }
  1849  
  1850  // This is the "perfect result" for the above.
  1851  func BenchmarkGetBoolFromMap(b *testing.B) {
  1852  	m := make(map[string]bool)
  1853  	key := "BenchmarkGetBool"
  1854  	m[key] = true
  1855  
  1856  	for i := 0; i < b.N; i++ {
  1857  		if !m[key] {
  1858  			b.Fatal("Map value was false")
  1859  		}
  1860  	}
  1861  }
  1862  
  1863  func TestKnownKeys(t *testing.T) {
  1864  	v := New()
  1865  	v.SetDefault("default", 45)
  1866  	if _, ok := v.GetKnownKeys()["default"]; !ok {
  1867  		t.Error("SetDefault didn't mark key as known")
  1868  	}
  1869  	v.BindEnv("bind", "my_env_var")
  1870  	if _, ok := v.GetKnownKeys()["bind"]; !ok {
  1871  		t.Error("BindEnv didn't mark key as known")
  1872  	}
  1873  	v.RegisterAlias("my_alias", "key")
  1874  	if _, ok := v.GetKnownKeys()["my_alias"]; !ok {
  1875  		t.Error("RegisterAlias didn't mark alias as known")
  1876  	}
  1877  	v.SetKnown("known")
  1878  	if _, ok := v.GetKnownKeys()["known"]; !ok {
  1879  		t.Error("SetKnown didn't mark key as known")
  1880  	}
  1881  }
  1882  
  1883  func TestIsKnown(t *testing.T) {
  1884  	v := New()
  1885  
  1886  	v.SetDefault("default", 45)
  1887  	assert.True(t, v.IsKnown("default"))
  1888  
  1889  	v.SetKnown("known")
  1890  	assert.True(t, v.IsKnown("known"))
  1891  
  1892  	v.SetKnown("UpperKnown")
  1893  	assert.True(t, v.IsKnown("UpperKnown"))
  1894  
  1895  	assert.False(t, v.IsKnown("unknown"))
  1896  }