1 // Copyright © 2014 Steve Francia <spf@spf13.com>.
3 // Use of this source code is governed by an MIT-style
4 // license that can be found in the LICENSE file.
21 "github.com/spf13/cast"
23 "github.com/spf13/pflag"
24 "github.com/stretchr/testify/assert"
27 var yamlExample = []byte(`Hacker: true
43 var yamlExampleWithExtras = []byte(`Existing: true
47 type testUnmarshalExtra struct {
51 var tomlExample = []byte(`
52 title = "TOML Example"
55 organization = "MongoDB"
56 Bio = "MongoDB Chief Developer Advocate & Hacker at Large"
57 dob = 1979-05-27T07:32:00Z # First class dates? Why not?`)
59 var jsonExample = []byte(`{
66 { "type": "Regular" },
67 { "type": "Chocolate" },
68 { "type": "Blueberry" },
69 { "type": "Devil's Food" }
74 var hclExample = []byte(`
94 var propertiesExample = []byte(`
99 p_batters.batter.type: Regular
102 var remoteExample = []byte(`{
111 SetConfigType("yaml")
112 r = bytes.NewReader(yamlExample)
113 unmarshalReader(r, v.config)
115 SetConfigType("json")
116 r = bytes.NewReader(jsonExample)
117 unmarshalReader(r, v.config)
120 r = bytes.NewReader(hclExample)
121 unmarshalReader(r, v.config)
123 SetConfigType("properties")
124 r = bytes.NewReader(propertiesExample)
125 unmarshalReader(r, v.config)
127 SetConfigType("toml")
128 r = bytes.NewReader(tomlExample)
129 unmarshalReader(r, v.config)
131 SetConfigType("json")
132 remote := bytes.NewReader(remoteExample)
133 unmarshalReader(remote, v.kvstore)
136 func initConfig(typ, config string) {
139 r := strings.NewReader(config)
141 if err := unmarshalReader(r, v.config); err != nil {
147 initConfig("yaml", string(yamlExample))
152 SetConfigType("json")
153 r := bytes.NewReader(jsonExample)
155 unmarshalReader(r, v.config)
158 func initProperties() {
160 SetConfigType("properties")
161 r := bytes.NewReader(propertiesExample)
163 unmarshalReader(r, v.config)
168 SetConfigType("toml")
169 r := bytes.NewReader(tomlExample)
171 unmarshalReader(r, v.config)
177 r := bytes.NewReader(hclExample)
179 unmarshalReader(r, v.config)
182 // make directories for testing
183 func initDirs(t *testing.T) (string, string, func()) {
186 testDirs = []string{`a a`, `b`, `c\c`, `D_`}
187 config = `improbable`
190 root, err := ioutil.TempDir("", "")
205 for _, dir := range testDirs {
206 err = os.Mkdir(dir, 0750)
209 err = ioutil.WriteFile(
210 path.Join(dir, config+".toml"),
211 []byte("key = \"value is "+dir+"\"\n"),
217 return root, config, func() {
223 //stubs for PFlag Values
224 type stringValue string
226 func newStringValue(val string, p *string) *stringValue {
228 return (*stringValue)(p)
231 func (s *stringValue) Set(val string) error {
232 *s = stringValue(val)
236 func (s *stringValue) Type() string {
240 func (s *stringValue) String() string {
241 return fmt.Sprintf("%s", *s)
244 func TestBasics(t *testing.T) {
245 SetConfigFile("/tmp/config.yaml")
246 filename, err := v.getConfigFile()
247 assert.Equal(t, "/tmp/config.yaml", filename)
248 assert.NoError(t, err)
251 func TestDefault(t *testing.T) {
252 SetDefault("age", 45)
253 assert.Equal(t, 45, Get("age"))
255 SetDefault("clothing.jacket", "slacks")
256 assert.Equal(t, "slacks", Get("clothing.jacket"))
258 SetConfigType("yaml")
259 err := ReadConfig(bytes.NewBuffer(yamlExample))
261 assert.NoError(t, err)
262 assert.Equal(t, "leather", Get("clothing.jacket"))
265 func TestUnmarshalling(t *testing.T) {
266 SetConfigType("yaml")
267 r := bytes.NewReader(yamlExample)
269 unmarshalReader(r, v.config)
270 assert.True(t, InConfig("name"))
271 assert.False(t, InConfig("state"))
272 assert.Equal(t, "steve", Get("name"))
273 assert.Equal(t, []interface{}{"skateboarding", "snowboarding", "go"}, Get("hobbies"))
274 assert.Equal(t, map[string]interface{}{"jacket": "leather", "trousers": "denim", "pants": map[string]interface{}{"size": "large"}}, Get("clothing"))
275 assert.Equal(t, 35, Get("age"))
278 func TestUnmarshalExact(t *testing.T) {
280 target := &testUnmarshalExtra{}
281 vip.SetConfigType("yaml")
282 r := bytes.NewReader(yamlExampleWithExtras)
284 err := vip.UnmarshalExact(target)
286 t.Fatal("UnmarshalExact should error when populating a struct from a conf that contains unused fields")
290 func TestOverrides(t *testing.T) {
292 assert.Equal(t, 40, Get("age"))
295 func TestDefaultPost(t *testing.T) {
296 assert.NotEqual(t, "NYC", Get("state"))
297 SetDefault("state", "NYC")
298 assert.Equal(t, "NYC", Get("state"))
301 func TestAliases(t *testing.T) {
302 RegisterAlias("years", "age")
303 assert.Equal(t, 40, Get("years"))
305 assert.Equal(t, 45, Get("age"))
308 func TestAliasInConfigFile(t *testing.T) {
309 // the config file specifies "beard". If we make this an alias for
310 // "hasbeard", we still want the old config file to work with beard.
311 RegisterAlias("beard", "hasbeard")
312 assert.Equal(t, true, Get("hasbeard"))
313 Set("hasbeard", false)
314 assert.Equal(t, false, Get("beard"))
317 func TestYML(t *testing.T) {
319 assert.Equal(t, "steve", Get("name"))
322 func TestJSON(t *testing.T) {
324 assert.Equal(t, "0001", Get("id"))
327 func TestProperties(t *testing.T) {
329 assert.Equal(t, "0001", Get("p_id"))
332 func TestTOML(t *testing.T) {
334 assert.Equal(t, "TOML Example", Get("title"))
337 func TestHCL(t *testing.T) {
339 assert.Equal(t, "0001", Get("id"))
340 assert.Equal(t, 0.55, Get("ppu"))
341 assert.Equal(t, "donut", Get("type"))
342 assert.Equal(t, "Cake", Get("name"))
344 assert.Equal(t, "0002", Get("id"))
345 assert.NotEqual(t, "cronut", Get("type"))
348 func TestRemotePrecedence(t *testing.T) {
351 remote := bytes.NewReader(remoteExample)
352 assert.Equal(t, "0001", Get("id"))
353 unmarshalReader(remote, v.kvstore)
354 assert.Equal(t, "0001", Get("id"))
355 assert.NotEqual(t, "cronut", Get("type"))
356 assert.Equal(t, "remote", Get("newkey"))
357 Set("newkey", "newvalue")
358 assert.NotEqual(t, "remote", Get("newkey"))
359 assert.Equal(t, "newvalue", Get("newkey"))
360 Set("newkey", "remote")
363 func TestEnv(t *testing.T) {
369 os.Setenv("ID", "13")
370 os.Setenv("FOOD", "apple")
371 os.Setenv("NAME", "crunk")
373 assert.Equal(t, "13", Get("id"))
374 assert.Equal(t, "apple", Get("f"))
375 assert.Equal(t, "Cake", Get("name"))
379 assert.Equal(t, "crunk", Get("name"))
383 func TestEnvPrefix(t *testing.T) {
386 SetEnvPrefix("foo") // will be uppercased automatically
388 BindEnv("f", "FOOD") // not using prefix
390 os.Setenv("FOO_ID", "13")
391 os.Setenv("FOOD", "apple")
392 os.Setenv("FOO_NAME", "crunk")
394 assert.Equal(t, "13", Get("id"))
395 assert.Equal(t, "apple", Get("f"))
396 assert.Equal(t, "Cake", Get("name"))
400 assert.Equal(t, "crunk", Get("name"))
403 func TestAutoEnv(t *testing.T) {
407 os.Setenv("FOO_BAR", "13")
408 assert.Equal(t, "13", Get("foo_bar"))
411 func TestAutoEnvWithPrefix(t *testing.T) {
416 os.Setenv("BAZ_BAR", "13")
417 assert.Equal(t, "13", Get("bar"))
420 func TestSetEnvKeyReplacer(t *testing.T) {
424 os.Setenv("REFRESH_INTERVAL", "30s")
426 replacer := strings.NewReplacer("-", "_")
427 SetEnvKeyReplacer(replacer)
429 assert.Equal(t, "30s", Get("refresh-interval"))
432 func TestAllKeys(t *testing.T) {
435 ks := sort.StringSlice{"title", "newkey", "owner.organization", "owner.dob", "owner.bio", "name", "beard", "ppu", "batters.batter", "hobbies", "clothing.jacket", "clothing.trousers", "clothing.pants.size", "age", "hacker", "id", "type", "eyes", "p_id", "p_ppu", "p_batters.batter.type", "p_type", "p_name", "foos"}
436 dob, _ := time.Parse(time.RFC3339, "1979-05-27T07:32:00Z")
437 all := map[string]interface{}{"owner": map[string]interface{}{"organization": "MongoDB", "bio": "MongoDB Chief Developer Advocate & Hacker at Large", "dob": dob}, "title": "TOML Example", "ppu": 0.55, "eyes": "brown", "clothing": map[string]interface{}{"trousers": "denim", "jacket": "leather", "pants": map[string]interface{}{"size": "large"}}, "id": "0001", "batters": map[string]interface{}{"batter": []interface{}{map[string]interface{}{"type": "Regular"}, map[string]interface{}{"type": "Chocolate"}, map[string]interface{}{"type": "Blueberry"}, map[string]interface{}{"type": "Devil's Food"}}}, "hacker": true, "beard": true, "hobbies": []interface{}{"skateboarding", "snowboarding", "go"}, "age": 35, "type": "donut", "newkey": "remote", "name": "Cake", "p_id": "0001", "p_ppu": "0.55", "p_name": "Cake", "p_batters": map[string]interface{}{"batter": map[string]interface{}{"type": "Regular"}}, "p_type": "donut", "foos": []map[string]interface{}{map[string]interface{}{"foo": []map[string]interface{}{map[string]interface{}{"key": 1}, map[string]interface{}{"key": 2}, map[string]interface{}{"key": 3}, map[string]interface{}{"key": 4}}}}}
439 var allkeys sort.StringSlice
444 assert.Equal(t, ks, allkeys)
445 assert.Equal(t, all, AllSettings())
448 func TestAllKeysWithEnv(t *testing.T) {
451 // bind and define environment variables (including a nested one)
454 v.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
455 os.Setenv("ID", "13")
456 os.Setenv("FOO_BAR", "baz")
458 expectedKeys := sort.StringSlice{"id", "foo.bar"}
460 keys := sort.StringSlice(v.AllKeys())
462 assert.Equal(t, expectedKeys, keys)
465 func TestAliasesOfAliases(t *testing.T) {
466 Set("Title", "Checking Case")
467 RegisterAlias("Foo", "Bar")
468 RegisterAlias("Bar", "Title")
469 assert.Equal(t, "Checking Case", Get("FOO"))
472 func TestRecursiveAliases(t *testing.T) {
473 RegisterAlias("Baz", "Roo")
474 RegisterAlias("Roo", "baz")
477 func TestUnmarshal(t *testing.T) {
478 SetDefault("port", 1313)
480 Set("duration", "1s1ms")
485 Duration time.Duration
492 t.Fatalf("unable to decode into struct, %v", err)
495 assert.Equal(t, &config{Name: "Steve", Port: 1313, Duration: time.Second + time.Millisecond}, &C)
500 t.Fatalf("unable to decode into struct, %v", err)
502 assert.Equal(t, &config{Name: "Steve", Port: 1234, Duration: time.Second + time.Millisecond}, &C)
505 func TestBindPFlags(t *testing.T) {
506 v := New() // create independent Viper object
507 flagSet := pflag.NewFlagSet("test", pflag.ContinueOnError)
509 var testValues = map[string]*string{
515 var mutatedTestValues = map[string]string{
518 "endpoint": "/public",
521 for name := range testValues {
522 testValues[name] = flagSet.String(name, "", "test")
525 err := v.BindPFlags(flagSet)
527 t.Fatalf("error binding flag set, %v", err)
530 flagSet.VisitAll(func(flag *pflag.Flag) {
531 flag.Value.Set(mutatedTestValues[flag.Name])
535 for name, expected := range mutatedTestValues {
536 assert.Equal(t, expected, v.Get(name))
541 func TestBindPFlagsStringSlice(t *testing.T) {
542 for _, testValue := range []struct {
547 {[]string{"jeden"}, "jeden"},
548 {[]string{"dwa", "trzy"}, "dwa,trzy"},
549 {[]string{"cztery", "piec , szesc"}, "cztery,\"piec , szesc\""}} {
551 for _, changed := range []bool{true, false} {
552 v := New() // create independent Viper object
553 flagSet := pflag.NewFlagSet("test", pflag.ContinueOnError)
554 flagSet.StringSlice("stringslice", testValue.Expected, "test")
555 flagSet.Visit(func(f *pflag.Flag) {
556 if len(testValue.Value) > 0 {
557 f.Value.Set(testValue.Value)
562 err := v.BindPFlags(flagSet)
564 t.Fatalf("error binding flag set, %v", err)
567 type TestStr struct {
571 if err := v.Unmarshal(val); err != nil {
572 t.Fatalf("%+#v cannot unmarshal: %s", testValue.Value, err)
574 assert.Equal(t, testValue.Expected, val.StringSlice)
579 func TestBindPFlag(t *testing.T) {
580 var testString = "testing"
581 var testValue = newStringValue(testString, &testString)
589 BindPFlag("testvalue", flag)
591 assert.Equal(t, testString, Get("testvalue"))
593 flag.Value.Set("testing_mutate")
594 flag.Changed = true //hack for pflag usage
596 assert.Equal(t, "testing_mutate", Get("testvalue"))
600 func TestBoundCaseSensitivity(t *testing.T) {
601 assert.Equal(t, "brown", Get("eyes"))
603 BindEnv("eYEs", "TURTLE_EYES")
604 os.Setenv("TURTLE_EYES", "blue")
606 assert.Equal(t, "blue", Get("eyes"))
608 var testString = "green"
609 var testValue = newStringValue(testString, &testString)
617 BindPFlag("eYEs", flag)
618 assert.Equal(t, "green", Get("eyes"))
622 func TestSizeInBytes(t *testing.T) {
623 input := map[string]uint{
629 "43 MB": 43 * (1 << 20),
630 "10mb": 10 * (1 << 20),
634 for str, expected := range input {
635 assert.Equal(t, expected, parseSizeInBytes(str), str)
639 func TestFindsNestedKeys(t *testing.T) {
641 dob, _ := time.Parse(time.RFC3339, "1979-05-27T07:32:00Z")
643 Set("super", map[string]interface{}{
644 "deep": map[string]interface{}{
649 expected := map[string]interface{}{
650 "super": map[string]interface{}{
651 "deep": map[string]interface{}{
655 "super.deep": map[string]interface{}{
658 "super.deep.nested": "value",
659 "owner.organization": "MongoDB",
660 "batters.batter": []interface{}{
661 map[string]interface{}{
664 map[string]interface{}{
667 map[string]interface{}{
670 map[string]interface{}{
671 "type": "Devil's Food",
674 "hobbies": []interface{}{
675 "skateboarding", "snowboarding", "go",
677 "title": "TOML Example",
679 "batters": map[string]interface{}{
680 "batter": []interface{}{
681 map[string]interface{}{
684 map[string]interface{}{
686 }, map[string]interface{}{
688 }, map[string]interface{}{
689 "type": "Devil's Food",
695 "owner": map[string]interface{}{
696 "organization": "MongoDB",
697 "bio": "MongoDB Chief Developer Advocate & Hacker at Large",
700 "owner.bio": "MongoDB Chief Developer Advocate & Hacker at Large",
706 "clothing": map[string]interface{}{
709 "pants": map[string]interface{}{
713 "clothing.jacket": "leather",
714 "clothing.pants.size": "large",
715 "clothing.trousers": "denim",
718 "foos": []map[string]interface{}{
719 map[string]interface{}{
720 "foo": []map[string]interface{}{
721 map[string]interface{}{
724 map[string]interface{}{
727 map[string]interface{}{
730 map[string]interface{}{
738 for key, expectedValue := range expected {
740 assert.Equal(t, expectedValue, v.Get(key))
745 func TestReadBufConfig(t *testing.T) {
747 v.SetConfigType("yaml")
748 v.ReadConfig(bytes.NewBuffer(yamlExample))
751 assert.True(t, v.InConfig("name"))
752 assert.False(t, v.InConfig("state"))
753 assert.Equal(t, "steve", v.Get("name"))
754 assert.Equal(t, []interface{}{"skateboarding", "snowboarding", "go"}, v.Get("hobbies"))
755 assert.Equal(t, map[string]interface{}{"jacket": "leather", "trousers": "denim", "pants": map[string]interface{}{"size": "large"}}, v.Get("clothing"))
756 assert.Equal(t, 35, v.Get("age"))
759 func TestIsSet(t *testing.T) {
761 v.SetConfigType("yaml")
762 v.ReadConfig(bytes.NewBuffer(yamlExample))
763 assert.True(t, v.IsSet("clothing.jacket"))
764 assert.False(t, v.IsSet("clothing.jackets"))
765 assert.False(t, v.IsSet("helloworld"))
766 v.Set("helloworld", "fubar")
767 assert.True(t, v.IsSet("helloworld"))
770 func TestDirsSearch(t *testing.T) {
772 root, config, cleanup := initDirs(t)
776 v.SetConfigName(config)
777 v.SetDefault(`key`, `default`)
779 entries, err := ioutil.ReadDir(root)
780 for _, e := range entries {
782 v.AddConfigPath(e.Name())
786 err = v.ReadInConfig()
789 assert.Equal(t, `value is `+path.Base(v.configPaths[0]), v.GetString(`key`))
792 func TestWrongDirsSearchNotFound(t *testing.T) {
794 _, config, cleanup := initDirs(t)
798 v.SetConfigName(config)
799 v.SetDefault(`key`, `default`)
801 v.AddConfigPath(`whattayoutalkingbout`)
802 v.AddConfigPath(`thispathaintthere`)
804 err := v.ReadInConfig()
805 assert.Equal(t, reflect.TypeOf(ConfigFileNotFoundError{"", ""}), reflect.TypeOf(err))
807 // Even though config did not load and the error might have
808 // been ignored by the client, the default still loads
809 assert.Equal(t, `default`, v.GetString(`key`))
812 func TestWrongDirsSearchNotFoundForMerge(t *testing.T) {
814 _, config, cleanup := initDirs(t)
818 v.SetConfigName(config)
819 v.SetDefault(`key`, `default`)
821 v.AddConfigPath(`whattayoutalkingbout`)
822 v.AddConfigPath(`thispathaintthere`)
824 err := v.MergeInConfig()
825 assert.Equal(t, reflect.TypeOf(ConfigFileNotFoundError{"", ""}), reflect.TypeOf(err))
827 // Even though config did not load and the error might have
828 // been ignored by the client, the default still loads
829 assert.Equal(t, `default`, v.GetString(`key`))
832 func TestSub(t *testing.T) {
834 v.SetConfigType("yaml")
835 v.ReadConfig(bytes.NewBuffer(yamlExample))
837 subv := v.Sub("clothing")
838 assert.Equal(t, v.Get("clothing.pants.size"), subv.Get("pants.size"))
840 subv = v.Sub("clothing.pants")
841 assert.Equal(t, v.Get("clothing.pants.size"), subv.Get("size"))
843 subv = v.Sub("clothing.pants.size")
844 assert.Equal(t, (*Viper)(nil), subv)
846 subv = v.Sub("missing.key")
847 assert.Equal(t, (*Viper)(nil), subv)
850 var yamlMergeExampleTgt = []byte(`
853 lagrenum: 765432101234567
861 var yamlMergeExampleSrc = []byte(`
864 lagrenum: 7654321001234567
871 func TestMergeConfig(t *testing.T) {
873 v.SetConfigType("yml")
874 if err := v.ReadConfig(bytes.NewBuffer(yamlMergeExampleTgt)); err != nil {
878 if pop := v.GetInt("hello.pop"); pop != 37890 {
879 t.Fatalf("pop != 37890, = %d", pop)
882 if pop := v.GetInt("hello.lagrenum"); pop != 765432101234567 {
883 t.Fatalf("lagrenum != 765432101234567, = %d", pop)
886 if pop := v.GetInt64("hello.lagrenum"); pop != int64(765432101234567) {
887 t.Fatalf("int64 lagrenum != 765432101234567, = %d", pop)
890 if world := v.GetStringSlice("hello.world"); len(world) != 4 {
891 t.Fatalf("len(world) != 4, = %d", len(world))
894 if fu := v.GetString("fu"); fu != "" {
895 t.Fatalf("fu != \"\", = %s", fu)
898 if err := v.MergeConfig(bytes.NewBuffer(yamlMergeExampleSrc)); err != nil {
902 if pop := v.GetInt("hello.pop"); pop != 45000 {
903 t.Fatalf("pop != 45000, = %d", pop)
906 if pop := v.GetInt("hello.lagrenum"); pop != 7654321001234567 {
907 t.Fatalf("lagrenum != 7654321001234567, = %d", pop)
910 if pop := v.GetInt64("hello.lagrenum"); pop != int64(7654321001234567) {
911 t.Fatalf("int64 lagrenum != 7654321001234567, = %d", pop)
914 if world := v.GetStringSlice("hello.world"); len(world) != 4 {
915 t.Fatalf("len(world) != 4, = %d", len(world))
918 if universe := v.GetStringSlice("hello.universe"); len(universe) != 2 {
919 t.Fatalf("len(universe) != 2, = %d", len(universe))
922 if fu := v.GetString("fu"); fu != "bar" {
923 t.Fatalf("fu != \"bar\", = %s", fu)
927 func TestMergeConfigNoMerge(t *testing.T) {
929 v.SetConfigType("yml")
930 if err := v.ReadConfig(bytes.NewBuffer(yamlMergeExampleTgt)); err != nil {
934 if pop := v.GetInt("hello.pop"); pop != 37890 {
935 t.Fatalf("pop != 37890, = %d", pop)
938 if world := v.GetStringSlice("hello.world"); len(world) != 4 {
939 t.Fatalf("len(world) != 4, = %d", len(world))
942 if fu := v.GetString("fu"); fu != "" {
943 t.Fatalf("fu != \"\", = %s", fu)
946 if err := v.ReadConfig(bytes.NewBuffer(yamlMergeExampleSrc)); err != nil {
950 if pop := v.GetInt("hello.pop"); pop != 45000 {
951 t.Fatalf("pop != 45000, = %d", pop)
954 if world := v.GetStringSlice("hello.world"); len(world) != 0 {
955 t.Fatalf("len(world) != 0, = %d", len(world))
958 if universe := v.GetStringSlice("hello.universe"); len(universe) != 2 {
959 t.Fatalf("len(universe) != 2, = %d", len(universe))
962 if fu := v.GetString("fu"); fu != "bar" {
963 t.Fatalf("fu != \"bar\", = %s", fu)
967 func TestUnmarshalingWithAliases(t *testing.T) {
969 v.SetDefault("ID", 1)
970 v.Set("name", "Steve")
971 v.Set("lastname", "Owen")
973 v.RegisterAlias("UserID", "ID")
974 v.RegisterAlias("Firstname", "name")
975 v.RegisterAlias("Surname", "lastname")
984 err := v.Unmarshal(&C)
986 t.Fatalf("unable to decode into struct, %v", err)
989 assert.Equal(t, &config{ID: 1, FirstName: "Steve", Surname: "Owen"}, &C)
992 func TestSetConfigNameClearsFileCache(t *testing.T) {
993 SetConfigFile("/tmp/config.yaml")
994 SetConfigName("default")
995 f, err := v.getConfigFile()
997 t.Fatalf("config file cache should have been cleared")
1002 func TestShadowedNestedValue(t *testing.T) {
1004 config := `name: steve
1011 initConfig("yaml", config)
1013 assert.Equal(t, "steve", GetString("name"))
1015 polyester := "polyester"
1016 SetDefault("clothing.shirt", polyester)
1017 SetDefault("clothing.jacket.price", 100)
1019 assert.Equal(t, "leather", GetString("clothing.jacket"))
1020 assert.Nil(t, Get("clothing.jacket.price"))
1021 assert.Equal(t, polyester, GetString("clothing.shirt"))
1023 clothingSettings := AllSettings()["clothing"].(map[string]interface{})
1024 assert.Equal(t, "leather", clothingSettings["jacket"])
1025 assert.Equal(t, polyester, clothingSettings["shirt"])
1028 func TestDotParameter(t *testing.T) {
1030 // shoud take precedence over batters defined in jsonExample
1031 r := bytes.NewReader([]byte(`{ "batters.batter": [ { "type": "Small" } ] }`))
1032 unmarshalReader(r, v.config)
1034 actual := Get("batters.batter")
1035 expected := []interface{}{map[string]interface{}{"type": "Small"}}
1036 assert.Equal(t, expected, actual)
1039 func TestCaseInsensitive(t *testing.T) {
1040 for _, config := range []struct {
1080 doTestCaseInsensitive(t, config.typ, config.content)
1084 func TestCaseInsensitiveSet(t *testing.T) {
1086 m1 := map[string]interface{}{
1088 "Bar": map[interface{}]interface {
1094 m2 := map[string]interface{}{
1096 "Bar": map[interface{}]interface {
1105 SetDefault("Given2", m2)
1106 SetDefault("Number2", 52)
1108 // Verify SetDefault
1109 if v := Get("number2"); v != 52 {
1110 t.Fatalf("Expected 52 got %q", v)
1113 if v := Get("given2.foo"); v != 52 {
1114 t.Fatalf("Expected 52 got %q", v)
1117 if v := Get("given2.bar.bcd"); v != "A" {
1118 t.Fatalf("Expected A got %q", v)
1121 if _, ok := m2["Foo"]; !ok {
1122 t.Fatal("Input map changed")
1126 if v := Get("number1"); v != 42 {
1127 t.Fatalf("Expected 42 got %q", v)
1130 if v := Get("given1.foo"); v != 32 {
1131 t.Fatalf("Expected 32 got %q", v)
1134 if v := Get("given1.bar.abc"); v != "A" {
1135 t.Fatalf("Expected A got %q", v)
1138 if _, ok := m1["Foo"]; !ok {
1139 t.Fatal("Input map changed")
1143 func TestParseNested(t *testing.T) {
1144 type duration struct {
1154 config := `[[parent]]
1159 initConfig("toml", config)
1162 err := v.UnmarshalKey("parent", &items)
1164 t.Fatalf("unable to decode into struct, %v", err)
1167 assert.Equal(t, 1, len(items))
1168 assert.Equal(t, 100*time.Millisecond, items[0].Delay)
1169 assert.Equal(t, 200*time.Millisecond, items[0].Nested.Delay)
1172 func doTestCaseInsensitive(t *testing.T, typ, config string) {
1173 initConfig(typ, config)
1175 assert.Equal(t, true, Get("rfd"))
1176 assert.Equal(t, true, Get("rFD"))
1177 assert.Equal(t, 1, cast.ToInt(Get("abcd")))
1178 assert.Equal(t, 1, cast.ToInt(Get("Abcd")))
1179 assert.Equal(t, 2, cast.ToInt(Get("ef.gh")))
1180 assert.Equal(t, 3, cast.ToInt(Get("ef.ijk")))
1181 assert.Equal(t, 4, cast.ToInt(Get("ef.lm.no")))
1182 assert.Equal(t, 5, cast.ToInt(Get("ef.lm.p.q")))
1186 func BenchmarkGetBool(b *testing.B) {
1187 key := "BenchmarkGetBool"
1191 for i := 0; i < b.N; i++ {
1192 if !v.GetBool(key) {
1193 b.Fatal("GetBool returned false")
1198 func BenchmarkGet(b *testing.B) {
1199 key := "BenchmarkGet"
1203 for i := 0; i < b.N; i++ {
1204 if !v.Get(key).(bool) {
1205 b.Fatal("Get returned false")
1210 // This is the "perfect result" for the above.
1211 func BenchmarkGetBoolFromMap(b *testing.B) {
1212 m := make(map[string]bool)
1213 key := "BenchmarkGetBool"
1216 for i := 0; i < b.N; i++ {
1218 b.Fatal("Map value was false")