github.com/gozelle/viper@v1.14.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" //nolint:staticcheck
    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/gozelle/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  var jsonMergeExampleTgt = []byte(`
  1916  {
  1917  	"hello": {
  1918  		"foo": null,
  1919  		"pop": 123456
  1920  	}
  1921  }
  1922  `)
  1923  
  1924  var jsonMergeExampleSrc = []byte(`
  1925  {
  1926  	"hello": {
  1927  		"foo": "foo str",
  1928  		"pop": "pop str"
  1929  	}
  1930  }
  1931  `)
  1932  
  1933  func TestMergeConfig(t *testing.T) {
  1934  	v := New()
  1935  	v.SetConfigType("yml")
  1936  	if err := v.ReadConfig(bytes.NewBuffer(yamlMergeExampleTgt)); err != nil {
  1937  		t.Fatal(err)
  1938  	}
  1939  	
  1940  	if pop := v.GetInt("hello.pop"); pop != 37890 {
  1941  		t.Fatalf("pop != 37890, = %d", pop)
  1942  	}
  1943  	
  1944  	if pop := v.GetInt32("hello.pop"); pop != int32(37890) {
  1945  		t.Fatalf("pop != 37890, = %d", pop)
  1946  	}
  1947  	
  1948  	if pop := v.GetInt64("hello.largenum"); pop != int64(765432101234567) {
  1949  		t.Fatalf("int64 largenum != 765432101234567, = %d", pop)
  1950  	}
  1951  	
  1952  	if pop := v.GetUint("hello.pop"); pop != 37890 {
  1953  		t.Fatalf("uint pop != 37890, = %d", pop)
  1954  	}
  1955  	
  1956  	if pop := v.GetUint16("hello.pop"); pop != uint16(37890) {
  1957  		t.Fatalf("uint pop != 37890, = %d", pop)
  1958  	}
  1959  	
  1960  	if pop := v.GetUint32("hello.pop"); pop != 37890 {
  1961  		t.Fatalf("uint32 pop != 37890, = %d", pop)
  1962  	}
  1963  	
  1964  	if pop := v.GetUint64("hello.num2pow63"); pop != 9223372036854775808 {
  1965  		t.Fatalf("uint64 num2pow63 != 9223372036854775808, = %d", pop)
  1966  	}
  1967  	
  1968  	if world := v.GetStringSlice("hello.world"); len(world) != 4 {
  1969  		t.Fatalf("len(world) != 4, = %d", len(world))
  1970  	}
  1971  	
  1972  	if fu := v.GetString("fu"); fu != "" {
  1973  		t.Fatalf("fu != \"\", = %s", fu)
  1974  	}
  1975  	
  1976  	if err := v.MergeConfig(bytes.NewBuffer(yamlMergeExampleSrc)); err != nil {
  1977  		t.Fatal(err)
  1978  	}
  1979  	
  1980  	if pop := v.GetInt("hello.pop"); pop != 45000 {
  1981  		t.Fatalf("pop != 45000, = %d", pop)
  1982  	}
  1983  	
  1984  	if pop := v.GetInt32("hello.pop"); pop != int32(45000) {
  1985  		t.Fatalf("pop != 45000, = %d", pop)
  1986  	}
  1987  	
  1988  	if pop := v.GetInt64("hello.largenum"); pop != int64(7654321001234567) {
  1989  		t.Fatalf("int64 largenum != 7654321001234567, = %d", pop)
  1990  	}
  1991  	
  1992  	if world := v.GetStringSlice("hello.world"); len(world) != 4 {
  1993  		t.Fatalf("len(world) != 4, = %d", len(world))
  1994  	}
  1995  	
  1996  	if universe := v.GetStringSlice("hello.universe"); len(universe) != 2 {
  1997  		t.Fatalf("len(universe) != 2, = %d", len(universe))
  1998  	}
  1999  	
  2000  	if ints := v.GetIntSlice("hello.ints"); len(ints) != 2 {
  2001  		t.Fatalf("len(ints) != 2, = %d", len(ints))
  2002  	}
  2003  	
  2004  	if fu := v.GetString("fu"); fu != "bar" {
  2005  		t.Fatalf("fu != \"bar\", = %s", fu)
  2006  	}
  2007  }
  2008  
  2009  func TestMergeConfigOverrideType(t *testing.T) {
  2010  	v := New()
  2011  	v.SetConfigType("json")
  2012  	if err := v.ReadConfig(bytes.NewBuffer(jsonMergeExampleTgt)); err != nil {
  2013  		t.Fatal(err)
  2014  	}
  2015  	
  2016  	if err := v.MergeConfig(bytes.NewBuffer(jsonMergeExampleSrc)); err != nil {
  2017  		t.Fatal(err)
  2018  	}
  2019  	
  2020  	if pop := v.GetString("hello.pop"); pop != "pop str" {
  2021  		t.Fatalf("pop != \"pop str\", = %s", pop)
  2022  	}
  2023  	
  2024  	if foo := v.GetString("hello.foo"); foo != "foo str" {
  2025  		t.Fatalf("foo != \"foo str\", = %s", foo)
  2026  	}
  2027  }
  2028  
  2029  func TestMergeConfigNoMerge(t *testing.T) {
  2030  	v := New()
  2031  	v.SetConfigType("yml")
  2032  	if err := v.ReadConfig(bytes.NewBuffer(yamlMergeExampleTgt)); err != nil {
  2033  		t.Fatal(err)
  2034  	}
  2035  	
  2036  	if pop := v.GetInt("hello.pop"); pop != 37890 {
  2037  		t.Fatalf("pop != 37890, = %d", pop)
  2038  	}
  2039  	
  2040  	if world := v.GetStringSlice("hello.world"); len(world) != 4 {
  2041  		t.Fatalf("len(world) != 4, = %d", len(world))
  2042  	}
  2043  	
  2044  	if fu := v.GetString("fu"); fu != "" {
  2045  		t.Fatalf("fu != \"\", = %s", fu)
  2046  	}
  2047  	
  2048  	if err := v.ReadConfig(bytes.NewBuffer(yamlMergeExampleSrc)); err != nil {
  2049  		t.Fatal(err)
  2050  	}
  2051  	
  2052  	if pop := v.GetInt("hello.pop"); pop != 45000 {
  2053  		t.Fatalf("pop != 45000, = %d", pop)
  2054  	}
  2055  	
  2056  	if world := v.GetStringSlice("hello.world"); len(world) != 0 {
  2057  		t.Fatalf("len(world) != 0, = %d", len(world))
  2058  	}
  2059  	
  2060  	if universe := v.GetStringSlice("hello.universe"); len(universe) != 2 {
  2061  		t.Fatalf("len(universe) != 2, = %d", len(universe))
  2062  	}
  2063  	
  2064  	if ints := v.GetIntSlice("hello.ints"); len(ints) != 2 {
  2065  		t.Fatalf("len(ints) != 2, = %d", len(ints))
  2066  	}
  2067  	
  2068  	if fu := v.GetString("fu"); fu != "bar" {
  2069  		t.Fatalf("fu != \"bar\", = %s", fu)
  2070  	}
  2071  }
  2072  
  2073  func TestMergeConfigMap(t *testing.T) {
  2074  	v := New()
  2075  	v.SetConfigType("yml")
  2076  	if err := v.ReadConfig(bytes.NewBuffer(yamlMergeExampleTgt)); err != nil {
  2077  		t.Fatal(err)
  2078  	}
  2079  	
  2080  	assert := func(i int) {
  2081  		large := v.GetInt64("hello.largenum")
  2082  		pop := v.GetInt("hello.pop")
  2083  		if large != 765432101234567 {
  2084  			t.Fatal("Got large num:", large)
  2085  		}
  2086  		
  2087  		if pop != i {
  2088  			t.Fatal("Got pop:", pop)
  2089  		}
  2090  	}
  2091  	
  2092  	assert(37890)
  2093  	
  2094  	update := map[string]interface{}{
  2095  		"Hello": map[string]interface{}{
  2096  			"Pop": 1234,
  2097  		},
  2098  		"World": map[interface{}]interface{}{
  2099  			"Rock": 345,
  2100  		},
  2101  	}
  2102  	
  2103  	if err := v.MergeConfigMap(update); err != nil {
  2104  		t.Fatal(err)
  2105  	}
  2106  	
  2107  	if rock := v.GetInt("world.rock"); rock != 345 {
  2108  		t.Fatal("Got rock:", rock)
  2109  	}
  2110  	
  2111  	assert(1234)
  2112  }
  2113  
  2114  func TestUnmarshalingWithAliases(t *testing.T) {
  2115  	v := New()
  2116  	v.SetDefault("ID", 1)
  2117  	v.Set("name", "Steve")
  2118  	v.Set("lastname", "Owen")
  2119  	
  2120  	v.RegisterAlias("UserID", "ID")
  2121  	v.RegisterAlias("Firstname", "name")
  2122  	v.RegisterAlias("Surname", "lastname")
  2123  	
  2124  	type config struct {
  2125  		ID        int
  2126  		FirstName string
  2127  		Surname   string
  2128  	}
  2129  	
  2130  	var C config
  2131  	err := v.Unmarshal(&C)
  2132  	if err != nil {
  2133  		t.Fatalf("unable to decode into struct, %v", err)
  2134  	}
  2135  	
  2136  	assert.Equal(t, &config{ID: 1, FirstName: "Steve", Surname: "Owen"}, &C)
  2137  }
  2138  
  2139  func TestSetConfigNameClearsFileCache(t *testing.T) {
  2140  	SetConfigFile("/tmp/config.yaml")
  2141  	SetConfigName("default")
  2142  	f, err := v.getConfigFile()
  2143  	if err == nil {
  2144  		t.Fatalf("config file cache should have been cleared")
  2145  	}
  2146  	assert.Empty(t, f)
  2147  }
  2148  
  2149  func TestShadowedNestedValue(t *testing.T) {
  2150  	config := `name: steve
  2151  clothing:
  2152    jacket: leather
  2153    trousers: denim
  2154    pants:
  2155      size: large
  2156  `
  2157  	initConfig("yaml", config)
  2158  	
  2159  	assert.Equal(t, "steve", GetString("name"))
  2160  	
  2161  	polyester := "polyester"
  2162  	SetDefault("clothing.shirt", polyester)
  2163  	SetDefault("clothing.jacket.price", 100)
  2164  	
  2165  	assert.Equal(t, "leather", GetString("clothing.jacket"))
  2166  	assert.Nil(t, Get("clothing.jacket.price"))
  2167  	assert.Equal(t, polyester, GetString("clothing.shirt"))
  2168  	
  2169  	clothingSettings := AllSettings()["clothing"].(map[string]interface{})
  2170  	assert.Equal(t, "leather", clothingSettings["jacket"])
  2171  	assert.Equal(t, polyester, clothingSettings["shirt"])
  2172  }
  2173  
  2174  func TestDotParameter(t *testing.T) {
  2175  	initJSON()
  2176  	// shoud take precedence over batters defined in jsonExample
  2177  	r := bytes.NewReader([]byte(`{ "batters.batter": [ { "type": "Small" } ] }`))
  2178  	unmarshalReader(r, v.config)
  2179  	
  2180  	actual := Get("batters.batter")
  2181  	expected := []interface{}{map[string]interface{}{"type": "Small"}}
  2182  	assert.Equal(t, expected, actual)
  2183  }
  2184  
  2185  func TestCaseInsensitive(t *testing.T) {
  2186  	for _, config := range []struct {
  2187  		typ     string
  2188  		content string
  2189  	}{
  2190  		{"yaml", `
  2191  aBcD: 1
  2192  eF:
  2193    gH: 2
  2194    iJk: 3
  2195    Lm:
  2196      nO: 4
  2197      P:
  2198        Q: 5
  2199        R: 6
  2200  `},
  2201  		{"json", `{
  2202    "aBcD": 1,
  2203    "eF": {
  2204      "iJk": 3,
  2205      "Lm": {
  2206        "P": {
  2207          "Q": 5,
  2208          "R": 6
  2209        },
  2210        "nO": 4
  2211      },
  2212      "gH": 2
  2213    }
  2214  }`},
  2215  		{"toml", `aBcD = 1
  2216  [eF]
  2217  gH = 2
  2218  iJk = 3
  2219  [eF.Lm]
  2220  nO = 4
  2221  [eF.Lm.P]
  2222  Q = 5
  2223  R = 6
  2224  `},
  2225  	} {
  2226  		doTestCaseInsensitive(t, config.typ, config.content)
  2227  	}
  2228  }
  2229  
  2230  func TestCaseInsensitiveSet(t *testing.T) {
  2231  	Reset()
  2232  	m1 := map[string]interface{}{
  2233  		"Foo": 32,
  2234  		"Bar": map[interface{}]interface{}{
  2235  			"ABc": "A",
  2236  			"cDE": "B",
  2237  		},
  2238  	}
  2239  	
  2240  	m2 := map[string]interface{}{
  2241  		"Foo": 52,
  2242  		"Bar": map[interface{}]interface{}{
  2243  			"bCd": "A",
  2244  			"eFG": "B",
  2245  		},
  2246  	}
  2247  	
  2248  	Set("Given1", m1)
  2249  	Set("Number1", 42)
  2250  	
  2251  	SetDefault("Given2", m2)
  2252  	SetDefault("Number2", 52)
  2253  	
  2254  	// Verify SetDefault
  2255  	if v := Get("number2"); v != 52 {
  2256  		t.Fatalf("Expected 52 got %q", v)
  2257  	}
  2258  	
  2259  	if v := Get("given2.foo"); v != 52 {
  2260  		t.Fatalf("Expected 52 got %q", v)
  2261  	}
  2262  	
  2263  	if v := Get("given2.bar.bcd"); v != "A" {
  2264  		t.Fatalf("Expected A got %q", v)
  2265  	}
  2266  	
  2267  	if _, ok := m2["Foo"]; !ok {
  2268  		t.Fatal("Input map changed")
  2269  	}
  2270  	
  2271  	// Verify Set
  2272  	if v := Get("number1"); v != 42 {
  2273  		t.Fatalf("Expected 42 got %q", v)
  2274  	}
  2275  	
  2276  	if v := Get("given1.foo"); v != 32 {
  2277  		t.Fatalf("Expected 32 got %q", v)
  2278  	}
  2279  	
  2280  	if v := Get("given1.bar.abc"); v != "A" {
  2281  		t.Fatalf("Expected A got %q", v)
  2282  	}
  2283  	
  2284  	if _, ok := m1["Foo"]; !ok {
  2285  		t.Fatal("Input map changed")
  2286  	}
  2287  }
  2288  
  2289  func TestParseNested(t *testing.T) {
  2290  	type duration struct {
  2291  		Delay time.Duration
  2292  	}
  2293  	
  2294  	type item struct {
  2295  		Name   string
  2296  		Delay  time.Duration
  2297  		Nested duration
  2298  	}
  2299  	
  2300  	config := `[[parent]]
  2301  	delay="100ms"
  2302  	[parent.nested]
  2303  	delay="200ms"
  2304  `
  2305  	initConfig("toml", config)
  2306  	
  2307  	var items []item
  2308  	err := v.UnmarshalKey("parent", &items)
  2309  	if err != nil {
  2310  		t.Fatalf("unable to decode into struct, %v", err)
  2311  	}
  2312  	
  2313  	assert.Equal(t, 1, len(items))
  2314  	assert.Equal(t, 100*time.Millisecond, items[0].Delay)
  2315  	assert.Equal(t, 200*time.Millisecond, items[0].Nested.Delay)
  2316  }
  2317  
  2318  func doTestCaseInsensitive(t *testing.T, typ, config string) {
  2319  	initConfig(typ, config)
  2320  	Set("RfD", true)
  2321  	assert.Equal(t, true, Get("rfd"))
  2322  	assert.Equal(t, true, Get("rFD"))
  2323  	assert.Equal(t, 1, cast.ToInt(Get("abcd")))
  2324  	assert.Equal(t, 1, cast.ToInt(Get("Abcd")))
  2325  	assert.Equal(t, 2, cast.ToInt(Get("ef.gh")))
  2326  	assert.Equal(t, 3, cast.ToInt(Get("ef.ijk")))
  2327  	assert.Equal(t, 4, cast.ToInt(Get("ef.lm.no")))
  2328  	assert.Equal(t, 5, cast.ToInt(Get("ef.lm.p.q")))
  2329  }
  2330  
  2331  func newViperWithConfigFile(t *testing.T) (*Viper, string, func()) {
  2332  	watchDir, err := ioutil.TempDir("", "")
  2333  	require.Nil(t, err)
  2334  	configFile := path.Join(watchDir, "config.yaml")
  2335  	err = ioutil.WriteFile(configFile, []byte("foo: bar\n"), 0o640)
  2336  	require.Nil(t, err)
  2337  	cleanup := func() {
  2338  		os.RemoveAll(watchDir)
  2339  	}
  2340  	v := New()
  2341  	v.SetConfigFile(configFile)
  2342  	err = v.ReadInConfig()
  2343  	require.Nil(t, err)
  2344  	require.Equal(t, "bar", v.Get("foo"))
  2345  	return v, configFile, cleanup
  2346  }
  2347  
  2348  func newViperWithSymlinkedConfigFile(t *testing.T) (*Viper, string, string, func()) {
  2349  	watchDir, err := ioutil.TempDir("", "")
  2350  	require.Nil(t, err)
  2351  	dataDir1 := path.Join(watchDir, "data1")
  2352  	err = os.Mkdir(dataDir1, 0o777)
  2353  	require.Nil(t, err)
  2354  	realConfigFile := path.Join(dataDir1, "config.yaml")
  2355  	t.Logf("Real config file location: %s\n", realConfigFile)
  2356  	err = ioutil.WriteFile(realConfigFile, []byte("foo: bar\n"), 0o640)
  2357  	require.Nil(t, err)
  2358  	cleanup := func() {
  2359  		os.RemoveAll(watchDir)
  2360  	}
  2361  	// now, symlink the tm `data1` dir to `data` in the baseDir
  2362  	os.Symlink(dataDir1, path.Join(watchDir, "data"))
  2363  	// and link the `<watchdir>/datadir1/config.yaml` to `<watchdir>/config.yaml`
  2364  	configFile := path.Join(watchDir, "config.yaml")
  2365  	os.Symlink(path.Join(watchDir, "data", "config.yaml"), configFile)
  2366  	t.Logf("Config file location: %s\n", path.Join(watchDir, "config.yaml"))
  2367  	// init Viper
  2368  	v := New()
  2369  	v.SetConfigFile(configFile)
  2370  	err = v.ReadInConfig()
  2371  	require.Nil(t, err)
  2372  	require.Equal(t, "bar", v.Get("foo"))
  2373  	return v, watchDir, configFile, cleanup
  2374  }
  2375  
  2376  func TestWatchFile(t *testing.T) {
  2377  	if runtime.GOOS == "linux" {
  2378  		// TODO(bep) FIX ME
  2379  		t.Skip("Skip test on Linux ...")
  2380  	}
  2381  	
  2382  	t.Run("file content changed", func(t *testing.T) {
  2383  		// given a `config.yaml` file being watched
  2384  		v, configFile, cleanup := newViperWithConfigFile(t)
  2385  		defer cleanup()
  2386  		_, err := os.Stat(configFile)
  2387  		require.NoError(t, err)
  2388  		t.Logf("test config file: %s\n", configFile)
  2389  		wg := sync.WaitGroup{}
  2390  		wg.Add(1)
  2391  		var wgDoneOnce sync.Once // OnConfigChange is called twice on Windows
  2392  		v.OnConfigChange(func(in fsnotify.Event) {
  2393  			t.Logf("config file changed")
  2394  			wgDoneOnce.Do(func() {
  2395  				wg.Done()
  2396  			})
  2397  		})
  2398  		v.WatchConfig()
  2399  		// when overwriting the file and waiting for the custom change notification handler to be triggered
  2400  		err = ioutil.WriteFile(configFile, []byte("foo: baz\n"), 0o640)
  2401  		wg.Wait()
  2402  		// then the config value should have changed
  2403  		require.Nil(t, err)
  2404  		assert.Equal(t, "baz", v.Get("foo"))
  2405  	})
  2406  	
  2407  	t.Run("link to real file changed (à la Kubernetes)", func(t *testing.T) {
  2408  		// skip if not executed on Linux
  2409  		if runtime.GOOS != "linux" {
  2410  			t.Skipf("Skipping test as symlink replacements don't work on non-linux environment...")
  2411  		}
  2412  		v, watchDir, _, _ := newViperWithSymlinkedConfigFile(t)
  2413  		// defer cleanup()
  2414  		wg := sync.WaitGroup{}
  2415  		v.WatchConfig()
  2416  		v.OnConfigChange(func(in fsnotify.Event) {
  2417  			t.Logf("config file changed")
  2418  			wg.Done()
  2419  		})
  2420  		wg.Add(1)
  2421  		// when link to another `config.yaml` file
  2422  		dataDir2 := path.Join(watchDir, "data2")
  2423  		err := os.Mkdir(dataDir2, 0o777)
  2424  		require.Nil(t, err)
  2425  		configFile2 := path.Join(dataDir2, "config.yaml")
  2426  		err = ioutil.WriteFile(configFile2, []byte("foo: baz\n"), 0o640)
  2427  		require.Nil(t, err)
  2428  		// change the symlink using the `ln -sfn` command
  2429  		err = exec.Command("ln", "-sfn", dataDir2, path.Join(watchDir, "data")).Run()
  2430  		require.Nil(t, err)
  2431  		wg.Wait()
  2432  		// then
  2433  		require.Nil(t, err)
  2434  		assert.Equal(t, "baz", v.Get("foo"))
  2435  	})
  2436  }
  2437  
  2438  func TestUnmarshal_DotSeparatorBackwardCompatibility(t *testing.T) {
  2439  	flags := pflag.NewFlagSet("test", pflag.ContinueOnError)
  2440  	flags.String("foo.bar", "cobra_flag", "")
  2441  	
  2442  	v := New()
  2443  	assert.NoError(t, v.BindPFlags(flags))
  2444  	
  2445  	config := &struct {
  2446  		Foo struct {
  2447  			Bar string
  2448  		}
  2449  	}{}
  2450  	
  2451  	assert.NoError(t, v.Unmarshal(config))
  2452  	assert.Equal(t, "cobra_flag", config.Foo.Bar)
  2453  }
  2454  
  2455  // var yamlExampleWithDot = []byte(`Hacker: true
  2456  // name: steve
  2457  // hobbies:
  2458  //     - skateboarding
  2459  //     - snowboarding
  2460  //     - go
  2461  // clothing:
  2462  //     jacket: leather
  2463  //     trousers: denim
  2464  //     pants:
  2465  //         size: large
  2466  // age: 35
  2467  // eyes : brown
  2468  // beard: true
  2469  // emails:
  2470  //     steve@hacker.com:
  2471  //         created: 01/02/03
  2472  //         active: true
  2473  // `)
  2474  
  2475  func TestKeyDelimiter(t *testing.T) {
  2476  	v := NewWithOptions(KeyDelimiter("::"))
  2477  	v.SetConfigType("yaml")
  2478  	r := strings.NewReader(string(yamlExampleWithDot))
  2479  	
  2480  	err := v.unmarshalReader(r, v.config)
  2481  	require.NoError(t, err)
  2482  	
  2483  	values := map[string]interface{}{
  2484  		"image": map[string]interface{}{
  2485  			"repository": "someImage",
  2486  			"tag":        "1.0.0",
  2487  		},
  2488  		"ingress": map[string]interface{}{
  2489  			"annotations": map[string]interface{}{
  2490  				"traefik.frontend.rule.type":                 "PathPrefix",
  2491  				"traefik.ingress.kubernetes.io/ssl-redirect": "true",
  2492  			},
  2493  		},
  2494  	}
  2495  	
  2496  	v.SetDefault("charts::values", values)
  2497  	
  2498  	assert.Equal(t, "leather", v.GetString("clothing::jacket"))
  2499  	assert.Equal(t, "01/02/03", v.GetString("emails::steve@hacker.com::created"))
  2500  	
  2501  	type config struct {
  2502  		Charts struct {
  2503  			Values map[string]interface{}
  2504  		}
  2505  	}
  2506  	
  2507  	expected := config{
  2508  		Charts: struct {
  2509  			Values map[string]interface{}
  2510  		}{
  2511  			Values: values,
  2512  		},
  2513  	}
  2514  	
  2515  	var actual config
  2516  	
  2517  	assert.NoError(t, v.Unmarshal(&actual))
  2518  	
  2519  	assert.Equal(t, expected, actual)
  2520  }
  2521  
  2522  var yamlDeepNestedSlices = []byte(`TV:
  2523  - title: "The Expanse"
  2524    title_i18n:
  2525      USA: "The Expanse"
  2526      Japan: "エクスパンス -巨獣めざめる-"
  2527    seasons:
  2528    - first_released: "December 14, 2015"
  2529      episodes:
  2530      - title: "Dulcinea"
  2531        air_date: "December 14, 2015"
  2532      - title: "The Big Empty"
  2533        air_date: "December 15, 2015"
  2534      - title: "Remember the Cant"
  2535        air_date: "December 22, 2015"
  2536    - first_released: "February 1, 2017"
  2537      episodes:
  2538      - title: "Safe"
  2539        air_date: "February 1, 2017"
  2540      - title: "Doors & Corners"
  2541        air_date: "February 1, 2017"
  2542      - title: "Static"
  2543        air_date: "February 8, 2017"
  2544    episodes:
  2545      - ["Dulcinea", "The Big Empty", "Remember the Cant"]
  2546      - ["Safe", "Doors & Corners", "Static"]
  2547  `)
  2548  
  2549  func TestSliceIndexAccess(t *testing.T) {
  2550  	v.SetConfigType("yaml")
  2551  	r := strings.NewReader(string(yamlDeepNestedSlices))
  2552  	
  2553  	err := v.unmarshalReader(r, v.config)
  2554  	require.NoError(t, err)
  2555  	
  2556  	assert.Equal(t, "The Expanse", v.GetString("tv.0.title"))
  2557  	assert.Equal(t, "February 1, 2017", v.GetString("tv.0.seasons.1.first_released"))
  2558  	assert.Equal(t, "Static", v.GetString("tv.0.seasons.1.episodes.2.title"))
  2559  	assert.Equal(t, "December 15, 2015", v.GetString("tv.0.seasons.0.episodes.1.air_date"))
  2560  	
  2561  	// Test nested keys with capital letters
  2562  	assert.Equal(t, "The Expanse", v.GetString("tv.0.title_i18n.USA"))
  2563  	assert.Equal(t, "エクスパンス -巨獣めざめる-", v.GetString("tv.0.title_i18n.Japan"))
  2564  	
  2565  	// Test for index out of bounds
  2566  	assert.Equal(t, "", v.GetString("tv.0.seasons.2.first_released"))
  2567  	
  2568  	// Accessing multidimensional arrays
  2569  	assert.Equal(t, "Static", v.GetString("tv.0.episodes.1.2"))
  2570  }
  2571  
  2572  func BenchmarkGetBool(b *testing.B) {
  2573  	key := "BenchmarkGetBool"
  2574  	v = New()
  2575  	v.Set(key, true)
  2576  	
  2577  	for i := 0; i < b.N; i++ {
  2578  		if !v.GetBool(key) {
  2579  			b.Fatal("GetBool returned false")
  2580  		}
  2581  	}
  2582  }
  2583  
  2584  func BenchmarkGet(b *testing.B) {
  2585  	key := "BenchmarkGet"
  2586  	v = New()
  2587  	v.Set(key, true)
  2588  	
  2589  	for i := 0; i < b.N; i++ {
  2590  		if !v.Get(key).(bool) {
  2591  			b.Fatal("Get returned false")
  2592  		}
  2593  	}
  2594  }
  2595  
  2596  // BenchmarkGetBoolFromMap is the "perfect result" for the above.
  2597  func BenchmarkGetBoolFromMap(b *testing.B) {
  2598  	m := make(map[string]bool)
  2599  	key := "BenchmarkGetBool"
  2600  	m[key] = true
  2601  	
  2602  	for i := 0; i < b.N; i++ {
  2603  		if !m[key] {
  2604  			b.Fatal("Map value was false")
  2605  		}
  2606  	}
  2607  }
  2608  
  2609  // Skip some tests on Windows that kept failing when Windows was added to the CI as a target.
  2610  func skipWindows(t *testing.T) {
  2611  	if runtime.GOOS == "windows" {
  2612  		t.Skip("Skip test on Windows")
  2613  	}
  2614  }