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