github.com/fengjian1993/viper@v1.11.0/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  	"github.com/spf13/pflag"
    30  	"github.com/stretchr/testify/assert"
    31  	"github.com/stretchr/testify/require"
    32  
    33  	"github.com/spf13/viper/internal/testutil"
    34  )
    35  
    36  var yamlExample = []byte(`Hacker: true
    37  name: steve
    38  hobbies:
    39  - skateboarding
    40  - snowboarding
    41  - go
    42  clothing:
    43    jacket: leather
    44    trousers: denim
    45    pants:
    46      size: large
    47  age: 35
    48  eyes : brown
    49  beard: true
    50  `)
    51  
    52  var yamlExampleWithExtras = []byte(`Existing: true
    53  Bogus: true
    54  `)
    55  
    56  type testUnmarshalExtra struct {
    57  	Existing bool
    58  }
    59  
    60  var tomlExample = []byte(`
    61  title = "TOML Example"
    62  
    63  [owner]
    64  organization = "MongoDB"
    65  Bio = "MongoDB Chief Developer Advocate & Hacker at Large"
    66  dob = 1979-05-27T07:32:00Z # First class dates? Why not?`)
    67  
    68  var dotenvExample = []byte(`
    69  TITLE_DOTENV="DotEnv Example"
    70  TYPE_DOTENV=donut
    71  NAME_DOTENV=Cake`)
    72  
    73  var jsonExample = []byte(`{
    74  "id": "0001",
    75  "type": "donut",
    76  "name": "Cake",
    77  "ppu": 0.55,
    78  "batters": {
    79          "batter": [
    80                  { "type": "Regular" },
    81                  { "type": "Chocolate" },
    82                  { "type": "Blueberry" },
    83                  { "type": "Devil's Food" }
    84              ]
    85      }
    86  }`)
    87  
    88  var hclExample = []byte(`
    89  id = "0001"
    90  type = "donut"
    91  name = "Cake"
    92  ppu = 0.55
    93  foos {
    94  	foo {
    95  		key = 1
    96  	}
    97  	foo {
    98  		key = 2
    99  	}
   100  	foo {
   101  		key = 3
   102  	}
   103  	foo {
   104  		key = 4
   105  	}
   106  }`)
   107  
   108  var propertiesExample = []byte(`
   109  p_id: 0001
   110  p_type: donut
   111  p_name: Cake
   112  p_ppu: 0.55
   113  p_batters.batter.type: Regular
   114  `)
   115  
   116  var remoteExample = []byte(`{
   117  "id":"0002",
   118  "type":"cronut",
   119  "newkey":"remote"
   120  }`)
   121  
   122  var iniExample = []byte(`; Package name
   123  NAME        = ini
   124  ; Package version
   125  VERSION     = v1
   126  ; Package import path
   127  IMPORT_PATH = gopkg.in/%(NAME)s.%(VERSION)s
   128  
   129  # Information about package author
   130  # Bio can be written in multiple lines.
   131  [author]
   132  NAME   = Unknown  ; Succeeding comment
   133  E-MAIL = fake@localhost
   134  GITHUB = https://github.com/%(NAME)s
   135  BIO    = """Gopher.
   136  Coding addict.
   137  Good man.
   138  """  # Succeeding comment`)
   139  
   140  func initConfigs() {
   141  	Reset()
   142  	var r io.Reader
   143  	SetConfigType("yaml")
   144  	r = bytes.NewReader(yamlExample)
   145  	unmarshalReader(r, v.config)
   146  
   147  	SetConfigType("json")
   148  	r = bytes.NewReader(jsonExample)
   149  	unmarshalReader(r, v.config)
   150  
   151  	SetConfigType("hcl")
   152  	r = bytes.NewReader(hclExample)
   153  	unmarshalReader(r, v.config)
   154  
   155  	SetConfigType("properties")
   156  	r = bytes.NewReader(propertiesExample)
   157  	unmarshalReader(r, v.config)
   158  
   159  	SetConfigType("toml")
   160  	r = bytes.NewReader(tomlExample)
   161  	unmarshalReader(r, v.config)
   162  
   163  	SetConfigType("env")
   164  	r = bytes.NewReader(dotenvExample)
   165  	unmarshalReader(r, v.config)
   166  
   167  	SetConfigType("json")
   168  	remote := bytes.NewReader(remoteExample)
   169  	unmarshalReader(remote, v.kvstore)
   170  
   171  	SetConfigType("ini")
   172  	r = bytes.NewReader(iniExample)
   173  	unmarshalReader(r, v.config)
   174  }
   175  
   176  func initConfig(typ, config string) {
   177  	Reset()
   178  	SetConfigType(typ)
   179  	r := strings.NewReader(config)
   180  
   181  	if err := unmarshalReader(r, v.config); err != nil {
   182  		panic(err)
   183  	}
   184  }
   185  
   186  func initYAML() {
   187  	initConfig("yaml", string(yamlExample))
   188  }
   189  
   190  func initJSON() {
   191  	Reset()
   192  	SetConfigType("json")
   193  	r := bytes.NewReader(jsonExample)
   194  
   195  	unmarshalReader(r, v.config)
   196  }
   197  
   198  func initProperties() {
   199  	Reset()
   200  	SetConfigType("properties")
   201  	r := bytes.NewReader(propertiesExample)
   202  
   203  	unmarshalReader(r, v.config)
   204  }
   205  
   206  func initTOML() {
   207  	Reset()
   208  	SetConfigType("toml")
   209  	r := bytes.NewReader(tomlExample)
   210  
   211  	unmarshalReader(r, v.config)
   212  }
   213  
   214  func initDotEnv() {
   215  	Reset()
   216  	SetConfigType("env")
   217  	r := bytes.NewReader(dotenvExample)
   218  
   219  	unmarshalReader(r, v.config)
   220  }
   221  
   222  func initHcl() {
   223  	Reset()
   224  	SetConfigType("hcl")
   225  	r := bytes.NewReader(hclExample)
   226  
   227  	unmarshalReader(r, v.config)
   228  }
   229  
   230  func initIni() {
   231  	Reset()
   232  	SetConfigType("ini")
   233  	r := bytes.NewReader(iniExample)
   234  
   235  	unmarshalReader(r, v.config)
   236  }
   237  
   238  // make directories for testing
   239  func initDirs(t *testing.T) (string, string, func()) {
   240  	var (
   241  		testDirs = []string{`a a`, `b`, `C_`}
   242  		config   = `improbable`
   243  	)
   244  
   245  	if runtime.GOOS != "windows" {
   246  		testDirs = append(testDirs, `d\d`)
   247  	}
   248  
   249  	root, err := ioutil.TempDir("", "")
   250  	require.NoError(t, err, "Failed to create temporary directory")
   251  
   252  	cleanup := true
   253  	defer func() {
   254  		if cleanup {
   255  			os.Chdir("..")
   256  			os.RemoveAll(root)
   257  		}
   258  	}()
   259  
   260  	assert.Nil(t, err)
   261  
   262  	err = os.Chdir(root)
   263  	require.Nil(t, err)
   264  
   265  	for _, dir := range testDirs {
   266  		err = os.Mkdir(dir, 0o750)
   267  		assert.Nil(t, err)
   268  
   269  		err = ioutil.WriteFile(
   270  			path.Join(dir, config+".toml"),
   271  			[]byte("key = \"value is "+dir+"\"\n"),
   272  			0o640)
   273  		assert.Nil(t, err)
   274  	}
   275  
   276  	cleanup = false
   277  	return root, config, func() {
   278  		os.Chdir("..")
   279  		os.RemoveAll(root)
   280  	}
   281  }
   282  
   283  // stubs for PFlag Values
   284  type stringValue string
   285  
   286  func newStringValue(val string, p *string) *stringValue {
   287  	*p = val
   288  	return (*stringValue)(p)
   289  }
   290  
   291  func (s *stringValue) Set(val string) error {
   292  	*s = stringValue(val)
   293  	return nil
   294  }
   295  
   296  func (s *stringValue) Type() string {
   297  	return "string"
   298  }
   299  
   300  func (s *stringValue) String() string {
   301  	return string(*s)
   302  }
   303  
   304  func TestGetConfigFile(t *testing.T) {
   305  	t.Run("config file set", func(t *testing.T) {
   306  		fs := afero.NewMemMapFs()
   307  
   308  		err := fs.Mkdir(testutil.AbsFilePath(t, "/etc/viper"), 0o777)
   309  		require.NoError(t, err)
   310  
   311  		_, err = fs.Create(testutil.AbsFilePath(t, "/etc/viper/config.yaml"))
   312  		require.NoError(t, err)
   313  
   314  		v := New()
   315  
   316  		v.SetFs(fs)
   317  		v.AddConfigPath("/etc/viper")
   318  		v.SetConfigFile(testutil.AbsFilePath(t, "/etc/viper/config.yaml"))
   319  
   320  		filename, err := v.getConfigFile()
   321  		assert.Equal(t, testutil.AbsFilePath(t, "/etc/viper/config.yaml"), filename)
   322  		assert.NoError(t, err)
   323  	})
   324  
   325  	t.Run("find file", func(t *testing.T) {
   326  		fs := afero.NewMemMapFs()
   327  
   328  		err := fs.Mkdir(testutil.AbsFilePath(t, "/etc/viper"), 0o777)
   329  		require.NoError(t, err)
   330  
   331  		_, err = fs.Create(testutil.AbsFilePath(t, "/etc/viper/config.yaml"))
   332  		require.NoError(t, err)
   333  
   334  		v := New()
   335  
   336  		v.SetFs(fs)
   337  		v.AddConfigPath("/etc/viper")
   338  
   339  		filename, err := v.getConfigFile()
   340  		assert.Equal(t, testutil.AbsFilePath(t, "/etc/viper/config.yaml"), filename)
   341  		assert.NoError(t, err)
   342  	})
   343  
   344  	t.Run("find files only", func(t *testing.T) {
   345  		fs := afero.NewMemMapFs()
   346  
   347  		err := fs.Mkdir(testutil.AbsFilePath(t, "/etc/config"), 0o777)
   348  		require.NoError(t, err)
   349  
   350  		_, err = fs.Create(testutil.AbsFilePath(t, "/etc/config/config.yaml"))
   351  		require.NoError(t, err)
   352  
   353  		v := New()
   354  
   355  		v.SetFs(fs)
   356  		v.AddConfigPath("/etc")
   357  		v.AddConfigPath("/etc/config")
   358  
   359  		filename, err := v.getConfigFile()
   360  		assert.Equal(t, testutil.AbsFilePath(t, "/etc/config/config.yaml"), filename)
   361  		assert.NoError(t, err)
   362  	})
   363  
   364  	t.Run("precedence", func(t *testing.T) {
   365  		fs := afero.NewMemMapFs()
   366  
   367  		err := fs.Mkdir(testutil.AbsFilePath(t, "/home/viper"), 0o777)
   368  		require.NoError(t, err)
   369  
   370  		_, err = fs.Create(testutil.AbsFilePath(t, "/home/viper/config.zml"))
   371  		require.NoError(t, err)
   372  
   373  		err = fs.Mkdir(testutil.AbsFilePath(t, "/etc/viper"), 0o777)
   374  		require.NoError(t, err)
   375  
   376  		_, err = fs.Create(testutil.AbsFilePath(t, "/etc/viper/config.bml"))
   377  		require.NoError(t, err)
   378  
   379  		err = fs.Mkdir(testutil.AbsFilePath(t, "/var/viper"), 0o777)
   380  		require.NoError(t, err)
   381  
   382  		_, err = fs.Create(testutil.AbsFilePath(t, "/var/viper/config.yaml"))
   383  		require.NoError(t, err)
   384  
   385  		v := New()
   386  
   387  		v.SetFs(fs)
   388  		v.AddConfigPath("/home/viper")
   389  		v.AddConfigPath("/etc/viper")
   390  		v.AddConfigPath("/var/viper")
   391  
   392  		filename, err := v.getConfigFile()
   393  		assert.Equal(t, testutil.AbsFilePath(t, "/var/viper/config.yaml"), filename)
   394  		assert.NoError(t, err)
   395  	})
   396  
   397  	t.Run("without extension", func(t *testing.T) {
   398  		fs := afero.NewMemMapFs()
   399  
   400  		err := fs.Mkdir(testutil.AbsFilePath(t, "/etc/viper"), 0o777)
   401  		require.NoError(t, err)
   402  
   403  		_, err = fs.Create(testutil.AbsFilePath(t, "/etc/viper/.dotfilenoext"))
   404  		require.NoError(t, err)
   405  
   406  		v := New()
   407  
   408  		v.SetFs(fs)
   409  		v.AddConfigPath("/etc/viper")
   410  		v.SetConfigName(".dotfilenoext")
   411  		v.SetConfigType("yaml")
   412  
   413  		filename, err := v.getConfigFile()
   414  		assert.Equal(t, testutil.AbsFilePath(t, "/etc/viper/.dotfilenoext"), filename)
   415  		assert.NoError(t, err)
   416  	})
   417  
   418  	t.Run("without extension and config type", func(t *testing.T) {
   419  		fs := afero.NewMemMapFs()
   420  
   421  		err := fs.Mkdir(testutil.AbsFilePath(t, "/etc/viper"), 0o777)
   422  		require.NoError(t, err)
   423  
   424  		_, err = fs.Create(testutil.AbsFilePath(t, "/etc/viper/.dotfilenoext"))
   425  		require.NoError(t, err)
   426  
   427  		v := New()
   428  
   429  		v.SetFs(fs)
   430  		v.AddConfigPath("/etc/viper")
   431  		v.SetConfigName(".dotfilenoext")
   432  
   433  		_, err = v.getConfigFile()
   434  		// unless config type is set, files without extension
   435  		// are not considered
   436  		assert.Error(t, err)
   437  	})
   438  }
   439  
   440  func TestReadInConfig(t *testing.T) {
   441  	t.Run("config file set", func(t *testing.T) {
   442  		fs := afero.NewMemMapFs()
   443  
   444  		err := fs.Mkdir("/etc/viper", 0o777)
   445  		require.NoError(t, err)
   446  
   447  		file, err := fs.Create(testutil.AbsFilePath(t, "/etc/viper/config.yaml"))
   448  		require.NoError(t, err)
   449  
   450  		_, err = file.Write([]byte(`key: value`))
   451  		require.NoError(t, err)
   452  
   453  		file.Close()
   454  
   455  		v := New()
   456  
   457  		v.SetFs(fs)
   458  		v.SetConfigFile(testutil.AbsFilePath(t, "/etc/viper/config.yaml"))
   459  
   460  		err = v.ReadInConfig()
   461  		require.NoError(t, err)
   462  
   463  		assert.Equal(t, "value", v.Get("key"))
   464  	})
   465  
   466  	t.Run("find file", func(t *testing.T) {
   467  		fs := afero.NewMemMapFs()
   468  
   469  		err := fs.Mkdir(testutil.AbsFilePath(t, "/etc/viper"), 0o777)
   470  		require.NoError(t, err)
   471  
   472  		file, err := fs.Create(testutil.AbsFilePath(t, "/etc/viper/config.yaml"))
   473  		require.NoError(t, err)
   474  
   475  		_, err = file.Write([]byte(`key: value`))
   476  		require.NoError(t, err)
   477  
   478  		file.Close()
   479  
   480  		v := New()
   481  
   482  		v.SetFs(fs)
   483  		v.AddConfigPath("/etc/viper")
   484  
   485  		err = v.ReadInConfig()
   486  		require.NoError(t, err)
   487  
   488  		assert.Equal(t, "value", v.Get("key"))
   489  	})
   490  }
   491  
   492  func TestDefault(t *testing.T) {
   493  	SetDefault("age", 45)
   494  	assert.Equal(t, 45, Get("age"))
   495  
   496  	SetDefault("clothing.jacket", "slacks")
   497  	assert.Equal(t, "slacks", Get("clothing.jacket"))
   498  
   499  	SetConfigType("yaml")
   500  	err := ReadConfig(bytes.NewBuffer(yamlExample))
   501  
   502  	assert.NoError(t, err)
   503  	assert.Equal(t, "leather", Get("clothing.jacket"))
   504  }
   505  
   506  func TestUnmarshaling(t *testing.T) {
   507  	SetConfigType("yaml")
   508  	r := bytes.NewReader(yamlExample)
   509  
   510  	unmarshalReader(r, v.config)
   511  	assert.True(t, InConfig("name"))
   512  	assert.True(t, InConfig("clothing.jacket"))
   513  	assert.False(t, InConfig("state"))
   514  	assert.False(t, InConfig("clothing.hat"))
   515  	assert.Equal(t, "steve", Get("name"))
   516  	assert.Equal(t, []interface{}{"skateboarding", "snowboarding", "go"}, Get("hobbies"))
   517  	assert.Equal(t, map[string]interface{}{"jacket": "leather", "trousers": "denim", "pants": map[string]interface{}{"size": "large"}}, Get("clothing"))
   518  	assert.Equal(t, 35, Get("age"))
   519  }
   520  
   521  func TestUnmarshalExact(t *testing.T) {
   522  	vip := New()
   523  	target := &testUnmarshalExtra{}
   524  	vip.SetConfigType("yaml")
   525  	r := bytes.NewReader(yamlExampleWithExtras)
   526  	vip.ReadConfig(r)
   527  	err := vip.UnmarshalExact(target)
   528  	if err == nil {
   529  		t.Fatal("UnmarshalExact should error when populating a struct from a conf that contains unused fields")
   530  	}
   531  }
   532  
   533  func TestOverrides(t *testing.T) {
   534  	Set("age", 40)
   535  	assert.Equal(t, 40, Get("age"))
   536  }
   537  
   538  func TestDefaultPost(t *testing.T) {
   539  	assert.NotEqual(t, "NYC", Get("state"))
   540  	SetDefault("state", "NYC")
   541  	assert.Equal(t, "NYC", Get("state"))
   542  }
   543  
   544  func TestAliases(t *testing.T) {
   545  	RegisterAlias("years", "age")
   546  	assert.Equal(t, 40, Get("years"))
   547  	Set("years", 45)
   548  	assert.Equal(t, 45, Get("age"))
   549  }
   550  
   551  func TestAliasInConfigFile(t *testing.T) {
   552  	// the config file specifies "beard".  If we make this an alias for
   553  	// "hasbeard", we still want the old config file to work with beard.
   554  	RegisterAlias("beard", "hasbeard")
   555  	assert.Equal(t, true, Get("hasbeard"))
   556  	Set("hasbeard", false)
   557  	assert.Equal(t, false, Get("beard"))
   558  }
   559  
   560  func TestYML(t *testing.T) {
   561  	initYAML()
   562  	assert.Equal(t, "steve", Get("name"))
   563  }
   564  
   565  func TestJSON(t *testing.T) {
   566  	initJSON()
   567  	assert.Equal(t, "0001", Get("id"))
   568  }
   569  
   570  func TestProperties(t *testing.T) {
   571  	initProperties()
   572  	assert.Equal(t, "0001", Get("p_id"))
   573  }
   574  
   575  func TestTOML(t *testing.T) {
   576  	initTOML()
   577  	assert.Equal(t, "TOML Example", Get("title"))
   578  }
   579  
   580  func TestDotEnv(t *testing.T) {
   581  	initDotEnv()
   582  	assert.Equal(t, "DotEnv Example", Get("title_dotenv"))
   583  }
   584  
   585  func TestHCL(t *testing.T) {
   586  	initHcl()
   587  	assert.Equal(t, "0001", Get("id"))
   588  	assert.Equal(t, 0.55, Get("ppu"))
   589  	assert.Equal(t, "donut", Get("type"))
   590  	assert.Equal(t, "Cake", Get("name"))
   591  	Set("id", "0002")
   592  	assert.Equal(t, "0002", Get("id"))
   593  	assert.NotEqual(t, "cronut", Get("type"))
   594  }
   595  
   596  func TestIni(t *testing.T) {
   597  	initIni()
   598  	assert.Equal(t, "ini", Get("default.name"))
   599  }
   600  
   601  func TestRemotePrecedence(t *testing.T) {
   602  	initJSON()
   603  
   604  	remote := bytes.NewReader(remoteExample)
   605  	assert.Equal(t, "0001", Get("id"))
   606  	unmarshalReader(remote, v.kvstore)
   607  	assert.Equal(t, "0001", Get("id"))
   608  	assert.NotEqual(t, "cronut", Get("type"))
   609  	assert.Equal(t, "remote", Get("newkey"))
   610  	Set("newkey", "newvalue")
   611  	assert.NotEqual(t, "remote", Get("newkey"))
   612  	assert.Equal(t, "newvalue", Get("newkey"))
   613  	Set("newkey", "remote")
   614  }
   615  
   616  func TestEnv(t *testing.T) {
   617  	initJSON()
   618  
   619  	BindEnv("id")
   620  	BindEnv("f", "FOOD", "OLD_FOOD")
   621  
   622  	testutil.Setenv(t, "ID", "13")
   623  	testutil.Setenv(t, "FOOD", "apple")
   624  	testutil.Setenv(t, "OLD_FOOD", "banana")
   625  	testutil.Setenv(t, "NAME", "crunk")
   626  
   627  	assert.Equal(t, "13", Get("id"))
   628  	assert.Equal(t, "apple", Get("f"))
   629  	assert.Equal(t, "Cake", Get("name"))
   630  
   631  	AutomaticEnv()
   632  
   633  	assert.Equal(t, "crunk", Get("name"))
   634  }
   635  
   636  func TestMultipleEnv(t *testing.T) {
   637  	initJSON()
   638  
   639  	BindEnv("f", "FOOD", "OLD_FOOD")
   640  
   641  	testutil.Setenv(t, "OLD_FOOD", "banana")
   642  
   643  	assert.Equal(t, "banana", Get("f"))
   644  }
   645  
   646  func TestEmptyEnv(t *testing.T) {
   647  	initJSON()
   648  
   649  	BindEnv("type") // Empty environment variable
   650  	BindEnv("name") // Bound, but not set environment variable
   651  
   652  	testutil.Setenv(t, "TYPE", "")
   653  
   654  	assert.Equal(t, "donut", Get("type"))
   655  	assert.Equal(t, "Cake", Get("name"))
   656  }
   657  
   658  func TestEmptyEnv_Allowed(t *testing.T) {
   659  	initJSON()
   660  
   661  	AllowEmptyEnv(true)
   662  
   663  	BindEnv("type") // Empty environment variable
   664  	BindEnv("name") // Bound, but not set environment variable
   665  
   666  	testutil.Setenv(t, "TYPE", "")
   667  
   668  	assert.Equal(t, "", Get("type"))
   669  	assert.Equal(t, "Cake", Get("name"))
   670  }
   671  
   672  func TestEnvPrefix(t *testing.T) {
   673  	initJSON()
   674  
   675  	SetEnvPrefix("foo") // will be uppercased automatically
   676  	BindEnv("id")
   677  	BindEnv("f", "FOOD") // not using prefix
   678  
   679  	testutil.Setenv(t, "FOO_ID", "13")
   680  	testutil.Setenv(t, "FOOD", "apple")
   681  	testutil.Setenv(t, "FOO_NAME", "crunk")
   682  
   683  	assert.Equal(t, "13", Get("id"))
   684  	assert.Equal(t, "apple", Get("f"))
   685  	assert.Equal(t, "Cake", Get("name"))
   686  
   687  	AutomaticEnv()
   688  
   689  	assert.Equal(t, "crunk", Get("name"))
   690  }
   691  
   692  func TestAutoEnv(t *testing.T) {
   693  	Reset()
   694  
   695  	AutomaticEnv()
   696  
   697  	testutil.Setenv(t, "FOO_BAR", "13")
   698  
   699  	assert.Equal(t, "13", Get("foo_bar"))
   700  }
   701  
   702  func TestAutoEnvWithPrefix(t *testing.T) {
   703  	Reset()
   704  
   705  	AutomaticEnv()
   706  	SetEnvPrefix("Baz")
   707  
   708  	testutil.Setenv(t, "BAZ_BAR", "13")
   709  
   710  	assert.Equal(t, "13", Get("bar"))
   711  }
   712  
   713  func TestSetEnvKeyReplacer(t *testing.T) {
   714  	Reset()
   715  
   716  	AutomaticEnv()
   717  
   718  	testutil.Setenv(t, "REFRESH_INTERVAL", "30s")
   719  
   720  	replacer := strings.NewReplacer("-", "_")
   721  	SetEnvKeyReplacer(replacer)
   722  
   723  	assert.Equal(t, "30s", Get("refresh-interval"))
   724  }
   725  
   726  func TestEnvKeyReplacer(t *testing.T) {
   727  	v := NewWithOptions(EnvKeyReplacer(strings.NewReplacer("-", "_")))
   728  
   729  	v.AutomaticEnv()
   730  
   731  	testutil.Setenv(t, "REFRESH_INTERVAL", "30s")
   732  
   733  	assert.Equal(t, "30s", v.Get("refresh-interval"))
   734  }
   735  
   736  func TestAllKeys(t *testing.T) {
   737  	initConfigs()
   738  
   739  	ks := sort.StringSlice{
   740  		"title",
   741  		"author.bio",
   742  		"author.e-mail",
   743  		"author.github",
   744  		"author.name",
   745  		"newkey",
   746  		"owner.organization",
   747  		"owner.dob",
   748  		"owner.bio",
   749  		"name",
   750  		"beard",
   751  		"ppu",
   752  		"batters.batter",
   753  		"hobbies",
   754  		"clothing.jacket",
   755  		"clothing.trousers",
   756  		"default.import_path",
   757  		"default.name",
   758  		"default.version",
   759  		"clothing.pants.size",
   760  		"age",
   761  		"hacker",
   762  		"id",
   763  		"type",
   764  		"eyes",
   765  		"p_id",
   766  		"p_ppu",
   767  		"p_batters.batter.type",
   768  		"p_type",
   769  		"p_name",
   770  		"foos",
   771  		"title_dotenv",
   772  		"type_dotenv",
   773  		"name_dotenv",
   774  	}
   775  	dob, _ := time.Parse(time.RFC3339, "1979-05-27T07:32:00Z")
   776  	all := map[string]interface{}{
   777  		"owner": map[string]interface{}{
   778  			"organization": "MongoDB",
   779  			"bio":          "MongoDB Chief Developer Advocate & Hacker at Large",
   780  			"dob":          dob,
   781  		},
   782  		"title": "TOML Example",
   783  		"author": map[string]interface{}{
   784  			"e-mail": "fake@localhost",
   785  			"github": "https://github.com/Unknown",
   786  			"name":   "Unknown",
   787  			"bio":    "Gopher.\nCoding addict.\nGood man.\n",
   788  		},
   789  		"ppu":  0.55,
   790  		"eyes": "brown",
   791  		"clothing": map[string]interface{}{
   792  			"trousers": "denim",
   793  			"jacket":   "leather",
   794  			"pants":    map[string]interface{}{"size": "large"},
   795  		},
   796  		"default": map[string]interface{}{
   797  			"import_path": "gopkg.in/ini.v1",
   798  			"name":        "ini",
   799  			"version":     "v1",
   800  		},
   801  		"id": "0001",
   802  		"batters": map[string]interface{}{
   803  			"batter": []interface{}{
   804  				map[string]interface{}{"type": "Regular"},
   805  				map[string]interface{}{"type": "Chocolate"},
   806  				map[string]interface{}{"type": "Blueberry"},
   807  				map[string]interface{}{"type": "Devil's Food"},
   808  			},
   809  		},
   810  		"hacker": true,
   811  		"beard":  true,
   812  		"hobbies": []interface{}{
   813  			"skateboarding",
   814  			"snowboarding",
   815  			"go",
   816  		},
   817  		"age":    35,
   818  		"type":   "donut",
   819  		"newkey": "remote",
   820  		"name":   "Cake",
   821  		"p_id":   "0001",
   822  		"p_ppu":  "0.55",
   823  		"p_name": "Cake",
   824  		"p_batters": map[string]interface{}{
   825  			"batter": map[string]interface{}{"type": "Regular"},
   826  		},
   827  		"p_type": "donut",
   828  		"foos": []map[string]interface{}{
   829  			{
   830  				"foo": []map[string]interface{}{
   831  					{"key": 1},
   832  					{"key": 2},
   833  					{"key": 3},
   834  					{"key": 4},
   835  				},
   836  			},
   837  		},
   838  		"title_dotenv": "DotEnv Example",
   839  		"type_dotenv":  "donut",
   840  		"name_dotenv":  "Cake",
   841  	}
   842  
   843  	allkeys := sort.StringSlice(AllKeys())
   844  	allkeys.Sort()
   845  	ks.Sort()
   846  
   847  	assert.Equal(t, ks, allkeys)
   848  	assert.Equal(t, all, AllSettings())
   849  }
   850  
   851  func TestAllKeysWithEnv(t *testing.T) {
   852  	v := New()
   853  
   854  	// bind and define environment variables (including a nested one)
   855  	v.BindEnv("id")
   856  	v.BindEnv("foo.bar")
   857  	v.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
   858  
   859  	testutil.Setenv(t, "ID", "13")
   860  	testutil.Setenv(t, "FOO_BAR", "baz")
   861  
   862  	expectedKeys := sort.StringSlice{"id", "foo.bar"}
   863  	expectedKeys.Sort()
   864  	keys := sort.StringSlice(v.AllKeys())
   865  	keys.Sort()
   866  	assert.Equal(t, expectedKeys, keys)
   867  }
   868  
   869  func TestAliasesOfAliases(t *testing.T) {
   870  	Set("Title", "Checking Case")
   871  	RegisterAlias("Foo", "Bar")
   872  	RegisterAlias("Bar", "Title")
   873  	assert.Equal(t, "Checking Case", Get("FOO"))
   874  }
   875  
   876  func TestRecursiveAliases(t *testing.T) {
   877  	RegisterAlias("Baz", "Roo")
   878  	RegisterAlias("Roo", "baz")
   879  }
   880  
   881  func TestUnmarshal(t *testing.T) {
   882  	SetDefault("port", 1313)
   883  	Set("name", "Steve")
   884  	Set("duration", "1s1ms")
   885  	Set("modes", []int{1, 2, 3})
   886  
   887  	type config struct {
   888  		Port     int
   889  		Name     string
   890  		Duration time.Duration
   891  		Modes    []int
   892  	}
   893  
   894  	var C config
   895  
   896  	err := Unmarshal(&C)
   897  	if err != nil {
   898  		t.Fatalf("unable to decode into struct, %v", err)
   899  	}
   900  
   901  	assert.Equal(
   902  		t,
   903  		&config{
   904  			Name:     "Steve",
   905  			Port:     1313,
   906  			Duration: time.Second + time.Millisecond,
   907  			Modes:    []int{1, 2, 3},
   908  		},
   909  		&C,
   910  	)
   911  
   912  	Set("port", 1234)
   913  	err = Unmarshal(&C)
   914  	if err != nil {
   915  		t.Fatalf("unable to decode into struct, %v", err)
   916  	}
   917  
   918  	assert.Equal(
   919  		t,
   920  		&config{
   921  			Name:     "Steve",
   922  			Port:     1234,
   923  			Duration: time.Second + time.Millisecond,
   924  			Modes:    []int{1, 2, 3},
   925  		},
   926  		&C,
   927  	)
   928  }
   929  
   930  func TestUnmarshalWithDecoderOptions(t *testing.T) {
   931  	Set("credentials", "{\"foo\":\"bar\"}")
   932  
   933  	opt := DecodeHook(mapstructure.ComposeDecodeHookFunc(
   934  		mapstructure.StringToTimeDurationHookFunc(),
   935  		mapstructure.StringToSliceHookFunc(","),
   936  		// Custom Decode Hook Function
   937  		func(rf reflect.Kind, rt reflect.Kind, data interface{}) (interface{}, error) {
   938  			if rf != reflect.String || rt != reflect.Map {
   939  				return data, nil
   940  			}
   941  			m := map[string]string{}
   942  			raw := data.(string)
   943  			if raw == "" {
   944  				return m, nil
   945  			}
   946  			return m, json.Unmarshal([]byte(raw), &m)
   947  		},
   948  	))
   949  
   950  	type config struct {
   951  		Credentials map[string]string
   952  	}
   953  
   954  	var C config
   955  
   956  	err := Unmarshal(&C, opt)
   957  	if err != nil {
   958  		t.Fatalf("unable to decode into struct, %v", err)
   959  	}
   960  
   961  	assert.Equal(t, &config{
   962  		Credentials: map[string]string{"foo": "bar"},
   963  	}, &C)
   964  }
   965  
   966  func TestBindPFlags(t *testing.T) {
   967  	v := New() // create independent Viper object
   968  	flagSet := pflag.NewFlagSet("test", pflag.ContinueOnError)
   969  
   970  	testValues := map[string]*string{
   971  		"host":     nil,
   972  		"port":     nil,
   973  		"endpoint": nil,
   974  	}
   975  
   976  	mutatedTestValues := map[string]string{
   977  		"host":     "localhost",
   978  		"port":     "6060",
   979  		"endpoint": "/public",
   980  	}
   981  
   982  	for name := range testValues {
   983  		testValues[name] = flagSet.String(name, "", "test")
   984  	}
   985  
   986  	err := v.BindPFlags(flagSet)
   987  	if err != nil {
   988  		t.Fatalf("error binding flag set, %v", err)
   989  	}
   990  
   991  	flagSet.VisitAll(func(flag *pflag.Flag) {
   992  		flag.Value.Set(mutatedTestValues[flag.Name])
   993  		flag.Changed = true
   994  	})
   995  
   996  	for name, expected := range mutatedTestValues {
   997  		assert.Equal(t, expected, v.Get(name))
   998  	}
   999  }
  1000  
  1001  // nolint: dupl
  1002  func TestBindPFlagsStringSlice(t *testing.T) {
  1003  	tests := []struct {
  1004  		Expected []string
  1005  		Value    string
  1006  	}{
  1007  		{[]string{}, ""},
  1008  		{[]string{"jeden"}, "jeden"},
  1009  		{[]string{"dwa", "trzy"}, "dwa,trzy"},
  1010  		{[]string{"cztery", "piec , szesc"}, "cztery,\"piec , szesc\""},
  1011  	}
  1012  
  1013  	v := New() // create independent Viper object
  1014  	defaultVal := []string{"default"}
  1015  	v.SetDefault("stringslice", defaultVal)
  1016  
  1017  	for _, testValue := range tests {
  1018  		flagSet := pflag.NewFlagSet("test", pflag.ContinueOnError)
  1019  		flagSet.StringSlice("stringslice", testValue.Expected, "test")
  1020  
  1021  		for _, changed := range []bool{true, false} {
  1022  			flagSet.VisitAll(func(f *pflag.Flag) {
  1023  				f.Value.Set(testValue.Value)
  1024  				f.Changed = changed
  1025  			})
  1026  
  1027  			err := v.BindPFlags(flagSet)
  1028  			if err != nil {
  1029  				t.Fatalf("error binding flag set, %v", err)
  1030  			}
  1031  
  1032  			type TestStr struct {
  1033  				StringSlice []string
  1034  			}
  1035  			val := &TestStr{}
  1036  			if err := v.Unmarshal(val); err != nil {
  1037  				t.Fatalf("%+#v cannot unmarshal: %s", testValue.Value, err)
  1038  			}
  1039  			if changed {
  1040  				assert.Equal(t, testValue.Expected, val.StringSlice)
  1041  				assert.Equal(t, testValue.Expected, v.Get("stringslice"))
  1042  			} else {
  1043  				assert.Equal(t, defaultVal, val.StringSlice)
  1044  			}
  1045  		}
  1046  	}
  1047  }
  1048  
  1049  // nolint: dupl
  1050  func TestBindPFlagsStringArray(t *testing.T) {
  1051  	tests := []struct {
  1052  		Expected []string
  1053  		Value    string
  1054  	}{
  1055  		{[]string{}, ""},
  1056  		{[]string{"jeden"}, "jeden"},
  1057  		{[]string{"dwa,trzy"}, "dwa,trzy"},
  1058  		{[]string{"cztery,\"piec , szesc\""}, "cztery,\"piec , szesc\""},
  1059  	}
  1060  
  1061  	v := New() // create independent Viper object
  1062  	defaultVal := []string{"default"}
  1063  	v.SetDefault("stringarray", defaultVal)
  1064  
  1065  	for _, testValue := range tests {
  1066  		flagSet := pflag.NewFlagSet("test", pflag.ContinueOnError)
  1067  		flagSet.StringArray("stringarray", testValue.Expected, "test")
  1068  
  1069  		for _, changed := range []bool{true, false} {
  1070  			flagSet.VisitAll(func(f *pflag.Flag) {
  1071  				f.Value.Set(testValue.Value)
  1072  				f.Changed = changed
  1073  			})
  1074  
  1075  			err := v.BindPFlags(flagSet)
  1076  			if err != nil {
  1077  				t.Fatalf("error binding flag set, %v", err)
  1078  			}
  1079  
  1080  			type TestStr struct {
  1081  				StringArray []string
  1082  			}
  1083  			val := &TestStr{}
  1084  			if err := v.Unmarshal(val); err != nil {
  1085  				t.Fatalf("%+#v cannot unmarshal: %s", testValue.Value, err)
  1086  			}
  1087  			if changed {
  1088  				assert.Equal(t, testValue.Expected, val.StringArray)
  1089  				assert.Equal(t, testValue.Expected, v.Get("stringarray"))
  1090  			} else {
  1091  				assert.Equal(t, defaultVal, val.StringArray)
  1092  			}
  1093  		}
  1094  	}
  1095  }
  1096  
  1097  // nolint: dupl
  1098  func TestBindPFlagsIntSlice(t *testing.T) {
  1099  	tests := []struct {
  1100  		Expected []int
  1101  		Value    string
  1102  	}{
  1103  		{[]int{}, ""},
  1104  		{[]int{1}, "1"},
  1105  		{[]int{2, 3}, "2,3"},
  1106  	}
  1107  
  1108  	v := New() // create independent Viper object
  1109  	defaultVal := []int{0}
  1110  	v.SetDefault("intslice", defaultVal)
  1111  
  1112  	for _, testValue := range tests {
  1113  		flagSet := pflag.NewFlagSet("test", pflag.ContinueOnError)
  1114  		flagSet.IntSlice("intslice", testValue.Expected, "test")
  1115  
  1116  		for _, changed := range []bool{true, false} {
  1117  			flagSet.VisitAll(func(f *pflag.Flag) {
  1118  				f.Value.Set(testValue.Value)
  1119  				f.Changed = changed
  1120  			})
  1121  
  1122  			err := v.BindPFlags(flagSet)
  1123  			if err != nil {
  1124  				t.Fatalf("error binding flag set, %v", err)
  1125  			}
  1126  
  1127  			type TestInt struct {
  1128  				IntSlice []int
  1129  			}
  1130  			val := &TestInt{}
  1131  			if err := v.Unmarshal(val); err != nil {
  1132  				t.Fatalf("%+#v cannot unmarshal: %s", testValue.Value, err)
  1133  			}
  1134  			if changed {
  1135  				assert.Equal(t, testValue.Expected, val.IntSlice)
  1136  				assert.Equal(t, testValue.Expected, v.Get("intslice"))
  1137  			} else {
  1138  				assert.Equal(t, defaultVal, val.IntSlice)
  1139  			}
  1140  		}
  1141  	}
  1142  }
  1143  
  1144  func TestBindPFlag(t *testing.T) {
  1145  	testString := "testing"
  1146  	testValue := newStringValue(testString, &testString)
  1147  
  1148  	flag := &pflag.Flag{
  1149  		Name:    "testflag",
  1150  		Value:   testValue,
  1151  		Changed: false,
  1152  	}
  1153  
  1154  	BindPFlag("testvalue", flag)
  1155  
  1156  	assert.Equal(t, testString, Get("testvalue"))
  1157  
  1158  	flag.Value.Set("testing_mutate")
  1159  	flag.Changed = true // hack for pflag usage
  1160  
  1161  	assert.Equal(t, "testing_mutate", Get("testvalue"))
  1162  }
  1163  
  1164  func TestBindPFlagDetectNilFlag(t *testing.T) {
  1165  	result := BindPFlag("testvalue", nil)
  1166  	assert.Error(t, result)
  1167  }
  1168  
  1169  func TestBindPFlagStringToString(t *testing.T) {
  1170  	tests := []struct {
  1171  		Expected map[string]string
  1172  		Value    string
  1173  	}{
  1174  		{map[string]string{}, ""},
  1175  		{map[string]string{"yo": "hi"}, "yo=hi"},
  1176  		{map[string]string{"yo": "hi", "oh": "hi=there"}, "yo=hi,oh=hi=there"},
  1177  		{map[string]string{"yo": ""}, "yo="},
  1178  		{map[string]string{"yo": "", "oh": "hi=there"}, "yo=,oh=hi=there"},
  1179  	}
  1180  
  1181  	v := New() // create independent Viper object
  1182  	defaultVal := map[string]string{}
  1183  	v.SetDefault("stringtostring", defaultVal)
  1184  
  1185  	for _, testValue := range tests {
  1186  		flagSet := pflag.NewFlagSet("test", pflag.ContinueOnError)
  1187  		flagSet.StringToString("stringtostring", testValue.Expected, "test")
  1188  
  1189  		for _, changed := range []bool{true, false} {
  1190  			flagSet.VisitAll(func(f *pflag.Flag) {
  1191  				f.Value.Set(testValue.Value)
  1192  				f.Changed = changed
  1193  			})
  1194  
  1195  			err := v.BindPFlags(flagSet)
  1196  			if err != nil {
  1197  				t.Fatalf("error binding flag set, %v", err)
  1198  			}
  1199  
  1200  			type TestMap struct {
  1201  				StringToString map[string]string
  1202  			}
  1203  			val := &TestMap{}
  1204  			if err := v.Unmarshal(val); err != nil {
  1205  				t.Fatalf("%+#v cannot unmarshal: %s", testValue.Value, err)
  1206  			}
  1207  			if changed {
  1208  				assert.Equal(t, testValue.Expected, val.StringToString)
  1209  			} else {
  1210  				assert.Equal(t, defaultVal, val.StringToString)
  1211  			}
  1212  		}
  1213  	}
  1214  }
  1215  
  1216  func TestBoundCaseSensitivity(t *testing.T) {
  1217  	assert.Equal(t, "brown", Get("eyes"))
  1218  
  1219  	BindEnv("eYEs", "TURTLE_EYES")
  1220  
  1221  	testutil.Setenv(t, "TURTLE_EYES", "blue")
  1222  
  1223  	assert.Equal(t, "blue", Get("eyes"))
  1224  
  1225  	testString := "green"
  1226  	testValue := newStringValue(testString, &testString)
  1227  
  1228  	flag := &pflag.Flag{
  1229  		Name:    "eyeballs",
  1230  		Value:   testValue,
  1231  		Changed: true,
  1232  	}
  1233  
  1234  	BindPFlag("eYEs", flag)
  1235  	assert.Equal(t, "green", Get("eyes"))
  1236  }
  1237  
  1238  func TestSizeInBytes(t *testing.T) {
  1239  	input := map[string]uint{
  1240  		"":               0,
  1241  		"b":              0,
  1242  		"12 bytes":       0,
  1243  		"200000000000gb": 0,
  1244  		"12 b":           12,
  1245  		"43 MB":          43 * (1 << 20),
  1246  		"10mb":           10 * (1 << 20),
  1247  		"1gb":            1 << 30,
  1248  	}
  1249  
  1250  	for str, expected := range input {
  1251  		assert.Equal(t, expected, parseSizeInBytes(str), str)
  1252  	}
  1253  }
  1254  
  1255  func TestFindsNestedKeys(t *testing.T) {
  1256  	initConfigs()
  1257  	dob, _ := time.Parse(time.RFC3339, "1979-05-27T07:32:00Z")
  1258  
  1259  	Set("super", map[string]interface{}{
  1260  		"deep": map[string]interface{}{
  1261  			"nested": "value",
  1262  		},
  1263  	})
  1264  
  1265  	expected := map[string]interface{}{
  1266  		"super": map[string]interface{}{
  1267  			"deep": map[string]interface{}{
  1268  				"nested": "value",
  1269  			},
  1270  		},
  1271  		"super.deep": map[string]interface{}{
  1272  			"nested": "value",
  1273  		},
  1274  		"super.deep.nested":  "value",
  1275  		"owner.organization": "MongoDB",
  1276  		"batters.batter": []interface{}{
  1277  			map[string]interface{}{
  1278  				"type": "Regular",
  1279  			},
  1280  			map[string]interface{}{
  1281  				"type": "Chocolate",
  1282  			},
  1283  			map[string]interface{}{
  1284  				"type": "Blueberry",
  1285  			},
  1286  			map[string]interface{}{
  1287  				"type": "Devil's Food",
  1288  			},
  1289  		},
  1290  		"hobbies": []interface{}{
  1291  			"skateboarding", "snowboarding", "go",
  1292  		},
  1293  		"TITLE_DOTENV": "DotEnv Example",
  1294  		"TYPE_DOTENV":  "donut",
  1295  		"NAME_DOTENV":  "Cake",
  1296  		"title":        "TOML Example",
  1297  		"newkey":       "remote",
  1298  		"batters": map[string]interface{}{
  1299  			"batter": []interface{}{
  1300  				map[string]interface{}{
  1301  					"type": "Regular",
  1302  				},
  1303  				map[string]interface{}{
  1304  					"type": "Chocolate",
  1305  				},
  1306  				map[string]interface{}{
  1307  					"type": "Blueberry",
  1308  				},
  1309  				map[string]interface{}{
  1310  					"type": "Devil's Food",
  1311  				},
  1312  			},
  1313  		},
  1314  		"eyes": "brown",
  1315  		"age":  35,
  1316  		"owner": map[string]interface{}{
  1317  			"organization": "MongoDB",
  1318  			"bio":          "MongoDB Chief Developer Advocate & Hacker at Large",
  1319  			"dob":          dob,
  1320  		},
  1321  		"owner.bio": "MongoDB Chief Developer Advocate & Hacker at Large",
  1322  		"type":      "donut",
  1323  		"id":        "0001",
  1324  		"name":      "Cake",
  1325  		"hacker":    true,
  1326  		"ppu":       0.55,
  1327  		"clothing": map[string]interface{}{
  1328  			"jacket":   "leather",
  1329  			"trousers": "denim",
  1330  			"pants": map[string]interface{}{
  1331  				"size": "large",
  1332  			},
  1333  		},
  1334  		"clothing.jacket":     "leather",
  1335  		"clothing.pants.size": "large",
  1336  		"clothing.trousers":   "denim",
  1337  		"owner.dob":           dob,
  1338  		"beard":               true,
  1339  		"foos": []map[string]interface{}{
  1340  			{
  1341  				"foo": []map[string]interface{}{
  1342  					{
  1343  						"key": 1,
  1344  					},
  1345  					{
  1346  						"key": 2,
  1347  					},
  1348  					{
  1349  						"key": 3,
  1350  					},
  1351  					{
  1352  						"key": 4,
  1353  					},
  1354  				},
  1355  			},
  1356  		},
  1357  	}
  1358  
  1359  	for key, expectedValue := range expected {
  1360  		assert.Equal(t, expectedValue, v.Get(key))
  1361  	}
  1362  }
  1363  
  1364  func TestReadBufConfig(t *testing.T) {
  1365  	v := New()
  1366  	v.SetConfigType("yaml")
  1367  	v.ReadConfig(bytes.NewBuffer(yamlExample))
  1368  	t.Log(v.AllKeys())
  1369  
  1370  	assert.True(t, v.InConfig("name"))
  1371  	assert.True(t, v.InConfig("clothing.jacket"))
  1372  	assert.False(t, v.InConfig("state"))
  1373  	assert.False(t, v.InConfig("clothing.hat"))
  1374  	assert.Equal(t, "steve", v.Get("name"))
  1375  	assert.Equal(t, []interface{}{"skateboarding", "snowboarding", "go"}, v.Get("hobbies"))
  1376  	assert.Equal(t, map[string]interface{}{"jacket": "leather", "trousers": "denim", "pants": map[string]interface{}{"size": "large"}}, v.Get("clothing"))
  1377  	assert.Equal(t, 35, v.Get("age"))
  1378  }
  1379  
  1380  func TestIsSet(t *testing.T) {
  1381  	v := New()
  1382  	v.SetConfigType("yaml")
  1383  
  1384  	/* config and defaults */
  1385  	v.ReadConfig(bytes.NewBuffer(yamlExample))
  1386  	v.SetDefault("clothing.shoes", "sneakers")
  1387  
  1388  	assert.True(t, v.IsSet("clothing"))
  1389  	assert.True(t, v.IsSet("clothing.jacket"))
  1390  	assert.False(t, v.IsSet("clothing.jackets"))
  1391  	assert.True(t, v.IsSet("clothing.shoes"))
  1392  
  1393  	/* state change */
  1394  	assert.False(t, v.IsSet("helloworld"))
  1395  	v.Set("helloworld", "fubar")
  1396  	assert.True(t, v.IsSet("helloworld"))
  1397  
  1398  	/* env */
  1399  	v.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
  1400  	v.BindEnv("eyes")
  1401  	v.BindEnv("foo")
  1402  	v.BindEnv("clothing.hat")
  1403  	v.BindEnv("clothing.hats")
  1404  
  1405  	testutil.Setenv(t, "FOO", "bar")
  1406  	testutil.Setenv(t, "CLOTHING_HAT", "bowler")
  1407  
  1408  	assert.True(t, v.IsSet("eyes"))           // in the config file
  1409  	assert.True(t, v.IsSet("foo"))            // in the environment
  1410  	assert.True(t, v.IsSet("clothing.hat"))   // in the environment
  1411  	assert.False(t, v.IsSet("clothing.hats")) // not defined
  1412  
  1413  	/* flags */
  1414  	flagset := pflag.NewFlagSet("testisset", pflag.ContinueOnError)
  1415  	flagset.Bool("foobaz", false, "foobaz")
  1416  	flagset.Bool("barbaz", false, "barbaz")
  1417  	foobaz, barbaz := flagset.Lookup("foobaz"), flagset.Lookup("barbaz")
  1418  	v.BindPFlag("foobaz", foobaz)
  1419  	v.BindPFlag("barbaz", barbaz)
  1420  	barbaz.Value.Set("true")
  1421  	barbaz.Changed = true // hack for pflag usage
  1422  
  1423  	assert.False(t, v.IsSet("foobaz"))
  1424  	assert.True(t, v.IsSet("barbaz"))
  1425  }
  1426  
  1427  func TestDirsSearch(t *testing.T) {
  1428  	root, config, cleanup := initDirs(t)
  1429  	defer cleanup()
  1430  
  1431  	v := New()
  1432  	v.SetConfigName(config)
  1433  	v.SetDefault(`key`, `default`)
  1434  
  1435  	entries, err := ioutil.ReadDir(root)
  1436  	assert.Nil(t, err)
  1437  	for _, e := range entries {
  1438  		if e.IsDir() {
  1439  			v.AddConfigPath(e.Name())
  1440  		}
  1441  	}
  1442  
  1443  	err = v.ReadInConfig()
  1444  	assert.Nil(t, err)
  1445  
  1446  	assert.Equal(t, `value is `+filepath.Base(v.configPaths[0]), v.GetString(`key`))
  1447  }
  1448  
  1449  func TestWrongDirsSearchNotFound(t *testing.T) {
  1450  	_, config, cleanup := initDirs(t)
  1451  	defer cleanup()
  1452  
  1453  	v := New()
  1454  	v.SetConfigName(config)
  1455  	v.SetDefault(`key`, `default`)
  1456  
  1457  	v.AddConfigPath(`whattayoutalkingbout`)
  1458  	v.AddConfigPath(`thispathaintthere`)
  1459  
  1460  	err := v.ReadInConfig()
  1461  	assert.Equal(t, reflect.TypeOf(ConfigFileNotFoundError{"", ""}), reflect.TypeOf(err))
  1462  
  1463  	// Even though config did not load and the error might have
  1464  	// been ignored by the client, the default still loads
  1465  	assert.Equal(t, `default`, v.GetString(`key`))
  1466  }
  1467  
  1468  func TestWrongDirsSearchNotFoundForMerge(t *testing.T) {
  1469  	_, config, cleanup := initDirs(t)
  1470  	defer cleanup()
  1471  
  1472  	v := New()
  1473  	v.SetConfigName(config)
  1474  	v.SetDefault(`key`, `default`)
  1475  
  1476  	v.AddConfigPath(`whattayoutalkingbout`)
  1477  	v.AddConfigPath(`thispathaintthere`)
  1478  
  1479  	err := v.MergeInConfig()
  1480  	assert.Equal(t, reflect.TypeOf(ConfigFileNotFoundError{"", ""}), reflect.TypeOf(err))
  1481  
  1482  	// Even though config did not load and the error might have
  1483  	// been ignored by the client, the default still loads
  1484  	assert.Equal(t, `default`, v.GetString(`key`))
  1485  }
  1486  
  1487  func TestSub(t *testing.T) {
  1488  	v := New()
  1489  	v.SetConfigType("yaml")
  1490  	v.ReadConfig(bytes.NewBuffer(yamlExample))
  1491  
  1492  	subv := v.Sub("clothing")
  1493  	assert.Equal(t, v.Get("clothing.pants.size"), subv.Get("pants.size"))
  1494  
  1495  	subv = v.Sub("clothing.pants")
  1496  	assert.Equal(t, v.Get("clothing.pants.size"), subv.Get("size"))
  1497  
  1498  	subv = v.Sub("clothing.pants.size")
  1499  	assert.Equal(t, (*Viper)(nil), subv)
  1500  
  1501  	subv = v.Sub("missing.key")
  1502  	assert.Equal(t, (*Viper)(nil), subv)
  1503  }
  1504  
  1505  var hclWriteExpected = []byte(`"foos" = {
  1506    "foo" = {
  1507      "key" = 1
  1508    }
  1509  
  1510    "foo" = {
  1511      "key" = 2
  1512    }
  1513  
  1514    "foo" = {
  1515      "key" = 3
  1516    }
  1517  
  1518    "foo" = {
  1519      "key" = 4
  1520    }
  1521  }
  1522  
  1523  "id" = "0001"
  1524  
  1525  "name" = "Cake"
  1526  
  1527  "ppu" = 0.55
  1528  
  1529  "type" = "donut"`)
  1530  
  1531  var jsonWriteExpected = []byte(`{
  1532    "batters": {
  1533      "batter": [
  1534        {
  1535          "type": "Regular"
  1536        },
  1537        {
  1538          "type": "Chocolate"
  1539        },
  1540        {
  1541          "type": "Blueberry"
  1542        },
  1543        {
  1544          "type": "Devil's Food"
  1545        }
  1546      ]
  1547    },
  1548    "id": "0001",
  1549    "name": "Cake",
  1550    "ppu": 0.55,
  1551    "type": "donut"
  1552  }`)
  1553  
  1554  var propertiesWriteExpected = []byte(`p_id = 0001
  1555  p_type = donut
  1556  p_name = Cake
  1557  p_ppu = 0.55
  1558  p_batters.batter.type = Regular
  1559  `)
  1560  
  1561  var yamlWriteExpected = []byte(`age: 35
  1562  beard: true
  1563  clothing:
  1564    jacket: leather
  1565    pants:
  1566      size: large
  1567    trousers: denim
  1568  eyes: brown
  1569  hacker: true
  1570  hobbies:
  1571  - skateboarding
  1572  - snowboarding
  1573  - go
  1574  name: steve
  1575  `)
  1576  
  1577  func TestWriteConfig(t *testing.T) {
  1578  	fs := afero.NewMemMapFs()
  1579  	testCases := map[string]struct {
  1580  		configName      string
  1581  		inConfigType    string
  1582  		outConfigType   string
  1583  		fileName        string
  1584  		input           []byte
  1585  		expectedContent []byte
  1586  	}{
  1587  		"hcl with file extension": {
  1588  			configName:      "c",
  1589  			inConfigType:    "hcl",
  1590  			outConfigType:   "hcl",
  1591  			fileName:        "c.hcl",
  1592  			input:           hclExample,
  1593  			expectedContent: hclWriteExpected,
  1594  		},
  1595  		"hcl without file extension": {
  1596  			configName:      "c",
  1597  			inConfigType:    "hcl",
  1598  			outConfigType:   "hcl",
  1599  			fileName:        "c",
  1600  			input:           hclExample,
  1601  			expectedContent: hclWriteExpected,
  1602  		},
  1603  		"hcl with file extension and mismatch type": {
  1604  			configName:      "c",
  1605  			inConfigType:    "hcl",
  1606  			outConfigType:   "json",
  1607  			fileName:        "c.hcl",
  1608  			input:           hclExample,
  1609  			expectedContent: hclWriteExpected,
  1610  		},
  1611  		"json with file extension": {
  1612  			configName:      "c",
  1613  			inConfigType:    "json",
  1614  			outConfigType:   "json",
  1615  			fileName:        "c.json",
  1616  			input:           jsonExample,
  1617  			expectedContent: jsonWriteExpected,
  1618  		},
  1619  		"json without file extension": {
  1620  			configName:      "c",
  1621  			inConfigType:    "json",
  1622  			outConfigType:   "json",
  1623  			fileName:        "c",
  1624  			input:           jsonExample,
  1625  			expectedContent: jsonWriteExpected,
  1626  		},
  1627  		"json with file extension and mismatch type": {
  1628  			configName:      "c",
  1629  			inConfigType:    "json",
  1630  			outConfigType:   "hcl",
  1631  			fileName:        "c.json",
  1632  			input:           jsonExample,
  1633  			expectedContent: jsonWriteExpected,
  1634  		},
  1635  		"properties with file extension": {
  1636  			configName:      "c",
  1637  			inConfigType:    "properties",
  1638  			outConfigType:   "properties",
  1639  			fileName:        "c.properties",
  1640  			input:           propertiesExample,
  1641  			expectedContent: propertiesWriteExpected,
  1642  		},
  1643  		"properties without file extension": {
  1644  			configName:      "c",
  1645  			inConfigType:    "properties",
  1646  			outConfigType:   "properties",
  1647  			fileName:        "c",
  1648  			input:           propertiesExample,
  1649  			expectedContent: propertiesWriteExpected,
  1650  		},
  1651  		"yaml with file extension": {
  1652  			configName:      "c",
  1653  			inConfigType:    "yaml",
  1654  			outConfigType:   "yaml",
  1655  			fileName:        "c.yaml",
  1656  			input:           yamlExample,
  1657  			expectedContent: yamlWriteExpected,
  1658  		},
  1659  		"yaml without file extension": {
  1660  			configName:      "c",
  1661  			inConfigType:    "yaml",
  1662  			outConfigType:   "yaml",
  1663  			fileName:        "c",
  1664  			input:           yamlExample,
  1665  			expectedContent: yamlWriteExpected,
  1666  		},
  1667  		"yaml with file extension and mismatch type": {
  1668  			configName:      "c",
  1669  			inConfigType:    "yaml",
  1670  			outConfigType:   "json",
  1671  			fileName:        "c.yaml",
  1672  			input:           yamlExample,
  1673  			expectedContent: yamlWriteExpected,
  1674  		},
  1675  	}
  1676  	for name, tc := range testCases {
  1677  		t.Run(name, func(t *testing.T) {
  1678  			v := New()
  1679  			v.SetFs(fs)
  1680  			v.SetConfigName(tc.fileName)
  1681  			v.SetConfigType(tc.inConfigType)
  1682  
  1683  			err := v.ReadConfig(bytes.NewBuffer(tc.input))
  1684  			if err != nil {
  1685  				t.Fatal(err)
  1686  			}
  1687  			v.SetConfigType(tc.outConfigType)
  1688  			if err := v.WriteConfigAs(tc.fileName); err != nil {
  1689  				t.Fatal(err)
  1690  			}
  1691  			read, err := afero.ReadFile(fs, tc.fileName)
  1692  			if err != nil {
  1693  				t.Fatal(err)
  1694  			}
  1695  			assert.Equal(t, tc.expectedContent, read)
  1696  		})
  1697  	}
  1698  }
  1699  
  1700  func TestWriteConfigTOML(t *testing.T) {
  1701  	fs := afero.NewMemMapFs()
  1702  
  1703  	testCases := map[string]struct {
  1704  		configName string
  1705  		configType string
  1706  		fileName   string
  1707  		input      []byte
  1708  	}{
  1709  		"with file extension": {
  1710  			configName: "c",
  1711  			configType: "toml",
  1712  			fileName:   "c.toml",
  1713  			input:      tomlExample,
  1714  		},
  1715  		"without file extension": {
  1716  			configName: "c",
  1717  			configType: "toml",
  1718  			fileName:   "c",
  1719  			input:      tomlExample,
  1720  		},
  1721  	}
  1722  	for name, tc := range testCases {
  1723  		t.Run(name, func(t *testing.T) {
  1724  			v := New()
  1725  			v.SetFs(fs)
  1726  			v.SetConfigName(tc.configName)
  1727  			v.SetConfigType(tc.configType)
  1728  			err := v.ReadConfig(bytes.NewBuffer(tc.input))
  1729  			if err != nil {
  1730  				t.Fatal(err)
  1731  			}
  1732  			if err := v.WriteConfigAs(tc.fileName); err != nil {
  1733  				t.Fatal(err)
  1734  			}
  1735  
  1736  			// The TOML String method does not order the contents.
  1737  			// Therefore, we must read the generated file and compare the data.
  1738  			v2 := New()
  1739  			v2.SetFs(fs)
  1740  			v2.SetConfigName(tc.configName)
  1741  			v2.SetConfigType(tc.configType)
  1742  			v2.SetConfigFile(tc.fileName)
  1743  			err = v2.ReadInConfig()
  1744  			if err != nil {
  1745  				t.Fatal(err)
  1746  			}
  1747  
  1748  			assert.Equal(t, v.GetString("title"), v2.GetString("title"))
  1749  			assert.Equal(t, v.GetString("owner.bio"), v2.GetString("owner.bio"))
  1750  			assert.Equal(t, v.GetString("owner.dob"), v2.GetString("owner.dob"))
  1751  			assert.Equal(t, v.GetString("owner.organization"), v2.GetString("owner.organization"))
  1752  		})
  1753  	}
  1754  }
  1755  
  1756  func TestWriteConfigDotEnv(t *testing.T) {
  1757  	fs := afero.NewMemMapFs()
  1758  	testCases := map[string]struct {
  1759  		configName string
  1760  		configType string
  1761  		fileName   string
  1762  		input      []byte
  1763  	}{
  1764  		"with file extension": {
  1765  			configName: "c",
  1766  			configType: "env",
  1767  			fileName:   "c.env",
  1768  			input:      dotenvExample,
  1769  		},
  1770  		"without file extension": {
  1771  			configName: "c",
  1772  			configType: "env",
  1773  			fileName:   "c",
  1774  			input:      dotenvExample,
  1775  		},
  1776  	}
  1777  	for name, tc := range testCases {
  1778  		t.Run(name, func(t *testing.T) {
  1779  			v := New()
  1780  			v.SetFs(fs)
  1781  			v.SetConfigName(tc.configName)
  1782  			v.SetConfigType(tc.configType)
  1783  			err := v.ReadConfig(bytes.NewBuffer(tc.input))
  1784  			if err != nil {
  1785  				t.Fatal(err)
  1786  			}
  1787  			if err := v.WriteConfigAs(tc.fileName); err != nil {
  1788  				t.Fatal(err)
  1789  			}
  1790  
  1791  			// The TOML String method does not order the contents.
  1792  			// Therefore, we must read the generated file and compare the data.
  1793  			v2 := New()
  1794  			v2.SetFs(fs)
  1795  			v2.SetConfigName(tc.configName)
  1796  			v2.SetConfigType(tc.configType)
  1797  			v2.SetConfigFile(tc.fileName)
  1798  			err = v2.ReadInConfig()
  1799  			if err != nil {
  1800  				t.Fatal(err)
  1801  			}
  1802  
  1803  			assert.Equal(t, v.GetString("title_dotenv"), v2.GetString("title_dotenv"))
  1804  			assert.Equal(t, v.GetString("type_dotenv"), v2.GetString("type_dotenv"))
  1805  			assert.Equal(t, v.GetString("kind_dotenv"), v2.GetString("kind_dotenv"))
  1806  		})
  1807  	}
  1808  }
  1809  
  1810  func TestSafeWriteConfig(t *testing.T) {
  1811  	v := New()
  1812  	fs := afero.NewMemMapFs()
  1813  	v.SetFs(fs)
  1814  	v.AddConfigPath("/test")
  1815  	v.SetConfigName("c")
  1816  	v.SetConfigType("yaml")
  1817  	require.NoError(t, v.ReadConfig(bytes.NewBuffer(yamlExample)))
  1818  	require.NoError(t, v.SafeWriteConfig())
  1819  	read, err := afero.ReadFile(fs, testutil.AbsFilePath(t, "/test/c.yaml"))
  1820  	require.NoError(t, err)
  1821  	assert.Equal(t, yamlWriteExpected, read)
  1822  }
  1823  
  1824  func TestSafeWriteConfigWithMissingConfigPath(t *testing.T) {
  1825  	v := New()
  1826  	fs := afero.NewMemMapFs()
  1827  	v.SetFs(fs)
  1828  	v.SetConfigName("c")
  1829  	v.SetConfigType("yaml")
  1830  	require.EqualError(t, v.SafeWriteConfig(), "missing configuration for 'configPath'")
  1831  }
  1832  
  1833  func TestSafeWriteConfigWithExistingFile(t *testing.T) {
  1834  	v := New()
  1835  	fs := afero.NewMemMapFs()
  1836  	fs.Create(testutil.AbsFilePath(t, "/test/c.yaml"))
  1837  	v.SetFs(fs)
  1838  	v.AddConfigPath("/test")
  1839  	v.SetConfigName("c")
  1840  	v.SetConfigType("yaml")
  1841  	err := v.SafeWriteConfig()
  1842  	require.Error(t, err)
  1843  	_, ok := err.(ConfigFileAlreadyExistsError)
  1844  	assert.True(t, ok, "Expected ConfigFileAlreadyExistsError")
  1845  }
  1846  
  1847  func TestSafeWriteAsConfig(t *testing.T) {
  1848  	v := New()
  1849  	fs := afero.NewMemMapFs()
  1850  	v.SetFs(fs)
  1851  	err := v.ReadConfig(bytes.NewBuffer(yamlExample))
  1852  	if err != nil {
  1853  		t.Fatal(err)
  1854  	}
  1855  	require.NoError(t, v.SafeWriteConfigAs("/test/c.yaml"))
  1856  	if _, err = afero.ReadFile(fs, "/test/c.yaml"); err != nil {
  1857  		t.Fatal(err)
  1858  	}
  1859  }
  1860  
  1861  func TestSafeWriteConfigAsWithExistingFile(t *testing.T) {
  1862  	v := New()
  1863  	fs := afero.NewMemMapFs()
  1864  	fs.Create("/test/c.yaml")
  1865  	v.SetFs(fs)
  1866  	err := v.SafeWriteConfigAs("/test/c.yaml")
  1867  	require.Error(t, err)
  1868  	_, ok := err.(ConfigFileAlreadyExistsError)
  1869  	assert.True(t, ok, "Expected ConfigFileAlreadyExistsError")
  1870  }
  1871  
  1872  func TestWriteHiddenFile(t *testing.T) {
  1873  	v := New()
  1874  	fs := afero.NewMemMapFs()
  1875  	fs.Create(testutil.AbsFilePath(t, "/test/.config"))
  1876  	v.SetFs(fs)
  1877  
  1878  	v.SetConfigName(".config")
  1879  	v.SetConfigType("yaml")
  1880  	v.AddConfigPath("/test")
  1881  
  1882  	err := v.ReadInConfig()
  1883  	require.NoError(t, err)
  1884  
  1885  	err = v.WriteConfig()
  1886  	require.NoError(t, err)
  1887  }
  1888  
  1889  var yamlMergeExampleTgt = []byte(`
  1890  hello:
  1891      pop: 37890
  1892      largenum: 765432101234567
  1893      num2pow63: 9223372036854775808
  1894      universe: null
  1895      world:
  1896      - us
  1897      - uk
  1898      - fr
  1899      - de
  1900  `)
  1901  
  1902  var yamlMergeExampleSrc = []byte(`
  1903  hello:
  1904      pop: 45000
  1905      largenum: 7654321001234567
  1906      universe:
  1907      - mw
  1908      - ad
  1909      ints:
  1910      - 1
  1911      - 2
  1912  fu: bar
  1913  `)
  1914  
  1915  func TestMergeConfig(t *testing.T) {
  1916  	v := New()
  1917  	v.SetConfigType("yml")
  1918  	if err := v.ReadConfig(bytes.NewBuffer(yamlMergeExampleTgt)); err != nil {
  1919  		t.Fatal(err)
  1920  	}
  1921  
  1922  	if pop := v.GetInt("hello.pop"); pop != 37890 {
  1923  		t.Fatalf("pop != 37890, = %d", pop)
  1924  	}
  1925  
  1926  	if pop := v.GetInt32("hello.pop"); pop != int32(37890) {
  1927  		t.Fatalf("pop != 37890, = %d", pop)
  1928  	}
  1929  
  1930  	if pop := v.GetInt64("hello.largenum"); pop != int64(765432101234567) {
  1931  		t.Fatalf("int64 largenum != 765432101234567, = %d", pop)
  1932  	}
  1933  
  1934  	if pop := v.GetUint("hello.pop"); pop != 37890 {
  1935  		t.Fatalf("uint pop != 37890, = %d", pop)
  1936  	}
  1937  
  1938  	if pop := v.GetUint32("hello.pop"); pop != 37890 {
  1939  		t.Fatalf("uint32 pop != 37890, = %d", pop)
  1940  	}
  1941  
  1942  	if pop := v.GetUint64("hello.num2pow63"); pop != 9223372036854775808 {
  1943  		t.Fatalf("uint64 num2pow63 != 9223372036854775808, = %d", pop)
  1944  	}
  1945  
  1946  	if world := v.GetStringSlice("hello.world"); len(world) != 4 {
  1947  		t.Fatalf("len(world) != 4, = %d", len(world))
  1948  	}
  1949  
  1950  	if fu := v.GetString("fu"); fu != "" {
  1951  		t.Fatalf("fu != \"\", = %s", fu)
  1952  	}
  1953  
  1954  	if err := v.MergeConfig(bytes.NewBuffer(yamlMergeExampleSrc)); err != nil {
  1955  		t.Fatal(err)
  1956  	}
  1957  
  1958  	if pop := v.GetInt("hello.pop"); pop != 45000 {
  1959  		t.Fatalf("pop != 45000, = %d", pop)
  1960  	}
  1961  
  1962  	if pop := v.GetInt32("hello.pop"); pop != int32(45000) {
  1963  		t.Fatalf("pop != 45000, = %d", pop)
  1964  	}
  1965  
  1966  	if pop := v.GetInt64("hello.largenum"); pop != int64(7654321001234567) {
  1967  		t.Fatalf("int64 largenum != 7654321001234567, = %d", pop)
  1968  	}
  1969  
  1970  	if world := v.GetStringSlice("hello.world"); len(world) != 4 {
  1971  		t.Fatalf("len(world) != 4, = %d", len(world))
  1972  	}
  1973  
  1974  	if universe := v.GetStringSlice("hello.universe"); len(universe) != 2 {
  1975  		t.Fatalf("len(universe) != 2, = %d", len(universe))
  1976  	}
  1977  
  1978  	if ints := v.GetIntSlice("hello.ints"); len(ints) != 2 {
  1979  		t.Fatalf("len(ints) != 2, = %d", len(ints))
  1980  	}
  1981  
  1982  	if fu := v.GetString("fu"); fu != "bar" {
  1983  		t.Fatalf("fu != \"bar\", = %s", fu)
  1984  	}
  1985  }
  1986  
  1987  func TestMergeConfigNoMerge(t *testing.T) {
  1988  	v := New()
  1989  	v.SetConfigType("yml")
  1990  	if err := v.ReadConfig(bytes.NewBuffer(yamlMergeExampleTgt)); err != nil {
  1991  		t.Fatal(err)
  1992  	}
  1993  
  1994  	if pop := v.GetInt("hello.pop"); pop != 37890 {
  1995  		t.Fatalf("pop != 37890, = %d", pop)
  1996  	}
  1997  
  1998  	if world := v.GetStringSlice("hello.world"); len(world) != 4 {
  1999  		t.Fatalf("len(world) != 4, = %d", len(world))
  2000  	}
  2001  
  2002  	if fu := v.GetString("fu"); fu != "" {
  2003  		t.Fatalf("fu != \"\", = %s", fu)
  2004  	}
  2005  
  2006  	if err := v.ReadConfig(bytes.NewBuffer(yamlMergeExampleSrc)); err != nil {
  2007  		t.Fatal(err)
  2008  	}
  2009  
  2010  	if pop := v.GetInt("hello.pop"); pop != 45000 {
  2011  		t.Fatalf("pop != 45000, = %d", pop)
  2012  	}
  2013  
  2014  	if world := v.GetStringSlice("hello.world"); len(world) != 0 {
  2015  		t.Fatalf("len(world) != 0, = %d", len(world))
  2016  	}
  2017  
  2018  	if universe := v.GetStringSlice("hello.universe"); len(universe) != 2 {
  2019  		t.Fatalf("len(universe) != 2, = %d", len(universe))
  2020  	}
  2021  
  2022  	if ints := v.GetIntSlice("hello.ints"); len(ints) != 2 {
  2023  		t.Fatalf("len(ints) != 2, = %d", len(ints))
  2024  	}
  2025  
  2026  	if fu := v.GetString("fu"); fu != "bar" {
  2027  		t.Fatalf("fu != \"bar\", = %s", fu)
  2028  	}
  2029  }
  2030  
  2031  func TestMergeConfigMap(t *testing.T) {
  2032  	v := New()
  2033  	v.SetConfigType("yml")
  2034  	if err := v.ReadConfig(bytes.NewBuffer(yamlMergeExampleTgt)); err != nil {
  2035  		t.Fatal(err)
  2036  	}
  2037  
  2038  	assert := func(i int) {
  2039  		large := v.GetInt64("hello.largenum")
  2040  		pop := v.GetInt("hello.pop")
  2041  		if large != 765432101234567 {
  2042  			t.Fatal("Got large num:", large)
  2043  		}
  2044  
  2045  		if pop != i {
  2046  			t.Fatal("Got pop:", pop)
  2047  		}
  2048  	}
  2049  
  2050  	assert(37890)
  2051  
  2052  	update := map[string]interface{}{
  2053  		"Hello": map[string]interface{}{
  2054  			"Pop": 1234,
  2055  		},
  2056  		"World": map[interface{}]interface{}{
  2057  			"Rock": 345,
  2058  		},
  2059  	}
  2060  
  2061  	if err := v.MergeConfigMap(update); err != nil {
  2062  		t.Fatal(err)
  2063  	}
  2064  
  2065  	if rock := v.GetInt("world.rock"); rock != 345 {
  2066  		t.Fatal("Got rock:", rock)
  2067  	}
  2068  
  2069  	assert(1234)
  2070  }
  2071  
  2072  func TestUnmarshalingWithAliases(t *testing.T) {
  2073  	v := New()
  2074  	v.SetDefault("ID", 1)
  2075  	v.Set("name", "Steve")
  2076  	v.Set("lastname", "Owen")
  2077  
  2078  	v.RegisterAlias("UserID", "ID")
  2079  	v.RegisterAlias("Firstname", "name")
  2080  	v.RegisterAlias("Surname", "lastname")
  2081  
  2082  	type config struct {
  2083  		ID        int
  2084  		FirstName string
  2085  		Surname   string
  2086  	}
  2087  
  2088  	var C config
  2089  	err := v.Unmarshal(&C)
  2090  	if err != nil {
  2091  		t.Fatalf("unable to decode into struct, %v", err)
  2092  	}
  2093  
  2094  	assert.Equal(t, &config{ID: 1, FirstName: "Steve", Surname: "Owen"}, &C)
  2095  }
  2096  
  2097  func TestSetConfigNameClearsFileCache(t *testing.T) {
  2098  	SetConfigFile("/tmp/config.yaml")
  2099  	SetConfigName("default")
  2100  	f, err := v.getConfigFile()
  2101  	if err == nil {
  2102  		t.Fatalf("config file cache should have been cleared")
  2103  	}
  2104  	assert.Empty(t, f)
  2105  }
  2106  
  2107  func TestShadowedNestedValue(t *testing.T) {
  2108  	config := `name: steve
  2109  clothing:
  2110    jacket: leather
  2111    trousers: denim
  2112    pants:
  2113      size: large
  2114  `
  2115  	initConfig("yaml", config)
  2116  
  2117  	assert.Equal(t, "steve", GetString("name"))
  2118  
  2119  	polyester := "polyester"
  2120  	SetDefault("clothing.shirt", polyester)
  2121  	SetDefault("clothing.jacket.price", 100)
  2122  
  2123  	assert.Equal(t, "leather", GetString("clothing.jacket"))
  2124  	assert.Nil(t, Get("clothing.jacket.price"))
  2125  	assert.Equal(t, polyester, GetString("clothing.shirt"))
  2126  
  2127  	clothingSettings := AllSettings()["clothing"].(map[string]interface{})
  2128  	assert.Equal(t, "leather", clothingSettings["jacket"])
  2129  	assert.Equal(t, polyester, clothingSettings["shirt"])
  2130  }
  2131  
  2132  func TestDotParameter(t *testing.T) {
  2133  	initJSON()
  2134  	// shoud take precedence over batters defined in jsonExample
  2135  	r := bytes.NewReader([]byte(`{ "batters.batter": [ { "type": "Small" } ] }`))
  2136  	unmarshalReader(r, v.config)
  2137  
  2138  	actual := Get("batters.batter")
  2139  	expected := []interface{}{map[string]interface{}{"type": "Small"}}
  2140  	assert.Equal(t, expected, actual)
  2141  }
  2142  
  2143  func TestCaseInsensitive(t *testing.T) {
  2144  	for _, config := range []struct {
  2145  		typ     string
  2146  		content string
  2147  	}{
  2148  		{"yaml", `
  2149  aBcD: 1
  2150  eF:
  2151    gH: 2
  2152    iJk: 3
  2153    Lm:
  2154      nO: 4
  2155      P:
  2156        Q: 5
  2157        R: 6
  2158  `},
  2159  		{"json", `{
  2160    "aBcD": 1,
  2161    "eF": {
  2162      "iJk": 3,
  2163      "Lm": {
  2164        "P": {
  2165          "Q": 5,
  2166          "R": 6
  2167        },
  2168        "nO": 4
  2169      },
  2170      "gH": 2
  2171    }
  2172  }`},
  2173  		{"toml", `aBcD = 1
  2174  [eF]
  2175  gH = 2
  2176  iJk = 3
  2177  [eF.Lm]
  2178  nO = 4
  2179  [eF.Lm.P]
  2180  Q = 5
  2181  R = 6
  2182  `},
  2183  	} {
  2184  		doTestCaseInsensitive(t, config.typ, config.content)
  2185  	}
  2186  }
  2187  
  2188  func TestCaseInsensitiveSet(t *testing.T) {
  2189  	Reset()
  2190  	m1 := map[string]interface{}{
  2191  		"Foo": 32,
  2192  		"Bar": map[interface{}]interface{}{
  2193  			"ABc": "A",
  2194  			"cDE": "B",
  2195  		},
  2196  	}
  2197  
  2198  	m2 := map[string]interface{}{
  2199  		"Foo": 52,
  2200  		"Bar": map[interface{}]interface{}{
  2201  			"bCd": "A",
  2202  			"eFG": "B",
  2203  		},
  2204  	}
  2205  
  2206  	Set("Given1", m1)
  2207  	Set("Number1", 42)
  2208  
  2209  	SetDefault("Given2", m2)
  2210  	SetDefault("Number2", 52)
  2211  
  2212  	// Verify SetDefault
  2213  	if v := Get("number2"); v != 52 {
  2214  		t.Fatalf("Expected 52 got %q", v)
  2215  	}
  2216  
  2217  	if v := Get("given2.foo"); v != 52 {
  2218  		t.Fatalf("Expected 52 got %q", v)
  2219  	}
  2220  
  2221  	if v := Get("given2.bar.bcd"); v != "A" {
  2222  		t.Fatalf("Expected A got %q", v)
  2223  	}
  2224  
  2225  	if _, ok := m2["Foo"]; !ok {
  2226  		t.Fatal("Input map changed")
  2227  	}
  2228  
  2229  	// Verify Set
  2230  	if v := Get("number1"); v != 42 {
  2231  		t.Fatalf("Expected 42 got %q", v)
  2232  	}
  2233  
  2234  	if v := Get("given1.foo"); v != 32 {
  2235  		t.Fatalf("Expected 32 got %q", v)
  2236  	}
  2237  
  2238  	if v := Get("given1.bar.abc"); v != "A" {
  2239  		t.Fatalf("Expected A got %q", v)
  2240  	}
  2241  
  2242  	if _, ok := m1["Foo"]; !ok {
  2243  		t.Fatal("Input map changed")
  2244  	}
  2245  }
  2246  
  2247  func TestParseNested(t *testing.T) {
  2248  	type duration struct {
  2249  		Delay time.Duration
  2250  	}
  2251  
  2252  	type item struct {
  2253  		Name   string
  2254  		Delay  time.Duration
  2255  		Nested duration
  2256  	}
  2257  
  2258  	config := `[[parent]]
  2259  	delay="100ms"
  2260  	[parent.nested]
  2261  	delay="200ms"
  2262  `
  2263  	initConfig("toml", config)
  2264  
  2265  	var items []item
  2266  	err := v.UnmarshalKey("parent", &items)
  2267  	if err != nil {
  2268  		t.Fatalf("unable to decode into struct, %v", err)
  2269  	}
  2270  
  2271  	assert.Equal(t, 1, len(items))
  2272  	assert.Equal(t, 100*time.Millisecond, items[0].Delay)
  2273  	assert.Equal(t, 200*time.Millisecond, items[0].Nested.Delay)
  2274  }
  2275  
  2276  func doTestCaseInsensitive(t *testing.T, typ, config string) {
  2277  	initConfig(typ, config)
  2278  	Set("RfD", true)
  2279  	assert.Equal(t, true, Get("rfd"))
  2280  	assert.Equal(t, true, Get("rFD"))
  2281  	assert.Equal(t, 1, cast.ToInt(Get("abcd")))
  2282  	assert.Equal(t, 1, cast.ToInt(Get("Abcd")))
  2283  	assert.Equal(t, 2, cast.ToInt(Get("ef.gh")))
  2284  	assert.Equal(t, 3, cast.ToInt(Get("ef.ijk")))
  2285  	assert.Equal(t, 4, cast.ToInt(Get("ef.lm.no")))
  2286  	assert.Equal(t, 5, cast.ToInt(Get("ef.lm.p.q")))
  2287  }
  2288  
  2289  func newViperWithConfigFile(t *testing.T) (*Viper, string, func()) {
  2290  	watchDir, err := ioutil.TempDir("", "")
  2291  	require.Nil(t, err)
  2292  	configFile := path.Join(watchDir, "config.yaml")
  2293  	err = ioutil.WriteFile(configFile, []byte("foo: bar\n"), 0o640)
  2294  	require.Nil(t, err)
  2295  	cleanup := func() {
  2296  		os.RemoveAll(watchDir)
  2297  	}
  2298  	v := New()
  2299  	v.SetConfigFile(configFile)
  2300  	err = v.ReadInConfig()
  2301  	require.Nil(t, err)
  2302  	require.Equal(t, "bar", v.Get("foo"))
  2303  	return v, configFile, cleanup
  2304  }
  2305  
  2306  func newViperWithSymlinkedConfigFile(t *testing.T) (*Viper, string, string, func()) {
  2307  	watchDir, err := ioutil.TempDir("", "")
  2308  	require.Nil(t, err)
  2309  	dataDir1 := path.Join(watchDir, "data1")
  2310  	err = os.Mkdir(dataDir1, 0o777)
  2311  	require.Nil(t, err)
  2312  	realConfigFile := path.Join(dataDir1, "config.yaml")
  2313  	t.Logf("Real config file location: %s\n", realConfigFile)
  2314  	err = ioutil.WriteFile(realConfigFile, []byte("foo: bar\n"), 0o640)
  2315  	require.Nil(t, err)
  2316  	cleanup := func() {
  2317  		os.RemoveAll(watchDir)
  2318  	}
  2319  	// now, symlink the tm `data1` dir to `data` in the baseDir
  2320  	os.Symlink(dataDir1, path.Join(watchDir, "data"))
  2321  	// and link the `<watchdir>/datadir1/config.yaml` to `<watchdir>/config.yaml`
  2322  	configFile := path.Join(watchDir, "config.yaml")
  2323  	os.Symlink(path.Join(watchDir, "data", "config.yaml"), configFile)
  2324  	t.Logf("Config file location: %s\n", path.Join(watchDir, "config.yaml"))
  2325  	// init Viper
  2326  	v := New()
  2327  	v.SetConfigFile(configFile)
  2328  	err = v.ReadInConfig()
  2329  	require.Nil(t, err)
  2330  	require.Equal(t, "bar", v.Get("foo"))
  2331  	return v, watchDir, configFile, cleanup
  2332  }
  2333  
  2334  func TestWatchFile(t *testing.T) {
  2335  	if runtime.GOOS == "linux" {
  2336  		// TODO(bep) FIX ME
  2337  		t.Skip("Skip test on Linux ...")
  2338  	}
  2339  
  2340  	t.Run("file content changed", func(t *testing.T) {
  2341  		// given a `config.yaml` file being watched
  2342  		v, configFile, cleanup := newViperWithConfigFile(t)
  2343  		defer cleanup()
  2344  		_, err := os.Stat(configFile)
  2345  		require.NoError(t, err)
  2346  		t.Logf("test config file: %s\n", configFile)
  2347  		wg := sync.WaitGroup{}
  2348  		wg.Add(1)
  2349  		var wgDoneOnce sync.Once // OnConfigChange is called twice on Windows
  2350  		v.OnConfigChange(func(in fsnotify.Event) {
  2351  			t.Logf("config file changed")
  2352  			wgDoneOnce.Do(func() {
  2353  				wg.Done()
  2354  			})
  2355  		})
  2356  		v.WatchConfig()
  2357  		// when overwriting the file and waiting for the custom change notification handler to be triggered
  2358  		err = ioutil.WriteFile(configFile, []byte("foo: baz\n"), 0o640)
  2359  		wg.Wait()
  2360  		// then the config value should have changed
  2361  		require.Nil(t, err)
  2362  		assert.Equal(t, "baz", v.Get("foo"))
  2363  	})
  2364  
  2365  	t.Run("link to real file changed (à la Kubernetes)", func(t *testing.T) {
  2366  		// skip if not executed on Linux
  2367  		if runtime.GOOS != "linux" {
  2368  			t.Skipf("Skipping test as symlink replacements don't work on non-linux environment...")
  2369  		}
  2370  		v, watchDir, _, _ := newViperWithSymlinkedConfigFile(t)
  2371  		// defer cleanup()
  2372  		wg := sync.WaitGroup{}
  2373  		v.WatchConfig()
  2374  		v.OnConfigChange(func(in fsnotify.Event) {
  2375  			t.Logf("config file changed")
  2376  			wg.Done()
  2377  		})
  2378  		wg.Add(1)
  2379  		// when link to another `config.yaml` file
  2380  		dataDir2 := path.Join(watchDir, "data2")
  2381  		err := os.Mkdir(dataDir2, 0o777)
  2382  		require.Nil(t, err)
  2383  		configFile2 := path.Join(dataDir2, "config.yaml")
  2384  		err = ioutil.WriteFile(configFile2, []byte("foo: baz\n"), 0o640)
  2385  		require.Nil(t, err)
  2386  		// change the symlink using the `ln -sfn` command
  2387  		err = exec.Command("ln", "-sfn", dataDir2, path.Join(watchDir, "data")).Run()
  2388  		require.Nil(t, err)
  2389  		wg.Wait()
  2390  		// then
  2391  		require.Nil(t, err)
  2392  		assert.Equal(t, "baz", v.Get("foo"))
  2393  	})
  2394  }
  2395  
  2396  func TestUnmarshal_DotSeparatorBackwardCompatibility(t *testing.T) {
  2397  	flags := pflag.NewFlagSet("test", pflag.ContinueOnError)
  2398  	flags.String("foo.bar", "cobra_flag", "")
  2399  
  2400  	v := New()
  2401  	assert.NoError(t, v.BindPFlags(flags))
  2402  
  2403  	config := &struct {
  2404  		Foo struct {
  2405  			Bar string
  2406  		}
  2407  	}{}
  2408  
  2409  	assert.NoError(t, v.Unmarshal(config))
  2410  	assert.Equal(t, "cobra_flag", config.Foo.Bar)
  2411  }
  2412  
  2413  var yamlExampleWithDot = []byte(`Hacker: true
  2414  name: steve
  2415  hobbies:
  2416    - skateboarding
  2417    - snowboarding
  2418    - go
  2419  clothing:
  2420    jacket: leather
  2421    trousers: denim
  2422    pants:
  2423      size: large
  2424  age: 35
  2425  eyes : brown
  2426  beard: true
  2427  emails:
  2428    steve@hacker.com:
  2429      created: 01/02/03
  2430      active: true
  2431  `)
  2432  
  2433  func TestKeyDelimiter(t *testing.T) {
  2434  	v := NewWithOptions(KeyDelimiter("::"))
  2435  	v.SetConfigType("yaml")
  2436  	r := strings.NewReader(string(yamlExampleWithDot))
  2437  
  2438  	err := v.unmarshalReader(r, v.config)
  2439  	require.NoError(t, err)
  2440  
  2441  	values := map[string]interface{}{
  2442  		"image": map[string]interface{}{
  2443  			"repository": "someImage",
  2444  			"tag":        "1.0.0",
  2445  		},
  2446  		"ingress": map[string]interface{}{
  2447  			"annotations": map[string]interface{}{
  2448  				"traefik.frontend.rule.type":                 "PathPrefix",
  2449  				"traefik.ingress.kubernetes.io/ssl-redirect": "true",
  2450  			},
  2451  		},
  2452  	}
  2453  
  2454  	v.SetDefault("charts::values", values)
  2455  
  2456  	assert.Equal(t, "leather", v.GetString("clothing::jacket"))
  2457  	assert.Equal(t, "01/02/03", v.GetString("emails::steve@hacker.com::created"))
  2458  
  2459  	type config struct {
  2460  		Charts struct {
  2461  			Values map[string]interface{}
  2462  		}
  2463  	}
  2464  
  2465  	expected := config{
  2466  		Charts: struct {
  2467  			Values map[string]interface{}
  2468  		}{
  2469  			Values: values,
  2470  		},
  2471  	}
  2472  
  2473  	var actual config
  2474  
  2475  	assert.NoError(t, v.Unmarshal(&actual))
  2476  
  2477  	assert.Equal(t, expected, actual)
  2478  }
  2479  
  2480  var yamlDeepNestedSlices = []byte(`TV:
  2481  - title: "The expanse"
  2482    seasons:
  2483    - first_released: "December 14, 2015"
  2484      episodes:
  2485      - title: "Dulcinea"
  2486        air_date: "December 14, 2015"
  2487      - title: "The Big Empty"
  2488        air_date: "December 15, 2015"
  2489      - title: "Remember the Cant"
  2490        air_date: "December 22, 2015"
  2491    - first_released: "February 1, 2017"
  2492      episodes:
  2493      - title: "Safe"
  2494        air_date: "February 1, 2017"
  2495      - title: "Doors & Corners"
  2496        air_date: "February 1, 2017"
  2497      - title: "Static"
  2498        air_date: "February 8, 2017"
  2499    episodes:
  2500      - ["Dulcinea", "The Big Empty", "Remember the Cant"]
  2501      - ["Safe", "Doors & Corners", "Static"]
  2502  `)
  2503  
  2504  func TestSliceIndexAccess(t *testing.T) {
  2505  	v.SetConfigType("yaml")
  2506  	r := strings.NewReader(string(yamlDeepNestedSlices))
  2507  
  2508  	err := v.unmarshalReader(r, v.config)
  2509  	require.NoError(t, err)
  2510  
  2511  	assert.Equal(t, "The expanse", v.GetString("tv.0.title"))
  2512  	assert.Equal(t, "February 1, 2017", v.GetString("tv.0.seasons.1.first_released"))
  2513  	assert.Equal(t, "Static", v.GetString("tv.0.seasons.1.episodes.2.title"))
  2514  	assert.Equal(t, "December 15, 2015", v.GetString("tv.0.seasons.0.episodes.1.air_date"))
  2515  
  2516  	// Test for index out of bounds
  2517  	assert.Equal(t, "", v.GetString("tv.0.seasons.2.first_released"))
  2518  
  2519  	// Accessing multidimensional arrays
  2520  	assert.Equal(t, "Static", v.GetString("tv.0.episodes.1.2"))
  2521  }
  2522  
  2523  func BenchmarkGetBool(b *testing.B) {
  2524  	key := "BenchmarkGetBool"
  2525  	v = New()
  2526  	v.Set(key, true)
  2527  
  2528  	for i := 0; i < b.N; i++ {
  2529  		if !v.GetBool(key) {
  2530  			b.Fatal("GetBool returned false")
  2531  		}
  2532  	}
  2533  }
  2534  
  2535  func BenchmarkGet(b *testing.B) {
  2536  	key := "BenchmarkGet"
  2537  	v = New()
  2538  	v.Set(key, true)
  2539  
  2540  	for i := 0; i < b.N; i++ {
  2541  		if !v.Get(key).(bool) {
  2542  			b.Fatal("Get returned false")
  2543  		}
  2544  	}
  2545  }
  2546  
  2547  // BenchmarkGetBoolFromMap is the "perfect result" for the above.
  2548  func BenchmarkGetBoolFromMap(b *testing.B) {
  2549  	m := make(map[string]bool)
  2550  	key := "BenchmarkGetBool"
  2551  	m[key] = true
  2552  
  2553  	for i := 0; i < b.N; i++ {
  2554  		if !m[key] {
  2555  			b.Fatal("Map value was false")
  2556  		}
  2557  	}
  2558  }
  2559  
  2560  // Skip some tests on Windows that kept failing when Windows was added to the CI as a target.
  2561  func skipWindows(t *testing.T) {
  2562  	if runtime.GOOS == "windows" {
  2563  		t.Skip("Skip test on Windows")
  2564  	}
  2565  }