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