github.com/tomarron/viper@v0.0.0-20160605220307-c1ccc378a054/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/ioutil" 12 "os" 13 "path" 14 "reflect" 15 "sort" 16 "strings" 17 "testing" 18 "time" 19 20 "github.com/spf13/pflag" 21 "github.com/stretchr/testify/assert" 22 ) 23 24 var yamlExample = []byte(`Hacker: true 25 name: steve 26 hobbies: 27 - skateboarding 28 - snowboarding 29 - go 30 clothing: 31 jacket: leather 32 trousers: denim 33 pants: 34 size: large 35 age: 35 36 eyes : brown 37 beard: true 38 `) 39 40 var yamlExampleWithExtras = []byte(`Existing: true 41 Bogus: true 42 `) 43 44 type testUnmarshalExtra struct { 45 Existing bool 46 } 47 48 var tomlExample = []byte(` 49 title = "TOML Example" 50 51 [owner] 52 organization = "MongoDB" 53 Bio = "MongoDB Chief Developer Advocate & Hacker at Large" 54 dob = 1979-05-27T07:32:00Z # First class dates? Why not?`) 55 56 var jsonExample = []byte(`{ 57 "id": "0001", 58 "type": "donut", 59 "name": "Cake", 60 "ppu": 0.55, 61 "batters": { 62 "batter": [ 63 { "type": "Regular" }, 64 { "type": "Chocolate" }, 65 { "type": "Blueberry" }, 66 { "type": "Devil's Food" } 67 ] 68 } 69 }`) 70 71 var hclExample = []byte(` 72 id = "0001" 73 type = "donut" 74 name = "Cake" 75 ppu = 0.55 76 foos { 77 foo { 78 key = 1 79 } 80 foo { 81 key = 2 82 } 83 foo { 84 key = 3 85 } 86 foo { 87 key = 4 88 } 89 }`) 90 91 var propertiesExample = []byte(` 92 p_id: 0001 93 p_type: donut 94 p_name: Cake 95 p_ppu: 0.55 96 p_batters.batter.type: Regular 97 `) 98 99 var remoteExample = []byte(`{ 100 "id":"0002", 101 "type":"cronut", 102 "newkey":"remote" 103 }`) 104 105 func initConfigs() { 106 Reset() 107 SetConfigType("yaml") 108 r := bytes.NewReader(yamlExample) 109 unmarshalReader(r, v.config) 110 111 SetConfigType("json") 112 r = bytes.NewReader(jsonExample) 113 unmarshalReader(r, v.config) 114 115 SetConfigType("hcl") 116 r = bytes.NewReader(hclExample) 117 unmarshalReader(r, v.config) 118 119 SetConfigType("properties") 120 r = bytes.NewReader(propertiesExample) 121 unmarshalReader(r, v.config) 122 123 SetConfigType("toml") 124 r = bytes.NewReader(tomlExample) 125 unmarshalReader(r, v.config) 126 127 SetConfigType("json") 128 remote := bytes.NewReader(remoteExample) 129 unmarshalReader(remote, v.kvstore) 130 } 131 132 func initYAML() { 133 Reset() 134 SetConfigType("yaml") 135 r := bytes.NewReader(yamlExample) 136 137 unmarshalReader(r, v.config) 138 } 139 140 func initJSON() { 141 Reset() 142 SetConfigType("json") 143 r := bytes.NewReader(jsonExample) 144 145 unmarshalReader(r, v.config) 146 } 147 148 func initProperties() { 149 Reset() 150 SetConfigType("properties") 151 r := bytes.NewReader(propertiesExample) 152 153 unmarshalReader(r, v.config) 154 } 155 156 func initTOML() { 157 Reset() 158 SetConfigType("toml") 159 r := bytes.NewReader(tomlExample) 160 161 unmarshalReader(r, v.config) 162 } 163 164 func initHcl() { 165 Reset() 166 SetConfigType("hcl") 167 r := bytes.NewReader(hclExample) 168 169 unmarshalReader(r, v.config) 170 } 171 172 // make directories for testing 173 func initDirs(t *testing.T) (string, string, func()) { 174 175 var ( 176 testDirs = []string{`a a`, `b`, `c\c`, `D_`} 177 config = `improbable` 178 ) 179 180 root, err := ioutil.TempDir("", "") 181 182 cleanup := true 183 defer func() { 184 if cleanup { 185 os.Chdir("..") 186 os.RemoveAll(root) 187 } 188 }() 189 190 assert.Nil(t, err) 191 192 err = os.Chdir(root) 193 assert.Nil(t, err) 194 195 for _, dir := range testDirs { 196 err = os.Mkdir(dir, 0750) 197 assert.Nil(t, err) 198 199 err = ioutil.WriteFile( 200 path.Join(dir, config+".toml"), 201 []byte("key = \"value is "+dir+"\"\n"), 202 0640) 203 assert.Nil(t, err) 204 } 205 206 cleanup = false 207 return root, config, func() { 208 os.Chdir("..") 209 os.RemoveAll(root) 210 } 211 } 212 213 //stubs for PFlag Values 214 type stringValue string 215 216 func newStringValue(val string, p *string) *stringValue { 217 *p = val 218 return (*stringValue)(p) 219 } 220 221 func (s *stringValue) Set(val string) error { 222 *s = stringValue(val) 223 return nil 224 } 225 226 func (s *stringValue) Type() string { 227 return "string" 228 } 229 230 func (s *stringValue) String() string { 231 return fmt.Sprintf("%s", *s) 232 } 233 234 func TestBasics(t *testing.T) { 235 SetConfigFile("/tmp/config.yaml") 236 assert.Equal(t, "/tmp/config.yaml", v.getConfigFile()) 237 } 238 239 func TestDefault(t *testing.T) { 240 SetDefault("age", 45) 241 assert.Equal(t, 45, Get("age")) 242 243 SetDefault("clothing.jacket", "slacks") 244 assert.Equal(t, "slacks", Get("clothing.jacket")) 245 246 SetConfigType("yaml") 247 err := ReadConfig(bytes.NewBuffer(yamlExample)) 248 249 assert.NoError(t, err) 250 assert.Equal(t, "leather", Get("clothing.jacket")) 251 } 252 253 func TestUnmarshalling(t *testing.T) { 254 SetConfigType("yaml") 255 r := bytes.NewReader(yamlExample) 256 257 unmarshalReader(r, v.config) 258 assert.True(t, InConfig("name")) 259 assert.False(t, InConfig("state")) 260 assert.Equal(t, "steve", Get("name")) 261 assert.Equal(t, []interface{}{"skateboarding", "snowboarding", "go"}, Get("hobbies")) 262 assert.Equal(t, map[interface{}]interface{}{"jacket": "leather", "trousers": "denim", "pants": map[interface{}]interface{}{"size": "large"}}, Get("clothing")) 263 assert.Equal(t, 35, Get("age")) 264 } 265 266 func TestUnmarshalExact(t *testing.T) { 267 vip := New() 268 target := &testUnmarshalExtra{} 269 vip.SetConfigType("yaml") 270 r := bytes.NewReader(yamlExampleWithExtras) 271 vip.ReadConfig(r) 272 err := vip.UnmarshalExact(target) 273 if err == nil { 274 t.Fatal("UnmarshalExact should error when populating a struct from a conf that contains unused fields") 275 } 276 } 277 278 func TestOverrides(t *testing.T) { 279 Set("age", 40) 280 assert.Equal(t, 40, Get("age")) 281 } 282 283 func TestDefaultPost(t *testing.T) { 284 assert.NotEqual(t, "NYC", Get("state")) 285 SetDefault("state", "NYC") 286 assert.Equal(t, "NYC", Get("state")) 287 } 288 289 func TestAliases(t *testing.T) { 290 RegisterAlias("years", "age") 291 assert.Equal(t, 40, Get("years")) 292 Set("years", 45) 293 assert.Equal(t, 45, Get("age")) 294 } 295 296 func TestAliasInConfigFile(t *testing.T) { 297 // the config file specifies "beard". If we make this an alias for 298 // "hasbeard", we still want the old config file to work with beard. 299 RegisterAlias("beard", "hasbeard") 300 assert.Equal(t, true, Get("hasbeard")) 301 Set("hasbeard", false) 302 assert.Equal(t, false, Get("beard")) 303 } 304 305 func TestYML(t *testing.T) { 306 initYAML() 307 assert.Equal(t, "steve", Get("name")) 308 } 309 310 func TestJSON(t *testing.T) { 311 initJSON() 312 assert.Equal(t, "0001", Get("id")) 313 } 314 315 func TestProperties(t *testing.T) { 316 initProperties() 317 assert.Equal(t, "0001", Get("p_id")) 318 } 319 320 func TestTOML(t *testing.T) { 321 initTOML() 322 assert.Equal(t, "TOML Example", Get("title")) 323 } 324 325 func TestHCL(t *testing.T) { 326 initHcl() 327 assert.Equal(t, "0001", Get("id")) 328 assert.Equal(t, 0.55, Get("ppu")) 329 assert.Equal(t, "donut", Get("type")) 330 assert.Equal(t, "Cake", Get("name")) 331 Set("id", "0002") 332 assert.Equal(t, "0002", Get("id")) 333 assert.NotEqual(t, "cronut", Get("type")) 334 } 335 336 func TestRemotePrecedence(t *testing.T) { 337 initJSON() 338 339 remote := bytes.NewReader(remoteExample) 340 assert.Equal(t, "0001", Get("id")) 341 unmarshalReader(remote, v.kvstore) 342 assert.Equal(t, "0001", Get("id")) 343 assert.NotEqual(t, "cronut", Get("type")) 344 assert.Equal(t, "remote", Get("newkey")) 345 Set("newkey", "newvalue") 346 assert.NotEqual(t, "remote", Get("newkey")) 347 assert.Equal(t, "newvalue", Get("newkey")) 348 Set("newkey", "remote") 349 } 350 351 func TestEnv(t *testing.T) { 352 initJSON() 353 354 BindEnv("id") 355 BindEnv("f", "FOOD") 356 357 os.Setenv("ID", "13") 358 os.Setenv("FOOD", "apple") 359 os.Setenv("NAME", "crunk") 360 361 assert.Equal(t, "13", Get("id")) 362 assert.Equal(t, "apple", Get("f")) 363 assert.Equal(t, "Cake", Get("name")) 364 365 AutomaticEnv() 366 367 assert.Equal(t, "crunk", Get("name")) 368 369 } 370 371 func TestEnvPrefix(t *testing.T) { 372 initJSON() 373 374 SetEnvPrefix("foo") // will be uppercased automatically 375 BindEnv("id") 376 BindEnv("f", "FOOD") // not using prefix 377 378 os.Setenv("FOO_ID", "13") 379 os.Setenv("FOOD", "apple") 380 os.Setenv("FOO_NAME", "crunk") 381 382 assert.Equal(t, "13", Get("id")) 383 assert.Equal(t, "apple", Get("f")) 384 assert.Equal(t, "Cake", Get("name")) 385 386 AutomaticEnv() 387 388 assert.Equal(t, "crunk", Get("name")) 389 } 390 391 func TestAutoEnv(t *testing.T) { 392 Reset() 393 394 AutomaticEnv() 395 os.Setenv("FOO_BAR", "13") 396 assert.Equal(t, "13", Get("foo_bar")) 397 } 398 399 func TestAutoEnvWithPrefix(t *testing.T) { 400 Reset() 401 402 AutomaticEnv() 403 SetEnvPrefix("Baz") 404 os.Setenv("BAZ_BAR", "13") 405 assert.Equal(t, "13", Get("bar")) 406 } 407 408 func TestSetEnvReplacer(t *testing.T) { 409 Reset() 410 411 AutomaticEnv() 412 os.Setenv("REFRESH_INTERVAL", "30s") 413 414 replacer := strings.NewReplacer("-", "_") 415 SetEnvKeyReplacer(replacer) 416 417 assert.Equal(t, "30s", Get("refresh-interval")) 418 } 419 420 func TestAllKeys(t *testing.T) { 421 initConfigs() 422 423 ks := sort.StringSlice{"title", "newkey", "owner", "name", "beard", "ppu", "batters", "hobbies", "clothing", "age", "hacker", "id", "type", "eyes", "p_id", "p_ppu", "p_batters.batter.type", "p_type", "p_name", "foos"} 424 dob, _ := time.Parse(time.RFC3339, "1979-05-27T07:32:00Z") 425 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[interface{}]interface{}{"trousers": "denim", "jacket": "leather", "pants": map[interface{}]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.batter.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}}}}} 426 427 var allkeys sort.StringSlice 428 allkeys = AllKeys() 429 allkeys.Sort() 430 ks.Sort() 431 432 assert.Equal(t, ks, allkeys) 433 assert.Equal(t, all, AllSettings()) 434 } 435 436 func TestCaseInSensitive(t *testing.T) { 437 assert.Equal(t, true, Get("hacker")) 438 Set("Title", "Checking Case") 439 assert.Equal(t, "Checking Case", Get("tItle")) 440 } 441 442 func TestAliasesOfAliases(t *testing.T) { 443 RegisterAlias("Foo", "Bar") 444 RegisterAlias("Bar", "Title") 445 assert.Equal(t, "Checking Case", Get("FOO")) 446 } 447 448 func TestRecursiveAliases(t *testing.T) { 449 RegisterAlias("Baz", "Roo") 450 RegisterAlias("Roo", "baz") 451 } 452 453 func TestUnmarshal(t *testing.T) { 454 SetDefault("port", 1313) 455 Set("name", "Steve") 456 457 type config struct { 458 Port int 459 Name string 460 } 461 462 var C config 463 464 err := Unmarshal(&C) 465 if err != nil { 466 t.Fatalf("unable to decode into struct, %v", err) 467 } 468 469 assert.Equal(t, &C, &config{Name: "Steve", Port: 1313}) 470 471 Set("port", 1234) 472 err = Unmarshal(&C) 473 if err != nil { 474 t.Fatalf("unable to decode into struct, %v", err) 475 } 476 assert.Equal(t, &C, &config{Name: "Steve", Port: 1234}) 477 } 478 479 func TestBindPFlags(t *testing.T) { 480 flagSet := pflag.NewFlagSet("test", pflag.ContinueOnError) 481 482 var testValues = map[string]*string{ 483 "host": nil, 484 "port": nil, 485 "endpoint": nil, 486 } 487 488 var mutatedTestValues = map[string]string{ 489 "host": "localhost", 490 "port": "6060", 491 "endpoint": "/public", 492 } 493 494 for name, _ := range testValues { 495 testValues[name] = flagSet.String(name, "", "test") 496 } 497 498 err := BindPFlags(flagSet) 499 if err != nil { 500 t.Fatalf("error binding flag set, %v", err) 501 } 502 503 flagSet.VisitAll(func(flag *pflag.Flag) { 504 flag.Value.Set(mutatedTestValues[flag.Name]) 505 flag.Changed = true 506 }) 507 508 for name, expected := range mutatedTestValues { 509 assert.Equal(t, Get(name), expected) 510 } 511 512 } 513 514 func TestBindPFlag(t *testing.T) { 515 var testString = "testing" 516 var testValue = newStringValue(testString, &testString) 517 518 flag := &pflag.Flag{ 519 Name: "testflag", 520 Value: testValue, 521 Changed: false, 522 } 523 524 BindPFlag("testvalue", flag) 525 526 assert.Equal(t, testString, Get("testvalue")) 527 528 flag.Value.Set("testing_mutate") 529 flag.Changed = true //hack for pflag usage 530 531 assert.Equal(t, "testing_mutate", Get("testvalue")) 532 533 } 534 535 func TestBoundCaseSensitivity(t *testing.T) { 536 537 assert.Equal(t, "brown", Get("eyes")) 538 539 BindEnv("eYEs", "TURTLE_EYES") 540 os.Setenv("TURTLE_EYES", "blue") 541 542 assert.Equal(t, "blue", Get("eyes")) 543 544 var testString = "green" 545 var testValue = newStringValue(testString, &testString) 546 547 flag := &pflag.Flag{ 548 Name: "eyeballs", 549 Value: testValue, 550 Changed: true, 551 } 552 553 BindPFlag("eYEs", flag) 554 assert.Equal(t, "green", Get("eyes")) 555 556 } 557 558 func TestSizeInBytes(t *testing.T) { 559 input := map[string]uint{ 560 "": 0, 561 "b": 0, 562 "12 bytes": 0, 563 "200000000000gb": 0, 564 "12 b": 12, 565 "43 MB": 43 * (1 << 20), 566 "10mb": 10 * (1 << 20), 567 "1gb": 1 << 30, 568 } 569 570 for str, expected := range input { 571 assert.Equal(t, expected, parseSizeInBytes(str), str) 572 } 573 } 574 575 func TestFindsNestedKeys(t *testing.T) { 576 initConfigs() 577 dob, _ := time.Parse(time.RFC3339, "1979-05-27T07:32:00Z") 578 579 Set("super", map[string]interface{}{ 580 "deep": map[string]interface{}{ 581 "nested": "value", 582 }, 583 }) 584 585 expected := map[string]interface{}{ 586 "super": map[string]interface{}{ 587 "deep": map[string]interface{}{ 588 "nested": "value", 589 }, 590 }, 591 "super.deep": map[string]interface{}{ 592 "nested": "value", 593 }, 594 "super.deep.nested": "value", 595 "owner.organization": "MongoDB", 596 "batters.batter": []interface{}{ 597 map[string]interface{}{ 598 "type": "Regular", 599 }, 600 map[string]interface{}{ 601 "type": "Chocolate", 602 }, 603 map[string]interface{}{ 604 "type": "Blueberry", 605 }, 606 map[string]interface{}{ 607 "type": "Devil's Food", 608 }, 609 }, 610 "hobbies": []interface{}{ 611 "skateboarding", "snowboarding", "go", 612 }, 613 "title": "TOML Example", 614 "newkey": "remote", 615 "batters": map[string]interface{}{ 616 "batter": []interface{}{ 617 map[string]interface{}{ 618 "type": "Regular", 619 }, 620 map[string]interface{}{ 621 "type": "Chocolate", 622 }, map[string]interface{}{ 623 "type": "Blueberry", 624 }, map[string]interface{}{ 625 "type": "Devil's Food", 626 }, 627 }, 628 }, 629 "eyes": "brown", 630 "age": 35, 631 "owner": map[string]interface{}{ 632 "organization": "MongoDB", 633 "Bio": "MongoDB Chief Developer Advocate & Hacker at Large", 634 "dob": dob, 635 }, 636 "owner.Bio": "MongoDB Chief Developer Advocate & Hacker at Large", 637 "type": "donut", 638 "id": "0001", 639 "name": "Cake", 640 "hacker": true, 641 "ppu": 0.55, 642 "clothing": map[interface{}]interface{}{ 643 "jacket": "leather", 644 "trousers": "denim", 645 "pants": map[interface{}]interface{}{ 646 "size": "large", 647 }, 648 }, 649 "clothing.jacket": "leather", 650 "clothing.pants.size": "large", 651 "clothing.trousers": "denim", 652 "owner.dob": dob, 653 "beard": true, 654 "foos": []map[string]interface{}{ 655 map[string]interface{}{ 656 "foo": []map[string]interface{}{ 657 map[string]interface{}{ 658 "key": 1, 659 }, 660 map[string]interface{}{ 661 "key": 2, 662 }, 663 map[string]interface{}{ 664 "key": 3, 665 }, 666 map[string]interface{}{ 667 "key": 4, 668 }, 669 }, 670 }, 671 }, 672 } 673 674 for key, expectedValue := range expected { 675 676 assert.Equal(t, expectedValue, v.Get(key)) 677 } 678 679 } 680 681 func TestReadBufConfig(t *testing.T) { 682 v := New() 683 v.SetConfigType("yaml") 684 v.ReadConfig(bytes.NewBuffer(yamlExample)) 685 t.Log(v.AllKeys()) 686 687 assert.True(t, v.InConfig("name")) 688 assert.False(t, v.InConfig("state")) 689 assert.Equal(t, "steve", v.Get("name")) 690 assert.Equal(t, []interface{}{"skateboarding", "snowboarding", "go"}, v.Get("hobbies")) 691 assert.Equal(t, map[interface{}]interface{}{"jacket": "leather", "trousers": "denim", "pants": map[interface{}]interface{}{"size": "large"}}, v.Get("clothing")) 692 assert.Equal(t, 35, v.Get("age")) 693 } 694 695 func TestIsSet(t *testing.T) { 696 v := New() 697 v.SetConfigType("yaml") 698 v.ReadConfig(bytes.NewBuffer(yamlExample)) 699 assert.True(t, v.IsSet("clothing.jacket")) 700 assert.False(t, v.IsSet("clothing.jackets")) 701 assert.False(t, v.IsSet("helloworld")) 702 v.Set("helloworld", "fubar") 703 assert.True(t, v.IsSet("helloworld")) 704 } 705 706 func TestDirsSearch(t *testing.T) { 707 708 root, config, cleanup := initDirs(t) 709 defer cleanup() 710 711 v := New() 712 v.SetConfigName(config) 713 v.SetDefault(`key`, `default`) 714 715 entries, err := ioutil.ReadDir(root) 716 for _, e := range entries { 717 if e.IsDir() { 718 v.AddConfigPath(e.Name()) 719 } 720 } 721 722 err = v.ReadInConfig() 723 assert.Nil(t, err) 724 725 assert.Equal(t, `value is `+path.Base(v.configPaths[0]), v.GetString(`key`)) 726 } 727 728 func TestWrongDirsSearchNotFound(t *testing.T) { 729 730 _, config, cleanup := initDirs(t) 731 defer cleanup() 732 733 v := New() 734 v.SetConfigName(config) 735 v.SetDefault(`key`, `default`) 736 737 v.AddConfigPath(`whattayoutalkingbout`) 738 v.AddConfigPath(`thispathaintthere`) 739 740 err := v.ReadInConfig() 741 assert.Equal(t, reflect.TypeOf(UnsupportedConfigError("")), reflect.TypeOf(err)) 742 743 // Even though config did not load and the error might have 744 // been ignored by the client, the default still loads 745 assert.Equal(t, `default`, v.GetString(`key`)) 746 } 747 748 func TestSub(t *testing.T) { 749 v := New() 750 v.SetConfigType("yaml") 751 v.ReadConfig(bytes.NewBuffer(yamlExample)) 752 753 subv := v.Sub("clothing") 754 assert.Equal(t, v.Get("clothing.pants.size"), subv.Get("pants.size")) 755 756 subv = v.Sub("clothing.pants") 757 assert.Equal(t, v.Get("clothing.pants.size"), subv.Get("size")) 758 759 subv = v.Sub("clothing.pants.size") 760 assert.Equal(t, subv, (*Viper)(nil)) 761 } 762 763 var yamlMergeExampleTgt = []byte(` 764 hello: 765 pop: 37890 766 world: 767 - us 768 - uk 769 - fr 770 - de 771 `) 772 773 var yamlMergeExampleSrc = []byte(` 774 hello: 775 pop: 45000 776 universe: 777 - mw 778 - ad 779 fu: bar 780 `) 781 782 func TestMergeConfig(t *testing.T) { 783 v := New() 784 v.SetConfigType("yml") 785 if err := v.ReadConfig(bytes.NewBuffer(yamlMergeExampleTgt)); err != nil { 786 t.Fatal(err) 787 } 788 789 if pop := v.GetInt("hello.pop"); pop != 37890 { 790 t.Fatalf("pop != 37890, = %d", pop) 791 } 792 793 if world := v.GetStringSlice("hello.world"); len(world) != 4 { 794 t.Fatalf("len(world) != 4, = %d", len(world)) 795 } 796 797 if fu := v.GetString("fu"); fu != "" { 798 t.Fatalf("fu != \"\", = %s", fu) 799 } 800 801 if err := v.MergeConfig(bytes.NewBuffer(yamlMergeExampleSrc)); err != nil { 802 t.Fatal(err) 803 } 804 805 if pop := v.GetInt("hello.pop"); pop != 45000 { 806 t.Fatalf("pop != 45000, = %d", pop) 807 } 808 809 if world := v.GetStringSlice("hello.world"); len(world) != 4 { 810 t.Fatalf("len(world) != 4, = %d", len(world)) 811 } 812 813 if universe := v.GetStringSlice("hello.universe"); len(universe) != 2 { 814 t.Fatalf("len(universe) != 2, = %d", len(universe)) 815 } 816 817 if fu := v.GetString("fu"); fu != "bar" { 818 t.Fatalf("fu != \"bar\", = %s", fu) 819 } 820 } 821 822 func TestMergeConfigNoMerge(t *testing.T) { 823 v := New() 824 v.SetConfigType("yml") 825 if err := v.ReadConfig(bytes.NewBuffer(yamlMergeExampleTgt)); err != nil { 826 t.Fatal(err) 827 } 828 829 if pop := v.GetInt("hello.pop"); pop != 37890 { 830 t.Fatalf("pop != 37890, = %d", pop) 831 } 832 833 if world := v.GetStringSlice("hello.world"); len(world) != 4 { 834 t.Fatalf("len(world) != 4, = %d", len(world)) 835 } 836 837 if fu := v.GetString("fu"); fu != "" { 838 t.Fatalf("fu != \"\", = %s", fu) 839 } 840 841 if err := v.ReadConfig(bytes.NewBuffer(yamlMergeExampleSrc)); err != nil { 842 t.Fatal(err) 843 } 844 845 if pop := v.GetInt("hello.pop"); pop != 45000 { 846 t.Fatalf("pop != 45000, = %d", pop) 847 } 848 849 if world := v.GetStringSlice("hello.world"); len(world) != 0 { 850 t.Fatalf("len(world) != 0, = %d", len(world)) 851 } 852 853 if universe := v.GetStringSlice("hello.universe"); len(universe) != 2 { 854 t.Fatalf("len(universe) != 2, = %d", len(universe)) 855 } 856 857 if fu := v.GetString("fu"); fu != "bar" { 858 t.Fatalf("fu != \"bar\", = %s", fu) 859 } 860 } 861 862 func TestUnmarshalingWithAliases(t *testing.T) { 863 SetDefault("Id", 1) 864 Set("name", "Steve") 865 Set("lastname", "Owen") 866 867 RegisterAlias("UserID", "Id") 868 RegisterAlias("Firstname", "name") 869 RegisterAlias("Surname", "lastname") 870 871 type config struct { 872 Id int 873 FirstName string 874 Surname string 875 } 876 877 var C config 878 879 err := Unmarshal(&C) 880 if err != nil { 881 t.Fatalf("unable to decode into struct, %v", err) 882 } 883 884 assert.Equal(t, &C, &config{Id: 1, FirstName: "Steve", Surname: "Owen"}) 885 }