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