OSDN Git Service

Hulk did something
[bytom/vapor.git] / vendor / github.com / spf13 / viper / viper_test.go
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         "fmt"
11         "io"
12         "io/ioutil"
13         "os"
14         "path"
15         "reflect"
16         "sort"
17         "strings"
18         "testing"
19         "time"
20
21         "github.com/spf13/cast"
22
23         "github.com/spf13/pflag"
24         "github.com/stretchr/testify/assert"
25 )
26
27 var yamlExample = []byte(`Hacker: true
28 name: steve
29 hobbies:
30 - skateboarding
31 - snowboarding
32 - go
33 clothing:
34   jacket: leather
35   trousers: denim
36   pants:
37     size: large
38 age: 35
39 eyes : brown
40 beard: true
41 `)
42
43 var yamlExampleWithExtras = []byte(`Existing: true
44 Bogus: true
45 `)
46
47 type testUnmarshalExtra struct {
48         Existing bool
49 }
50
51 var tomlExample = []byte(`
52 title = "TOML Example"
53
54 [owner]
55 organization = "MongoDB"
56 Bio = "MongoDB Chief Developer Advocate & Hacker at Large"
57 dob = 1979-05-27T07:32:00Z # First class dates? Why not?`)
58
59 var jsonExample = []byte(`{
60 "id": "0001",
61 "type": "donut",
62 "name": "Cake",
63 "ppu": 0.55,
64 "batters": {
65         "batter": [
66                 { "type": "Regular" },
67                 { "type": "Chocolate" },
68                 { "type": "Blueberry" },
69                 { "type": "Devil's Food" }
70             ]
71     }
72 }`)
73
74 var hclExample = []byte(`
75 id = "0001"
76 type = "donut"
77 name = "Cake"
78 ppu = 0.55
79 foos {
80         foo {
81                 key = 1
82         }
83         foo {
84                 key = 2
85         }
86         foo {
87                 key = 3
88         }
89         foo {
90                 key = 4
91         }
92 }`)
93
94 var propertiesExample = []byte(`
95 p_id: 0001
96 p_type: donut
97 p_name: Cake
98 p_ppu: 0.55
99 p_batters.batter.type: Regular
100 `)
101
102 var remoteExample = []byte(`{
103 "id":"0002",
104 "type":"cronut",
105 "newkey":"remote"
106 }`)
107
108 func initConfigs() {
109         Reset()
110         var r io.Reader
111         SetConfigType("yaml")
112         r = bytes.NewReader(yamlExample)
113         unmarshalReader(r, v.config)
114
115         SetConfigType("json")
116         r = bytes.NewReader(jsonExample)
117         unmarshalReader(r, v.config)
118
119         SetConfigType("hcl")
120         r = bytes.NewReader(hclExample)
121         unmarshalReader(r, v.config)
122
123         SetConfigType("properties")
124         r = bytes.NewReader(propertiesExample)
125         unmarshalReader(r, v.config)
126
127         SetConfigType("toml")
128         r = bytes.NewReader(tomlExample)
129         unmarshalReader(r, v.config)
130
131         SetConfigType("json")
132         remote := bytes.NewReader(remoteExample)
133         unmarshalReader(remote, v.kvstore)
134 }
135
136 func initConfig(typ, config string) {
137         Reset()
138         SetConfigType(typ)
139         r := strings.NewReader(config)
140
141         if err := unmarshalReader(r, v.config); err != nil {
142                 panic(err)
143         }
144 }
145
146 func initYAML() {
147         initConfig("yaml", string(yamlExample))
148 }
149
150 func initJSON() {
151         Reset()
152         SetConfigType("json")
153         r := bytes.NewReader(jsonExample)
154
155         unmarshalReader(r, v.config)
156 }
157
158 func initProperties() {
159         Reset()
160         SetConfigType("properties")
161         r := bytes.NewReader(propertiesExample)
162
163         unmarshalReader(r, v.config)
164 }
165
166 func initTOML() {
167         Reset()
168         SetConfigType("toml")
169         r := bytes.NewReader(tomlExample)
170
171         unmarshalReader(r, v.config)
172 }
173
174 func initHcl() {
175         Reset()
176         SetConfigType("hcl")
177         r := bytes.NewReader(hclExample)
178
179         unmarshalReader(r, v.config)
180 }
181
182 // make directories for testing
183 func initDirs(t *testing.T) (string, string, func()) {
184
185         var (
186                 testDirs = []string{`a a`, `b`, `c\c`, `D_`}
187                 config   = `improbable`
188         )
189
190         root, err := ioutil.TempDir("", "")
191
192         cleanup := true
193         defer func() {
194                 if cleanup {
195                         os.Chdir("..")
196                         os.RemoveAll(root)
197                 }
198         }()
199
200         assert.Nil(t, err)
201
202         err = os.Chdir(root)
203         assert.Nil(t, err)
204
205         for _, dir := range testDirs {
206                 err = os.Mkdir(dir, 0750)
207                 assert.Nil(t, err)
208
209                 err = ioutil.WriteFile(
210                         path.Join(dir, config+".toml"),
211                         []byte("key = \"value is "+dir+"\"\n"),
212                         0640)
213                 assert.Nil(t, err)
214         }
215
216         cleanup = false
217         return root, config, func() {
218                 os.Chdir("..")
219                 os.RemoveAll(root)
220         }
221 }
222
223 //stubs for PFlag Values
224 type stringValue string
225
226 func newStringValue(val string, p *string) *stringValue {
227         *p = val
228         return (*stringValue)(p)
229 }
230
231 func (s *stringValue) Set(val string) error {
232         *s = stringValue(val)
233         return nil
234 }
235
236 func (s *stringValue) Type() string {
237         return "string"
238 }
239
240 func (s *stringValue) String() string {
241         return fmt.Sprintf("%s", *s)
242 }
243
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)
249 }
250
251 func TestDefault(t *testing.T) {
252         SetDefault("age", 45)
253         assert.Equal(t, 45, Get("age"))
254
255         SetDefault("clothing.jacket", "slacks")
256         assert.Equal(t, "slacks", Get("clothing.jacket"))
257
258         SetConfigType("yaml")
259         err := ReadConfig(bytes.NewBuffer(yamlExample))
260
261         assert.NoError(t, err)
262         assert.Equal(t, "leather", Get("clothing.jacket"))
263 }
264
265 func TestUnmarshalling(t *testing.T) {
266         SetConfigType("yaml")
267         r := bytes.NewReader(yamlExample)
268
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"))
276 }
277
278 func TestUnmarshalExact(t *testing.T) {
279         vip := New()
280         target := &testUnmarshalExtra{}
281         vip.SetConfigType("yaml")
282         r := bytes.NewReader(yamlExampleWithExtras)
283         vip.ReadConfig(r)
284         err := vip.UnmarshalExact(target)
285         if err == nil {
286                 t.Fatal("UnmarshalExact should error when populating a struct from a conf that contains unused fields")
287         }
288 }
289
290 func TestOverrides(t *testing.T) {
291         Set("age", 40)
292         assert.Equal(t, 40, Get("age"))
293 }
294
295 func TestDefaultPost(t *testing.T) {
296         assert.NotEqual(t, "NYC", Get("state"))
297         SetDefault("state", "NYC")
298         assert.Equal(t, "NYC", Get("state"))
299 }
300
301 func TestAliases(t *testing.T) {
302         RegisterAlias("years", "age")
303         assert.Equal(t, 40, Get("years"))
304         Set("years", 45)
305         assert.Equal(t, 45, Get("age"))
306 }
307
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"))
315 }
316
317 func TestYML(t *testing.T) {
318         initYAML()
319         assert.Equal(t, "steve", Get("name"))
320 }
321
322 func TestJSON(t *testing.T) {
323         initJSON()
324         assert.Equal(t, "0001", Get("id"))
325 }
326
327 func TestProperties(t *testing.T) {
328         initProperties()
329         assert.Equal(t, "0001", Get("p_id"))
330 }
331
332 func TestTOML(t *testing.T) {
333         initTOML()
334         assert.Equal(t, "TOML Example", Get("title"))
335 }
336
337 func TestHCL(t *testing.T) {
338         initHcl()
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"))
343         Set("id", "0002")
344         assert.Equal(t, "0002", Get("id"))
345         assert.NotEqual(t, "cronut", Get("type"))
346 }
347
348 func TestRemotePrecedence(t *testing.T) {
349         initJSON()
350
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")
361 }
362
363 func TestEnv(t *testing.T) {
364         initJSON()
365
366         BindEnv("id")
367         BindEnv("f", "FOOD")
368
369         os.Setenv("ID", "13")
370         os.Setenv("FOOD", "apple")
371         os.Setenv("NAME", "crunk")
372
373         assert.Equal(t, "13", Get("id"))
374         assert.Equal(t, "apple", Get("f"))
375         assert.Equal(t, "Cake", Get("name"))
376
377         AutomaticEnv()
378
379         assert.Equal(t, "crunk", Get("name"))
380
381 }
382
383 func TestEnvPrefix(t *testing.T) {
384         initJSON()
385
386         SetEnvPrefix("foo") // will be uppercased automatically
387         BindEnv("id")
388         BindEnv("f", "FOOD") // not using prefix
389
390         os.Setenv("FOO_ID", "13")
391         os.Setenv("FOOD", "apple")
392         os.Setenv("FOO_NAME", "crunk")
393
394         assert.Equal(t, "13", Get("id"))
395         assert.Equal(t, "apple", Get("f"))
396         assert.Equal(t, "Cake", Get("name"))
397
398         AutomaticEnv()
399
400         assert.Equal(t, "crunk", Get("name"))
401 }
402
403 func TestAutoEnv(t *testing.T) {
404         Reset()
405
406         AutomaticEnv()
407         os.Setenv("FOO_BAR", "13")
408         assert.Equal(t, "13", Get("foo_bar"))
409 }
410
411 func TestAutoEnvWithPrefix(t *testing.T) {
412         Reset()
413
414         AutomaticEnv()
415         SetEnvPrefix("Baz")
416         os.Setenv("BAZ_BAR", "13")
417         assert.Equal(t, "13", Get("bar"))
418 }
419
420 func TestSetEnvKeyReplacer(t *testing.T) {
421         Reset()
422
423         AutomaticEnv()
424         os.Setenv("REFRESH_INTERVAL", "30s")
425
426         replacer := strings.NewReplacer("-", "_")
427         SetEnvKeyReplacer(replacer)
428
429         assert.Equal(t, "30s", Get("refresh-interval"))
430 }
431
432 func TestAllKeys(t *testing.T) {
433         initConfigs()
434
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}}}}}
438
439         var allkeys sort.StringSlice
440         allkeys = AllKeys()
441         allkeys.Sort()
442         ks.Sort()
443
444         assert.Equal(t, ks, allkeys)
445         assert.Equal(t, all, AllSettings())
446 }
447
448 func TestAllKeysWithEnv(t *testing.T) {
449         v := New()
450
451         // bind and define environment variables (including a nested one)
452         v.BindEnv("id")
453         v.BindEnv("foo.bar")
454         v.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
455         os.Setenv("ID", "13")
456         os.Setenv("FOO_BAR", "baz")
457
458         expectedKeys := sort.StringSlice{"id", "foo.bar"}
459         expectedKeys.Sort()
460         keys := sort.StringSlice(v.AllKeys())
461         keys.Sort()
462         assert.Equal(t, expectedKeys, keys)
463 }
464
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"))
470 }
471
472 func TestRecursiveAliases(t *testing.T) {
473         RegisterAlias("Baz", "Roo")
474         RegisterAlias("Roo", "baz")
475 }
476
477 func TestUnmarshal(t *testing.T) {
478         SetDefault("port", 1313)
479         Set("name", "Steve")
480         Set("duration", "1s1ms")
481
482         type config struct {
483                 Port     int
484                 Name     string
485                 Duration time.Duration
486         }
487
488         var C config
489
490         err := Unmarshal(&C)
491         if err != nil {
492                 t.Fatalf("unable to decode into struct, %v", err)
493         }
494
495         assert.Equal(t, &config{Name: "Steve", Port: 1313, Duration: time.Second + time.Millisecond}, &C)
496
497         Set("port", 1234)
498         err = Unmarshal(&C)
499         if err != nil {
500                 t.Fatalf("unable to decode into struct, %v", err)
501         }
502         assert.Equal(t, &config{Name: "Steve", Port: 1234, Duration: time.Second + time.Millisecond}, &C)
503 }
504
505 func TestBindPFlags(t *testing.T) {
506         v := New() // create independent Viper object
507         flagSet := pflag.NewFlagSet("test", pflag.ContinueOnError)
508
509         var testValues = map[string]*string{
510                 "host":     nil,
511                 "port":     nil,
512                 "endpoint": nil,
513         }
514
515         var mutatedTestValues = map[string]string{
516                 "host":     "localhost",
517                 "port":     "6060",
518                 "endpoint": "/public",
519         }
520
521         for name := range testValues {
522                 testValues[name] = flagSet.String(name, "", "test")
523         }
524
525         err := v.BindPFlags(flagSet)
526         if err != nil {
527                 t.Fatalf("error binding flag set, %v", err)
528         }
529
530         flagSet.VisitAll(func(flag *pflag.Flag) {
531                 flag.Value.Set(mutatedTestValues[flag.Name])
532                 flag.Changed = true
533         })
534
535         for name, expected := range mutatedTestValues {
536                 assert.Equal(t, expected, v.Get(name))
537         }
538
539 }
540
541 func TestBindPFlagsStringSlice(t *testing.T) {
542         for _, testValue := range []struct {
543                 Expected []string
544                 Value    string
545         }{
546                 {[]string{}, ""},
547                 {[]string{"jeden"}, "jeden"},
548                 {[]string{"dwa", "trzy"}, "dwa,trzy"},
549                 {[]string{"cztery", "piec , szesc"}, "cztery,\"piec , szesc\""}} {
550
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)
558                                         f.Changed = changed
559                                 }
560                         })
561
562                         err := v.BindPFlags(flagSet)
563                         if err != nil {
564                                 t.Fatalf("error binding flag set, %v", err)
565                         }
566
567                         type TestStr struct {
568                                 StringSlice []string
569                         }
570                         val := &TestStr{}
571                         if err := v.Unmarshal(val); err != nil {
572                                 t.Fatalf("%+#v cannot unmarshal: %s", testValue.Value, err)
573                         }
574                         assert.Equal(t, testValue.Expected, val.StringSlice)
575                 }
576         }
577 }
578
579 func TestBindPFlag(t *testing.T) {
580         var testString = "testing"
581         var testValue = newStringValue(testString, &testString)
582
583         flag := &pflag.Flag{
584                 Name:    "testflag",
585                 Value:   testValue,
586                 Changed: false,
587         }
588
589         BindPFlag("testvalue", flag)
590
591         assert.Equal(t, testString, Get("testvalue"))
592
593         flag.Value.Set("testing_mutate")
594         flag.Changed = true //hack for pflag usage
595
596         assert.Equal(t, "testing_mutate", Get("testvalue"))
597
598 }
599
600 func TestBoundCaseSensitivity(t *testing.T) {
601         assert.Equal(t, "brown", Get("eyes"))
602
603         BindEnv("eYEs", "TURTLE_EYES")
604         os.Setenv("TURTLE_EYES", "blue")
605
606         assert.Equal(t, "blue", Get("eyes"))
607
608         var testString = "green"
609         var testValue = newStringValue(testString, &testString)
610
611         flag := &pflag.Flag{
612                 Name:    "eyeballs",
613                 Value:   testValue,
614                 Changed: true,
615         }
616
617         BindPFlag("eYEs", flag)
618         assert.Equal(t, "green", Get("eyes"))
619
620 }
621
622 func TestSizeInBytes(t *testing.T) {
623         input := map[string]uint{
624                 "":               0,
625                 "b":              0,
626                 "12 bytes":       0,
627                 "200000000000gb": 0,
628                 "12 b":           12,
629                 "43 MB":          43 * (1 << 20),
630                 "10mb":           10 * (1 << 20),
631                 "1gb":            1 << 30,
632         }
633
634         for str, expected := range input {
635                 assert.Equal(t, expected, parseSizeInBytes(str), str)
636         }
637 }
638
639 func TestFindsNestedKeys(t *testing.T) {
640         initConfigs()
641         dob, _ := time.Parse(time.RFC3339, "1979-05-27T07:32:00Z")
642
643         Set("super", map[string]interface{}{
644                 "deep": map[string]interface{}{
645                         "nested": "value",
646                 },
647         })
648
649         expected := map[string]interface{}{
650                 "super": map[string]interface{}{
651                         "deep": map[string]interface{}{
652                                 "nested": "value",
653                         },
654                 },
655                 "super.deep": map[string]interface{}{
656                         "nested": "value",
657                 },
658                 "super.deep.nested":  "value",
659                 "owner.organization": "MongoDB",
660                 "batters.batter": []interface{}{
661                         map[string]interface{}{
662                                 "type": "Regular",
663                         },
664                         map[string]interface{}{
665                                 "type": "Chocolate",
666                         },
667                         map[string]interface{}{
668                                 "type": "Blueberry",
669                         },
670                         map[string]interface{}{
671                                 "type": "Devil's Food",
672                         },
673                 },
674                 "hobbies": []interface{}{
675                         "skateboarding", "snowboarding", "go",
676                 },
677                 "title":  "TOML Example",
678                 "newkey": "remote",
679                 "batters": map[string]interface{}{
680                         "batter": []interface{}{
681                                 map[string]interface{}{
682                                         "type": "Regular",
683                                 },
684                                 map[string]interface{}{
685                                         "type": "Chocolate",
686                                 }, map[string]interface{}{
687                                         "type": "Blueberry",
688                                 }, map[string]interface{}{
689                                         "type": "Devil's Food",
690                                 },
691                         },
692                 },
693                 "eyes": "brown",
694                 "age":  35,
695                 "owner": map[string]interface{}{
696                         "organization": "MongoDB",
697                         "bio":          "MongoDB Chief Developer Advocate & Hacker at Large",
698                         "dob":          dob,
699                 },
700                 "owner.bio": "MongoDB Chief Developer Advocate & Hacker at Large",
701                 "type":      "donut",
702                 "id":        "0001",
703                 "name":      "Cake",
704                 "hacker":    true,
705                 "ppu":       0.55,
706                 "clothing": map[string]interface{}{
707                         "jacket":   "leather",
708                         "trousers": "denim",
709                         "pants": map[string]interface{}{
710                                 "size": "large",
711                         },
712                 },
713                 "clothing.jacket":     "leather",
714                 "clothing.pants.size": "large",
715                 "clothing.trousers":   "denim",
716                 "owner.dob":           dob,
717                 "beard":               true,
718                 "foos": []map[string]interface{}{
719                         map[string]interface{}{
720                                 "foo": []map[string]interface{}{
721                                         map[string]interface{}{
722                                                 "key": 1,
723                                         },
724                                         map[string]interface{}{
725                                                 "key": 2,
726                                         },
727                                         map[string]interface{}{
728                                                 "key": 3,
729                                         },
730                                         map[string]interface{}{
731                                                 "key": 4,
732                                         },
733                                 },
734                         },
735                 },
736         }
737
738         for key, expectedValue := range expected {
739
740                 assert.Equal(t, expectedValue, v.Get(key))
741         }
742
743 }
744
745 func TestReadBufConfig(t *testing.T) {
746         v := New()
747         v.SetConfigType("yaml")
748         v.ReadConfig(bytes.NewBuffer(yamlExample))
749         t.Log(v.AllKeys())
750
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"))
757 }
758
759 func TestIsSet(t *testing.T) {
760         v := New()
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"))
768 }
769
770 func TestDirsSearch(t *testing.T) {
771
772         root, config, cleanup := initDirs(t)
773         defer cleanup()
774
775         v := New()
776         v.SetConfigName(config)
777         v.SetDefault(`key`, `default`)
778
779         entries, err := ioutil.ReadDir(root)
780         for _, e := range entries {
781                 if e.IsDir() {
782                         v.AddConfigPath(e.Name())
783                 }
784         }
785
786         err = v.ReadInConfig()
787         assert.Nil(t, err)
788
789         assert.Equal(t, `value is `+path.Base(v.configPaths[0]), v.GetString(`key`))
790 }
791
792 func TestWrongDirsSearchNotFound(t *testing.T) {
793
794         _, config, cleanup := initDirs(t)
795         defer cleanup()
796
797         v := New()
798         v.SetConfigName(config)
799         v.SetDefault(`key`, `default`)
800
801         v.AddConfigPath(`whattayoutalkingbout`)
802         v.AddConfigPath(`thispathaintthere`)
803
804         err := v.ReadInConfig()
805         assert.Equal(t, reflect.TypeOf(ConfigFileNotFoundError{"", ""}), reflect.TypeOf(err))
806
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`))
810 }
811
812 func TestWrongDirsSearchNotFoundForMerge(t *testing.T) {
813
814         _, config, cleanup := initDirs(t)
815         defer cleanup()
816
817         v := New()
818         v.SetConfigName(config)
819         v.SetDefault(`key`, `default`)
820
821         v.AddConfigPath(`whattayoutalkingbout`)
822         v.AddConfigPath(`thispathaintthere`)
823
824         err := v.MergeInConfig()
825         assert.Equal(t, reflect.TypeOf(ConfigFileNotFoundError{"", ""}), reflect.TypeOf(err))
826
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`))
830 }
831
832 func TestSub(t *testing.T) {
833         v := New()
834         v.SetConfigType("yaml")
835         v.ReadConfig(bytes.NewBuffer(yamlExample))
836
837         subv := v.Sub("clothing")
838         assert.Equal(t, v.Get("clothing.pants.size"), subv.Get("pants.size"))
839
840         subv = v.Sub("clothing.pants")
841         assert.Equal(t, v.Get("clothing.pants.size"), subv.Get("size"))
842
843         subv = v.Sub("clothing.pants.size")
844         assert.Equal(t, (*Viper)(nil), subv)
845
846         subv = v.Sub("missing.key")
847         assert.Equal(t, (*Viper)(nil), subv)
848 }
849
850 var yamlMergeExampleTgt = []byte(`
851 hello:
852     pop: 37890
853     lagrenum: 765432101234567
854     world:
855     - us
856     - uk
857     - fr
858     - de
859 `)
860
861 var yamlMergeExampleSrc = []byte(`
862 hello:
863     pop: 45000
864     lagrenum: 7654321001234567
865     universe:
866     - mw
867     - ad
868 fu: bar
869 `)
870
871 func TestMergeConfig(t *testing.T) {
872         v := New()
873         v.SetConfigType("yml")
874         if err := v.ReadConfig(bytes.NewBuffer(yamlMergeExampleTgt)); err != nil {
875                 t.Fatal(err)
876         }
877
878         if pop := v.GetInt("hello.pop"); pop != 37890 {
879                 t.Fatalf("pop != 37890, = %d", pop)
880         }
881
882         if pop := v.GetInt("hello.lagrenum"); pop != 765432101234567 {
883                 t.Fatalf("lagrenum != 765432101234567, = %d", pop)
884         }
885
886         if pop := v.GetInt64("hello.lagrenum"); pop != int64(765432101234567) {
887                 t.Fatalf("int64 lagrenum != 765432101234567, = %d", pop)
888         }
889
890         if world := v.GetStringSlice("hello.world"); len(world) != 4 {
891                 t.Fatalf("len(world) != 4, = %d", len(world))
892         }
893
894         if fu := v.GetString("fu"); fu != "" {
895                 t.Fatalf("fu != \"\", = %s", fu)
896         }
897
898         if err := v.MergeConfig(bytes.NewBuffer(yamlMergeExampleSrc)); err != nil {
899                 t.Fatal(err)
900         }
901
902         if pop := v.GetInt("hello.pop"); pop != 45000 {
903                 t.Fatalf("pop != 45000, = %d", pop)
904         }
905
906         if pop := v.GetInt("hello.lagrenum"); pop != 7654321001234567 {
907                 t.Fatalf("lagrenum != 7654321001234567, = %d", pop)
908         }
909
910         if pop := v.GetInt64("hello.lagrenum"); pop != int64(7654321001234567) {
911                 t.Fatalf("int64 lagrenum != 7654321001234567, = %d", pop)
912         }
913
914         if world := v.GetStringSlice("hello.world"); len(world) != 4 {
915                 t.Fatalf("len(world) != 4, = %d", len(world))
916         }
917
918         if universe := v.GetStringSlice("hello.universe"); len(universe) != 2 {
919                 t.Fatalf("len(universe) != 2, = %d", len(universe))
920         }
921
922         if fu := v.GetString("fu"); fu != "bar" {
923                 t.Fatalf("fu != \"bar\", = %s", fu)
924         }
925 }
926
927 func TestMergeConfigNoMerge(t *testing.T) {
928         v := New()
929         v.SetConfigType("yml")
930         if err := v.ReadConfig(bytes.NewBuffer(yamlMergeExampleTgt)); err != nil {
931                 t.Fatal(err)
932         }
933
934         if pop := v.GetInt("hello.pop"); pop != 37890 {
935                 t.Fatalf("pop != 37890, = %d", pop)
936         }
937
938         if world := v.GetStringSlice("hello.world"); len(world) != 4 {
939                 t.Fatalf("len(world) != 4, = %d", len(world))
940         }
941
942         if fu := v.GetString("fu"); fu != "" {
943                 t.Fatalf("fu != \"\", = %s", fu)
944         }
945
946         if err := v.ReadConfig(bytes.NewBuffer(yamlMergeExampleSrc)); err != nil {
947                 t.Fatal(err)
948         }
949
950         if pop := v.GetInt("hello.pop"); pop != 45000 {
951                 t.Fatalf("pop != 45000, = %d", pop)
952         }
953
954         if world := v.GetStringSlice("hello.world"); len(world) != 0 {
955                 t.Fatalf("len(world) != 0, = %d", len(world))
956         }
957
958         if universe := v.GetStringSlice("hello.universe"); len(universe) != 2 {
959                 t.Fatalf("len(universe) != 2, = %d", len(universe))
960         }
961
962         if fu := v.GetString("fu"); fu != "bar" {
963                 t.Fatalf("fu != \"bar\", = %s", fu)
964         }
965 }
966
967 func TestUnmarshalingWithAliases(t *testing.T) {
968         v := New()
969         v.SetDefault("ID", 1)
970         v.Set("name", "Steve")
971         v.Set("lastname", "Owen")
972
973         v.RegisterAlias("UserID", "ID")
974         v.RegisterAlias("Firstname", "name")
975         v.RegisterAlias("Surname", "lastname")
976
977         type config struct {
978                 ID        int
979                 FirstName string
980                 Surname   string
981         }
982
983         var C config
984         err := v.Unmarshal(&C)
985         if err != nil {
986                 t.Fatalf("unable to decode into struct, %v", err)
987         }
988
989         assert.Equal(t, &config{ID: 1, FirstName: "Steve", Surname: "Owen"}, &C)
990 }
991
992 func TestSetConfigNameClearsFileCache(t *testing.T) {
993         SetConfigFile("/tmp/config.yaml")
994         SetConfigName("default")
995         f, err := v.getConfigFile()
996         if err == nil {
997                 t.Fatalf("config file cache should have been cleared")
998         }
999         assert.Empty(t, f)
1000 }
1001
1002 func TestShadowedNestedValue(t *testing.T) {
1003
1004         config := `name: steve
1005 clothing:
1006   jacket: leather
1007   trousers: denim
1008   pants:
1009     size: large
1010 `
1011         initConfig("yaml", config)
1012
1013         assert.Equal(t, "steve", GetString("name"))
1014
1015         polyester := "polyester"
1016         SetDefault("clothing.shirt", polyester)
1017         SetDefault("clothing.jacket.price", 100)
1018
1019         assert.Equal(t, "leather", GetString("clothing.jacket"))
1020         assert.Nil(t, Get("clothing.jacket.price"))
1021         assert.Equal(t, polyester, GetString("clothing.shirt"))
1022
1023         clothingSettings := AllSettings()["clothing"].(map[string]interface{})
1024         assert.Equal(t, "leather", clothingSettings["jacket"])
1025         assert.Equal(t, polyester, clothingSettings["shirt"])
1026 }
1027
1028 func TestDotParameter(t *testing.T) {
1029         initJSON()
1030         // shoud take precedence over batters defined in jsonExample
1031         r := bytes.NewReader([]byte(`{ "batters.batter": [ { "type": "Small" } ] }`))
1032         unmarshalReader(r, v.config)
1033
1034         actual := Get("batters.batter")
1035         expected := []interface{}{map[string]interface{}{"type": "Small"}}
1036         assert.Equal(t, expected, actual)
1037 }
1038
1039 func TestCaseInsensitive(t *testing.T) {
1040         for _, config := range []struct {
1041                 typ     string
1042                 content string
1043         }{
1044                 {"yaml", `
1045 aBcD: 1
1046 eF:
1047   gH: 2
1048   iJk: 3
1049   Lm:
1050     nO: 4
1051     P:
1052       Q: 5
1053       R: 6
1054 `},
1055                 {"json", `{
1056   "aBcD": 1,
1057   "eF": {
1058     "iJk": 3,
1059     "Lm": {
1060       "P": {
1061         "Q": 5,
1062         "R": 6
1063       },
1064       "nO": 4
1065     },
1066     "gH": 2
1067   }
1068 }`},
1069                 {"toml", `aBcD = 1
1070 [eF]
1071 gH = 2
1072 iJk = 3
1073 [eF.Lm]
1074 nO = 4
1075 [eF.Lm.P]
1076 Q = 5
1077 R = 6
1078 `},
1079         } {
1080                 doTestCaseInsensitive(t, config.typ, config.content)
1081         }
1082 }
1083
1084 func TestCaseInsensitiveSet(t *testing.T) {
1085         Reset()
1086         m1 := map[string]interface{}{
1087                 "Foo": 32,
1088                 "Bar": map[interface{}]interface {
1089                 }{
1090                         "ABc": "A",
1091                         "cDE": "B"},
1092         }
1093
1094         m2 := map[string]interface{}{
1095                 "Foo": 52,
1096                 "Bar": map[interface{}]interface {
1097                 }{
1098                         "bCd": "A",
1099                         "eFG": "B"},
1100         }
1101
1102         Set("Given1", m1)
1103         Set("Number1", 42)
1104
1105         SetDefault("Given2", m2)
1106         SetDefault("Number2", 52)
1107
1108         // Verify SetDefault
1109         if v := Get("number2"); v != 52 {
1110                 t.Fatalf("Expected 52 got %q", v)
1111         }
1112
1113         if v := Get("given2.foo"); v != 52 {
1114                 t.Fatalf("Expected 52 got %q", v)
1115         }
1116
1117         if v := Get("given2.bar.bcd"); v != "A" {
1118                 t.Fatalf("Expected A got %q", v)
1119         }
1120
1121         if _, ok := m2["Foo"]; !ok {
1122                 t.Fatal("Input map changed")
1123         }
1124
1125         // Verify Set
1126         if v := Get("number1"); v != 42 {
1127                 t.Fatalf("Expected 42 got %q", v)
1128         }
1129
1130         if v := Get("given1.foo"); v != 32 {
1131                 t.Fatalf("Expected 32 got %q", v)
1132         }
1133
1134         if v := Get("given1.bar.abc"); v != "A" {
1135                 t.Fatalf("Expected A got %q", v)
1136         }
1137
1138         if _, ok := m1["Foo"]; !ok {
1139                 t.Fatal("Input map changed")
1140         }
1141 }
1142
1143 func TestParseNested(t *testing.T) {
1144         type duration struct {
1145                 Delay time.Duration
1146         }
1147
1148         type item struct {
1149                 Name   string
1150                 Delay  time.Duration
1151                 Nested duration
1152         }
1153
1154         config := `[[parent]]
1155         delay="100ms"
1156         [parent.nested]
1157         delay="200ms"
1158 `
1159         initConfig("toml", config)
1160
1161         var items []item
1162         err := v.UnmarshalKey("parent", &items)
1163         if err != nil {
1164                 t.Fatalf("unable to decode into struct, %v", err)
1165         }
1166
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)
1170 }
1171
1172 func doTestCaseInsensitive(t *testing.T, typ, config string) {
1173         initConfig(typ, config)
1174         Set("RfD", true)
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")))
1183
1184 }
1185
1186 func BenchmarkGetBool(b *testing.B) {
1187         key := "BenchmarkGetBool"
1188         v = New()
1189         v.Set(key, true)
1190
1191         for i := 0; i < b.N; i++ {
1192                 if !v.GetBool(key) {
1193                         b.Fatal("GetBool returned false")
1194                 }
1195         }
1196 }
1197
1198 func BenchmarkGet(b *testing.B) {
1199         key := "BenchmarkGet"
1200         v = New()
1201         v.Set(key, true)
1202
1203         for i := 0; i < b.N; i++ {
1204                 if !v.Get(key).(bool) {
1205                         b.Fatal("Get returned false")
1206                 }
1207         }
1208 }
1209
1210 // This is the "perfect result" for the above.
1211 func BenchmarkGetBoolFromMap(b *testing.B) {
1212         m := make(map[string]bool)
1213         key := "BenchmarkGetBool"
1214         m[key] = true
1215
1216         for i := 0; i < b.N; i++ {
1217                 if !m[key] {
1218                         b.Fatal("Map value was false")
1219                 }
1220         }
1221 }