gl.tzv.io/spf13/viper@v0.0.0-20170410042614-f1b07f75fe6a/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 "fmt" 11 "io" 12 "io/ioutil" 13 "os" 14 "path" 15 "reflect" 16 "sort" 17 "strings" 18 "testing" 19 "time" 20 21 "gl.tzv.io/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 TestSetEnvReplacer(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 TestBindPFlag(t *testing.T) { 542 var testString = "testing" 543 var testValue = newStringValue(testString, &testString) 544 545 flag := &pflag.Flag{ 546 Name: "testflag", 547 Value: testValue, 548 Changed: false, 549 } 550 551 BindPFlag("testvalue", flag) 552 553 assert.Equal(t, testString, Get("testvalue")) 554 555 flag.Value.Set("testing_mutate") 556 flag.Changed = true //hack for pflag usage 557 558 assert.Equal(t, "testing_mutate", Get("testvalue")) 559 560 } 561 562 func TestBoundCaseSensitivity(t *testing.T) { 563 assert.Equal(t, "brown", Get("eyes")) 564 565 BindEnv("eYEs", "TURTLE_EYES") 566 os.Setenv("TURTLE_EYES", "blue") 567 568 assert.Equal(t, "blue", Get("eyes")) 569 570 var testString = "green" 571 var testValue = newStringValue(testString, &testString) 572 573 flag := &pflag.Flag{ 574 Name: "eyeballs", 575 Value: testValue, 576 Changed: true, 577 } 578 579 BindPFlag("eYEs", flag) 580 assert.Equal(t, "green", Get("eyes")) 581 582 } 583 584 func TestSizeInBytes(t *testing.T) { 585 input := map[string]uint{ 586 "": 0, 587 "b": 0, 588 "12 bytes": 0, 589 "200000000000gb": 0, 590 "12 b": 12, 591 "43 MB": 43 * (1 << 20), 592 "10mb": 10 * (1 << 20), 593 "1gb": 1 << 30, 594 } 595 596 for str, expected := range input { 597 assert.Equal(t, expected, parseSizeInBytes(str), str) 598 } 599 } 600 601 func TestFindsNestedKeys(t *testing.T) { 602 initConfigs() 603 dob, _ := time.Parse(time.RFC3339, "1979-05-27T07:32:00Z") 604 605 Set("super", map[string]interface{}{ 606 "deep": map[string]interface{}{ 607 "nested": "value", 608 }, 609 }) 610 611 expected := map[string]interface{}{ 612 "super": map[string]interface{}{ 613 "deep": map[string]interface{}{ 614 "nested": "value", 615 }, 616 }, 617 "super.deep": map[string]interface{}{ 618 "nested": "value", 619 }, 620 "super.deep.nested": "value", 621 "owner.organization": "MongoDB", 622 "batters.batter": []interface{}{ 623 map[string]interface{}{ 624 "type": "Regular", 625 }, 626 map[string]interface{}{ 627 "type": "Chocolate", 628 }, 629 map[string]interface{}{ 630 "type": "Blueberry", 631 }, 632 map[string]interface{}{ 633 "type": "Devil's Food", 634 }, 635 }, 636 "hobbies": []interface{}{ 637 "skateboarding", "snowboarding", "go", 638 }, 639 "title": "TOML Example", 640 "newkey": "remote", 641 "batters": map[string]interface{}{ 642 "batter": []interface{}{ 643 map[string]interface{}{ 644 "type": "Regular", 645 }, 646 map[string]interface{}{ 647 "type": "Chocolate", 648 }, map[string]interface{}{ 649 "type": "Blueberry", 650 }, map[string]interface{}{ 651 "type": "Devil's Food", 652 }, 653 }, 654 }, 655 "eyes": "brown", 656 "age": 35, 657 "owner": map[string]interface{}{ 658 "organization": "MongoDB", 659 "bio": "MongoDB Chief Developer Advocate & Hacker at Large", 660 "dob": dob, 661 }, 662 "owner.bio": "MongoDB Chief Developer Advocate & Hacker at Large", 663 "type": "donut", 664 "id": "0001", 665 "name": "Cake", 666 "hacker": true, 667 "ppu": 0.55, 668 "clothing": map[string]interface{}{ 669 "jacket": "leather", 670 "trousers": "denim", 671 "pants": map[string]interface{}{ 672 "size": "large", 673 }, 674 }, 675 "clothing.jacket": "leather", 676 "clothing.pants.size": "large", 677 "clothing.trousers": "denim", 678 "owner.dob": dob, 679 "beard": true, 680 "foos": []map[string]interface{}{ 681 map[string]interface{}{ 682 "foo": []map[string]interface{}{ 683 map[string]interface{}{ 684 "key": 1, 685 }, 686 map[string]interface{}{ 687 "key": 2, 688 }, 689 map[string]interface{}{ 690 "key": 3, 691 }, 692 map[string]interface{}{ 693 "key": 4, 694 }, 695 }, 696 }, 697 }, 698 } 699 700 for key, expectedValue := range expected { 701 702 assert.Equal(t, expectedValue, v.Get(key)) 703 } 704 705 } 706 707 func TestReadBufConfig(t *testing.T) { 708 v := New() 709 v.SetConfigType("yaml") 710 v.ReadConfig(bytes.NewBuffer(yamlExample)) 711 t.Log(v.AllKeys()) 712 713 assert.True(t, v.InConfig("name")) 714 assert.False(t, v.InConfig("state")) 715 assert.Equal(t, "steve", v.Get("name")) 716 assert.Equal(t, []interface{}{"skateboarding", "snowboarding", "go"}, v.Get("hobbies")) 717 assert.Equal(t, map[string]interface{}{"jacket": "leather", "trousers": "denim", "pants": map[string]interface{}{"size": "large"}}, v.Get("clothing")) 718 assert.Equal(t, 35, v.Get("age")) 719 } 720 721 func TestIsSet(t *testing.T) { 722 v := New() 723 v.SetConfigType("yaml") 724 v.ReadConfig(bytes.NewBuffer(yamlExample)) 725 assert.True(t, v.IsSet("clothing.jacket")) 726 assert.False(t, v.IsSet("clothing.jackets")) 727 assert.False(t, v.IsSet("helloworld")) 728 v.Set("helloworld", "fubar") 729 assert.True(t, v.IsSet("helloworld")) 730 } 731 732 func TestDirsSearch(t *testing.T) { 733 734 root, config, cleanup := initDirs(t) 735 defer cleanup() 736 737 v := New() 738 v.SetConfigName(config) 739 v.SetDefault(`key`, `default`) 740 741 entries, err := ioutil.ReadDir(root) 742 for _, e := range entries { 743 if e.IsDir() { 744 v.AddConfigPath(e.Name()) 745 } 746 } 747 748 err = v.ReadInConfig() 749 assert.Nil(t, err) 750 751 assert.Equal(t, `value is `+path.Base(v.configPaths[0]), v.GetString(`key`)) 752 } 753 754 func TestWrongDirsSearchNotFound(t *testing.T) { 755 756 _, config, cleanup := initDirs(t) 757 defer cleanup() 758 759 v := New() 760 v.SetConfigName(config) 761 v.SetDefault(`key`, `default`) 762 763 v.AddConfigPath(`whattayoutalkingbout`) 764 v.AddConfigPath(`thispathaintthere`) 765 766 err := v.ReadInConfig() 767 assert.Equal(t, reflect.TypeOf(ConfigFileNotFoundError{"", ""}), reflect.TypeOf(err)) 768 769 // Even though config did not load and the error might have 770 // been ignored by the client, the default still loads 771 assert.Equal(t, `default`, v.GetString(`key`)) 772 } 773 774 func TestWrongDirsSearchNotFoundForMerge(t *testing.T) { 775 776 _, config, cleanup := initDirs(t) 777 defer cleanup() 778 779 v := New() 780 v.SetConfigName(config) 781 v.SetDefault(`key`, `default`) 782 783 v.AddConfigPath(`whattayoutalkingbout`) 784 v.AddConfigPath(`thispathaintthere`) 785 786 err := v.MergeInConfig() 787 assert.Equal(t, reflect.TypeOf(ConfigFileNotFoundError{"", ""}), reflect.TypeOf(err)) 788 789 // Even though config did not load and the error might have 790 // been ignored by the client, the default still loads 791 assert.Equal(t, `default`, v.GetString(`key`)) 792 } 793 794 func TestSub(t *testing.T) { 795 v := New() 796 v.SetConfigType("yaml") 797 v.ReadConfig(bytes.NewBuffer(yamlExample)) 798 799 subv := v.Sub("clothing") 800 assert.Equal(t, v.Get("clothing.pants.size"), subv.Get("pants.size")) 801 802 subv = v.Sub("clothing.pants") 803 assert.Equal(t, v.Get("clothing.pants.size"), subv.Get("size")) 804 805 subv = v.Sub("clothing.pants.size") 806 assert.Equal(t, (*Viper)(nil), subv) 807 808 subv = v.Sub("missing.key") 809 assert.Equal(t, (*Viper)(nil), subv) 810 } 811 812 var yamlMergeExampleTgt = []byte(` 813 hello: 814 pop: 37890 815 lagrenum: 765432101234567 816 world: 817 - us 818 - uk 819 - fr 820 - de 821 `) 822 823 var yamlMergeExampleSrc = []byte(` 824 hello: 825 pop: 45000 826 lagrenum: 7654321001234567 827 universe: 828 - mw 829 - ad 830 fu: bar 831 `) 832 833 func TestMergeConfig(t *testing.T) { 834 v := New() 835 v.SetConfigType("yml") 836 if err := v.ReadConfig(bytes.NewBuffer(yamlMergeExampleTgt)); err != nil { 837 t.Fatal(err) 838 } 839 840 if pop := v.GetInt("hello.pop"); pop != 37890 { 841 t.Fatalf("pop != 37890, = %d", pop) 842 } 843 844 if pop := v.GetInt("hello.lagrenum"); pop != 765432101234567 { 845 t.Fatalf("lagrenum != 765432101234567, = %d", pop) 846 } 847 848 if pop := v.GetInt64("hello.lagrenum"); pop != int64(765432101234567) { 849 t.Fatalf("int64 lagrenum != 765432101234567, = %d", pop) 850 } 851 852 if world := v.GetStringSlice("hello.world"); len(world) != 4 { 853 t.Fatalf("len(world) != 4, = %d", len(world)) 854 } 855 856 if fu := v.GetString("fu"); fu != "" { 857 t.Fatalf("fu != \"\", = %s", fu) 858 } 859 860 if err := v.MergeConfig(bytes.NewBuffer(yamlMergeExampleSrc)); err != nil { 861 t.Fatal(err) 862 } 863 864 if pop := v.GetInt("hello.pop"); pop != 45000 { 865 t.Fatalf("pop != 45000, = %d", pop) 866 } 867 868 if pop := v.GetInt("hello.lagrenum"); pop != 7654321001234567 { 869 t.Fatalf("lagrenum != 7654321001234567, = %d", pop) 870 } 871 872 if pop := v.GetInt64("hello.lagrenum"); pop != int64(7654321001234567) { 873 t.Fatalf("int64 lagrenum != 7654321001234567, = %d", pop) 874 } 875 876 if world := v.GetStringSlice("hello.world"); len(world) != 4 { 877 t.Fatalf("len(world) != 4, = %d", len(world)) 878 } 879 880 if universe := v.GetStringSlice("hello.universe"); len(universe) != 2 { 881 t.Fatalf("len(universe) != 2, = %d", len(universe)) 882 } 883 884 if fu := v.GetString("fu"); fu != "bar" { 885 t.Fatalf("fu != \"bar\", = %s", fu) 886 } 887 } 888 889 func TestMergeConfigNoMerge(t *testing.T) { 890 v := New() 891 v.SetConfigType("yml") 892 if err := v.ReadConfig(bytes.NewBuffer(yamlMergeExampleTgt)); err != nil { 893 t.Fatal(err) 894 } 895 896 if pop := v.GetInt("hello.pop"); pop != 37890 { 897 t.Fatalf("pop != 37890, = %d", pop) 898 } 899 900 if world := v.GetStringSlice("hello.world"); len(world) != 4 { 901 t.Fatalf("len(world) != 4, = %d", len(world)) 902 } 903 904 if fu := v.GetString("fu"); fu != "" { 905 t.Fatalf("fu != \"\", = %s", fu) 906 } 907 908 if err := v.ReadConfig(bytes.NewBuffer(yamlMergeExampleSrc)); err != nil { 909 t.Fatal(err) 910 } 911 912 if pop := v.GetInt("hello.pop"); pop != 45000 { 913 t.Fatalf("pop != 45000, = %d", pop) 914 } 915 916 if world := v.GetStringSlice("hello.world"); len(world) != 0 { 917 t.Fatalf("len(world) != 0, = %d", len(world)) 918 } 919 920 if universe := v.GetStringSlice("hello.universe"); len(universe) != 2 { 921 t.Fatalf("len(universe) != 2, = %d", len(universe)) 922 } 923 924 if fu := v.GetString("fu"); fu != "bar" { 925 t.Fatalf("fu != \"bar\", = %s", fu) 926 } 927 } 928 929 func TestUnmarshalingWithAliases(t *testing.T) { 930 v := New() 931 v.SetDefault("ID", 1) 932 v.Set("name", "Steve") 933 v.Set("lastname", "Owen") 934 935 v.RegisterAlias("UserID", "ID") 936 v.RegisterAlias("Firstname", "name") 937 v.RegisterAlias("Surname", "lastname") 938 939 type config struct { 940 ID int 941 FirstName string 942 Surname string 943 } 944 945 var C config 946 err := v.Unmarshal(&C) 947 if err != nil { 948 t.Fatalf("unable to decode into struct, %v", err) 949 } 950 951 assert.Equal(t, &config{ID: 1, FirstName: "Steve", Surname: "Owen"}, &C) 952 } 953 954 func TestSetConfigNameClearsFileCache(t *testing.T) { 955 SetConfigFile("/tmp/config.yaml") 956 SetConfigName("default") 957 f, err := v.getConfigFile() 958 if err == nil { 959 t.Fatalf("config file cache should have been cleared") 960 } 961 assert.Empty(t, f) 962 } 963 964 func TestShadowedNestedValue(t *testing.T) { 965 966 config := `name: steve 967 clothing: 968 jacket: leather 969 trousers: denim 970 pants: 971 size: large 972 ` 973 initConfig("yaml", config) 974 975 assert.Equal(t, "steve", GetString("name")) 976 977 polyester := "polyester" 978 SetDefault("clothing.shirt", polyester) 979 SetDefault("clothing.jacket.price", 100) 980 981 assert.Equal(t, "leather", GetString("clothing.jacket")) 982 assert.Nil(t, Get("clothing.jacket.price")) 983 assert.Equal(t, polyester, GetString("clothing.shirt")) 984 985 clothingSettings := AllSettings()["clothing"].(map[string]interface{}) 986 assert.Equal(t, "leather", clothingSettings["jacket"]) 987 assert.Equal(t, polyester, clothingSettings["shirt"]) 988 } 989 990 func TestDotParameter(t *testing.T) { 991 initJSON() 992 // shoud take precedence over batters defined in jsonExample 993 r := bytes.NewReader([]byte(`{ "batters.batter": [ { "type": "Small" } ] }`)) 994 unmarshalReader(r, v.config) 995 996 actual := Get("batters.batter") 997 expected := []interface{}{map[string]interface{}{"type": "Small"}} 998 assert.Equal(t, expected, actual) 999 } 1000 1001 func TestCaseInsensitive(t *testing.T) { 1002 for _, config := range []struct { 1003 typ string 1004 content string 1005 }{ 1006 {"yaml", ` 1007 aBcD: 1 1008 eF: 1009 gH: 2 1010 iJk: 3 1011 Lm: 1012 nO: 4 1013 P: 1014 Q: 5 1015 R: 6 1016 `}, 1017 {"json", `{ 1018 "aBcD": 1, 1019 "eF": { 1020 "iJk": 3, 1021 "Lm": { 1022 "P": { 1023 "Q": 5, 1024 "R": 6 1025 }, 1026 "nO": 4 1027 }, 1028 "gH": 2 1029 } 1030 }`}, 1031 {"toml", `aBcD = 1 1032 [eF] 1033 gH = 2 1034 iJk = 3 1035 [eF.Lm] 1036 nO = 4 1037 [eF.Lm.P] 1038 Q = 5 1039 R = 6 1040 `}, 1041 } { 1042 doTestCaseInsensitive(t, config.typ, config.content) 1043 } 1044 } 1045 1046 func TestCaseInsensitiveSet(t *testing.T) { 1047 Reset() 1048 m1 := map[string]interface{}{ 1049 "Foo": 32, 1050 "Bar": map[interface{}]interface { 1051 }{ 1052 "ABc": "A", 1053 "cDE": "B"}, 1054 } 1055 1056 m2 := map[string]interface{}{ 1057 "Foo": 52, 1058 "Bar": map[interface{}]interface { 1059 }{ 1060 "bCd": "A", 1061 "eFG": "B"}, 1062 } 1063 1064 Set("Given1", m1) 1065 Set("Number1", 42) 1066 1067 SetDefault("Given2", m2) 1068 SetDefault("Number2", 52) 1069 1070 // Verify SetDefault 1071 if v := Get("number2"); v != 52 { 1072 t.Fatalf("Expected 52 got %q", v) 1073 } 1074 1075 if v := Get("given2.foo"); v != 52 { 1076 t.Fatalf("Expected 52 got %q", v) 1077 } 1078 1079 if v := Get("given2.bar.bcd"); v != "A" { 1080 t.Fatalf("Expected A got %q", v) 1081 } 1082 1083 if _, ok := m2["Foo"]; !ok { 1084 t.Fatal("Input map changed") 1085 } 1086 1087 // Verify Set 1088 if v := Get("number1"); v != 42 { 1089 t.Fatalf("Expected 42 got %q", v) 1090 } 1091 1092 if v := Get("given1.foo"); v != 32 { 1093 t.Fatalf("Expected 32 got %q", v) 1094 } 1095 1096 if v := Get("given1.bar.abc"); v != "A" { 1097 t.Fatalf("Expected A got %q", v) 1098 } 1099 1100 if _, ok := m1["Foo"]; !ok { 1101 t.Fatal("Input map changed") 1102 } 1103 } 1104 1105 func doTestCaseInsensitive(t *testing.T, typ, config string) { 1106 initConfig(typ, config) 1107 Set("RfD", true) 1108 assert.Equal(t, true, Get("rfd")) 1109 assert.Equal(t, true, Get("rFD")) 1110 assert.Equal(t, 1, cast.ToInt(Get("abcd"))) 1111 assert.Equal(t, 1, cast.ToInt(Get("Abcd"))) 1112 assert.Equal(t, 2, cast.ToInt(Get("ef.gh"))) 1113 assert.Equal(t, 3, cast.ToInt(Get("ef.ijk"))) 1114 assert.Equal(t, 4, cast.ToInt(Get("ef.lm.no"))) 1115 assert.Equal(t, 5, cast.ToInt(Get("ef.lm.p.q"))) 1116 1117 } 1118 1119 func BenchmarkGetBool(b *testing.B) { 1120 key := "BenchmarkGetBool" 1121 v = New() 1122 v.Set(key, true) 1123 1124 for i := 0; i < b.N; i++ { 1125 if !v.GetBool(key) { 1126 b.Fatal("GetBool returned false") 1127 } 1128 } 1129 } 1130 1131 func BenchmarkGet(b *testing.B) { 1132 key := "BenchmarkGet" 1133 v = New() 1134 v.Set(key, true) 1135 1136 for i := 0; i < b.N; i++ { 1137 if !v.Get(key).(bool) { 1138 b.Fatal("Get returned false") 1139 } 1140 } 1141 } 1142 1143 // This is the "perfect result" for the above. 1144 func BenchmarkGetBoolFromMap(b *testing.B) { 1145 m := make(map[string]bool) 1146 key := "BenchmarkGetBool" 1147 m[key] = true 1148 1149 for i := 0; i < b.N; i++ { 1150 if !m[key] { 1151 b.Fatal("Map value was false") 1152 } 1153 } 1154 }