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