1package toml 2 3import ( 4 "bytes" 5 "encoding/json" 6 "errors" 7 "fmt" 8 "io/ioutil" 9 "os" 10 "reflect" 11 "strconv" 12 "strings" 13 "testing" 14 "time" 15) 16 17type basicMarshalTestStruct struct { 18 String string `toml:"Zstring"` 19 StringList []string `toml:"Ystrlist"` 20 BasicMarshalTestSubAnonymousStruct 21 Sub basicMarshalTestSubStruct `toml:"Xsubdoc"` 22 SubList []basicMarshalTestSubStruct `toml:"Wsublist"` 23} 24 25type basicMarshalTestSubStruct struct { 26 String2 string 27} 28 29type BasicMarshalTestSubAnonymousStruct struct { 30 String3 string 31} 32 33var basicTestData = basicMarshalTestStruct{ 34 String: "Hello", 35 StringList: []string{"Howdy", "Hey There"}, 36 BasicMarshalTestSubAnonymousStruct: BasicMarshalTestSubAnonymousStruct{"One"}, 37 Sub: basicMarshalTestSubStruct{"Two"}, 38 SubList: []basicMarshalTestSubStruct{{"Three"}, {"Four"}}, 39} 40 41var basicTestToml = []byte(`String3 = "One" 42Ystrlist = ["Howdy", "Hey There"] 43Zstring = "Hello" 44 45[[Wsublist]] 46 String2 = "Three" 47 48[[Wsublist]] 49 String2 = "Four" 50 51[Xsubdoc] 52 String2 = "Two" 53`) 54 55var basicTestTomlCustomIndentation = []byte(`String3 = "One" 56Ystrlist = ["Howdy", "Hey There"] 57Zstring = "Hello" 58 59[[Wsublist]] 60 String2 = "Three" 61 62[[Wsublist]] 63 String2 = "Four" 64 65[Xsubdoc] 66 String2 = "Two" 67`) 68 69var basicTestTomlOrdered = []byte(`Zstring = "Hello" 70Ystrlist = ["Howdy", "Hey There"] 71String3 = "One" 72 73[Xsubdoc] 74 String2 = "Two" 75 76[[Wsublist]] 77 String2 = "Three" 78 79[[Wsublist]] 80 String2 = "Four" 81`) 82 83var marshalTestToml = []byte(`title = "TOML Marshal Testing" 84 85[basic] 86 bool = true 87 date = 1979-05-27T07:32:00Z 88 float = 123.4 89 float64 = 123.456782132399 90 int = 5000 91 string = "Bite me" 92 uint = 5001 93 94[basic_lists] 95 bools = [true, false, true] 96 dates = [1979-05-27T07:32:00Z, 1980-05-27T07:32:00Z] 97 floats = [12.3, 45.6, 78.9] 98 ints = [8001, 8001, 8002] 99 strings = ["One", "Two", "Three"] 100 uints = [5002, 5003] 101 102[basic_map] 103 one = "one" 104 two = "two" 105 106[subdoc] 107 108 [subdoc.first] 109 name = "First" 110 111 [subdoc.second] 112 name = "Second" 113 114[[subdoclist]] 115 name = "List.First" 116 117[[subdoclist]] 118 name = "List.Second" 119 120[[subdocptrs]] 121 name = "Second" 122`) 123 124var marshalOrderPreserveToml = []byte(`title = "TOML Marshal Testing" 125 126[basic_lists] 127 floats = [12.3, 45.6, 78.9] 128 bools = [true, false, true] 129 dates = [1979-05-27T07:32:00Z, 1980-05-27T07:32:00Z] 130 ints = [8001, 8001, 8002] 131 uints = [5002, 5003] 132 strings = ["One", "Two", "Three"] 133 134[[subdocptrs]] 135 name = "Second" 136 137[basic_map] 138 one = "one" 139 two = "two" 140 141[subdoc] 142 143 [subdoc.second] 144 name = "Second" 145 146 [subdoc.first] 147 name = "First" 148 149[basic] 150 uint = 5001 151 bool = true 152 float = 123.4 153 float64 = 123.456782132399 154 int = 5000 155 string = "Bite me" 156 date = 1979-05-27T07:32:00Z 157 158[[subdoclist]] 159 name = "List.First" 160 161[[subdoclist]] 162 name = "List.Second" 163`) 164 165var mashalOrderPreserveMapToml = []byte(`title = "TOML Marshal Testing" 166 167[basic_map] 168 one = "one" 169 two = "two" 170 171[long_map] 172 a7 = "1" 173 b3 = "2" 174 c8 = "3" 175 d4 = "4" 176 e6 = "5" 177 f5 = "6" 178 g10 = "7" 179 h1 = "8" 180 i2 = "9" 181 j9 = "10" 182`) 183 184type Conf struct { 185 Name string 186 Age int 187 Inter interface{} 188} 189 190type NestedStruct struct { 191 FirstName string 192 LastName string 193 Age int 194} 195 196var doc = []byte(`Name = "rui" 197Age = 18 198 199[Inter] 200 FirstName = "wang" 201 LastName = "jl" 202 Age = 100`) 203 204func TestInterface(t *testing.T) { 205 var config Conf 206 config.Inter = &NestedStruct{} 207 err := Unmarshal(doc, &config) 208 expected := Conf{ 209 Name: "rui", 210 Age: 18, 211 Inter: &NestedStruct{ 212 FirstName: "wang", 213 LastName: "jl", 214 Age: 100, 215 }, 216 } 217 if err != nil || !reflect.DeepEqual(config, expected) { 218 t.Errorf("Bad unmarshal: expected %v, got %v", expected, config) 219 } 220} 221 222func TestBasicMarshal(t *testing.T) { 223 result, err := Marshal(basicTestData) 224 if err != nil { 225 t.Fatal(err) 226 } 227 expected := basicTestToml 228 if !bytes.Equal(result, expected) { 229 t.Errorf("Bad marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expected, result) 230 } 231} 232 233func TestBasicMarshalCustomIndentation(t *testing.T) { 234 var result bytes.Buffer 235 err := NewEncoder(&result).Indentation("\t").Encode(basicTestData) 236 if err != nil { 237 t.Fatal(err) 238 } 239 expected := basicTestTomlCustomIndentation 240 if !bytes.Equal(result.Bytes(), expected) { 241 t.Errorf("Bad marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expected, result.Bytes()) 242 } 243} 244 245func TestBasicMarshalWrongIndentation(t *testing.T) { 246 var result bytes.Buffer 247 err := NewEncoder(&result).Indentation(" \n").Encode(basicTestData) 248 if err.Error() != "invalid indentation: must only contains space or tab characters" { 249 t.Error("expect err:invalid indentation: must only contains space or tab characters but got:", err) 250 } 251} 252 253func TestBasicMarshalOrdered(t *testing.T) { 254 var result bytes.Buffer 255 err := NewEncoder(&result).Order(OrderPreserve).Encode(basicTestData) 256 if err != nil { 257 t.Fatal(err) 258 } 259 expected := basicTestTomlOrdered 260 if !bytes.Equal(result.Bytes(), expected) { 261 t.Errorf("Bad marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expected, result.Bytes()) 262 } 263} 264 265func TestBasicMarshalWithPointer(t *testing.T) { 266 result, err := Marshal(&basicTestData) 267 if err != nil { 268 t.Fatal(err) 269 } 270 expected := basicTestToml 271 if !bytes.Equal(result, expected) { 272 t.Errorf("Bad marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expected, result) 273 } 274} 275 276func TestBasicMarshalOrderedWithPointer(t *testing.T) { 277 var result bytes.Buffer 278 err := NewEncoder(&result).Order(OrderPreserve).Encode(&basicTestData) 279 if err != nil { 280 t.Fatal(err) 281 } 282 expected := basicTestTomlOrdered 283 if !bytes.Equal(result.Bytes(), expected) { 284 t.Errorf("Bad marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expected, result.Bytes()) 285 } 286} 287 288func TestBasicUnmarshal(t *testing.T) { 289 result := basicMarshalTestStruct{} 290 err := Unmarshal(basicTestToml, &result) 291 expected := basicTestData 292 if err != nil { 293 t.Fatal(err) 294 } 295 if !reflect.DeepEqual(result, expected) { 296 t.Errorf("Bad unmarshal: expected %v, got %v", expected, result) 297 } 298} 299 300type quotedKeyMarshalTestStruct struct { 301 String string `toml:"Z.string-àéù"` 302 Float float64 `toml:"Yfloat-"` 303 Sub basicMarshalTestSubStruct `toml:"Xsubdoc-àéù"` 304 SubList []basicMarshalTestSubStruct `toml:"W.sublist-"` 305} 306 307var quotedKeyMarshalTestData = quotedKeyMarshalTestStruct{ 308 String: "Hello", 309 Float: 3.5, 310 Sub: basicMarshalTestSubStruct{"One"}, 311 SubList: []basicMarshalTestSubStruct{{"Two"}, {"Three"}}, 312} 313 314var quotedKeyMarshalTestToml = []byte(`"Yfloat-" = 3.5 315"Z.string-àéù" = "Hello" 316 317[["W.sublist-"]] 318 String2 = "Two" 319 320[["W.sublist-"]] 321 String2 = "Three" 322 323["Xsubdoc-àéù"] 324 String2 = "One" 325`) 326 327func TestBasicMarshalQuotedKey(t *testing.T) { 328 result, err := Marshal(quotedKeyMarshalTestData) 329 if err != nil { 330 t.Fatal(err) 331 } 332 expected := quotedKeyMarshalTestToml 333 if !bytes.Equal(result, expected) { 334 t.Errorf("Bad marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expected, result) 335 } 336} 337 338func TestBasicUnmarshalQuotedKey(t *testing.T) { 339 tree, err := LoadBytes(quotedKeyMarshalTestToml) 340 if err != nil { 341 t.Fatal(err) 342 } 343 344 var q quotedKeyMarshalTestStruct 345 tree.Unmarshal(&q) 346 fmt.Println(q) 347 348 if !reflect.DeepEqual(quotedKeyMarshalTestData, q) { 349 t.Errorf("Bad unmarshal: expected\n-----\n%v\n-----\ngot\n-----\n%v\n-----\n", quotedKeyMarshalTestData, q) 350 } 351} 352 353type testDoc struct { 354 Title string `toml:"title"` 355 BasicLists testDocBasicLists `toml:"basic_lists"` 356 SubDocPtrs []*testSubDoc `toml:"subdocptrs"` 357 BasicMap map[string]string `toml:"basic_map"` 358 Subdocs testDocSubs `toml:"subdoc"` 359 Basics testDocBasics `toml:"basic"` 360 SubDocList []testSubDoc `toml:"subdoclist"` 361 err int `toml:"shouldntBeHere"` 362 unexported int `toml:"shouldntBeHere"` 363 Unexported2 int `toml:"-"` 364} 365 366type testMapDoc struct { 367 Title string `toml:"title"` 368 BasicMap map[string]string `toml:"basic_map"` 369 LongMap map[string]string `toml:"long_map"` 370} 371 372type testDocBasics struct { 373 Uint uint `toml:"uint"` 374 Bool bool `toml:"bool"` 375 Float32 float32 `toml:"float"` 376 Float64 float64 `toml:"float64"` 377 Int int `toml:"int"` 378 String *string `toml:"string"` 379 Date time.Time `toml:"date"` 380 unexported int `toml:"shouldntBeHere"` 381} 382 383type testDocBasicLists struct { 384 Floats []*float32 `toml:"floats"` 385 Bools []bool `toml:"bools"` 386 Dates []time.Time `toml:"dates"` 387 Ints []int `toml:"ints"` 388 UInts []uint `toml:"uints"` 389 Strings []string `toml:"strings"` 390} 391 392type testDocSubs struct { 393 Second *testSubDoc `toml:"second"` 394 First testSubDoc `toml:"first"` 395} 396 397type testSubDoc struct { 398 Name string `toml:"name"` 399 unexported int `toml:"shouldntBeHere"` 400} 401 402var biteMe = "Bite me" 403var float1 float32 = 12.3 404var float2 float32 = 45.6 405var float3 float32 = 78.9 406var subdoc = testSubDoc{"Second", 0} 407 408var docData = testDoc{ 409 Title: "TOML Marshal Testing", 410 unexported: 0, 411 Unexported2: 0, 412 Basics: testDocBasics{ 413 Bool: true, 414 Date: time.Date(1979, 5, 27, 7, 32, 0, 0, time.UTC), 415 Float32: 123.4, 416 Float64: 123.456782132399, 417 Int: 5000, 418 Uint: 5001, 419 String: &biteMe, 420 unexported: 0, 421 }, 422 BasicLists: testDocBasicLists{ 423 Bools: []bool{true, false, true}, 424 Dates: []time.Time{ 425 time.Date(1979, 5, 27, 7, 32, 0, 0, time.UTC), 426 time.Date(1980, 5, 27, 7, 32, 0, 0, time.UTC), 427 }, 428 Floats: []*float32{&float1, &float2, &float3}, 429 Ints: []int{8001, 8001, 8002}, 430 Strings: []string{"One", "Two", "Three"}, 431 UInts: []uint{5002, 5003}, 432 }, 433 BasicMap: map[string]string{ 434 "one": "one", 435 "two": "two", 436 }, 437 Subdocs: testDocSubs{ 438 First: testSubDoc{"First", 0}, 439 Second: &subdoc, 440 }, 441 SubDocList: []testSubDoc{ 442 {"List.First", 0}, 443 {"List.Second", 0}, 444 }, 445 SubDocPtrs: []*testSubDoc{&subdoc}, 446} 447 448var mapTestDoc = testMapDoc{ 449 Title: "TOML Marshal Testing", 450 BasicMap: map[string]string{ 451 "one": "one", 452 "two": "two", 453 }, 454 LongMap: map[string]string{ 455 "h1": "8", 456 "i2": "9", 457 "b3": "2", 458 "d4": "4", 459 "f5": "6", 460 "e6": "5", 461 "a7": "1", 462 "c8": "3", 463 "j9": "10", 464 "g10": "7", 465 }, 466} 467 468func TestDocMarshal(t *testing.T) { 469 result, err := Marshal(docData) 470 if err != nil { 471 t.Fatal(err) 472 } 473 if !bytes.Equal(result, marshalTestToml) { 474 t.Errorf("Bad marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", marshalTestToml, result) 475 } 476} 477 478func TestDocMarshalOrdered(t *testing.T) { 479 var result bytes.Buffer 480 err := NewEncoder(&result).Order(OrderPreserve).Encode(docData) 481 if err != nil { 482 t.Fatal(err) 483 } 484 if !bytes.Equal(result.Bytes(), marshalOrderPreserveToml) { 485 t.Errorf("Bad marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", marshalOrderPreserveToml, result.Bytes()) 486 } 487} 488 489func TestDocMarshalMaps(t *testing.T) { 490 result, err := Marshal(mapTestDoc) 491 if err != nil { 492 t.Fatal(err) 493 } 494 if !bytes.Equal(result, mashalOrderPreserveMapToml) { 495 t.Errorf("Bad marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", mashalOrderPreserveMapToml, result) 496 } 497} 498 499func TestDocMarshalOrderedMaps(t *testing.T) { 500 var result bytes.Buffer 501 err := NewEncoder(&result).Order(OrderPreserve).Encode(mapTestDoc) 502 if err != nil { 503 t.Fatal(err) 504 } 505 if !bytes.Equal(result.Bytes(), mashalOrderPreserveMapToml) { 506 t.Errorf("Bad marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", mashalOrderPreserveMapToml, result.Bytes()) 507 } 508} 509 510func TestDocMarshalPointer(t *testing.T) { 511 result, err := Marshal(&docData) 512 if err != nil { 513 t.Fatal(err) 514 } 515 516 if !bytes.Equal(result, marshalTestToml) { 517 t.Errorf("Bad marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", marshalTestToml, result) 518 } 519} 520 521func TestDocUnmarshal(t *testing.T) { 522 result := testDoc{} 523 err := Unmarshal(marshalTestToml, &result) 524 expected := docData 525 if err != nil { 526 t.Fatal(err) 527 } 528 if !reflect.DeepEqual(result, expected) { 529 resStr, _ := json.MarshalIndent(result, "", " ") 530 expStr, _ := json.MarshalIndent(expected, "", " ") 531 t.Errorf("Bad unmarshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expStr, resStr) 532 } 533} 534 535func TestDocPartialUnmarshal(t *testing.T) { 536 file, err := ioutil.TempFile("", "test-*.toml") 537 if err != nil { 538 t.Fatal(err) 539 } 540 defer os.Remove(file.Name()) 541 542 err = ioutil.WriteFile(file.Name(), marshalTestToml, 0) 543 if err != nil { 544 t.Fatal(err) 545 } 546 547 tree, _ := LoadFile(file.Name()) 548 subTree := tree.Get("subdoc").(*Tree) 549 550 result := testDocSubs{} 551 err = subTree.Unmarshal(&result) 552 expected := docData.Subdocs 553 if err != nil { 554 t.Fatal(err) 555 } 556 if !reflect.DeepEqual(result, expected) { 557 resStr, _ := json.MarshalIndent(result, "", " ") 558 expStr, _ := json.MarshalIndent(expected, "", " ") 559 t.Errorf("Bad partial unmartial: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expStr, resStr) 560 } 561} 562 563type tomlTypeCheckTest struct { 564 name string 565 item interface{} 566 typ int //0=primitive, 1=otherslice, 2=treeslice, 3=tree 567} 568 569func TestTypeChecks(t *testing.T) { 570 tests := []tomlTypeCheckTest{ 571 {"bool", true, 0}, 572 {"bool", false, 0}, 573 {"int", int(2), 0}, 574 {"int8", int8(2), 0}, 575 {"int16", int16(2), 0}, 576 {"int32", int32(2), 0}, 577 {"int64", int64(2), 0}, 578 {"uint", uint(2), 0}, 579 {"uint8", uint8(2), 0}, 580 {"uint16", uint16(2), 0}, 581 {"uint32", uint32(2), 0}, 582 {"uint64", uint64(2), 0}, 583 {"float32", float32(3.14), 0}, 584 {"float64", float64(3.14), 0}, 585 {"string", "lorem ipsum", 0}, 586 {"time", time.Date(2015, 1, 1, 0, 0, 0, 0, time.UTC), 0}, 587 {"stringlist", []string{"hello", "hi"}, 1}, 588 {"stringlistptr", &[]string{"hello", "hi"}, 1}, 589 {"stringarray", [2]string{"hello", "hi"}, 1}, 590 {"stringarrayptr", &[2]string{"hello", "hi"}, 1}, 591 {"timelist", []time.Time{time.Date(2015, 1, 1, 0, 0, 0, 0, time.UTC)}, 1}, 592 {"timelistptr", &[]time.Time{time.Date(2015, 1, 1, 0, 0, 0, 0, time.UTC)}, 1}, 593 {"timearray", [1]time.Time{time.Date(2015, 1, 1, 0, 0, 0, 0, time.UTC)}, 1}, 594 {"timearrayptr", &[1]time.Time{time.Date(2015, 1, 1, 0, 0, 0, 0, time.UTC)}, 1}, 595 {"objectlist", []tomlTypeCheckTest{}, 2}, 596 {"objectlistptr", &[]tomlTypeCheckTest{}, 2}, 597 {"objectarray", [2]tomlTypeCheckTest{{}, {}}, 2}, 598 {"objectlistptr", &[2]tomlTypeCheckTest{{}, {}}, 2}, 599 {"object", tomlTypeCheckTest{}, 3}, 600 {"objectptr", &tomlTypeCheckTest{}, 3}, 601 } 602 603 for _, test := range tests { 604 expected := []bool{false, false, false, false} 605 expected[test.typ] = true 606 result := []bool{ 607 isPrimitive(reflect.TypeOf(test.item)), 608 isOtherSequence(reflect.TypeOf(test.item)), 609 isTreeSequence(reflect.TypeOf(test.item)), 610 isTree(reflect.TypeOf(test.item)), 611 } 612 if !reflect.DeepEqual(expected, result) { 613 t.Errorf("Bad type check on %q: expected %v, got %v", test.name, expected, result) 614 } 615 } 616} 617 618type unexportedMarshalTestStruct struct { 619 String string `toml:"string"` 620 StringList []string `toml:"strlist"` 621 Sub basicMarshalTestSubStruct `toml:"subdoc"` 622 SubList []basicMarshalTestSubStruct `toml:"sublist"` 623 unexported int `toml:"shouldntBeHere"` 624 Unexported2 int `toml:"-"` 625} 626 627var unexportedTestData = unexportedMarshalTestStruct{ 628 String: "Hello", 629 StringList: []string{"Howdy", "Hey There"}, 630 Sub: basicMarshalTestSubStruct{"One"}, 631 SubList: []basicMarshalTestSubStruct{{"Two"}, {"Three"}}, 632 unexported: 0, 633 Unexported2: 0, 634} 635 636var unexportedTestToml = []byte(`string = "Hello" 637strlist = ["Howdy","Hey There"] 638unexported = 1 639shouldntBeHere = 2 640 641[subdoc] 642 String2 = "One" 643 644[[sublist]] 645 String2 = "Two" 646 647[[sublist]] 648 String2 = "Three" 649`) 650 651func TestUnexportedUnmarshal(t *testing.T) { 652 result := unexportedMarshalTestStruct{} 653 err := Unmarshal(unexportedTestToml, &result) 654 expected := unexportedTestData 655 if err != nil { 656 t.Fatal(err) 657 } 658 if !reflect.DeepEqual(result, expected) { 659 t.Errorf("Bad unexported unmarshal: expected %v, got %v", expected, result) 660 } 661} 662 663type errStruct struct { 664 Bool bool `toml:"bool"` 665 Date time.Time `toml:"date"` 666 Float float64 `toml:"float"` 667 Int int16 `toml:"int"` 668 String *string `toml:"string"` 669} 670 671var errTomls = []string{ 672 "bool = truly\ndate = 1979-05-27T07:32:00Z\nfloat = 123.4\nint = 5000\nstring = \"Bite me\"", 673 "bool = true\ndate = 1979-05-27T07:3200Z\nfloat = 123.4\nint = 5000\nstring = \"Bite me\"", 674 "bool = true\ndate = 1979-05-27T07:32:00Z\nfloat = 123a4\nint = 5000\nstring = \"Bite me\"", 675 "bool = true\ndate = 1979-05-27T07:32:00Z\nfloat = 123.4\nint = j000\nstring = \"Bite me\"", 676 "bool = true\ndate = 1979-05-27T07:32:00Z\nfloat = 123.4\nint = 5000\nstring = Bite me", 677 "bool = true\ndate = 1979-05-27T07:32:00Z\nfloat = 123.4\nint = 5000\nstring = Bite me", 678 "bool = 1\ndate = 1979-05-27T07:32:00Z\nfloat = 123.4\nint = 5000\nstring = \"Bite me\"", 679 "bool = true\ndate = 1\nfloat = 123.4\nint = 5000\nstring = \"Bite me\"", 680 "bool = true\ndate = 1979-05-27T07:32:00Z\n\"sorry\"\nint = 5000\nstring = \"Bite me\"", 681 "bool = true\ndate = 1979-05-27T07:32:00Z\nfloat = 123.4\nint = \"sorry\"\nstring = \"Bite me\"", 682 "bool = true\ndate = 1979-05-27T07:32:00Z\nfloat = 123.4\nint = 5000\nstring = 1", 683} 684 685type mapErr struct { 686 Vals map[string]float64 687} 688 689type intErr struct { 690 Int1 int 691 Int2 int8 692 Int3 int16 693 Int4 int32 694 Int5 int64 695 UInt1 uint 696 UInt2 uint8 697 UInt3 uint16 698 UInt4 uint32 699 UInt5 uint64 700 Flt1 float32 701 Flt2 float64 702} 703 704var intErrTomls = []string{ 705 "Int1 = []\nInt2 = 2\nInt3 = 3\nInt4 = 4\nInt5 = 5\nUInt1 = 1\nUInt2 = 2\nUInt3 = 3\nUInt4 = 4\nUInt5 = 5\nFlt1 = 1.0\nFlt2 = 2.0", 706 "Int1 = 1\nInt2 = []\nInt3 = 3\nInt4 = 4\nInt5 = 5\nUInt1 = 1\nUInt2 = 2\nUInt3 = 3\nUInt4 = 4\nUInt5 = 5\nFlt1 = 1.0\nFlt2 = 2.0", 707 "Int1 = 1\nInt2 = 2\nInt3 = []\nInt4 = 4\nInt5 = 5\nUInt1 = 1\nUInt2 = 2\nUInt3 = 3\nUInt4 = 4\nUInt5 = 5\nFlt1 = 1.0\nFlt2 = 2.0", 708 "Int1 = 1\nInt2 = 2\nInt3 = 3\nInt4 = []\nInt5 = 5\nUInt1 = 1\nUInt2 = 2\nUInt3 = 3\nUInt4 = 4\nUInt5 = 5\nFlt1 = 1.0\nFlt2 = 2.0", 709 "Int1 = 1\nInt2 = 2\nInt3 = 3\nInt4 = 4\nInt5 = []\nUInt1 = 1\nUInt2 = 2\nUInt3 = 3\nUInt4 = 4\nUInt5 = 5\nFlt1 = 1.0\nFlt2 = 2.0", 710 "Int1 = 1\nInt2 = 2\nInt3 = 3\nInt4 = 4\nInt5 = 5\nUInt1 = []\nUInt2 = 2\nUInt3 = 3\nUInt4 = 4\nUInt5 = 5\nFlt1 = 1.0\nFlt2 = 2.0", 711 "Int1 = 1\nInt2 = 2\nInt3 = 3\nInt4 = 4\nInt5 = 5\nUInt1 = 1\nUInt2 = []\nUInt3 = 3\nUInt4 = 4\nUInt5 = 5\nFlt1 = 1.0\nFlt2 = 2.0", 712 "Int1 = 1\nInt2 = 2\nInt3 = 3\nInt4 = 4\nInt5 = 5\nUInt1 = 1\nUInt2 = 2\nUInt3 = []\nUInt4 = 4\nUInt5 = 5\nFlt1 = 1.0\nFlt2 = 2.0", 713 "Int1 = 1\nInt2 = 2\nInt3 = 3\nInt4 = 4\nInt5 = 5\nUInt1 = 1\nUInt2 = 2\nUInt3 = 3\nUInt4 = []\nUInt5 = 5\nFlt1 = 1.0\nFlt2 = 2.0", 714 "Int1 = 1\nInt2 = 2\nInt3 = 3\nInt4 = 4\nInt5 = 5\nUInt1 = 1\nUInt2 = 2\nUInt3 = 3\nUInt4 = 4\nUInt5 = []\nFlt1 = 1.0\nFlt2 = 2.0", 715 "Int1 = 1\nInt2 = 2\nInt3 = 3\nInt4 = 4\nInt5 = 5\nUInt1 = 1\nUInt2 = 2\nUInt3 = 3\nUInt4 = 4\nUInt5 = 5\nFlt1 = []\nFlt2 = 2.0", 716 "Int1 = 1\nInt2 = 2\nInt3 = 3\nInt4 = 4\nInt5 = 5\nUInt1 = 1\nUInt2 = 2\nUInt3 = 3\nUInt4 = 4\nUInt5 = 5\nFlt1 = 1.0\nFlt2 = []", 717} 718 719func TestErrUnmarshal(t *testing.T) { 720 for ind, toml := range errTomls { 721 result := errStruct{} 722 err := Unmarshal([]byte(toml), &result) 723 if err == nil { 724 t.Errorf("Expected err from case %d\n", ind) 725 } 726 } 727 result2 := mapErr{} 728 err := Unmarshal([]byte("[Vals]\nfred=\"1.2\""), &result2) 729 if err == nil { 730 t.Errorf("Expected err from map") 731 } 732 for ind, toml := range intErrTomls { 733 result3 := intErr{} 734 err := Unmarshal([]byte(toml), &result3) 735 if err == nil { 736 t.Errorf("Expected int err from case %d\n", ind) 737 } 738 } 739} 740 741type emptyMarshalTestStruct struct { 742 Title string `toml:"title"` 743 Bool bool `toml:"bool"` 744 Int int `toml:"int"` 745 String string `toml:"string"` 746 StringList []string `toml:"stringlist"` 747 Ptr *basicMarshalTestStruct `toml:"ptr"` 748 Map map[string]string `toml:"map"` 749} 750 751var emptyTestData = emptyMarshalTestStruct{ 752 Title: "Placeholder", 753 Bool: false, 754 Int: 0, 755 String: "", 756 StringList: []string{}, 757 Ptr: nil, 758 Map: map[string]string{}, 759} 760 761var emptyTestToml = []byte(`bool = false 762int = 0 763string = "" 764stringlist = [] 765title = "Placeholder" 766 767[map] 768`) 769 770type emptyMarshalTestStruct2 struct { 771 Title string `toml:"title"` 772 Bool bool `toml:"bool,omitempty"` 773 Int int `toml:"int, omitempty"` 774 String string `toml:"string,omitempty "` 775 StringList []string `toml:"stringlist,omitempty"` 776 Ptr *basicMarshalTestStruct `toml:"ptr,omitempty"` 777 Map map[string]string `toml:"map,omitempty"` 778} 779 780var emptyTestData2 = emptyMarshalTestStruct2{ 781 Title: "Placeholder", 782 Bool: false, 783 Int: 0, 784 String: "", 785 StringList: []string{}, 786 Ptr: nil, 787 Map: map[string]string{}, 788} 789 790var emptyTestToml2 = []byte(`title = "Placeholder" 791`) 792 793func TestEmptyMarshal(t *testing.T) { 794 result, err := Marshal(emptyTestData) 795 if err != nil { 796 t.Fatal(err) 797 } 798 expected := emptyTestToml 799 if !bytes.Equal(result, expected) { 800 t.Errorf("Bad empty marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expected, result) 801 } 802} 803 804func TestEmptyMarshalOmit(t *testing.T) { 805 result, err := Marshal(emptyTestData2) 806 if err != nil { 807 t.Fatal(err) 808 } 809 expected := emptyTestToml2 810 if !bytes.Equal(result, expected) { 811 t.Errorf("Bad empty omit marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expected, result) 812 } 813} 814 815func TestEmptyUnmarshal(t *testing.T) { 816 result := emptyMarshalTestStruct{} 817 err := Unmarshal(emptyTestToml, &result) 818 expected := emptyTestData 819 if err != nil { 820 t.Fatal(err) 821 } 822 if !reflect.DeepEqual(result, expected) { 823 t.Errorf("Bad empty unmarshal: expected %v, got %v", expected, result) 824 } 825} 826 827func TestEmptyUnmarshalOmit(t *testing.T) { 828 result := emptyMarshalTestStruct2{} 829 err := Unmarshal(emptyTestToml, &result) 830 expected := emptyTestData2 831 if err != nil { 832 t.Fatal(err) 833 } 834 if !reflect.DeepEqual(result, expected) { 835 t.Errorf("Bad empty omit unmarshal: expected %v, got %v", expected, result) 836 } 837} 838 839type pointerMarshalTestStruct struct { 840 Str *string 841 List *[]string 842 ListPtr *[]*string 843 Map *map[string]string 844 MapPtr *map[string]*string 845 EmptyStr *string 846 EmptyList *[]string 847 EmptyMap *map[string]string 848 DblPtr *[]*[]*string 849} 850 851var pointerStr = "Hello" 852var pointerList = []string{"Hello back"} 853var pointerListPtr = []*string{&pointerStr} 854var pointerMap = map[string]string{"response": "Goodbye"} 855var pointerMapPtr = map[string]*string{"alternate": &pointerStr} 856var pointerTestData = pointerMarshalTestStruct{ 857 Str: &pointerStr, 858 List: &pointerList, 859 ListPtr: &pointerListPtr, 860 Map: &pointerMap, 861 MapPtr: &pointerMapPtr, 862 EmptyStr: nil, 863 EmptyList: nil, 864 EmptyMap: nil, 865} 866 867var pointerTestToml = []byte(`List = ["Hello back"] 868ListPtr = ["Hello"] 869Str = "Hello" 870 871[Map] 872 response = "Goodbye" 873 874[MapPtr] 875 alternate = "Hello" 876`) 877 878func TestPointerMarshal(t *testing.T) { 879 result, err := Marshal(pointerTestData) 880 if err != nil { 881 t.Fatal(err) 882 } 883 expected := pointerTestToml 884 if !bytes.Equal(result, expected) { 885 t.Errorf("Bad pointer marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expected, result) 886 } 887} 888 889func TestPointerUnmarshal(t *testing.T) { 890 result := pointerMarshalTestStruct{} 891 err := Unmarshal(pointerTestToml, &result) 892 expected := pointerTestData 893 if err != nil { 894 t.Fatal(err) 895 } 896 if !reflect.DeepEqual(result, expected) { 897 t.Errorf("Bad pointer unmarshal: expected %v, got %v", expected, result) 898 } 899} 900 901func TestUnmarshalTypeMismatch(t *testing.T) { 902 result := pointerMarshalTestStruct{} 903 err := Unmarshal([]byte("List = 123"), &result) 904 if !strings.HasPrefix(err.Error(), "(1, 1): Can't convert 123(int64) to []string(slice)") { 905 t.Errorf("Type mismatch must be reported: got %v", err.Error()) 906 } 907} 908 909type nestedMarshalTestStruct struct { 910 String [][]string 911 //Struct [][]basicMarshalTestSubStruct 912 StringPtr *[]*[]*string 913 // StructPtr *[]*[]*basicMarshalTestSubStruct 914} 915 916var str1 = "Three" 917var str2 = "Four" 918var strPtr = []*string{&str1, &str2} 919var strPtr2 = []*[]*string{&strPtr} 920 921var nestedTestData = nestedMarshalTestStruct{ 922 String: [][]string{{"Five", "Six"}, {"One", "Two"}}, 923 StringPtr: &strPtr2, 924} 925 926var nestedTestToml = []byte(`String = [["Five", "Six"], ["One", "Two"]] 927StringPtr = [["Three", "Four"]] 928`) 929 930func TestNestedMarshal(t *testing.T) { 931 result, err := Marshal(nestedTestData) 932 if err != nil { 933 t.Fatal(err) 934 } 935 expected := nestedTestToml 936 if !bytes.Equal(result, expected) { 937 t.Errorf("Bad nested marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expected, result) 938 } 939} 940 941func TestNestedUnmarshal(t *testing.T) { 942 result := nestedMarshalTestStruct{} 943 err := Unmarshal(nestedTestToml, &result) 944 expected := nestedTestData 945 if err != nil { 946 t.Fatal(err) 947 } 948 if !reflect.DeepEqual(result, expected) { 949 t.Errorf("Bad nested unmarshal: expected %v, got %v", expected, result) 950 } 951} 952 953type customMarshalerParent struct { 954 Self customMarshaler `toml:"me"` 955 Friends []customMarshaler `toml:"friends"` 956} 957 958type customMarshaler struct { 959 FirstName string 960 LastName string 961} 962 963func (c customMarshaler) MarshalTOML() ([]byte, error) { 964 fullName := fmt.Sprintf("%s %s", c.FirstName, c.LastName) 965 return []byte(fullName), nil 966} 967 968var customMarshalerData = customMarshaler{FirstName: "Sally", LastName: "Fields"} 969var customMarshalerToml = []byte(`Sally Fields`) 970var nestedCustomMarshalerData = customMarshalerParent{ 971 Self: customMarshaler{FirstName: "Maiku", LastName: "Suteda"}, 972 Friends: []customMarshaler{customMarshalerData}, 973} 974var nestedCustomMarshalerToml = []byte(`friends = ["Sally Fields"] 975me = "Maiku Suteda" 976`) 977var nestedCustomMarshalerTomlForUnmarshal = []byte(`[friends] 978FirstName = "Sally" 979LastName = "Fields"`) 980 981func TestCustomMarshaler(t *testing.T) { 982 result, err := Marshal(customMarshalerData) 983 if err != nil { 984 t.Fatal(err) 985 } 986 expected := customMarshalerToml 987 if !bytes.Equal(result, expected) { 988 t.Errorf("Bad custom marshaler: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expected, result) 989 } 990} 991 992type IntOrString string 993 994func (x *IntOrString) MarshalTOML() ([]byte, error) { 995 s := *(*string)(x) 996 _, err := strconv.Atoi(s) 997 if err != nil { 998 return []byte(fmt.Sprintf(`"%s"`, s)), nil 999 } 1000 return []byte(s), nil 1001} 1002 1003func TestNestedCustomMarshaler(t *testing.T) { 1004 num := IntOrString("100") 1005 str := IntOrString("hello") 1006 var parent = struct { 1007 IntField *IntOrString `toml:"int"` 1008 StringField *IntOrString `toml:"string"` 1009 }{ 1010 &num, 1011 &str, 1012 } 1013 1014 result, err := Marshal(parent) 1015 if err != nil { 1016 t.Fatal(err) 1017 } 1018 expected := `int = 100 1019string = "hello" 1020` 1021 if !bytes.Equal(result, []byte(expected)) { 1022 t.Errorf("Bad nested text marshaler: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expected, result) 1023 } 1024} 1025 1026type textMarshaler struct { 1027 FirstName string 1028 LastName string 1029} 1030 1031func (m textMarshaler) MarshalText() ([]byte, error) { 1032 fullName := fmt.Sprintf("%s %s", m.FirstName, m.LastName) 1033 return []byte(fullName), nil 1034} 1035 1036func TestTextMarshaler(t *testing.T) { 1037 m := textMarshaler{FirstName: "Sally", LastName: "Fields"} 1038 1039 result, err := Marshal(m) 1040 if err != nil { 1041 t.Fatal(err) 1042 } 1043 expected := `Sally Fields` 1044 if !bytes.Equal(result, []byte(expected)) { 1045 t.Errorf("Bad text marshaler: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expected, result) 1046 } 1047} 1048 1049func TestUnmarshalTextMarshaler(t *testing.T) { 1050 var nested = struct { 1051 Friends textMarshaler `toml:"friends"` 1052 }{} 1053 1054 var expected = struct { 1055 Friends textMarshaler `toml:"friends"` 1056 }{ 1057 Friends: textMarshaler{FirstName: "Sally", LastName: "Fields"}, 1058 } 1059 1060 err := Unmarshal(nestedCustomMarshalerTomlForUnmarshal, &nested) 1061 if err != nil { 1062 t.Fatal(err) 1063 } 1064 if !reflect.DeepEqual(nested, expected) { 1065 t.Errorf("Bad unmarshal: expected %v, got %v", expected, nested) 1066 } 1067} 1068 1069func TestNestedTextMarshaler(t *testing.T) { 1070 var parent = struct { 1071 Self textMarshaler `toml:"me"` 1072 Friends []textMarshaler `toml:"friends"` 1073 Stranger *textMarshaler `toml:"stranger"` 1074 }{ 1075 Self: textMarshaler{FirstName: "Maiku", LastName: "Suteda"}, 1076 Friends: []textMarshaler{textMarshaler{FirstName: "Sally", LastName: "Fields"}}, 1077 Stranger: &textMarshaler{FirstName: "Earl", LastName: "Henson"}, 1078 } 1079 1080 result, err := Marshal(parent) 1081 if err != nil { 1082 t.Fatal(err) 1083 } 1084 expected := `friends = ["Sally Fields"] 1085me = "Maiku Suteda" 1086stranger = "Earl Henson" 1087` 1088 if !bytes.Equal(result, []byte(expected)) { 1089 t.Errorf("Bad nested text marshaler: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expected, result) 1090 } 1091} 1092 1093type precedentMarshaler struct { 1094 FirstName string 1095 LastName string 1096} 1097 1098func (m precedentMarshaler) MarshalText() ([]byte, error) { 1099 return []byte("shadowed"), nil 1100} 1101 1102func (m precedentMarshaler) MarshalTOML() ([]byte, error) { 1103 fullName := fmt.Sprintf("%s %s", m.FirstName, m.LastName) 1104 return []byte(fullName), nil 1105} 1106 1107func TestPrecedentMarshaler(t *testing.T) { 1108 m := textMarshaler{FirstName: "Sally", LastName: "Fields"} 1109 1110 result, err := Marshal(m) 1111 if err != nil { 1112 t.Fatal(err) 1113 } 1114 expected := `Sally Fields` 1115 if !bytes.Equal(result, []byte(expected)) { 1116 t.Errorf("Bad text marshaler: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expected, result) 1117 } 1118} 1119 1120type customPointerMarshaler struct { 1121 FirstName string 1122 LastName string 1123} 1124 1125func (m *customPointerMarshaler) MarshalTOML() ([]byte, error) { 1126 return []byte(`"hidden"`), nil 1127} 1128 1129type textPointerMarshaler struct { 1130 FirstName string 1131 LastName string 1132} 1133 1134func (m *textPointerMarshaler) MarshalText() ([]byte, error) { 1135 return []byte("hidden"), nil 1136} 1137 1138func TestPointerMarshaler(t *testing.T) { 1139 var parent = struct { 1140 Self customPointerMarshaler `toml:"me"` 1141 Stranger *customPointerMarshaler `toml:"stranger"` 1142 Friend textPointerMarshaler `toml:"friend"` 1143 Fiend *textPointerMarshaler `toml:"fiend"` 1144 }{ 1145 Self: customPointerMarshaler{FirstName: "Maiku", LastName: "Suteda"}, 1146 Stranger: &customPointerMarshaler{FirstName: "Earl", LastName: "Henson"}, 1147 Friend: textPointerMarshaler{FirstName: "Sally", LastName: "Fields"}, 1148 Fiend: &textPointerMarshaler{FirstName: "Casper", LastName: "Snider"}, 1149 } 1150 1151 result, err := Marshal(parent) 1152 if err != nil { 1153 t.Fatal(err) 1154 } 1155 expected := `fiend = "hidden" 1156stranger = "hidden" 1157 1158[friend] 1159 FirstName = "Sally" 1160 LastName = "Fields" 1161 1162[me] 1163 FirstName = "Maiku" 1164 LastName = "Suteda" 1165` 1166 if !bytes.Equal(result, []byte(expected)) { 1167 t.Errorf("Bad nested text marshaler: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expected, result) 1168 } 1169} 1170 1171func TestPointerCustomMarshalerSequence(t *testing.T) { 1172 var customPointerMarshalerSlice *[]*customPointerMarshaler 1173 var customPointerMarshalerArray *[2]*customPointerMarshaler 1174 1175 if !isCustomMarshalerSequence(reflect.TypeOf(customPointerMarshalerSlice)) { 1176 t.Errorf("error: should be a sequence of custom marshaler interfaces") 1177 } 1178 if !isCustomMarshalerSequence(reflect.TypeOf(customPointerMarshalerArray)) { 1179 t.Errorf("error: should be a sequence of custom marshaler interfaces") 1180 } 1181} 1182 1183func TestPointerTextMarshalerSequence(t *testing.T) { 1184 var textPointerMarshalerSlice *[]*textPointerMarshaler 1185 var textPointerMarshalerArray *[2]*textPointerMarshaler 1186 1187 if !isTextMarshalerSequence(reflect.TypeOf(textPointerMarshalerSlice)) { 1188 t.Errorf("error: should be a sequence of text marshaler interfaces") 1189 } 1190 if !isTextMarshalerSequence(reflect.TypeOf(textPointerMarshalerArray)) { 1191 t.Errorf("error: should be a sequence of text marshaler interfaces") 1192 } 1193} 1194 1195var commentTestToml = []byte(` 1196# it's a comment on type 1197[postgres] 1198 # isCommented = "dvalue" 1199 noComment = "cvalue" 1200 1201 # A comment on AttrB with a 1202 # break line 1203 password = "bvalue" 1204 1205 # A comment on AttrA 1206 user = "avalue" 1207 1208 [[postgres.My]] 1209 1210 # a comment on my on typeC 1211 My = "Foo" 1212 1213 [[postgres.My]] 1214 1215 # a comment on my on typeC 1216 My = "Baar" 1217`) 1218 1219func TestMarshalComment(t *testing.T) { 1220 type TypeC struct { 1221 My string `comment:"a comment on my on typeC"` 1222 } 1223 type TypeB struct { 1224 AttrA string `toml:"user" comment:"A comment on AttrA"` 1225 AttrB string `toml:"password" comment:"A comment on AttrB with a\n break line"` 1226 AttrC string `toml:"noComment"` 1227 AttrD string `toml:"isCommented" commented:"true"` 1228 My []TypeC 1229 } 1230 type TypeA struct { 1231 TypeB TypeB `toml:"postgres" comment:"it's a comment on type"` 1232 } 1233 1234 ta := []TypeC{{My: "Foo"}, {My: "Baar"}} 1235 config := TypeA{TypeB{AttrA: "avalue", AttrB: "bvalue", AttrC: "cvalue", AttrD: "dvalue", My: ta}} 1236 result, err := Marshal(config) 1237 if err != nil { 1238 t.Fatal(err) 1239 } 1240 expected := commentTestToml 1241 if !bytes.Equal(result, expected) { 1242 t.Errorf("Bad marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expected, result) 1243 } 1244} 1245 1246func TestMarshalMultilineCommented(t *testing.T) { 1247 expectedToml := []byte(`# MultilineArray = [ 1248 # 100, 1249 # 200, 1250 # 300, 1251# ] 1252# MultilineNestedArray = [ 1253 # [ 1254 # "a", 1255 # "b", 1256 # "c", 1257# ], 1258 # [ 1259 # "d", 1260 # "e", 1261 # "f", 1262# ], 1263# ] 1264# MultilineString = """ 1265# I 1266# am 1267# Allen""" 1268NonCommented = "Not commented line" 1269`) 1270 type StructWithMultiline struct { 1271 NonCommented string 1272 MultilineString string `commented:"true" multiline:"true"` 1273 MultilineArray []int `commented:"true"` 1274 MultilineNestedArray [][]string `commented:"true"` 1275 } 1276 1277 var buf bytes.Buffer 1278 enc := NewEncoder(&buf) 1279 if err := enc.ArraysWithOneElementPerLine(true).Encode(StructWithMultiline{ 1280 NonCommented: "Not commented line", 1281 MultilineString: "I\nam\nAllen", 1282 MultilineArray: []int{100, 200, 300}, 1283 MultilineNestedArray: [][]string{ 1284 {"a", "b", "c"}, 1285 {"d", "e", "f"}, 1286 }, 1287 }); err == nil { 1288 result := buf.Bytes() 1289 if !bytes.Equal(result, expectedToml) { 1290 t.Errorf("Bad marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expectedToml, result) 1291 } 1292 } else { 1293 t.Fatal(err) 1294 } 1295} 1296 1297func TestMarshalMultilineLiteral(t *testing.T) { 1298 type Doc struct { 1299 Value string `multiline:"true" literal:"true"` 1300 } 1301 1302 d := Doc{ 1303 Value: "hello\nworld\ttest\nend", 1304 } 1305 1306 expected := []byte(`Value = ''' 1307hello 1308world test 1309end 1310''' 1311`) 1312 1313 b, err := Marshal(d) 1314 if err != nil { 1315 t.Fatal("unexpected error") 1316 } 1317 1318 if !bytes.Equal(b, expected) { 1319 t.Errorf("Bad marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expected, b) 1320 } 1321} 1322 1323func TestMarshalNonPrimitiveTypeCommented(t *testing.T) { 1324 expectedToml := []byte(` 1325# [CommentedMapField] 1326 1327 # [CommentedMapField.CommentedMapField1] 1328 # SingleLineString = "This line should be commented out" 1329 1330 # [CommentedMapField.CommentedMapField2] 1331 # SingleLineString = "This line should be commented out" 1332 1333# [CommentedStructField] 1334 1335 # [CommentedStructField.CommentedStructField] 1336 # MultilineArray = [ 1337 # 1, 1338 # 2, 1339 # ] 1340 # MultilineNestedArray = [ 1341 # [ 1342 # 10, 1343 # 20, 1344 # ], 1345 # [ 1346 # 100, 1347 # 200, 1348 # ], 1349 # ] 1350 # MultilineString = """ 1351# This line 1352# should be 1353# commented out""" 1354 1355 # [CommentedStructField.NotCommentedStructField] 1356 # MultilineArray = [ 1357 # 1, 1358 # 2, 1359 # ] 1360 # MultilineNestedArray = [ 1361 # [ 1362 # 10, 1363 # 20, 1364 # ], 1365 # [ 1366 # 100, 1367 # 200, 1368 # ], 1369 # ] 1370 # MultilineString = """ 1371# This line 1372# should be 1373# commented out""" 1374 1375[NotCommentedStructField] 1376 1377 # [NotCommentedStructField.CommentedStructField] 1378 # MultilineArray = [ 1379 # 1, 1380 # 2, 1381 # ] 1382 # MultilineNestedArray = [ 1383 # [ 1384 # 10, 1385 # 20, 1386 # ], 1387 # [ 1388 # 100, 1389 # 200, 1390 # ], 1391 # ] 1392 # MultilineString = """ 1393# This line 1394# should be 1395# commented out""" 1396 1397 [NotCommentedStructField.NotCommentedStructField] 1398 MultilineArray = [ 1399 3, 1400 4, 1401 ] 1402 MultilineNestedArray = [ 1403 [ 1404 30, 1405 40, 1406 ], 1407 [ 1408 300, 1409 400, 1410 ], 1411 ] 1412 MultilineString = """ 1413This line 1414should NOT be 1415commented out""" 1416`) 1417 type InnerStruct struct { 1418 MultilineString string `multiline:"true"` 1419 MultilineArray []int 1420 MultilineNestedArray [][]int 1421 } 1422 type MiddleStruct struct { 1423 NotCommentedStructField InnerStruct 1424 CommentedStructField InnerStruct `commented:"true"` 1425 } 1426 type OuterStruct struct { 1427 CommentedStructField MiddleStruct `commented:"true"` 1428 NotCommentedStructField MiddleStruct 1429 CommentedMapField map[string]struct{ SingleLineString string } `commented:"true"` 1430 } 1431 1432 commentedTestStruct := OuterStruct{ 1433 CommentedStructField: MiddleStruct{ 1434 NotCommentedStructField: InnerStruct{ 1435 MultilineString: "This line\nshould be\ncommented out", 1436 MultilineArray: []int{1, 2}, 1437 MultilineNestedArray: [][]int{{10, 20}, {100, 200}}, 1438 }, 1439 CommentedStructField: InnerStruct{ 1440 MultilineString: "This line\nshould be\ncommented out", 1441 MultilineArray: []int{1, 2}, 1442 MultilineNestedArray: [][]int{{10, 20}, {100, 200}}, 1443 }, 1444 }, 1445 NotCommentedStructField: MiddleStruct{ 1446 NotCommentedStructField: InnerStruct{ 1447 MultilineString: "This line\nshould NOT be\ncommented out", 1448 MultilineArray: []int{3, 4}, 1449 MultilineNestedArray: [][]int{{30, 40}, {300, 400}}, 1450 }, 1451 CommentedStructField: InnerStruct{ 1452 MultilineString: "This line\nshould be\ncommented out", 1453 MultilineArray: []int{1, 2}, 1454 MultilineNestedArray: [][]int{{10, 20}, {100, 200}}, 1455 }, 1456 }, 1457 CommentedMapField: map[string]struct{ SingleLineString string }{ 1458 "CommentedMapField1": { 1459 SingleLineString: "This line should be commented out", 1460 }, 1461 "CommentedMapField2": { 1462 SingleLineString: "This line should be commented out", 1463 }, 1464 }, 1465 } 1466 1467 var buf bytes.Buffer 1468 enc := NewEncoder(&buf) 1469 if err := enc.ArraysWithOneElementPerLine(true).Encode(commentedTestStruct); err == nil { 1470 result := buf.Bytes() 1471 if !bytes.Equal(result, expectedToml) { 1472 t.Errorf("Bad marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expectedToml, result) 1473 } 1474 } else { 1475 t.Fatal(err) 1476 } 1477} 1478 1479type mapsTestStruct struct { 1480 Simple map[string]string 1481 Paths map[string]string 1482 Other map[string]float64 1483 X struct { 1484 Y struct { 1485 Z map[string]bool 1486 } 1487 } 1488} 1489 1490var mapsTestData = mapsTestStruct{ 1491 Simple: map[string]string{ 1492 "one plus one": "two", 1493 "next": "three", 1494 }, 1495 Paths: map[string]string{ 1496 "/this/is/a/path": "/this/is/also/a/path", 1497 "/heloo.txt": "/tmp/lololo.txt", 1498 }, 1499 Other: map[string]float64{ 1500 "testing": 3.9999, 1501 }, 1502 X: struct{ Y struct{ Z map[string]bool } }{ 1503 Y: struct{ Z map[string]bool }{ 1504 Z: map[string]bool{ 1505 "is.Nested": true, 1506 }, 1507 }, 1508 }, 1509} 1510var mapsTestToml = []byte(` 1511[Other] 1512 "testing" = 3.9999 1513 1514[Paths] 1515 "/heloo.txt" = "/tmp/lololo.txt" 1516 "/this/is/a/path" = "/this/is/also/a/path" 1517 1518[Simple] 1519 "next" = "three" 1520 "one plus one" = "two" 1521 1522[X] 1523 1524 [X.Y] 1525 1526 [X.Y.Z] 1527 "is.Nested" = true 1528`) 1529 1530func TestEncodeQuotedMapKeys(t *testing.T) { 1531 var buf bytes.Buffer 1532 if err := NewEncoder(&buf).QuoteMapKeys(true).Encode(mapsTestData); err != nil { 1533 t.Fatal(err) 1534 } 1535 result := buf.Bytes() 1536 expected := mapsTestToml 1537 if !bytes.Equal(result, expected) { 1538 t.Errorf("Bad maps marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expected, result) 1539 } 1540} 1541 1542func TestDecodeQuotedMapKeys(t *testing.T) { 1543 result := mapsTestStruct{} 1544 err := NewDecoder(bytes.NewBuffer(mapsTestToml)).Decode(&result) 1545 expected := mapsTestData 1546 if err != nil { 1547 t.Fatal(err) 1548 } 1549 if !reflect.DeepEqual(result, expected) { 1550 t.Errorf("Bad maps unmarshal: expected %v, got %v", expected, result) 1551 } 1552} 1553 1554type structArrayNoTag struct { 1555 A struct { 1556 B []int64 1557 C []int64 1558 } 1559} 1560 1561func TestMarshalArray(t *testing.T) { 1562 expected := []byte(` 1563[A] 1564 B = [1, 2, 3] 1565 C = [1] 1566`) 1567 1568 m := structArrayNoTag{ 1569 A: struct { 1570 B []int64 1571 C []int64 1572 }{ 1573 B: []int64{1, 2, 3}, 1574 C: []int64{1}, 1575 }, 1576 } 1577 1578 b, err := Marshal(m) 1579 1580 if err != nil { 1581 t.Fatal(err) 1582 } 1583 1584 if !bytes.Equal(b, expected) { 1585 t.Errorf("Bad arrays marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expected, b) 1586 } 1587} 1588 1589func TestMarshalArrayOnePerLine(t *testing.T) { 1590 expected := []byte(` 1591[A] 1592 B = [ 1593 1, 1594 2, 1595 3, 1596 ] 1597 C = [1] 1598`) 1599 1600 m := structArrayNoTag{ 1601 A: struct { 1602 B []int64 1603 C []int64 1604 }{ 1605 B: []int64{1, 2, 3}, 1606 C: []int64{1}, 1607 }, 1608 } 1609 1610 var buf bytes.Buffer 1611 encoder := NewEncoder(&buf).ArraysWithOneElementPerLine(true) 1612 err := encoder.Encode(m) 1613 1614 if err != nil { 1615 t.Fatal(err) 1616 } 1617 1618 b := buf.Bytes() 1619 1620 if !bytes.Equal(b, expected) { 1621 t.Errorf("Bad arrays marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expected, b) 1622 } 1623} 1624 1625var customTagTestToml = []byte(` 1626[postgres] 1627 password = "bvalue" 1628 user = "avalue" 1629 1630 [[postgres.My]] 1631 My = "Foo" 1632 1633 [[postgres.My]] 1634 My = "Baar" 1635`) 1636 1637func TestMarshalCustomTag(t *testing.T) { 1638 type TypeC struct { 1639 My string 1640 } 1641 type TypeB struct { 1642 AttrA string `file:"user"` 1643 AttrB string `file:"password"` 1644 My []TypeC 1645 } 1646 type TypeA struct { 1647 TypeB TypeB `file:"postgres"` 1648 } 1649 1650 ta := []TypeC{{My: "Foo"}, {My: "Baar"}} 1651 config := TypeA{TypeB{AttrA: "avalue", AttrB: "bvalue", My: ta}} 1652 var buf bytes.Buffer 1653 err := NewEncoder(&buf).SetTagName("file").Encode(config) 1654 if err != nil { 1655 t.Fatal(err) 1656 } 1657 expected := customTagTestToml 1658 result := buf.Bytes() 1659 if !bytes.Equal(result, expected) { 1660 t.Errorf("Bad marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expected, result) 1661 } 1662} 1663 1664var customCommentTagTestToml = []byte(` 1665# db connection 1666[postgres] 1667 1668 # db pass 1669 password = "bvalue" 1670 1671 # db user 1672 user = "avalue" 1673`) 1674 1675func TestMarshalCustomComment(t *testing.T) { 1676 type TypeB struct { 1677 AttrA string `toml:"user" descr:"db user"` 1678 AttrB string `toml:"password" descr:"db pass"` 1679 } 1680 type TypeA struct { 1681 TypeB TypeB `toml:"postgres" descr:"db connection"` 1682 } 1683 1684 config := TypeA{TypeB{AttrA: "avalue", AttrB: "bvalue"}} 1685 var buf bytes.Buffer 1686 err := NewEncoder(&buf).SetTagComment("descr").Encode(config) 1687 if err != nil { 1688 t.Fatal(err) 1689 } 1690 expected := customCommentTagTestToml 1691 result := buf.Bytes() 1692 if !bytes.Equal(result, expected) { 1693 t.Errorf("Bad marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expected, result) 1694 } 1695} 1696 1697var customCommentedTagTestToml = []byte(` 1698[postgres] 1699 # password = "bvalue" 1700 # user = "avalue" 1701`) 1702 1703func TestMarshalCustomCommented(t *testing.T) { 1704 type TypeB struct { 1705 AttrA string `toml:"user" disable:"true"` 1706 AttrB string `toml:"password" disable:"true"` 1707 } 1708 type TypeA struct { 1709 TypeB TypeB `toml:"postgres"` 1710 } 1711 1712 config := TypeA{TypeB{AttrA: "avalue", AttrB: "bvalue"}} 1713 var buf bytes.Buffer 1714 err := NewEncoder(&buf).SetTagCommented("disable").Encode(config) 1715 if err != nil { 1716 t.Fatal(err) 1717 } 1718 expected := customCommentedTagTestToml 1719 result := buf.Bytes() 1720 if !bytes.Equal(result, expected) { 1721 t.Errorf("Bad marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expected, result) 1722 } 1723} 1724 1725func TestMarshalDirectMultilineString(t *testing.T) { 1726 tree := newTree() 1727 tree.SetWithOptions("mykey", SetOptions{ 1728 Multiline: true, 1729 }, "my\x11multiline\nstring\ba\tb\fc\rd\"e\\!") 1730 result, err := tree.Marshal() 1731 if err != nil { 1732 t.Fatal("marshal should not error:", err) 1733 } 1734 expected := []byte("mykey = \"\"\"\nmy\\u0011multiline\nstring\\ba\tb\\fc\rd\"e\\!\"\"\"\n") 1735 if !bytes.Equal(result, expected) { 1736 t.Errorf("Bad marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expected, result) 1737 } 1738} 1739 1740func TestUnmarshalTabInStringAndQuotedKey(t *testing.T) { 1741 type Test struct { 1742 Field1 string `toml:"Fie ld1"` 1743 Field2 string 1744 } 1745 1746 type TestCase struct { 1747 desc string 1748 input []byte 1749 expected Test 1750 } 1751 1752 testCases := []TestCase{ 1753 { 1754 desc: "multiline string with tab", 1755 input: []byte("Field2 = \"\"\"\nhello\tworld\"\"\""), 1756 expected: Test{ 1757 Field2: "hello\tworld", 1758 }, 1759 }, 1760 { 1761 desc: "quoted key with tab", 1762 input: []byte("\"Fie\tld1\" = \"key with tab\""), 1763 expected: Test{ 1764 Field1: "key with tab", 1765 }, 1766 }, 1767 { 1768 desc: "basic string tab", 1769 input: []byte("Field2 = \"hello\tworld\""), 1770 expected: Test{ 1771 Field2: "hello\tworld", 1772 }, 1773 }, 1774 } 1775 1776 for i := range testCases { 1777 result := Test{} 1778 err := Unmarshal(testCases[i].input, &result) 1779 if err != nil { 1780 t.Errorf("%s test error:%v", testCases[i].desc, err) 1781 continue 1782 } 1783 1784 if !reflect.DeepEqual(result, testCases[i].expected) { 1785 t.Errorf("%s test error: expected\n-----\n%+v\n-----\ngot\n-----\n%+v\n-----\n", 1786 testCases[i].desc, testCases[i].expected, result) 1787 } 1788 } 1789} 1790 1791var customMultilineTagTestToml = []byte(`int_slice = [ 1792 1, 1793 2, 1794 3, 1795] 1796`) 1797 1798func TestMarshalCustomMultiline(t *testing.T) { 1799 type TypeA struct { 1800 AttrA []int `toml:"int_slice" mltln:"true"` 1801 } 1802 1803 config := TypeA{AttrA: []int{1, 2, 3}} 1804 var buf bytes.Buffer 1805 err := NewEncoder(&buf).ArraysWithOneElementPerLine(true).SetTagMultiline("mltln").Encode(config) 1806 if err != nil { 1807 t.Fatal(err) 1808 } 1809 expected := customMultilineTagTestToml 1810 result := buf.Bytes() 1811 if !bytes.Equal(result, expected) { 1812 t.Errorf("Bad marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expected, result) 1813 } 1814} 1815 1816func TestMultilineWithAdjacentQuotationMarks(t *testing.T) { 1817 type testStruct struct { 1818 Str string `multiline:"true"` 1819 } 1820 type testCase struct { 1821 expected []byte 1822 data testStruct 1823 } 1824 1825 testCases := []testCase{ 1826 { 1827 expected: []byte(`Str = """ 1828hello\"""" 1829`), 1830 data: testStruct{ 1831 Str: "hello\"", 1832 }, 1833 }, 1834 { 1835 expected: []byte(`Str = """ 1836""\"""\"""\"""" 1837`), 1838 data: testStruct{ 1839 Str: "\"\"\"\"\"\"\"\"\"", 1840 }, 1841 }, 1842 } 1843 for i := range testCases { 1844 result, err := Marshal(testCases[i].data) 1845 if err != nil { 1846 t.Fatal(err) 1847 } 1848 1849 if !bytes.Equal(result, testCases[i].expected) { 1850 t.Errorf("Bad marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", 1851 testCases[i].expected, result) 1852 } else { 1853 var data testStruct 1854 if err = Unmarshal(result, &data); err != nil { 1855 t.Fatal(err) 1856 } 1857 if data.Str != testCases[i].data.Str { 1858 t.Errorf("Round trip test fail: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", 1859 testCases[i].data.Str, data.Str) 1860 } 1861 } 1862 } 1863} 1864 1865func TestMarshalEmbedTree(t *testing.T) { 1866 expected := []byte(`OuterField1 = "Out" 1867OuterField2 = 1024 1868 1869[TreeField] 1870 InnerField1 = "In" 1871 InnerField2 = 2048 1872 1873 [TreeField.EmbedStruct] 1874 EmbedField = "Embed" 1875`) 1876 type InnerStruct struct { 1877 InnerField1 string 1878 InnerField2 int 1879 EmbedStruct struct { 1880 EmbedField string 1881 } 1882 } 1883 1884 type OuterStruct struct { 1885 OuterField1 string 1886 OuterField2 int 1887 TreeField *Tree 1888 } 1889 1890 tree, err := Load(` 1891InnerField1 = "In" 1892InnerField2 = 2048 1893 1894[EmbedStruct] 1895 EmbedField = "Embed" 1896`) 1897 if err != nil { 1898 t.Fatal(err) 1899 } 1900 1901 out := OuterStruct{ 1902 "Out", 1903 1024, 1904 tree, 1905 } 1906 actual, _ := Marshal(out) 1907 1908 if !bytes.Equal(actual, expected) { 1909 t.Errorf("Bad marshal: expected %s, got %s", expected, actual) 1910 } 1911} 1912 1913var testDocBasicToml = []byte(` 1914[document] 1915 bool_val = true 1916 date_val = 1979-05-27T07:32:00Z 1917 float_val = 123.4 1918 int_val = 5000 1919 string_val = "Bite me" 1920 uint_val = 5001 1921`) 1922 1923type testDocCustomTag struct { 1924 Doc testDocBasicsCustomTag `file:"document"` 1925} 1926type testDocBasicsCustomTag struct { 1927 Bool bool `file:"bool_val"` 1928 Date time.Time `file:"date_val"` 1929 Float float32 `file:"float_val"` 1930 Int int `file:"int_val"` 1931 Uint uint `file:"uint_val"` 1932 String *string `file:"string_val"` 1933 unexported int `file:"shouldntBeHere"` 1934} 1935 1936var testDocCustomTagData = testDocCustomTag{ 1937 Doc: testDocBasicsCustomTag{ 1938 Bool: true, 1939 Date: time.Date(1979, 5, 27, 7, 32, 0, 0, time.UTC), 1940 Float: 123.4, 1941 Int: 5000, 1942 Uint: 5001, 1943 String: &biteMe, 1944 unexported: 0, 1945 }, 1946} 1947 1948func TestUnmarshalCustomTag(t *testing.T) { 1949 buf := bytes.NewBuffer(testDocBasicToml) 1950 1951 result := testDocCustomTag{} 1952 err := NewDecoder(buf).SetTagName("file").Decode(&result) 1953 if err != nil { 1954 t.Fatal(err) 1955 } 1956 expected := testDocCustomTagData 1957 if !reflect.DeepEqual(result, expected) { 1958 resStr, _ := json.MarshalIndent(result, "", " ") 1959 expStr, _ := json.MarshalIndent(expected, "", " ") 1960 t.Errorf("Bad unmarshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expStr, resStr) 1961 1962 } 1963} 1964 1965func TestUnmarshalMap(t *testing.T) { 1966 testToml := []byte(` 1967 a = 1 1968 b = 2 1969 c = 3 1970 `) 1971 var result map[string]int 1972 err := Unmarshal(testToml, &result) 1973 if err != nil { 1974 t.Errorf("Received unexpected error: %s", err) 1975 return 1976 } 1977 1978 expected := map[string]int{ 1979 "a": 1, 1980 "b": 2, 1981 "c": 3, 1982 } 1983 1984 if !reflect.DeepEqual(result, expected) { 1985 t.Errorf("Bad unmarshal: expected %v, got %v", expected, result) 1986 } 1987} 1988 1989func TestUnmarshalMapWithTypedKey(t *testing.T) { 1990 testToml := []byte(` 1991 a = 1 1992 b = 2 1993 c = 3 1994 `) 1995 1996 type letter string 1997 var result map[letter]int 1998 err := Unmarshal(testToml, &result) 1999 if err != nil { 2000 t.Errorf("Received unexpected error: %s", err) 2001 return 2002 } 2003 2004 expected := map[letter]int{ 2005 "a": 1, 2006 "b": 2, 2007 "c": 3, 2008 } 2009 2010 if !reflect.DeepEqual(result, expected) { 2011 t.Errorf("Bad unmarshal: expected %v, got %v", expected, result) 2012 } 2013} 2014 2015func TestUnmarshalNonPointer(t *testing.T) { 2016 a := 1 2017 err := Unmarshal([]byte{}, a) 2018 if err == nil { 2019 t.Fatal("unmarshal should err when given a non pointer") 2020 } 2021} 2022 2023func TestUnmarshalInvalidPointerKind(t *testing.T) { 2024 a := 1 2025 err := Unmarshal([]byte{}, &a) 2026 if err == nil { 2027 t.Fatal("unmarshal should err when given an invalid pointer type") 2028 } 2029} 2030 2031func TestMarshalSlice(t *testing.T) { 2032 m := make([]int, 1) 2033 m[0] = 1 2034 2035 var buf bytes.Buffer 2036 err := NewEncoder(&buf).Encode(&m) 2037 if err == nil { 2038 t.Error("expected error, got nil") 2039 return 2040 } 2041 if err.Error() != "Only pointer to struct can be marshaled to TOML" { 2042 t.Fail() 2043 } 2044} 2045 2046func TestMarshalSlicePointer(t *testing.T) { 2047 m := make([]int, 1) 2048 m[0] = 1 2049 2050 var buf bytes.Buffer 2051 err := NewEncoder(&buf).Encode(m) 2052 if err == nil { 2053 t.Error("expected error, got nil") 2054 return 2055 } 2056 if err.Error() != "Only a struct or map can be marshaled to TOML" { 2057 t.Fail() 2058 } 2059} 2060 2061func TestMarshalNestedArrayInlineTables(t *testing.T) { 2062 type table struct { 2063 Value1 int `toml:"ZValue1"` 2064 Value2 int `toml:"YValue2"` 2065 Value3 int `toml:"XValue3"` 2066 } 2067 2068 type nestedTable struct { 2069 Table table 2070 } 2071 2072 nestedArray := struct { 2073 Simple [][]table 2074 SimplePointer *[]*[]table 2075 Nested [][]nestedTable 2076 NestedPointer *[]*[]nestedTable 2077 }{ 2078 Simple: [][]table{{{Value1: 1}, {Value1: 10}}}, 2079 SimplePointer: &[]*[]table{{{Value2: 2}}}, 2080 Nested: [][]nestedTable{{{Table: table{Value3: 3}}}}, 2081 NestedPointer: &[]*[]nestedTable{{{Table: table{Value3: -3}}}}, 2082 } 2083 2084 expectedPreserve := `Simple = [[{ ZValue1 = 1, YValue2 = 0, XValue3 = 0 }, { ZValue1 = 10, YValue2 = 0, XValue3 = 0 }]] 2085SimplePointer = [[{ ZValue1 = 0, YValue2 = 2, XValue3 = 0 }]] 2086Nested = [[{ Table = { ZValue1 = 0, YValue2 = 0, XValue3 = 3 } }]] 2087NestedPointer = [[{ Table = { ZValue1 = 0, YValue2 = 0, XValue3 = -3 } }]] 2088` 2089 2090 expectedAlphabetical := `Nested = [[{ Table = { XValue3 = 3, YValue2 = 0, ZValue1 = 0 } }]] 2091NestedPointer = [[{ Table = { XValue3 = -3, YValue2 = 0, ZValue1 = 0 } }]] 2092Simple = [[{ XValue3 = 0, YValue2 = 0, ZValue1 = 1 }, { XValue3 = 0, YValue2 = 0, ZValue1 = 10 }]] 2093SimplePointer = [[{ XValue3 = 0, YValue2 = 2, ZValue1 = 0 }]] 2094` 2095 2096 var bufPreserve bytes.Buffer 2097 if err := NewEncoder(&bufPreserve).Order(OrderPreserve).Encode(nestedArray); err != nil { 2098 t.Fatalf("unexpected error: %s", err.Error()) 2099 } 2100 if !bytes.Equal(bufPreserve.Bytes(), []byte(expectedPreserve)) { 2101 t.Errorf("Bad marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expectedPreserve, bufPreserve.String()) 2102 } 2103 2104 var bufAlphabetical bytes.Buffer 2105 if err := NewEncoder(&bufAlphabetical).Order(OrderAlphabetical).Encode(nestedArray); err != nil { 2106 t.Fatalf("unexpected error: %s", err.Error()) 2107 } 2108 if !bytes.Equal(bufAlphabetical.Bytes(), []byte(expectedAlphabetical)) { 2109 t.Errorf("Bad marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expectedAlphabetical, bufAlphabetical.String()) 2110 } 2111} 2112 2113type testDuration struct { 2114 Nanosec time.Duration `toml:"nanosec"` 2115 Microsec1 time.Duration `toml:"microsec1"` 2116 Microsec2 *time.Duration `toml:"microsec2"` 2117 Millisec time.Duration `toml:"millisec"` 2118 Sec time.Duration `toml:"sec"` 2119 Min time.Duration `toml:"min"` 2120 Hour time.Duration `toml:"hour"` 2121 Mixed time.Duration `toml:"mixed"` 2122 AString string `toml:"a_string"` 2123} 2124 2125var testDurationToml = []byte(` 2126nanosec = "1ns" 2127microsec1 = "1us" 2128microsec2 = "1µs" 2129millisec = "1ms" 2130sec = "1s" 2131min = "1m" 2132hour = "1h" 2133mixed = "1h1m1s1ms1µs1ns" 2134a_string = "15s" 2135`) 2136 2137func TestUnmarshalDuration(t *testing.T) { 2138 buf := bytes.NewBuffer(testDurationToml) 2139 2140 result := testDuration{} 2141 err := NewDecoder(buf).Decode(&result) 2142 if err != nil { 2143 t.Fatal(err) 2144 } 2145 ms := time.Duration(1) * time.Microsecond 2146 expected := testDuration{ 2147 Nanosec: 1, 2148 Microsec1: time.Microsecond, 2149 Microsec2: &ms, 2150 Millisec: time.Millisecond, 2151 Sec: time.Second, 2152 Min: time.Minute, 2153 Hour: time.Hour, 2154 Mixed: time.Hour + 2155 time.Minute + 2156 time.Second + 2157 time.Millisecond + 2158 time.Microsecond + 2159 time.Nanosecond, 2160 AString: "15s", 2161 } 2162 if !reflect.DeepEqual(result, expected) { 2163 resStr, _ := json.MarshalIndent(result, "", " ") 2164 expStr, _ := json.MarshalIndent(expected, "", " ") 2165 t.Errorf("Bad unmarshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expStr, resStr) 2166 2167 } 2168} 2169 2170var testDurationToml2 = []byte(`a_string = "15s" 2171hour = "1h0m0s" 2172microsec1 = "1µs" 2173microsec2 = "1µs" 2174millisec = "1ms" 2175min = "1m0s" 2176mixed = "1h1m1.001001001s" 2177nanosec = "1ns" 2178sec = "1s" 2179`) 2180 2181func TestMarshalDuration(t *testing.T) { 2182 ms := time.Duration(1) * time.Microsecond 2183 data := testDuration{ 2184 Nanosec: 1, 2185 Microsec1: time.Microsecond, 2186 Microsec2: &ms, 2187 Millisec: time.Millisecond, 2188 Sec: time.Second, 2189 Min: time.Minute, 2190 Hour: time.Hour, 2191 Mixed: time.Hour + 2192 time.Minute + 2193 time.Second + 2194 time.Millisecond + 2195 time.Microsecond + 2196 time.Nanosecond, 2197 AString: "15s", 2198 } 2199 2200 var buf bytes.Buffer 2201 err := NewEncoder(&buf).Encode(data) 2202 if err != nil { 2203 t.Fatal(err) 2204 } 2205 expected := testDurationToml2 2206 result := buf.Bytes() 2207 if !bytes.Equal(result, expected) { 2208 t.Errorf("Bad marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expected, result) 2209 } 2210} 2211 2212type testBadDuration struct { 2213 Val time.Duration `toml:"val"` 2214} 2215 2216var testBadDurationToml = []byte(`val = "1z"`) 2217 2218func TestUnmarshalBadDuration(t *testing.T) { 2219 buf := bytes.NewBuffer(testBadDurationToml) 2220 2221 result := testBadDuration{} 2222 err := NewDecoder(buf).Decode(&result) 2223 if err == nil { 2224 t.Fatal("expected bad duration error") 2225 } 2226} 2227 2228var testCamelCaseKeyToml = []byte(`fooBar = 10`) 2229 2230func TestUnmarshalCamelCaseKey(t *testing.T) { 2231 var x struct { 2232 FooBar int 2233 B int 2234 } 2235 2236 if err := Unmarshal(testCamelCaseKeyToml, &x); err != nil { 2237 t.Fatal(err) 2238 } 2239 2240 if x.FooBar != 10 { 2241 t.Fatal("Did not set camelCase'd key") 2242 } 2243} 2244 2245func TestUnmarshalNegativeUint(t *testing.T) { 2246 type check struct{ U uint } 2247 2248 tree, _ := Load("u = -1") 2249 err := tree.Unmarshal(&check{}) 2250 if err.Error() != "(1, 1): -1(int64) is negative so does not fit in uint" { 2251 t.Error("expect err:(1, 1): -1(int64) is negative so does not fit in uint but got:", err) 2252 } 2253} 2254 2255func TestUnmarshalCheckConversionFloatInt(t *testing.T) { 2256 type conversionCheck struct { 2257 U uint 2258 I int 2259 F float64 2260 } 2261 2262 treeU, _ := Load("u = 1e300") 2263 treeI, _ := Load("i = 1e300") 2264 treeF, _ := Load("f = 9223372036854775806") 2265 2266 errU := treeU.Unmarshal(&conversionCheck{}) 2267 errI := treeI.Unmarshal(&conversionCheck{}) 2268 errF := treeF.Unmarshal(&conversionCheck{}) 2269 2270 if errU.Error() != "(1, 1): Can't convert 1e+300(float64) to uint" { 2271 t.Error("expect err:(1, 1): Can't convert 1e+300(float64) to uint but got:", errU) 2272 } 2273 if errI.Error() != "(1, 1): Can't convert 1e+300(float64) to int" { 2274 t.Error("expect err:(1, 1): Can't convert 1e+300(float64) to int but got:", errI) 2275 } 2276 if errF.Error() != "(1, 1): Can't convert 9223372036854775806(int64) to float64" { 2277 t.Error("expect err:(1, 1): Can't convert 9223372036854775806(int64) to float64 but got:", errF) 2278 } 2279} 2280 2281func TestUnmarshalOverflow(t *testing.T) { 2282 type overflow struct { 2283 U8 uint8 2284 I8 int8 2285 F32 float32 2286 } 2287 2288 treeU8, _ := Load("u8 = 300") 2289 treeI8, _ := Load("i8 = 300") 2290 treeF32, _ := Load("f32 = 1e300") 2291 2292 errU8 := treeU8.Unmarshal(&overflow{}) 2293 errI8 := treeI8.Unmarshal(&overflow{}) 2294 errF32 := treeF32.Unmarshal(&overflow{}) 2295 2296 if errU8.Error() != "(1, 1): 300(int64) would overflow uint8" { 2297 t.Error("expect err:(1, 1): 300(int64) would overflow uint8 but got:", errU8) 2298 } 2299 if errI8.Error() != "(1, 1): 300(int64) would overflow int8" { 2300 t.Error("expect err:(1, 1): 300(int64) would overflow int8 but got:", errI8) 2301 } 2302 if errF32.Error() != "(1, 1): 1e+300(float64) would overflow float32" { 2303 t.Error("expect err:(1, 1): 1e+300(float64) would overflow float32 but got:", errF32) 2304 } 2305} 2306 2307func TestUnmarshalDefault(t *testing.T) { 2308 type EmbeddedStruct struct { 2309 StringField string `default:"c"` 2310 } 2311 2312 type aliasUint uint 2313 2314 var doc struct { 2315 StringField string `default:"a"` 2316 BoolField bool `default:"true"` 2317 UintField uint `default:"1"` 2318 Uint8Field uint8 `default:"8"` 2319 Uint16Field uint16 `default:"16"` 2320 Uint32Field uint32 `default:"32"` 2321 Uint64Field uint64 `default:"64"` 2322 IntField int `default:"-1"` 2323 Int8Field int8 `default:"-8"` 2324 Int16Field int16 `default:"-16"` 2325 Int32Field int32 `default:"-32"` 2326 Int64Field int64 `default:"-64"` 2327 Float32Field float32 `default:"32.1"` 2328 Float64Field float64 `default:"64.1"` 2329 DurationField time.Duration `default:"120ms"` 2330 DurationField2 time.Duration `default:"120000000"` 2331 NonEmbeddedStruct struct { 2332 StringField string `default:"b"` 2333 } 2334 EmbeddedStruct 2335 AliasUintField aliasUint `default:"1000"` 2336 } 2337 2338 err := Unmarshal([]byte(``), &doc) 2339 if err != nil { 2340 t.Fatal(err) 2341 } 2342 if doc.BoolField != true { 2343 t.Errorf("BoolField should be true, not %t", doc.BoolField) 2344 } 2345 if doc.StringField != "a" { 2346 t.Errorf("StringField should be \"a\", not %s", doc.StringField) 2347 } 2348 if doc.UintField != 1 { 2349 t.Errorf("UintField should be 1, not %d", doc.UintField) 2350 } 2351 if doc.Uint8Field != 8 { 2352 t.Errorf("Uint8Field should be 8, not %d", doc.Uint8Field) 2353 } 2354 if doc.Uint16Field != 16 { 2355 t.Errorf("Uint16Field should be 16, not %d", doc.Uint16Field) 2356 } 2357 if doc.Uint32Field != 32 { 2358 t.Errorf("Uint32Field should be 32, not %d", doc.Uint32Field) 2359 } 2360 if doc.Uint64Field != 64 { 2361 t.Errorf("Uint64Field should be 64, not %d", doc.Uint64Field) 2362 } 2363 if doc.IntField != -1 { 2364 t.Errorf("IntField should be -1, not %d", doc.IntField) 2365 } 2366 if doc.Int8Field != -8 { 2367 t.Errorf("Int8Field should be -8, not %d", doc.Int8Field) 2368 } 2369 if doc.Int16Field != -16 { 2370 t.Errorf("Int16Field should be -16, not %d", doc.Int16Field) 2371 } 2372 if doc.Int32Field != -32 { 2373 t.Errorf("Int32Field should be -32, not %d", doc.Int32Field) 2374 } 2375 if doc.Int64Field != -64 { 2376 t.Errorf("Int64Field should be -64, not %d", doc.Int64Field) 2377 } 2378 if doc.Float32Field != 32.1 { 2379 t.Errorf("Float32Field should be 32.1, not %f", doc.Float32Field) 2380 } 2381 if doc.Float64Field != 64.1 { 2382 t.Errorf("Float64Field should be 64.1, not %f", doc.Float64Field) 2383 } 2384 if doc.DurationField != 120*time.Millisecond { 2385 t.Errorf("DurationField should be 120ms, not %s", doc.DurationField.String()) 2386 } 2387 if doc.DurationField2 != 120*time.Millisecond { 2388 t.Errorf("DurationField2 should be 120000000, not %d", doc.DurationField2) 2389 } 2390 if doc.NonEmbeddedStruct.StringField != "b" { 2391 t.Errorf("StringField should be \"b\", not %s", doc.NonEmbeddedStruct.StringField) 2392 } 2393 if doc.EmbeddedStruct.StringField != "c" { 2394 t.Errorf("StringField should be \"c\", not %s", doc.EmbeddedStruct.StringField) 2395 } 2396 if doc.AliasUintField != 1000 { 2397 t.Errorf("AliasUintField should be 1000, not %d", doc.AliasUintField) 2398 } 2399} 2400 2401func TestUnmarshalDefaultFailureBool(t *testing.T) { 2402 var doc struct { 2403 Field bool `default:"blah"` 2404 } 2405 2406 err := Unmarshal([]byte(``), &doc) 2407 if err == nil { 2408 t.Fatal("should error") 2409 } 2410} 2411 2412func TestUnmarshalDefaultFailureInt(t *testing.T) { 2413 var doc struct { 2414 Field int `default:"blah"` 2415 } 2416 2417 err := Unmarshal([]byte(``), &doc) 2418 if err == nil { 2419 t.Fatal("should error") 2420 } 2421} 2422 2423func TestUnmarshalDefaultFailureInt64(t *testing.T) { 2424 var doc struct { 2425 Field int64 `default:"blah"` 2426 } 2427 2428 err := Unmarshal([]byte(``), &doc) 2429 if err == nil { 2430 t.Fatal("should error") 2431 } 2432} 2433 2434func TestUnmarshalDefaultFailureFloat64(t *testing.T) { 2435 var doc struct { 2436 Field float64 `default:"blah"` 2437 } 2438 2439 err := Unmarshal([]byte(``), &doc) 2440 if err == nil { 2441 t.Fatal("should error") 2442 } 2443} 2444 2445func TestUnmarshalDefaultFailureDuration(t *testing.T) { 2446 var doc struct { 2447 Field time.Duration `default:"blah"` 2448 } 2449 2450 err := Unmarshal([]byte(``), &doc) 2451 if err == nil { 2452 t.Fatal("should error") 2453 } 2454} 2455 2456func TestUnmarshalDefaultFailureUnsupported(t *testing.T) { 2457 var doc struct { 2458 Field struct{} `default:"blah"` 2459 } 2460 2461 err := Unmarshal([]byte(``), &doc) 2462 if err == nil { 2463 t.Fatal("should error") 2464 } 2465} 2466 2467func TestMarshalNestedAnonymousStructs(t *testing.T) { 2468 type Embedded struct { 2469 Value string `toml:"value"` 2470 Top struct { 2471 Value string `toml:"value"` 2472 } `toml:"top"` 2473 } 2474 2475 type Named struct { 2476 Value string `toml:"value"` 2477 } 2478 2479 var doc struct { 2480 Embedded 2481 Named `toml:"named"` 2482 Anonymous struct { 2483 Value string `toml:"value"` 2484 } `toml:"anonymous"` 2485 } 2486 2487 expected := `value = "" 2488 2489[anonymous] 2490 value = "" 2491 2492[named] 2493 value = "" 2494 2495[top] 2496 value = "" 2497` 2498 2499 result, err := Marshal(doc) 2500 if err != nil { 2501 t.Fatalf("unexpected error: %s", err.Error()) 2502 } 2503 if !bytes.Equal(result, []byte(expected)) { 2504 t.Errorf("Bad marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expected, string(result)) 2505 } 2506} 2507 2508func TestEncoderPromoteNestedAnonymousStructs(t *testing.T) { 2509 type Embedded struct { 2510 Value string `toml:"value"` 2511 } 2512 2513 var doc struct { 2514 Embedded 2515 } 2516 2517 expected := ` 2518[Embedded] 2519 value = "" 2520` 2521 var buf bytes.Buffer 2522 if err := NewEncoder(&buf).PromoteAnonymous(true).Encode(doc); err != nil { 2523 t.Fatalf("unexpected error: %s", err.Error()) 2524 } 2525 if !bytes.Equal(buf.Bytes(), []byte(expected)) { 2526 t.Errorf("Bad marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expected, buf.String()) 2527 } 2528} 2529 2530func TestMarshalNestedAnonymousStructs_DuplicateField(t *testing.T) { 2531 type Embedded struct { 2532 Value string `toml:"value"` 2533 Top struct { 2534 Value string `toml:"value"` 2535 } `toml:"top"` 2536 } 2537 2538 var doc struct { 2539 Value string `toml:"value"` 2540 Embedded 2541 } 2542 doc.Embedded.Value = "shadowed" 2543 doc.Value = "shadows" 2544 2545 expected := `value = "shadows" 2546 2547[top] 2548 value = "" 2549` 2550 2551 result, err := Marshal(doc) 2552 if err != nil { 2553 t.Fatalf("unexpected error: %s", err.Error()) 2554 } 2555 if !bytes.Equal(result, []byte(expected)) { 2556 t.Errorf("Bad marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expected, string(result)) 2557 } 2558} 2559 2560func TestUnmarshalNestedAnonymousStructs(t *testing.T) { 2561 type Nested struct { 2562 Value string `toml:"nested_field"` 2563 } 2564 type Deep struct { 2565 Nested 2566 } 2567 type Document struct { 2568 Deep 2569 Value string `toml:"own_field"` 2570 } 2571 2572 var doc Document 2573 2574 err := Unmarshal([]byte(`nested_field = "nested value"`+"\n"+`own_field = "own value"`), &doc) 2575 if err != nil { 2576 t.Fatal("should not error") 2577 } 2578 if doc.Value != "own value" || doc.Nested.Value != "nested value" { 2579 t.Fatal("unexpected values") 2580 } 2581} 2582 2583func TestUnmarshalNestedAnonymousStructs_Controversial(t *testing.T) { 2584 type Nested struct { 2585 Value string `toml:"nested"` 2586 } 2587 type Deep struct { 2588 Nested 2589 } 2590 type Document struct { 2591 Deep 2592 Value string `toml:"own"` 2593 } 2594 2595 var doc Document 2596 2597 err := Unmarshal([]byte(`nested = "nested value"`+"\n"+`own = "own value"`), &doc) 2598 if err == nil { 2599 t.Fatal("should error") 2600 } 2601} 2602 2603type unexportedFieldPreservationTest struct { 2604 Exported string `toml:"exported"` 2605 unexported string 2606 Nested1 unexportedFieldPreservationTestNested `toml:"nested1"` 2607 Nested2 *unexportedFieldPreservationTestNested `toml:"nested2"` 2608 Nested3 *unexportedFieldPreservationTestNested `toml:"nested3"` 2609 Slice1 []unexportedFieldPreservationTestNested `toml:"slice1"` 2610 Slice2 []*unexportedFieldPreservationTestNested `toml:"slice2"` 2611} 2612 2613type unexportedFieldPreservationTestNested struct { 2614 Exported1 string `toml:"exported1"` 2615 unexported1 string 2616} 2617 2618func TestUnmarshalPreservesUnexportedFields(t *testing.T) { 2619 toml := ` 2620 exported = "visible" 2621 unexported = "ignored" 2622 2623 [nested1] 2624 exported1 = "visible1" 2625 unexported1 = "ignored1" 2626 2627 [nested2] 2628 exported1 = "visible2" 2629 unexported1 = "ignored2" 2630 2631 [nested3] 2632 exported1 = "visible3" 2633 unexported1 = "ignored3" 2634 2635 [[slice1]] 2636 exported1 = "visible3" 2637 2638 [[slice1]] 2639 exported1 = "visible4" 2640 2641 [[slice2]] 2642 exported1 = "visible5" 2643 ` 2644 2645 t.Run("unexported field should not be set from toml", func(t *testing.T) { 2646 var actual unexportedFieldPreservationTest 2647 err := Unmarshal([]byte(toml), &actual) 2648 2649 if err != nil { 2650 t.Fatal("did not expect an error") 2651 } 2652 2653 expect := unexportedFieldPreservationTest{ 2654 Exported: "visible", 2655 unexported: "", 2656 Nested1: unexportedFieldPreservationTestNested{"visible1", ""}, 2657 Nested2: &unexportedFieldPreservationTestNested{"visible2", ""}, 2658 Nested3: &unexportedFieldPreservationTestNested{"visible3", ""}, 2659 Slice1: []unexportedFieldPreservationTestNested{ 2660 {Exported1: "visible3"}, 2661 {Exported1: "visible4"}, 2662 }, 2663 Slice2: []*unexportedFieldPreservationTestNested{ 2664 {Exported1: "visible5"}, 2665 }, 2666 } 2667 2668 if !reflect.DeepEqual(actual, expect) { 2669 t.Fatalf("%+v did not equal %+v", actual, expect) 2670 } 2671 }) 2672 2673 t.Run("unexported field should be preserved", func(t *testing.T) { 2674 actual := unexportedFieldPreservationTest{ 2675 Exported: "foo", 2676 unexported: "bar", 2677 Nested1: unexportedFieldPreservationTestNested{"baz", "bax"}, 2678 Nested2: nil, 2679 Nested3: &unexportedFieldPreservationTestNested{"baz", "bax"}, 2680 } 2681 err := Unmarshal([]byte(toml), &actual) 2682 2683 if err != nil { 2684 t.Fatal("did not expect an error") 2685 } 2686 2687 expect := unexportedFieldPreservationTest{ 2688 Exported: "visible", 2689 unexported: "bar", 2690 Nested1: unexportedFieldPreservationTestNested{"visible1", "bax"}, 2691 Nested2: &unexportedFieldPreservationTestNested{"visible2", ""}, 2692 Nested3: &unexportedFieldPreservationTestNested{"visible3", "bax"}, 2693 Slice1: []unexportedFieldPreservationTestNested{ 2694 {Exported1: "visible3"}, 2695 {Exported1: "visible4"}, 2696 }, 2697 Slice2: []*unexportedFieldPreservationTestNested{ 2698 {Exported1: "visible5"}, 2699 }, 2700 } 2701 2702 if !reflect.DeepEqual(actual, expect) { 2703 t.Fatalf("%+v did not equal %+v", actual, expect) 2704 } 2705 }) 2706} 2707 2708func TestTreeMarshal(t *testing.T) { 2709 cases := [][]byte{ 2710 basicTestToml, 2711 marshalTestToml, 2712 emptyTestToml, 2713 pointerTestToml, 2714 } 2715 for _, expected := range cases { 2716 t.Run("", func(t *testing.T) { 2717 tree, err := LoadBytes(expected) 2718 if err != nil { 2719 t.Fatal(err) 2720 } 2721 result, err := tree.Marshal() 2722 if err != nil { 2723 t.Fatal(err) 2724 } 2725 if !bytes.Equal(result, expected) { 2726 t.Errorf("Bad marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expected, result) 2727 } 2728 }) 2729 } 2730} 2731 2732func TestMarshalArrays(t *testing.T) { 2733 cases := []struct { 2734 Data interface{} 2735 Expected string 2736 }{ 2737 { 2738 Data: struct { 2739 XY [2]int 2740 }{ 2741 XY: [2]int{1, 2}, 2742 }, 2743 Expected: `XY = [1, 2] 2744`, 2745 }, 2746 { 2747 Data: struct { 2748 XY [1][2]int 2749 }{ 2750 XY: [1][2]int{{1, 2}}, 2751 }, 2752 Expected: `XY = [[1, 2]] 2753`, 2754 }, 2755 { 2756 Data: struct { 2757 XY [1][]int 2758 }{ 2759 XY: [1][]int{{1, 2}}, 2760 }, 2761 Expected: `XY = [[1, 2]] 2762`, 2763 }, 2764 { 2765 Data: struct { 2766 XY [][2]int 2767 }{ 2768 XY: [][2]int{{1, 2}}, 2769 }, 2770 Expected: `XY = [[1, 2]] 2771`, 2772 }, 2773 } 2774 for _, tc := range cases { 2775 t.Run("", func(t *testing.T) { 2776 result, err := Marshal(tc.Data) 2777 if err != nil { 2778 t.Fatal(err) 2779 } 2780 if !bytes.Equal(result, []byte(tc.Expected)) { 2781 t.Errorf("Bad marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", []byte(tc.Expected), result) 2782 } 2783 }) 2784 } 2785} 2786 2787func TestUnmarshalLocalDate(t *testing.T) { 2788 t.Run("ToLocalDate", func(t *testing.T) { 2789 type dateStruct struct { 2790 Date LocalDate 2791 } 2792 2793 toml := `date = 1979-05-27` 2794 2795 var obj dateStruct 2796 2797 err := Unmarshal([]byte(toml), &obj) 2798 2799 if err != nil { 2800 t.Fatal(err) 2801 } 2802 2803 if obj.Date.Year != 1979 { 2804 t.Errorf("expected year 1979, got %d", obj.Date.Year) 2805 } 2806 if obj.Date.Month != 5 { 2807 t.Errorf("expected month 5, got %d", obj.Date.Month) 2808 } 2809 if obj.Date.Day != 27 { 2810 t.Errorf("expected day 27, got %d", obj.Date.Day) 2811 } 2812 }) 2813 2814 t.Run("ToLocalDate", func(t *testing.T) { 2815 type dateStruct struct { 2816 Date time.Time 2817 } 2818 2819 toml := `date = 1979-05-27` 2820 2821 var obj dateStruct 2822 2823 err := Unmarshal([]byte(toml), &obj) 2824 2825 if err != nil { 2826 t.Fatal(err) 2827 } 2828 2829 if obj.Date.Year() != 1979 { 2830 t.Errorf("expected year 1979, got %d", obj.Date.Year()) 2831 } 2832 if obj.Date.Month() != 5 { 2833 t.Errorf("expected month 5, got %d", obj.Date.Month()) 2834 } 2835 if obj.Date.Day() != 27 { 2836 t.Errorf("expected day 27, got %d", obj.Date.Day()) 2837 } 2838 }) 2839} 2840 2841func TestMarshalLocalDate(t *testing.T) { 2842 type dateStruct struct { 2843 Date LocalDate 2844 } 2845 2846 obj := dateStruct{Date: LocalDate{ 2847 Year: 1979, 2848 Month: 5, 2849 Day: 27, 2850 }} 2851 2852 b, err := Marshal(obj) 2853 2854 if err != nil { 2855 t.Fatalf("unexpected error: %v", err) 2856 } 2857 2858 got := string(b) 2859 expected := `Date = 1979-05-27 2860` 2861 2862 if got != expected { 2863 t.Errorf("expected '%s', got '%s'", expected, got) 2864 } 2865} 2866 2867func TestUnmarshalLocalDateTime(t *testing.T) { 2868 examples := []struct { 2869 name string 2870 in string 2871 out LocalDateTime 2872 }{ 2873 { 2874 name: "normal", 2875 in: "1979-05-27T07:32:00", 2876 out: LocalDateTime{ 2877 Date: LocalDate{ 2878 Year: 1979, 2879 Month: 5, 2880 Day: 27, 2881 }, 2882 Time: LocalTime{ 2883 Hour: 7, 2884 Minute: 32, 2885 Second: 0, 2886 Nanosecond: 0, 2887 }, 2888 }}, 2889 { 2890 name: "with nanoseconds", 2891 in: "1979-05-27T00:32:00.999999", 2892 out: LocalDateTime{ 2893 Date: LocalDate{ 2894 Year: 1979, 2895 Month: 5, 2896 Day: 27, 2897 }, 2898 Time: LocalTime{ 2899 Hour: 0, 2900 Minute: 32, 2901 Second: 0, 2902 Nanosecond: 999999000, 2903 }, 2904 }, 2905 }, 2906 } 2907 2908 for i, example := range examples { 2909 toml := fmt.Sprintf(`date = %s`, example.in) 2910 2911 t.Run(fmt.Sprintf("ToLocalDateTime_%d_%s", i, example.name), func(t *testing.T) { 2912 type dateStruct struct { 2913 Date LocalDateTime 2914 } 2915 2916 var obj dateStruct 2917 2918 err := Unmarshal([]byte(toml), &obj) 2919 2920 if err != nil { 2921 t.Fatal(err) 2922 } 2923 2924 if obj.Date != example.out { 2925 t.Errorf("expected '%s', got '%s'", example.out, obj.Date) 2926 } 2927 }) 2928 2929 t.Run(fmt.Sprintf("ToTime_%d_%s", i, example.name), func(t *testing.T) { 2930 type dateStruct struct { 2931 Date time.Time 2932 } 2933 2934 var obj dateStruct 2935 2936 err := Unmarshal([]byte(toml), &obj) 2937 2938 if err != nil { 2939 t.Fatal(err) 2940 } 2941 2942 if obj.Date.Year() != example.out.Date.Year { 2943 t.Errorf("expected year %d, got %d", example.out.Date.Year, obj.Date.Year()) 2944 } 2945 if obj.Date.Month() != example.out.Date.Month { 2946 t.Errorf("expected month %d, got %d", example.out.Date.Month, obj.Date.Month()) 2947 } 2948 if obj.Date.Day() != example.out.Date.Day { 2949 t.Errorf("expected day %d, got %d", example.out.Date.Day, obj.Date.Day()) 2950 } 2951 if obj.Date.Hour() != example.out.Time.Hour { 2952 t.Errorf("expected hour %d, got %d", example.out.Time.Hour, obj.Date.Hour()) 2953 } 2954 if obj.Date.Minute() != example.out.Time.Minute { 2955 t.Errorf("expected minute %d, got %d", example.out.Time.Minute, obj.Date.Minute()) 2956 } 2957 if obj.Date.Second() != example.out.Time.Second { 2958 t.Errorf("expected second %d, got %d", example.out.Time.Second, obj.Date.Second()) 2959 } 2960 if obj.Date.Nanosecond() != example.out.Time.Nanosecond { 2961 t.Errorf("expected nanoseconds %d, got %d", example.out.Time.Nanosecond, obj.Date.Nanosecond()) 2962 } 2963 }) 2964 } 2965} 2966 2967func TestMarshalLocalDateTime(t *testing.T) { 2968 type dateStruct struct { 2969 DateTime LocalDateTime 2970 } 2971 2972 examples := []struct { 2973 name string 2974 in LocalDateTime 2975 out string 2976 }{ 2977 { 2978 name: "normal", 2979 out: "DateTime = 1979-05-27T07:32:00\n", 2980 in: LocalDateTime{ 2981 Date: LocalDate{ 2982 Year: 1979, 2983 Month: 5, 2984 Day: 27, 2985 }, 2986 Time: LocalTime{ 2987 Hour: 7, 2988 Minute: 32, 2989 Second: 0, 2990 Nanosecond: 0, 2991 }, 2992 }}, 2993 { 2994 name: "with nanoseconds", 2995 out: "DateTime = 1979-05-27T00:32:00.999999000\n", 2996 in: LocalDateTime{ 2997 Date: LocalDate{ 2998 Year: 1979, 2999 Month: 5, 3000 Day: 27, 3001 }, 3002 Time: LocalTime{ 3003 Hour: 0, 3004 Minute: 32, 3005 Second: 0, 3006 Nanosecond: 999999000, 3007 }, 3008 }, 3009 }, 3010 } 3011 3012 for i, example := range examples { 3013 t.Run(fmt.Sprintf("%d_%s", i, example.name), func(t *testing.T) { 3014 obj := dateStruct{ 3015 DateTime: example.in, 3016 } 3017 b, err := Marshal(obj) 3018 3019 if err != nil { 3020 t.Fatalf("unexpected error: %v", err) 3021 } 3022 3023 got := string(b) 3024 3025 if got != example.out { 3026 t.Errorf("expected '%s', got '%s'", example.out, got) 3027 } 3028 }) 3029 } 3030} 3031 3032func TestUnmarshalLocalTime(t *testing.T) { 3033 examples := []struct { 3034 name string 3035 in string 3036 out LocalTime 3037 }{ 3038 { 3039 name: "normal", 3040 in: "07:32:00", 3041 out: LocalTime{ 3042 Hour: 7, 3043 Minute: 32, 3044 Second: 0, 3045 Nanosecond: 0, 3046 }, 3047 }, 3048 { 3049 name: "with nanoseconds", 3050 in: "00:32:00.999999", 3051 out: LocalTime{ 3052 Hour: 0, 3053 Minute: 32, 3054 Second: 0, 3055 Nanosecond: 999999000, 3056 }, 3057 }, 3058 } 3059 3060 for i, example := range examples { 3061 toml := fmt.Sprintf(`Time = %s`, example.in) 3062 3063 t.Run(fmt.Sprintf("ToLocalTime_%d_%s", i, example.name), func(t *testing.T) { 3064 type dateStruct struct { 3065 Time LocalTime 3066 } 3067 3068 var obj dateStruct 3069 3070 err := Unmarshal([]byte(toml), &obj) 3071 3072 if err != nil { 3073 t.Fatal(err) 3074 } 3075 3076 if obj.Time != example.out { 3077 t.Errorf("expected '%s', got '%s'", example.out, obj.Time) 3078 } 3079 }) 3080 } 3081} 3082 3083func TestMarshalLocalTime(t *testing.T) { 3084 type timeStruct struct { 3085 Time LocalTime 3086 } 3087 3088 examples := []struct { 3089 name string 3090 in LocalTime 3091 out string 3092 }{ 3093 { 3094 name: "normal", 3095 out: "Time = 07:32:00\n", 3096 in: LocalTime{ 3097 Hour: 7, 3098 Minute: 32, 3099 Second: 0, 3100 Nanosecond: 0, 3101 }}, 3102 { 3103 name: "with nanoseconds", 3104 out: "Time = 00:32:00.999999000\n", 3105 in: LocalTime{ 3106 Hour: 0, 3107 Minute: 32, 3108 Second: 0, 3109 Nanosecond: 999999000, 3110 }, 3111 }, 3112 } 3113 3114 for i, example := range examples { 3115 t.Run(fmt.Sprintf("%d_%s", i, example.name), func(t *testing.T) { 3116 obj := timeStruct{ 3117 Time: example.in, 3118 } 3119 b, err := Marshal(obj) 3120 3121 if err != nil { 3122 t.Fatalf("unexpected error: %v", err) 3123 } 3124 3125 got := string(b) 3126 3127 if got != example.out { 3128 t.Errorf("expected '%s', got '%s'", example.out, got) 3129 } 3130 }) 3131 } 3132} 3133 3134// test case for issue #339 3135func TestUnmarshalSameInnerField(t *testing.T) { 3136 type InterStruct2 struct { 3137 Test string 3138 Name string 3139 Age int 3140 } 3141 type Inter2 struct { 3142 Name string 3143 Age int 3144 InterStruct2 InterStruct2 3145 } 3146 type Server struct { 3147 Name string `toml:"name"` 3148 Inter2 Inter2 `toml:"inter2"` 3149 } 3150 3151 var server Server 3152 3153 if err := Unmarshal([]byte(`name = "123" 3154[inter2] 3155name = "inter2" 3156age = 222`), &server); err == nil { 3157 expected := Server{ 3158 Name: "123", 3159 Inter2: Inter2{ 3160 Name: "inter2", 3161 Age: 222, 3162 }, 3163 } 3164 if !reflect.DeepEqual(server, expected) { 3165 t.Errorf("Bad unmarshal: expected %v, got %v", expected, server) 3166 } 3167 } else { 3168 t.Fatalf("unexpected error: %v", err) 3169 } 3170} 3171 3172func TestMarshalInterface(t *testing.T) { 3173 type InnerStruct struct { 3174 InnerField string 3175 } 3176 3177 type OuterStruct struct { 3178 PrimitiveField interface{} 3179 ArrayField interface{} 3180 StructArrayField interface{} 3181 MapField map[string]interface{} 3182 StructField interface{} 3183 PointerField interface{} 3184 NilField interface{} 3185 InterfacePointerField *interface{} 3186 } 3187 3188 expected := []byte(`ArrayField = [1, 2, 3] 3189InterfacePointerField = "hello world" 3190PrimitiveField = "string" 3191 3192[MapField] 3193 key1 = "value1" 3194 key2 = false 3195 3196 [MapField.key3] 3197 InnerField = "value3" 3198 3199[PointerField] 3200 InnerField = "yyy" 3201 3202[[StructArrayField]] 3203 InnerField = "s1" 3204 3205[[StructArrayField]] 3206 InnerField = "s2" 3207 3208[StructField] 3209 InnerField = "xxx" 3210`) 3211 3212 var h interface{} = "hello world" 3213 if result, err := Marshal(OuterStruct{ 3214 "string", 3215 []int{1, 2, 3}, 3216 []InnerStruct{{"s1"}, {"s2"}}, 3217 map[string]interface{}{ 3218 "key1": "value1", 3219 "key2": false, 3220 "key3": InnerStruct{"value3"}, 3221 "nil value": nil, 3222 }, 3223 InnerStruct{ 3224 "xxx", 3225 }, 3226 &InnerStruct{ 3227 "yyy", 3228 }, 3229 nil, 3230 &h, 3231 }); err == nil { 3232 if !bytes.Equal(result, expected) { 3233 t.Errorf("Bad marshal: expected\n----\n%s\n----\ngot\n----\n%s\n----\n", expected, result) 3234 } 3235 } else { 3236 t.Fatal(err) 3237 } 3238} 3239 3240func TestUnmarshalToNilInterface(t *testing.T) { 3241 toml := []byte(` 3242PrimitiveField = "Hello" 3243ArrayField = [1,2,3] 3244InterfacePointerField = "World" 3245 3246[StructField] 3247Field1 = 123 3248Field2 = "Field2" 3249 3250[MapField] 3251MapField1 = [4,5,6] 3252MapField2 = {A = "A"} 3253MapField3 = false 3254 3255[[StructArrayField]] 3256Name = "Allen" 3257Age = 20 3258 3259[[StructArrayField]] 3260Name = "Jack" 3261Age = 23 3262`) 3263 3264 type OuterStruct struct { 3265 PrimitiveField interface{} 3266 ArrayField interface{} 3267 StructArrayField interface{} 3268 MapField map[string]interface{} 3269 StructField interface{} 3270 NilField interface{} 3271 InterfacePointerField *interface{} 3272 } 3273 3274 var s interface{} = "World" 3275 expected := OuterStruct{ 3276 PrimitiveField: "Hello", 3277 ArrayField: []interface{}{int64(1), int64(2), int64(3)}, 3278 StructField: map[string]interface{}{ 3279 "Field1": int64(123), 3280 "Field2": "Field2", 3281 }, 3282 MapField: map[string]interface{}{ 3283 "MapField1": []interface{}{int64(4), int64(5), int64(6)}, 3284 "MapField2": map[string]interface{}{ 3285 "A": "A", 3286 }, 3287 "MapField3": false, 3288 }, 3289 NilField: nil, 3290 InterfacePointerField: &s, 3291 StructArrayField: []map[string]interface{}{ 3292 { 3293 "Name": "Allen", 3294 "Age": int64(20), 3295 }, 3296 { 3297 "Name": "Jack", 3298 "Age": int64(23), 3299 }, 3300 }, 3301 } 3302 actual := OuterStruct{} 3303 if err := Unmarshal(toml, &actual); err == nil { 3304 if !reflect.DeepEqual(actual, expected) { 3305 t.Errorf("Bad unmarshal: expected %v, got %v", expected, actual) 3306 } 3307 } else { 3308 t.Fatal(err) 3309 } 3310} 3311 3312func TestUnmarshalToNonNilInterface(t *testing.T) { 3313 toml := []byte(` 3314PrimitiveField = "Allen" 3315ArrayField = [1,2,3] 3316 3317[StructField] 3318InnerField = "After1" 3319 3320[PointerField] 3321InnerField = "After2" 3322 3323[InterfacePointerField] 3324InnerField = "After" 3325 3326[MapField] 3327MapField1 = [4,5,6] 3328MapField2 = {A = "A"} 3329MapField3 = false 3330 3331[[StructArrayField]] 3332InnerField = "After3" 3333 3334[[StructArrayField]] 3335InnerField = "After4" 3336`) 3337 type InnerStruct struct { 3338 InnerField interface{} 3339 } 3340 3341 type OuterStruct struct { 3342 PrimitiveField interface{} 3343 ArrayField interface{} 3344 StructArrayField interface{} 3345 MapField map[string]interface{} 3346 StructField interface{} 3347 PointerField interface{} 3348 NilField interface{} 3349 InterfacePointerField *interface{} 3350 } 3351 3352 var s interface{} = InnerStruct{"After"} 3353 expected := OuterStruct{ 3354 PrimitiveField: "Allen", 3355 ArrayField: []int{1, 2, 3}, 3356 StructField: InnerStruct{InnerField: "After1"}, 3357 MapField: map[string]interface{}{ 3358 "MapField1": []interface{}{int64(4), int64(5), int64(6)}, 3359 "MapField2": map[string]interface{}{ 3360 "A": "A", 3361 }, 3362 "MapField3": false, 3363 }, 3364 PointerField: &InnerStruct{InnerField: "After2"}, 3365 NilField: nil, 3366 InterfacePointerField: &s, 3367 StructArrayField: []InnerStruct{ 3368 {InnerField: "After3"}, 3369 {InnerField: "After4"}, 3370 }, 3371 } 3372 actual := OuterStruct{ 3373 PrimitiveField: "aaa", 3374 ArrayField: []int{100, 200, 300, 400}, 3375 StructField: InnerStruct{InnerField: "Before1"}, 3376 MapField: map[string]interface{}{ 3377 "MapField1": []int{4, 5, 6}, 3378 "MapField2": map[string]string{ 3379 "B": "BBB", 3380 }, 3381 "MapField3": true, 3382 }, 3383 PointerField: &InnerStruct{InnerField: "Before2"}, 3384 NilField: nil, 3385 InterfacePointerField: &s, 3386 StructArrayField: []InnerStruct{ 3387 {InnerField: "Before3"}, 3388 {InnerField: "Before4"}, 3389 }, 3390 } 3391 if err := Unmarshal(toml, &actual); err == nil { 3392 if !reflect.DeepEqual(actual, expected) { 3393 t.Errorf("Bad unmarshal: expected %v, got %v", expected, actual) 3394 } 3395 } else { 3396 t.Fatal(err) 3397 } 3398} 3399 3400func TestUnmarshalEmbedTree(t *testing.T) { 3401 toml := []byte(` 3402OuterField1 = "Out" 3403OuterField2 = 1024 3404 3405[TreeField] 3406InnerField1 = "In" 3407InnerField2 = 2048 3408 3409 [TreeField.EmbedStruct] 3410 EmbedField = "Embed" 3411 3412`) 3413 type InnerStruct struct { 3414 InnerField1 string 3415 InnerField2 int 3416 EmbedStruct struct { 3417 EmbedField string 3418 } 3419 } 3420 3421 type OuterStruct struct { 3422 OuterField1 string 3423 OuterField2 int 3424 TreeField *Tree 3425 } 3426 3427 out := OuterStruct{} 3428 actual := InnerStruct{} 3429 expected := InnerStruct{ 3430 "In", 3431 2048, 3432 struct { 3433 EmbedField string 3434 }{ 3435 EmbedField: "Embed", 3436 }, 3437 } 3438 if err := Unmarshal(toml, &out); err != nil { 3439 t.Fatal(err) 3440 } 3441 if err := out.TreeField.Unmarshal(&actual); err != nil { 3442 t.Fatal(err) 3443 } 3444 3445 if !reflect.DeepEqual(actual, expected) { 3446 t.Errorf("Bad unmarshal: expected %v, got %v", expected, actual) 3447 } 3448} 3449 3450func TestMarshalNil(t *testing.T) { 3451 if _, err := Marshal(nil); err == nil { 3452 t.Errorf("Expected err from nil marshal") 3453 } 3454 if _, err := Marshal((*struct{})(nil)); err == nil { 3455 t.Errorf("Expected err from nil marshal") 3456 } 3457} 3458 3459func TestUnmarshalNil(t *testing.T) { 3460 if err := Unmarshal([]byte(`whatever = "whatever"`), nil); err == nil { 3461 t.Errorf("Expected err from nil marshal") 3462 } 3463 if err := Unmarshal([]byte(`whatever = "whatever"`), (*struct{})(nil)); err == nil { 3464 t.Errorf("Expected err from nil marshal") 3465 } 3466} 3467 3468var sliceTomlDemo = []byte(`str_slice = ["Howdy","Hey There"] 3469str_slice_ptr= ["Howdy","Hey There"] 3470int_slice=[1,2] 3471int_slice_ptr=[1,2] 3472[[struct_slice]] 3473String2="1" 3474[[struct_slice]] 3475String2="2" 3476[[struct_slice_ptr]] 3477String2="1" 3478[[struct_slice_ptr]] 3479String2="2" 3480`) 3481 3482type sliceStruct struct { 3483 Slice []string ` toml:"str_slice" ` 3484 SlicePtr *[]string ` toml:"str_slice_ptr" ` 3485 IntSlice []int ` toml:"int_slice" ` 3486 IntSlicePtr *[]int ` toml:"int_slice_ptr" ` 3487 StructSlice []basicMarshalTestSubStruct ` toml:"struct_slice" ` 3488 StructSlicePtr *[]basicMarshalTestSubStruct ` toml:"struct_slice_ptr" ` 3489} 3490 3491type arrayStruct struct { 3492 Slice [4]string ` toml:"str_slice" ` 3493 SlicePtr *[4]string ` toml:"str_slice_ptr" ` 3494 IntSlice [4]int ` toml:"int_slice" ` 3495 IntSlicePtr *[4]int ` toml:"int_slice_ptr" ` 3496 StructSlice [4]basicMarshalTestSubStruct ` toml:"struct_slice" ` 3497 StructSlicePtr *[4]basicMarshalTestSubStruct ` toml:"struct_slice_ptr" ` 3498} 3499 3500type arrayTooSmallStruct struct { 3501 Slice [1]string ` toml:"str_slice" ` 3502 StructSlice [1]basicMarshalTestSubStruct ` toml:"struct_slice" ` 3503} 3504 3505func TestUnmarshalSlice(t *testing.T) { 3506 tree, _ := LoadBytes(sliceTomlDemo) 3507 tree, _ = TreeFromMap(tree.ToMap()) 3508 3509 var actual sliceStruct 3510 err := tree.Unmarshal(&actual) 3511 if err != nil { 3512 t.Error("shound not err", err) 3513 } 3514 expected := sliceStruct{ 3515 Slice: []string{"Howdy", "Hey There"}, 3516 SlicePtr: &[]string{"Howdy", "Hey There"}, 3517 IntSlice: []int{1, 2}, 3518 IntSlicePtr: &[]int{1, 2}, 3519 StructSlice: []basicMarshalTestSubStruct{{"1"}, {"2"}}, 3520 StructSlicePtr: &[]basicMarshalTestSubStruct{{"1"}, {"2"}}, 3521 } 3522 if !reflect.DeepEqual(actual, expected) { 3523 t.Errorf("Bad unmarshal: expected %v, got %v", expected, actual) 3524 } 3525 3526} 3527 3528func TestUnmarshalSliceFail(t *testing.T) { 3529 tree, _ := TreeFromMap(map[string]interface{}{ 3530 "str_slice": []int{1, 2}, 3531 }) 3532 3533 var actual sliceStruct 3534 err := tree.Unmarshal(&actual) 3535 if err.Error() != "(0, 0): Can't convert 1(int64) to string" { 3536 t.Error("expect err:(0, 0): Can't convert 1(int64) to string but got ", err) 3537 } 3538} 3539 3540func TestUnmarshalSliceFail2(t *testing.T) { 3541 tree, _ := Load(`str_slice=[1,2]`) 3542 3543 var actual sliceStruct 3544 err := tree.Unmarshal(&actual) 3545 if err.Error() != "(1, 1): Can't convert 1(int64) to string" { 3546 t.Error("expect err:(1, 1): Can't convert 1(int64) to string but got ", err) 3547 } 3548 3549} 3550 3551func TestMarshalMixedTypeArray(t *testing.T) { 3552 type InnerStruct struct { 3553 IntField int 3554 StrField string 3555 } 3556 3557 type TestStruct struct { 3558 ArrayField []interface{} 3559 } 3560 3561 expected := []byte(`ArrayField = [3.14, 100, true, "hello world", { IntField = 100, StrField = "inner1" }, [{ IntField = 200, StrField = "inner2" }, { IntField = 300, StrField = "inner3" }]] 3562`) 3563 3564 if result, err := Marshal(TestStruct{ 3565 ArrayField: []interface{}{ 3566 3.14, 3567 100, 3568 true, 3569 "hello world", 3570 InnerStruct{ 3571 IntField: 100, 3572 StrField: "inner1", 3573 }, 3574 []InnerStruct{ 3575 {IntField: 200, StrField: "inner2"}, 3576 {IntField: 300, StrField: "inner3"}, 3577 }, 3578 }, 3579 }); err == nil { 3580 if !bytes.Equal(result, expected) { 3581 t.Errorf("Bad marshal: expected\n----\n%s\n----\ngot\n----\n%s\n----\n", expected, result) 3582 } 3583 } else { 3584 t.Fatal(err) 3585 } 3586} 3587 3588func TestUnmarshalMixedTypeArray(t *testing.T) { 3589 type TestStruct struct { 3590 ArrayField []interface{} 3591 } 3592 3593 toml := []byte(`ArrayField = [3.14,100,true,"hello world",{Field = "inner1"},[{Field = "inner2"},{Field = "inner3"}]] 3594`) 3595 3596 actual := TestStruct{} 3597 expected := TestStruct{ 3598 ArrayField: []interface{}{ 3599 3.14, 3600 int64(100), 3601 true, 3602 "hello world", 3603 map[string]interface{}{ 3604 "Field": "inner1", 3605 }, 3606 []map[string]interface{}{ 3607 {"Field": "inner2"}, 3608 {"Field": "inner3"}, 3609 }, 3610 }, 3611 } 3612 3613 if err := Unmarshal(toml, &actual); err == nil { 3614 if !reflect.DeepEqual(actual, expected) { 3615 t.Errorf("Bad unmarshal: expected %#v, got %#v", expected, actual) 3616 } 3617 } else { 3618 t.Fatal(err) 3619 } 3620} 3621 3622func TestUnmarshalArray(t *testing.T) { 3623 var tree *Tree 3624 var err error 3625 3626 tree, _ = LoadBytes(sliceTomlDemo) 3627 var actual1 arrayStruct 3628 err = tree.Unmarshal(&actual1) 3629 if err != nil { 3630 t.Error("shound not err", err) 3631 } 3632 3633 tree, _ = TreeFromMap(tree.ToMap()) 3634 var actual2 arrayStruct 3635 err = tree.Unmarshal(&actual2) 3636 if err != nil { 3637 t.Error("shound not err", err) 3638 } 3639 3640 expected := arrayStruct{ 3641 Slice: [4]string{"Howdy", "Hey There"}, 3642 SlicePtr: &[4]string{"Howdy", "Hey There"}, 3643 IntSlice: [4]int{1, 2}, 3644 IntSlicePtr: &[4]int{1, 2}, 3645 StructSlice: [4]basicMarshalTestSubStruct{{"1"}, {"2"}}, 3646 StructSlicePtr: &[4]basicMarshalTestSubStruct{{"1"}, {"2"}}, 3647 } 3648 if !reflect.DeepEqual(actual1, expected) { 3649 t.Errorf("Bad unmarshal: expected %v, got %v", expected, actual1) 3650 } 3651 if !reflect.DeepEqual(actual2, expected) { 3652 t.Errorf("Bad unmarshal: expected %v, got %v", expected, actual2) 3653 } 3654} 3655 3656func TestUnmarshalArrayFail(t *testing.T) { 3657 tree, _ := TreeFromMap(map[string]interface{}{ 3658 "str_slice": []string{"Howdy", "Hey There"}, 3659 }) 3660 3661 var actual arrayTooSmallStruct 3662 err := tree.Unmarshal(&actual) 3663 if err.Error() != "(0, 0): unmarshal: TOML array length (2) exceeds destination array length (1)" { 3664 t.Error("expect err:(0, 0): unmarshal: TOML array length (2) exceeds destination array length (1) but got ", err) 3665 } 3666} 3667 3668func TestUnmarshalArrayFail2(t *testing.T) { 3669 tree, _ := Load(`str_slice=["Howdy","Hey There"]`) 3670 3671 var actual arrayTooSmallStruct 3672 err := tree.Unmarshal(&actual) 3673 if err.Error() != "(1, 1): unmarshal: TOML array length (2) exceeds destination array length (1)" { 3674 t.Error("expect err:(1, 1): unmarshal: TOML array length (2) exceeds destination array length (1) but got ", err) 3675 } 3676} 3677 3678func TestUnmarshalArrayFail3(t *testing.T) { 3679 tree, _ := Load(`[[struct_slice]] 3680String2="1" 3681[[struct_slice]] 3682String2="2"`) 3683 3684 var actual arrayTooSmallStruct 3685 err := tree.Unmarshal(&actual) 3686 if err.Error() != "(3, 1): unmarshal: TOML array length (2) exceeds destination array length (1)" { 3687 t.Error("expect err:(3, 1): unmarshal: TOML array length (2) exceeds destination array length (1) but got ", err) 3688 } 3689} 3690 3691func TestDecoderStrict(t *testing.T) { 3692 input := ` 3693[decoded] 3694 key = "" 3695 3696[undecoded] 3697 key = "" 3698 3699 [undecoded.inner] 3700 key = "" 3701 3702 [[undecoded.array]] 3703 key = "" 3704 3705 [[undecoded.array]] 3706 key = "" 3707 3708` 3709 var doc struct { 3710 Decoded struct { 3711 Key string 3712 } 3713 } 3714 3715 expected := `undecoded keys: ["undecoded.array.0.key" "undecoded.array.1.key" "undecoded.inner.key" "undecoded.key"]` 3716 3717 err := NewDecoder(bytes.NewReader([]byte(input))).Strict(true).Decode(&doc) 3718 if err == nil { 3719 t.Error("expected error, got none") 3720 } else if err.Error() != expected { 3721 t.Errorf("expect err: %s, got: %s", expected, err.Error()) 3722 } 3723 3724 if err := NewDecoder(bytes.NewReader([]byte(input))).Decode(&doc); err != nil { 3725 t.Errorf("unexpected err: %s", err) 3726 } 3727 3728 var m map[string]interface{} 3729 if err := NewDecoder(bytes.NewReader([]byte(input))).Decode(&m); err != nil { 3730 t.Errorf("unexpected err: %s", err) 3731 } 3732} 3733 3734func TestDecoderStrictValid(t *testing.T) { 3735 input := ` 3736[decoded] 3737 key = "" 3738` 3739 var doc struct { 3740 Decoded struct { 3741 Key string 3742 } 3743 } 3744 3745 err := NewDecoder(bytes.NewReader([]byte(input))).Strict(true).Decode(&doc) 3746 if err != nil { 3747 t.Fatal("unexpected error:", err) 3748 } 3749} 3750 3751type docUnmarshalTOML struct { 3752 Decoded struct { 3753 Key string 3754 } 3755} 3756 3757func (d *docUnmarshalTOML) UnmarshalTOML(i interface{}) error { 3758 if iMap, ok := i.(map[string]interface{}); !ok { 3759 return fmt.Errorf("type assertion error: wants %T, have %T", map[string]interface{}{}, i) 3760 } else if key, ok := iMap["key"]; !ok { 3761 return fmt.Errorf("key '%s' not in map", "key") 3762 } else if keyString, ok := key.(string); !ok { 3763 return fmt.Errorf("type assertion error: wants %T, have %T", "", key) 3764 } else { 3765 d.Decoded.Key = keyString 3766 } 3767 return nil 3768} 3769 3770func TestDecoderStrictCustomUnmarshal(t *testing.T) { 3771 input := `key = "ok"` 3772 var doc docUnmarshalTOML 3773 err := NewDecoder(bytes.NewReader([]byte(input))).Strict(true).Decode(&doc) 3774 if err != nil { 3775 t.Fatal("unexpected error:", err) 3776 } 3777 if doc.Decoded.Key != "ok" { 3778 t.Errorf("Bad unmarshal: expected ok, got %v", doc.Decoded.Key) 3779 } 3780} 3781 3782type parent struct { 3783 Doc docUnmarshalTOML 3784 DocPointer *docUnmarshalTOML 3785} 3786 3787func TestCustomUnmarshal(t *testing.T) { 3788 input := ` 3789[Doc] 3790 key = "ok1" 3791[DocPointer] 3792 key = "ok2" 3793` 3794 3795 var d parent 3796 if err := Unmarshal([]byte(input), &d); err != nil { 3797 t.Fatalf("unexpected err: %s", err.Error()) 3798 } 3799 if d.Doc.Decoded.Key != "ok1" { 3800 t.Errorf("Bad unmarshal: expected ok, got %v", d.Doc.Decoded.Key) 3801 } 3802 if d.DocPointer.Decoded.Key != "ok2" { 3803 t.Errorf("Bad unmarshal: expected ok, got %v", d.DocPointer.Decoded.Key) 3804 } 3805} 3806 3807func TestCustomUnmarshalError(t *testing.T) { 3808 input := ` 3809[Doc] 3810 key = 1 3811[DocPointer] 3812 key = "ok2" 3813` 3814 3815 expected := "(2, 1): unmarshal toml: type assertion error: wants string, have int64" 3816 3817 var d parent 3818 err := Unmarshal([]byte(input), &d) 3819 if err == nil { 3820 t.Error("expected error, got none") 3821 } else if err.Error() != expected { 3822 t.Errorf("expect err: %s, got: %s", expected, err.Error()) 3823 } 3824} 3825 3826type intWrapper struct { 3827 Value int 3828} 3829 3830func (w *intWrapper) UnmarshalText(text []byte) error { 3831 var err error 3832 if w.Value, err = strconv.Atoi(string(text)); err == nil { 3833 return nil 3834 } 3835 if b, err := strconv.ParseBool(string(text)); err == nil { 3836 if b { 3837 w.Value = 1 3838 } 3839 return nil 3840 } 3841 if f, err := strconv.ParseFloat(string(text), 32); err == nil { 3842 w.Value = int(f) 3843 return nil 3844 } 3845 return fmt.Errorf("unsupported: %s", text) 3846} 3847 3848func TestTextUnmarshal(t *testing.T) { 3849 var doc struct { 3850 UnixTime intWrapper 3851 Version *intWrapper 3852 3853 Bool intWrapper 3854 Int intWrapper 3855 Float intWrapper 3856 } 3857 3858 input := ` 3859UnixTime = "12" 3860Version = "42" 3861Bool = true 3862Int = 21 3863Float = 2.0 3864` 3865 3866 if err := Unmarshal([]byte(input), &doc); err != nil { 3867 t.Fatalf("unexpected err: %s", err.Error()) 3868 } 3869 if doc.UnixTime.Value != 12 { 3870 t.Fatalf("expected UnixTime: 12 got: %d", doc.UnixTime.Value) 3871 } 3872 if doc.Version.Value != 42 { 3873 t.Fatalf("expected Version: 42 got: %d", doc.Version.Value) 3874 } 3875 if doc.Bool.Value != 1 { 3876 t.Fatalf("expected Bool: 1 got: %d", doc.Bool.Value) 3877 } 3878 if doc.Int.Value != 21 { 3879 t.Fatalf("expected Int: 21 got: %d", doc.Int.Value) 3880 } 3881 if doc.Float.Value != 2 { 3882 t.Fatalf("expected Float: 2 got: %d", doc.Float.Value) 3883 } 3884} 3885 3886func TestTextUnmarshalError(t *testing.T) { 3887 var doc struct { 3888 Failer intWrapper 3889 } 3890 3891 input := `Failer = "hello"` 3892 if err := Unmarshal([]byte(input), &doc); err == nil { 3893 t.Fatalf("expected err, got none") 3894 } 3895} 3896 3897// issue406 3898func TestPreserveNotEmptyField(t *testing.T) { 3899 toml := []byte(`Field1 = "ccc"`) 3900 type Inner struct { 3901 InnerField1 string 3902 InnerField2 int 3903 } 3904 type TestStruct struct { 3905 Field1 string 3906 Field2 int 3907 Field3 Inner 3908 } 3909 3910 actual := TestStruct{ 3911 "aaa", 3912 100, 3913 Inner{ 3914 "bbb", 3915 200, 3916 }, 3917 } 3918 3919 expected := TestStruct{ 3920 "ccc", 3921 100, 3922 Inner{ 3923 "bbb", 3924 200, 3925 }, 3926 } 3927 3928 err := Unmarshal(toml, &actual) 3929 if err != nil { 3930 t.Fatal(err) 3931 } 3932 3933 if !reflect.DeepEqual(actual, expected) { 3934 t.Errorf("Bad unmarshal: expected %+v, got %+v", expected, actual) 3935 } 3936} 3937 3938// github issue 432 3939func TestUnmarshalEmptyInterface(t *testing.T) { 3940 doc := []byte(`User = "pelletier"`) 3941 3942 var v interface{} 3943 3944 err := Unmarshal(doc, &v) 3945 if err != nil { 3946 t.Fatal(err) 3947 } 3948 3949 x, ok := v.(map[string]interface{}) 3950 if !ok { 3951 t.Fatal(err) 3952 } 3953 3954 if x["User"] != "pelletier" { 3955 t.Fatalf("expected User=pelletier, but got %v", x) 3956 } 3957} 3958 3959func TestUnmarshalEmptyInterfaceDeep(t *testing.T) { 3960 doc := []byte(` 3961User = "pelletier" 3962Age = 99 3963 3964[foo] 3965bar = 42 3966`) 3967 3968 var v interface{} 3969 3970 err := Unmarshal(doc, &v) 3971 if err != nil { 3972 t.Fatal(err) 3973 } 3974 3975 x, ok := v.(map[string]interface{}) 3976 if !ok { 3977 t.Fatal(err) 3978 } 3979 3980 expected := map[string]interface{}{ 3981 "User": "pelletier", 3982 "Age": 99, 3983 "foo": map[string]interface{}{ 3984 "bar": 42, 3985 }, 3986 } 3987 3988 reflect.DeepEqual(x, expected) 3989} 3990 3991type Config struct { 3992 Key string `toml:"key"` 3993 Obj Custom `toml:"obj"` 3994} 3995 3996type Custom struct { 3997 v string 3998} 3999 4000func (c *Custom) UnmarshalTOML(v interface{}) error { 4001 c.v = "called" 4002 return nil 4003} 4004 4005func TestGithubIssue431(t *testing.T) { 4006 doc := `key = "value"` 4007 tree, err := LoadBytes([]byte(doc)) 4008 if err != nil { 4009 t.Fatalf("unexpected error: %s", err) 4010 } 4011 4012 var c Config 4013 if err := tree.Unmarshal(&c); err != nil { 4014 t.Fatalf("unexpected error: %s", err) 4015 } 4016 4017 if c.Key != "value" { 4018 t.Errorf("expected c.Key='value', not '%s'", c.Key) 4019 } 4020 4021 if c.Obj.v == "called" { 4022 t.Errorf("UnmarshalTOML should not have been called") 4023 } 4024} 4025 4026type durationString struct { 4027 time.Duration 4028} 4029 4030func (d *durationString) UnmarshalTOML(v interface{}) error { 4031 d.Duration = 10 * time.Second 4032 return nil 4033} 4034 4035type config437Error struct { 4036} 4037 4038func (e *config437Error) UnmarshalTOML(v interface{}) error { 4039 return errors.New("expected") 4040} 4041 4042type config437 struct { 4043 HTTP struct { 4044 PingTimeout durationString `toml:"PingTimeout"` 4045 ErrorField config437Error 4046 } `toml:"HTTP"` 4047} 4048 4049func TestGithubIssue437(t *testing.T) { 4050 src := ` 4051[HTTP] 4052PingTimeout = "32m" 4053` 4054 cfg := &config437{} 4055 cfg.HTTP.PingTimeout = durationString{time.Second} 4056 4057 r := strings.NewReader(src) 4058 err := NewDecoder(r).Decode(cfg) 4059 if err != nil { 4060 t.Fatalf("unexpected errors %s", err) 4061 } 4062 expected := durationString{10 * time.Second} 4063 if cfg.HTTP.PingTimeout != expected { 4064 t.Fatalf("expected '%s', got '%s'", expected, cfg.HTTP.PingTimeout) 4065 } 4066} 4067 4068func TestLeafUnmarshalerError(t *testing.T) { 4069 src := ` 4070[HTTP] 4071ErrorField = "foo" 4072` 4073 cfg := &config437{} 4074 4075 r := strings.NewReader(src) 4076 err := NewDecoder(r).Decode(cfg) 4077 if err == nil { 4078 t.Fatalf("error was expected") 4079 } 4080} 4081