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 1479func TestCompactComments(t *testing.T) { 1480 expected := []byte(` 1481[first-section] 1482 # comment for first-key 1483 first-key = 1 1484 # comment for second-key 1485 second-key = "value" 1486 # comment for commented third-key 1487 # third-key = [] 1488 1489[second-section] 1490 # comment for first-key 1491 first-key = 2 1492 # comment for second-key 1493 second-key = "another value" 1494 # comment for commented third-key 1495 # third-key = ["value1", "value2"] 1496`) 1497 type Settings struct { 1498 FirstKey int `toml:"first-key" comment:"comment for first-key"` 1499 SecondKey string `toml:"second-key" comment:"comment for second-key"` 1500 ThirdKey []string `toml:"third-key" comment:"comment for commented third-key" commented:"true"` 1501 } 1502 type Config struct { 1503 FirstSection Settings `toml:"first-section"` 1504 SecondSection Settings `toml:"second-section"` 1505 } 1506 data := Config{ 1507 FirstSection: Settings{1, "value", []string{}}, 1508 SecondSection: Settings{2, "another value", []string{"value1", "value2"}}, 1509 } 1510 buf := new(bytes.Buffer) 1511 if err := NewEncoder(buf).CompactComments(true).Encode(data); err != nil { 1512 t.Fatal(err) 1513 } 1514 1515 if !bytes.Equal(expected, buf.Bytes()) { 1516 t.Errorf("Bad marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expected, buf.Bytes()) 1517 } 1518} 1519 1520type mapsTestStruct struct { 1521 Simple map[string]string 1522 Paths map[string]string 1523 Other map[string]float64 1524 X struct { 1525 Y struct { 1526 Z map[string]bool 1527 } 1528 } 1529} 1530 1531var mapsTestData = mapsTestStruct{ 1532 Simple: map[string]string{ 1533 "one plus one": "two", 1534 "next": "three", 1535 }, 1536 Paths: map[string]string{ 1537 "/this/is/a/path": "/this/is/also/a/path", 1538 "/heloo.txt": "/tmp/lololo.txt", 1539 }, 1540 Other: map[string]float64{ 1541 "testing": 3.9999, 1542 }, 1543 X: struct{ Y struct{ Z map[string]bool } }{ 1544 Y: struct{ Z map[string]bool }{ 1545 Z: map[string]bool{ 1546 "is.Nested": true, 1547 }, 1548 }, 1549 }, 1550} 1551var mapsTestToml = []byte(` 1552[Other] 1553 "testing" = 3.9999 1554 1555[Paths] 1556 "/heloo.txt" = "/tmp/lololo.txt" 1557 "/this/is/a/path" = "/this/is/also/a/path" 1558 1559[Simple] 1560 "next" = "three" 1561 "one plus one" = "two" 1562 1563[X] 1564 1565 [X.Y] 1566 1567 [X.Y.Z] 1568 "is.Nested" = true 1569`) 1570 1571func TestEncodeQuotedMapKeys(t *testing.T) { 1572 var buf bytes.Buffer 1573 if err := NewEncoder(&buf).QuoteMapKeys(true).Encode(mapsTestData); err != nil { 1574 t.Fatal(err) 1575 } 1576 result := buf.Bytes() 1577 expected := mapsTestToml 1578 if !bytes.Equal(result, expected) { 1579 t.Errorf("Bad maps marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expected, result) 1580 } 1581} 1582 1583func TestDecodeQuotedMapKeys(t *testing.T) { 1584 result := mapsTestStruct{} 1585 err := NewDecoder(bytes.NewBuffer(mapsTestToml)).Decode(&result) 1586 expected := mapsTestData 1587 if err != nil { 1588 t.Fatal(err) 1589 } 1590 if !reflect.DeepEqual(result, expected) { 1591 t.Errorf("Bad maps unmarshal: expected %v, got %v", expected, result) 1592 } 1593} 1594 1595type structArrayNoTag struct { 1596 A struct { 1597 B []int64 1598 C []int64 1599 } 1600} 1601 1602func TestMarshalArray(t *testing.T) { 1603 expected := []byte(` 1604[A] 1605 B = [1, 2, 3] 1606 C = [1] 1607`) 1608 1609 m := structArrayNoTag{ 1610 A: struct { 1611 B []int64 1612 C []int64 1613 }{ 1614 B: []int64{1, 2, 3}, 1615 C: []int64{1}, 1616 }, 1617 } 1618 1619 b, err := Marshal(m) 1620 1621 if err != nil { 1622 t.Fatal(err) 1623 } 1624 1625 if !bytes.Equal(b, expected) { 1626 t.Errorf("Bad arrays marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expected, b) 1627 } 1628} 1629 1630func TestMarshalArrayOnePerLine(t *testing.T) { 1631 expected := []byte(` 1632[A] 1633 B = [ 1634 1, 1635 2, 1636 3, 1637 ] 1638 C = [1] 1639`) 1640 1641 m := structArrayNoTag{ 1642 A: struct { 1643 B []int64 1644 C []int64 1645 }{ 1646 B: []int64{1, 2, 3}, 1647 C: []int64{1}, 1648 }, 1649 } 1650 1651 var buf bytes.Buffer 1652 encoder := NewEncoder(&buf).ArraysWithOneElementPerLine(true) 1653 err := encoder.Encode(m) 1654 1655 if err != nil { 1656 t.Fatal(err) 1657 } 1658 1659 b := buf.Bytes() 1660 1661 if !bytes.Equal(b, expected) { 1662 t.Errorf("Bad arrays marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expected, b) 1663 } 1664} 1665 1666var customTagTestToml = []byte(` 1667[postgres] 1668 password = "bvalue" 1669 user = "avalue" 1670 1671 [[postgres.My]] 1672 My = "Foo" 1673 1674 [[postgres.My]] 1675 My = "Baar" 1676`) 1677 1678func TestMarshalCustomTag(t *testing.T) { 1679 type TypeC struct { 1680 My string 1681 } 1682 type TypeB struct { 1683 AttrA string `file:"user"` 1684 AttrB string `file:"password"` 1685 My []TypeC 1686 } 1687 type TypeA struct { 1688 TypeB TypeB `file:"postgres"` 1689 } 1690 1691 ta := []TypeC{{My: "Foo"}, {My: "Baar"}} 1692 config := TypeA{TypeB{AttrA: "avalue", AttrB: "bvalue", My: ta}} 1693 var buf bytes.Buffer 1694 err := NewEncoder(&buf).SetTagName("file").Encode(config) 1695 if err != nil { 1696 t.Fatal(err) 1697 } 1698 expected := customTagTestToml 1699 result := buf.Bytes() 1700 if !bytes.Equal(result, expected) { 1701 t.Errorf("Bad marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expected, result) 1702 } 1703} 1704 1705var customCommentTagTestToml = []byte(` 1706# db connection 1707[postgres] 1708 1709 # db pass 1710 password = "bvalue" 1711 1712 # db user 1713 user = "avalue" 1714`) 1715 1716func TestMarshalCustomComment(t *testing.T) { 1717 type TypeB struct { 1718 AttrA string `toml:"user" descr:"db user"` 1719 AttrB string `toml:"password" descr:"db pass"` 1720 } 1721 type TypeA struct { 1722 TypeB TypeB `toml:"postgres" descr:"db connection"` 1723 } 1724 1725 config := TypeA{TypeB{AttrA: "avalue", AttrB: "bvalue"}} 1726 var buf bytes.Buffer 1727 err := NewEncoder(&buf).SetTagComment("descr").Encode(config) 1728 if err != nil { 1729 t.Fatal(err) 1730 } 1731 expected := customCommentTagTestToml 1732 result := buf.Bytes() 1733 if !bytes.Equal(result, expected) { 1734 t.Errorf("Bad marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expected, result) 1735 } 1736} 1737 1738var customCommentedTagTestToml = []byte(` 1739[postgres] 1740 # password = "bvalue" 1741 # user = "avalue" 1742`) 1743 1744func TestMarshalCustomCommented(t *testing.T) { 1745 type TypeB struct { 1746 AttrA string `toml:"user" disable:"true"` 1747 AttrB string `toml:"password" disable:"true"` 1748 } 1749 type TypeA struct { 1750 TypeB TypeB `toml:"postgres"` 1751 } 1752 1753 config := TypeA{TypeB{AttrA: "avalue", AttrB: "bvalue"}} 1754 var buf bytes.Buffer 1755 err := NewEncoder(&buf).SetTagCommented("disable").Encode(config) 1756 if err != nil { 1757 t.Fatal(err) 1758 } 1759 expected := customCommentedTagTestToml 1760 result := buf.Bytes() 1761 if !bytes.Equal(result, expected) { 1762 t.Errorf("Bad marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expected, result) 1763 } 1764} 1765 1766func TestMarshalDirectMultilineString(t *testing.T) { 1767 tree := newTree() 1768 tree.SetWithOptions("mykey", SetOptions{ 1769 Multiline: true, 1770 }, "my\x11multiline\nstring\ba\tb\fc\rd\"e\\!") 1771 result, err := tree.Marshal() 1772 if err != nil { 1773 t.Fatal("marshal should not error:", err) 1774 } 1775 expected := []byte("mykey = \"\"\"\nmy\\u0011multiline\nstring\\ba\tb\\fc\rd\"e\\!\"\"\"\n") 1776 if !bytes.Equal(result, expected) { 1777 t.Errorf("Bad marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expected, result) 1778 } 1779} 1780 1781func TestUnmarshalTabInStringAndQuotedKey(t *testing.T) { 1782 type Test struct { 1783 Field1 string `toml:"Fie ld1"` 1784 Field2 string 1785 } 1786 1787 type TestCase struct { 1788 desc string 1789 input []byte 1790 expected Test 1791 } 1792 1793 testCases := []TestCase{ 1794 { 1795 desc: "multiline string with tab", 1796 input: []byte("Field2 = \"\"\"\nhello\tworld\"\"\""), 1797 expected: Test{ 1798 Field2: "hello\tworld", 1799 }, 1800 }, 1801 { 1802 desc: "quoted key with tab", 1803 input: []byte("\"Fie\tld1\" = \"key with tab\""), 1804 expected: Test{ 1805 Field1: "key with tab", 1806 }, 1807 }, 1808 { 1809 desc: "basic string tab", 1810 input: []byte("Field2 = \"hello\tworld\""), 1811 expected: Test{ 1812 Field2: "hello\tworld", 1813 }, 1814 }, 1815 } 1816 1817 for i := range testCases { 1818 result := Test{} 1819 err := Unmarshal(testCases[i].input, &result) 1820 if err != nil { 1821 t.Errorf("%s test error:%v", testCases[i].desc, err) 1822 continue 1823 } 1824 1825 if !reflect.DeepEqual(result, testCases[i].expected) { 1826 t.Errorf("%s test error: expected\n-----\n%+v\n-----\ngot\n-----\n%+v\n-----\n", 1827 testCases[i].desc, testCases[i].expected, result) 1828 } 1829 } 1830} 1831 1832var customMultilineTagTestToml = []byte(`int_slice = [ 1833 1, 1834 2, 1835 3, 1836] 1837`) 1838 1839func TestMarshalCustomMultiline(t *testing.T) { 1840 type TypeA struct { 1841 AttrA []int `toml:"int_slice" mltln:"true"` 1842 } 1843 1844 config := TypeA{AttrA: []int{1, 2, 3}} 1845 var buf bytes.Buffer 1846 err := NewEncoder(&buf).ArraysWithOneElementPerLine(true).SetTagMultiline("mltln").Encode(config) 1847 if err != nil { 1848 t.Fatal(err) 1849 } 1850 expected := customMultilineTagTestToml 1851 result := buf.Bytes() 1852 if !bytes.Equal(result, expected) { 1853 t.Errorf("Bad marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expected, result) 1854 } 1855} 1856 1857func TestMultilineWithAdjacentQuotationMarks(t *testing.T) { 1858 type testStruct struct { 1859 Str string `multiline:"true"` 1860 } 1861 type testCase struct { 1862 expected []byte 1863 data testStruct 1864 } 1865 1866 testCases := []testCase{ 1867 { 1868 expected: []byte(`Str = """ 1869hello\"""" 1870`), 1871 data: testStruct{ 1872 Str: "hello\"", 1873 }, 1874 }, 1875 { 1876 expected: []byte(`Str = """ 1877""\"""\"""\"""" 1878`), 1879 data: testStruct{ 1880 Str: "\"\"\"\"\"\"\"\"\"", 1881 }, 1882 }, 1883 } 1884 for i := range testCases { 1885 result, err := Marshal(testCases[i].data) 1886 if err != nil { 1887 t.Fatal(err) 1888 } 1889 1890 if !bytes.Equal(result, testCases[i].expected) { 1891 t.Errorf("Bad marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", 1892 testCases[i].expected, result) 1893 } else { 1894 var data testStruct 1895 if err = Unmarshal(result, &data); err != nil { 1896 t.Fatal(err) 1897 } 1898 if data.Str != testCases[i].data.Str { 1899 t.Errorf("Round trip test fail: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", 1900 testCases[i].data.Str, data.Str) 1901 } 1902 } 1903 } 1904} 1905 1906func TestMarshalEmbedTree(t *testing.T) { 1907 expected := []byte(`OuterField1 = "Out" 1908OuterField2 = 1024 1909 1910[TreeField] 1911 InnerField1 = "In" 1912 InnerField2 = 2048 1913 1914 [TreeField.EmbedStruct] 1915 EmbedField = "Embed" 1916`) 1917 type InnerStruct struct { 1918 InnerField1 string 1919 InnerField2 int 1920 EmbedStruct struct { 1921 EmbedField string 1922 } 1923 } 1924 1925 type OuterStruct struct { 1926 OuterField1 string 1927 OuterField2 int 1928 TreeField *Tree 1929 } 1930 1931 tree, err := Load(` 1932InnerField1 = "In" 1933InnerField2 = 2048 1934 1935[EmbedStruct] 1936 EmbedField = "Embed" 1937`) 1938 if err != nil { 1939 t.Fatal(err) 1940 } 1941 1942 out := OuterStruct{ 1943 "Out", 1944 1024, 1945 tree, 1946 } 1947 actual, _ := Marshal(out) 1948 1949 if !bytes.Equal(actual, expected) { 1950 t.Errorf("Bad marshal: expected %s, got %s", expected, actual) 1951 } 1952} 1953 1954var testDocBasicToml = []byte(` 1955[document] 1956 bool_val = true 1957 date_val = 1979-05-27T07:32:00Z 1958 float_val = 123.4 1959 int_val = 5000 1960 string_val = "Bite me" 1961 uint_val = 5001 1962`) 1963 1964type testDocCustomTag struct { 1965 Doc testDocBasicsCustomTag `file:"document"` 1966} 1967type testDocBasicsCustomTag struct { 1968 Bool bool `file:"bool_val"` 1969 Date time.Time `file:"date_val"` 1970 Float float32 `file:"float_val"` 1971 Int int `file:"int_val"` 1972 Uint uint `file:"uint_val"` 1973 String *string `file:"string_val"` 1974 unexported int `file:"shouldntBeHere"` 1975} 1976 1977var testDocCustomTagData = testDocCustomTag{ 1978 Doc: testDocBasicsCustomTag{ 1979 Bool: true, 1980 Date: time.Date(1979, 5, 27, 7, 32, 0, 0, time.UTC), 1981 Float: 123.4, 1982 Int: 5000, 1983 Uint: 5001, 1984 String: &biteMe, 1985 unexported: 0, 1986 }, 1987} 1988 1989func TestUnmarshalCustomTag(t *testing.T) { 1990 buf := bytes.NewBuffer(testDocBasicToml) 1991 1992 result := testDocCustomTag{} 1993 err := NewDecoder(buf).SetTagName("file").Decode(&result) 1994 if err != nil { 1995 t.Fatal(err) 1996 } 1997 expected := testDocCustomTagData 1998 if !reflect.DeepEqual(result, expected) { 1999 resStr, _ := json.MarshalIndent(result, "", " ") 2000 expStr, _ := json.MarshalIndent(expected, "", " ") 2001 t.Errorf("Bad unmarshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expStr, resStr) 2002 2003 } 2004} 2005 2006func TestUnmarshalMap(t *testing.T) { 2007 testToml := []byte(` 2008 a = 1 2009 b = 2 2010 c = 3 2011 `) 2012 var result map[string]int 2013 err := Unmarshal(testToml, &result) 2014 if err != nil { 2015 t.Errorf("Received unexpected error: %s", err) 2016 return 2017 } 2018 2019 expected := map[string]int{ 2020 "a": 1, 2021 "b": 2, 2022 "c": 3, 2023 } 2024 2025 if !reflect.DeepEqual(result, expected) { 2026 t.Errorf("Bad unmarshal: expected %v, got %v", expected, result) 2027 } 2028} 2029 2030func TestUnmarshalMapWithTypedKey(t *testing.T) { 2031 testToml := []byte(` 2032 a = 1 2033 b = 2 2034 c = 3 2035 `) 2036 2037 type letter string 2038 var result map[letter]int 2039 err := Unmarshal(testToml, &result) 2040 if err != nil { 2041 t.Errorf("Received unexpected error: %s", err) 2042 return 2043 } 2044 2045 expected := map[letter]int{ 2046 "a": 1, 2047 "b": 2, 2048 "c": 3, 2049 } 2050 2051 if !reflect.DeepEqual(result, expected) { 2052 t.Errorf("Bad unmarshal: expected %v, got %v", expected, result) 2053 } 2054} 2055 2056func TestUnmarshalNonPointer(t *testing.T) { 2057 a := 1 2058 err := Unmarshal([]byte{}, a) 2059 if err == nil { 2060 t.Fatal("unmarshal should err when given a non pointer") 2061 } 2062} 2063 2064func TestUnmarshalInvalidPointerKind(t *testing.T) { 2065 a := 1 2066 err := Unmarshal([]byte{}, &a) 2067 if err == nil { 2068 t.Fatal("unmarshal should err when given an invalid pointer type") 2069 } 2070} 2071 2072func TestMarshalSlice(t *testing.T) { 2073 m := make([]int, 1) 2074 m[0] = 1 2075 2076 var buf bytes.Buffer 2077 err := NewEncoder(&buf).Encode(&m) 2078 if err == nil { 2079 t.Error("expected error, got nil") 2080 return 2081 } 2082 if err.Error() != "Only pointer to struct can be marshaled to TOML" { 2083 t.Fail() 2084 } 2085} 2086 2087func TestMarshalSlicePointer(t *testing.T) { 2088 m := make([]int, 1) 2089 m[0] = 1 2090 2091 var buf bytes.Buffer 2092 err := NewEncoder(&buf).Encode(m) 2093 if err == nil { 2094 t.Error("expected error, got nil") 2095 return 2096 } 2097 if err.Error() != "Only a struct or map can be marshaled to TOML" { 2098 t.Fail() 2099 } 2100} 2101 2102func TestMarshalNestedArrayInlineTables(t *testing.T) { 2103 type table struct { 2104 Value1 int `toml:"ZValue1"` 2105 Value2 int `toml:"YValue2"` 2106 Value3 int `toml:"XValue3"` 2107 } 2108 2109 type nestedTable struct { 2110 Table table 2111 } 2112 2113 nestedArray := struct { 2114 Simple [][]table 2115 SimplePointer *[]*[]table 2116 Nested [][]nestedTable 2117 NestedPointer *[]*[]nestedTable 2118 }{ 2119 Simple: [][]table{{{Value1: 1}, {Value1: 10}}}, 2120 SimplePointer: &[]*[]table{{{Value2: 2}}}, 2121 Nested: [][]nestedTable{{{Table: table{Value3: 3}}}}, 2122 NestedPointer: &[]*[]nestedTable{{{Table: table{Value3: -3}}}}, 2123 } 2124 2125 expectedPreserve := `Simple = [[{ ZValue1 = 1, YValue2 = 0, XValue3 = 0 }, { ZValue1 = 10, YValue2 = 0, XValue3 = 0 }]] 2126SimplePointer = [[{ ZValue1 = 0, YValue2 = 2, XValue3 = 0 }]] 2127Nested = [[{ Table = { ZValue1 = 0, YValue2 = 0, XValue3 = 3 } }]] 2128NestedPointer = [[{ Table = { ZValue1 = 0, YValue2 = 0, XValue3 = -3 } }]] 2129` 2130 2131 expectedAlphabetical := `Nested = [[{ Table = { XValue3 = 3, YValue2 = 0, ZValue1 = 0 } }]] 2132NestedPointer = [[{ Table = { XValue3 = -3, YValue2 = 0, ZValue1 = 0 } }]] 2133Simple = [[{ XValue3 = 0, YValue2 = 0, ZValue1 = 1 }, { XValue3 = 0, YValue2 = 0, ZValue1 = 10 }]] 2134SimplePointer = [[{ XValue3 = 0, YValue2 = 2, ZValue1 = 0 }]] 2135` 2136 2137 var bufPreserve bytes.Buffer 2138 if err := NewEncoder(&bufPreserve).Order(OrderPreserve).Encode(nestedArray); err != nil { 2139 t.Fatalf("unexpected error: %s", err.Error()) 2140 } 2141 if !bytes.Equal(bufPreserve.Bytes(), []byte(expectedPreserve)) { 2142 t.Errorf("Bad marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expectedPreserve, bufPreserve.String()) 2143 } 2144 2145 var bufAlphabetical bytes.Buffer 2146 if err := NewEncoder(&bufAlphabetical).Order(OrderAlphabetical).Encode(nestedArray); err != nil { 2147 t.Fatalf("unexpected error: %s", err.Error()) 2148 } 2149 if !bytes.Equal(bufAlphabetical.Bytes(), []byte(expectedAlphabetical)) { 2150 t.Errorf("Bad marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expectedAlphabetical, bufAlphabetical.String()) 2151 } 2152} 2153 2154type testDuration struct { 2155 Nanosec time.Duration `toml:"nanosec"` 2156 Microsec1 time.Duration `toml:"microsec1"` 2157 Microsec2 *time.Duration `toml:"microsec2"` 2158 Millisec time.Duration `toml:"millisec"` 2159 Sec time.Duration `toml:"sec"` 2160 Min time.Duration `toml:"min"` 2161 Hour time.Duration `toml:"hour"` 2162 Mixed time.Duration `toml:"mixed"` 2163 AString string `toml:"a_string"` 2164} 2165 2166var testDurationToml = []byte(` 2167nanosec = "1ns" 2168microsec1 = "1us" 2169microsec2 = "1µs" 2170millisec = "1ms" 2171sec = "1s" 2172min = "1m" 2173hour = "1h" 2174mixed = "1h1m1s1ms1µs1ns" 2175a_string = "15s" 2176`) 2177 2178func TestUnmarshalDuration(t *testing.T) { 2179 buf := bytes.NewBuffer(testDurationToml) 2180 2181 result := testDuration{} 2182 err := NewDecoder(buf).Decode(&result) 2183 if err != nil { 2184 t.Fatal(err) 2185 } 2186 ms := time.Duration(1) * time.Microsecond 2187 expected := testDuration{ 2188 Nanosec: 1, 2189 Microsec1: time.Microsecond, 2190 Microsec2: &ms, 2191 Millisec: time.Millisecond, 2192 Sec: time.Second, 2193 Min: time.Minute, 2194 Hour: time.Hour, 2195 Mixed: time.Hour + 2196 time.Minute + 2197 time.Second + 2198 time.Millisecond + 2199 time.Microsecond + 2200 time.Nanosecond, 2201 AString: "15s", 2202 } 2203 if !reflect.DeepEqual(result, expected) { 2204 resStr, _ := json.MarshalIndent(result, "", " ") 2205 expStr, _ := json.MarshalIndent(expected, "", " ") 2206 t.Errorf("Bad unmarshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expStr, resStr) 2207 2208 } 2209} 2210 2211var testDurationToml2 = []byte(`a_string = "15s" 2212hour = "1h0m0s" 2213microsec1 = "1µs" 2214microsec2 = "1µs" 2215millisec = "1ms" 2216min = "1m0s" 2217mixed = "1h1m1.001001001s" 2218nanosec = "1ns" 2219sec = "1s" 2220`) 2221 2222func TestMarshalDuration(t *testing.T) { 2223 ms := time.Duration(1) * time.Microsecond 2224 data := testDuration{ 2225 Nanosec: 1, 2226 Microsec1: time.Microsecond, 2227 Microsec2: &ms, 2228 Millisec: time.Millisecond, 2229 Sec: time.Second, 2230 Min: time.Minute, 2231 Hour: time.Hour, 2232 Mixed: time.Hour + 2233 time.Minute + 2234 time.Second + 2235 time.Millisecond + 2236 time.Microsecond + 2237 time.Nanosecond, 2238 AString: "15s", 2239 } 2240 2241 var buf bytes.Buffer 2242 err := NewEncoder(&buf).Encode(data) 2243 if err != nil { 2244 t.Fatal(err) 2245 } 2246 expected := testDurationToml2 2247 result := buf.Bytes() 2248 if !bytes.Equal(result, expected) { 2249 t.Errorf("Bad marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expected, result) 2250 } 2251} 2252 2253type testBadDuration struct { 2254 Val time.Duration `toml:"val"` 2255} 2256 2257var testBadDurationToml = []byte(`val = "1z"`) 2258 2259func TestUnmarshalBadDuration(t *testing.T) { 2260 buf := bytes.NewBuffer(testBadDurationToml) 2261 2262 result := testBadDuration{} 2263 err := NewDecoder(buf).Decode(&result) 2264 if err == nil { 2265 t.Fatal("expected bad duration error") 2266 } 2267} 2268 2269var testCamelCaseKeyToml = []byte(`fooBar = 10`) 2270 2271func TestUnmarshalCamelCaseKey(t *testing.T) { 2272 var x struct { 2273 FooBar int 2274 B int 2275 } 2276 2277 if err := Unmarshal(testCamelCaseKeyToml, &x); err != nil { 2278 t.Fatal(err) 2279 } 2280 2281 if x.FooBar != 10 { 2282 t.Fatal("Did not set camelCase'd key") 2283 } 2284} 2285 2286func TestUnmarshalNegativeUint(t *testing.T) { 2287 type check struct{ U uint } 2288 2289 tree, _ := Load("u = -1") 2290 err := tree.Unmarshal(&check{}) 2291 if err.Error() != "(1, 1): -1(int64) is negative so does not fit in uint" { 2292 t.Error("expect err:(1, 1): -1(int64) is negative so does not fit in uint but got:", err) 2293 } 2294} 2295 2296func TestUnmarshalCheckConversionFloatInt(t *testing.T) { 2297 type conversionCheck struct { 2298 U uint 2299 I int 2300 F float64 2301 } 2302 2303 treeU, _ := Load("u = 1e300") 2304 treeI, _ := Load("i = 1e300") 2305 treeF, _ := Load("f = 9223372036854775806") 2306 2307 errU := treeU.Unmarshal(&conversionCheck{}) 2308 errI := treeI.Unmarshal(&conversionCheck{}) 2309 errF := treeF.Unmarshal(&conversionCheck{}) 2310 2311 if errU.Error() != "(1, 1): Can't convert 1e+300(float64) to uint" { 2312 t.Error("expect err:(1, 1): Can't convert 1e+300(float64) to uint but got:", errU) 2313 } 2314 if errI.Error() != "(1, 1): Can't convert 1e+300(float64) to int" { 2315 t.Error("expect err:(1, 1): Can't convert 1e+300(float64) to int but got:", errI) 2316 } 2317 if errF.Error() != "(1, 1): Can't convert 9223372036854775806(int64) to float64" { 2318 t.Error("expect err:(1, 1): Can't convert 9223372036854775806(int64) to float64 but got:", errF) 2319 } 2320} 2321 2322func TestUnmarshalOverflow(t *testing.T) { 2323 type overflow struct { 2324 U8 uint8 2325 I8 int8 2326 F32 float32 2327 } 2328 2329 treeU8, _ := Load("u8 = 300") 2330 treeI8, _ := Load("i8 = 300") 2331 treeF32, _ := Load("f32 = 1e300") 2332 2333 errU8 := treeU8.Unmarshal(&overflow{}) 2334 errI8 := treeI8.Unmarshal(&overflow{}) 2335 errF32 := treeF32.Unmarshal(&overflow{}) 2336 2337 if errU8.Error() != "(1, 1): 300(int64) would overflow uint8" { 2338 t.Error("expect err:(1, 1): 300(int64) would overflow uint8 but got:", errU8) 2339 } 2340 if errI8.Error() != "(1, 1): 300(int64) would overflow int8" { 2341 t.Error("expect err:(1, 1): 300(int64) would overflow int8 but got:", errI8) 2342 } 2343 if errF32.Error() != "(1, 1): 1e+300(float64) would overflow float32" { 2344 t.Error("expect err:(1, 1): 1e+300(float64) would overflow float32 but got:", errF32) 2345 } 2346} 2347 2348func TestUnmarshalDefault(t *testing.T) { 2349 type EmbeddedStruct struct { 2350 StringField string `default:"c"` 2351 } 2352 2353 type aliasUint uint 2354 2355 var doc struct { 2356 StringField string `default:"a"` 2357 BoolField bool `default:"true"` 2358 UintField uint `default:"1"` 2359 Uint8Field uint8 `default:"8"` 2360 Uint16Field uint16 `default:"16"` 2361 Uint32Field uint32 `default:"32"` 2362 Uint64Field uint64 `default:"64"` 2363 IntField int `default:"-1"` 2364 Int8Field int8 `default:"-8"` 2365 Int16Field int16 `default:"-16"` 2366 Int32Field int32 `default:"-32"` 2367 Int64Field int64 `default:"-64"` 2368 Float32Field float32 `default:"32.1"` 2369 Float64Field float64 `default:"64.1"` 2370 DurationField time.Duration `default:"120ms"` 2371 DurationField2 time.Duration `default:"120000000"` 2372 NonEmbeddedStruct struct { 2373 StringField string `default:"b"` 2374 } 2375 EmbeddedStruct 2376 AliasUintField aliasUint `default:"1000"` 2377 } 2378 2379 err := Unmarshal([]byte(``), &doc) 2380 if err != nil { 2381 t.Fatal(err) 2382 } 2383 if doc.BoolField != true { 2384 t.Errorf("BoolField should be true, not %t", doc.BoolField) 2385 } 2386 if doc.StringField != "a" { 2387 t.Errorf("StringField should be \"a\", not %s", doc.StringField) 2388 } 2389 if doc.UintField != 1 { 2390 t.Errorf("UintField should be 1, not %d", doc.UintField) 2391 } 2392 if doc.Uint8Field != 8 { 2393 t.Errorf("Uint8Field should be 8, not %d", doc.Uint8Field) 2394 } 2395 if doc.Uint16Field != 16 { 2396 t.Errorf("Uint16Field should be 16, not %d", doc.Uint16Field) 2397 } 2398 if doc.Uint32Field != 32 { 2399 t.Errorf("Uint32Field should be 32, not %d", doc.Uint32Field) 2400 } 2401 if doc.Uint64Field != 64 { 2402 t.Errorf("Uint64Field should be 64, not %d", doc.Uint64Field) 2403 } 2404 if doc.IntField != -1 { 2405 t.Errorf("IntField should be -1, not %d", doc.IntField) 2406 } 2407 if doc.Int8Field != -8 { 2408 t.Errorf("Int8Field should be -8, not %d", doc.Int8Field) 2409 } 2410 if doc.Int16Field != -16 { 2411 t.Errorf("Int16Field should be -16, not %d", doc.Int16Field) 2412 } 2413 if doc.Int32Field != -32 { 2414 t.Errorf("Int32Field should be -32, not %d", doc.Int32Field) 2415 } 2416 if doc.Int64Field != -64 { 2417 t.Errorf("Int64Field should be -64, not %d", doc.Int64Field) 2418 } 2419 if doc.Float32Field != 32.1 { 2420 t.Errorf("Float32Field should be 32.1, not %f", doc.Float32Field) 2421 } 2422 if doc.Float64Field != 64.1 { 2423 t.Errorf("Float64Field should be 64.1, not %f", doc.Float64Field) 2424 } 2425 if doc.DurationField != 120*time.Millisecond { 2426 t.Errorf("DurationField should be 120ms, not %s", doc.DurationField.String()) 2427 } 2428 if doc.DurationField2 != 120*time.Millisecond { 2429 t.Errorf("DurationField2 should be 120000000, not %d", doc.DurationField2) 2430 } 2431 if doc.NonEmbeddedStruct.StringField != "b" { 2432 t.Errorf("StringField should be \"b\", not %s", doc.NonEmbeddedStruct.StringField) 2433 } 2434 if doc.EmbeddedStruct.StringField != "c" { 2435 t.Errorf("StringField should be \"c\", not %s", doc.EmbeddedStruct.StringField) 2436 } 2437 if doc.AliasUintField != 1000 { 2438 t.Errorf("AliasUintField should be 1000, not %d", doc.AliasUintField) 2439 } 2440} 2441 2442func TestUnmarshalDefaultFailureBool(t *testing.T) { 2443 var doc struct { 2444 Field bool `default:"blah"` 2445 } 2446 2447 err := Unmarshal([]byte(``), &doc) 2448 if err == nil { 2449 t.Fatal("should error") 2450 } 2451} 2452 2453func TestUnmarshalDefaultFailureInt(t *testing.T) { 2454 var doc struct { 2455 Field int `default:"blah"` 2456 } 2457 2458 err := Unmarshal([]byte(``), &doc) 2459 if err == nil { 2460 t.Fatal("should error") 2461 } 2462} 2463 2464func TestUnmarshalDefaultFailureInt64(t *testing.T) { 2465 var doc struct { 2466 Field int64 `default:"blah"` 2467 } 2468 2469 err := Unmarshal([]byte(``), &doc) 2470 if err == nil { 2471 t.Fatal("should error") 2472 } 2473} 2474 2475func TestUnmarshalDefaultFailureFloat64(t *testing.T) { 2476 var doc struct { 2477 Field float64 `default:"blah"` 2478 } 2479 2480 err := Unmarshal([]byte(``), &doc) 2481 if err == nil { 2482 t.Fatal("should error") 2483 } 2484} 2485 2486func TestUnmarshalDefaultFailureDuration(t *testing.T) { 2487 var doc struct { 2488 Field time.Duration `default:"blah"` 2489 } 2490 2491 err := Unmarshal([]byte(``), &doc) 2492 if err == nil { 2493 t.Fatal("should error") 2494 } 2495} 2496 2497func TestUnmarshalDefaultFailureUnsupported(t *testing.T) { 2498 var doc struct { 2499 Field struct{} `default:"blah"` 2500 } 2501 2502 err := Unmarshal([]byte(``), &doc) 2503 if err == nil { 2504 t.Fatal("should error") 2505 } 2506} 2507 2508func TestMarshalNestedAnonymousStructs(t *testing.T) { 2509 type Embedded struct { 2510 Value string `toml:"value"` 2511 Top struct { 2512 Value string `toml:"value"` 2513 } `toml:"top"` 2514 } 2515 2516 type Named struct { 2517 Value string `toml:"value"` 2518 } 2519 2520 var doc struct { 2521 Embedded 2522 Named `toml:"named"` 2523 Anonymous struct { 2524 Value string `toml:"value"` 2525 } `toml:"anonymous"` 2526 } 2527 2528 expected := `value = "" 2529 2530[anonymous] 2531 value = "" 2532 2533[named] 2534 value = "" 2535 2536[top] 2537 value = "" 2538` 2539 2540 result, err := Marshal(doc) 2541 if err != nil { 2542 t.Fatalf("unexpected error: %s", err.Error()) 2543 } 2544 if !bytes.Equal(result, []byte(expected)) { 2545 t.Errorf("Bad marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expected, string(result)) 2546 } 2547} 2548 2549func TestEncoderPromoteNestedAnonymousStructs(t *testing.T) { 2550 type Embedded struct { 2551 Value string `toml:"value"` 2552 } 2553 2554 var doc struct { 2555 Embedded 2556 } 2557 2558 expected := ` 2559[Embedded] 2560 value = "" 2561` 2562 var buf bytes.Buffer 2563 if err := NewEncoder(&buf).PromoteAnonymous(true).Encode(doc); err != nil { 2564 t.Fatalf("unexpected error: %s", err.Error()) 2565 } 2566 if !bytes.Equal(buf.Bytes(), []byte(expected)) { 2567 t.Errorf("Bad marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expected, buf.String()) 2568 } 2569} 2570 2571func TestMarshalNestedAnonymousStructs_DuplicateField(t *testing.T) { 2572 type Embedded struct { 2573 Value string `toml:"value"` 2574 Top struct { 2575 Value string `toml:"value"` 2576 } `toml:"top"` 2577 } 2578 2579 var doc struct { 2580 Value string `toml:"value"` 2581 Embedded 2582 } 2583 doc.Embedded.Value = "shadowed" 2584 doc.Value = "shadows" 2585 2586 expected := `value = "shadows" 2587 2588[top] 2589 value = "" 2590` 2591 2592 result, err := Marshal(doc) 2593 if err != nil { 2594 t.Fatalf("unexpected error: %s", err.Error()) 2595 } 2596 if !bytes.Equal(result, []byte(expected)) { 2597 t.Errorf("Bad marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expected, string(result)) 2598 } 2599} 2600 2601func TestUnmarshalNestedAnonymousStructs(t *testing.T) { 2602 type Nested struct { 2603 Value string `toml:"nested_field"` 2604 } 2605 type Deep struct { 2606 Nested 2607 } 2608 type Document struct { 2609 Deep 2610 Value string `toml:"own_field"` 2611 } 2612 2613 var doc Document 2614 2615 err := Unmarshal([]byte(`nested_field = "nested value"`+"\n"+`own_field = "own value"`), &doc) 2616 if err != nil { 2617 t.Fatal("should not error") 2618 } 2619 if doc.Value != "own value" || doc.Nested.Value != "nested value" { 2620 t.Fatal("unexpected values") 2621 } 2622} 2623 2624func TestUnmarshalNestedAnonymousStructs_Controversial(t *testing.T) { 2625 type Nested struct { 2626 Value string `toml:"nested"` 2627 } 2628 type Deep struct { 2629 Nested 2630 } 2631 type Document struct { 2632 Deep 2633 Value string `toml:"own"` 2634 } 2635 2636 var doc Document 2637 2638 err := Unmarshal([]byte(`nested = "nested value"`+"\n"+`own = "own value"`), &doc) 2639 if err == nil { 2640 t.Fatal("should error") 2641 } 2642} 2643 2644type unexportedFieldPreservationTest struct { 2645 Exported string `toml:"exported"` 2646 unexported string 2647 Nested1 unexportedFieldPreservationTestNested `toml:"nested1"` 2648 Nested2 *unexportedFieldPreservationTestNested `toml:"nested2"` 2649 Nested3 *unexportedFieldPreservationTestNested `toml:"nested3"` 2650 Slice1 []unexportedFieldPreservationTestNested `toml:"slice1"` 2651 Slice2 []*unexportedFieldPreservationTestNested `toml:"slice2"` 2652} 2653 2654type unexportedFieldPreservationTestNested struct { 2655 Exported1 string `toml:"exported1"` 2656 unexported1 string 2657} 2658 2659func TestUnmarshalPreservesUnexportedFields(t *testing.T) { 2660 toml := ` 2661 exported = "visible" 2662 unexported = "ignored" 2663 2664 [nested1] 2665 exported1 = "visible1" 2666 unexported1 = "ignored1" 2667 2668 [nested2] 2669 exported1 = "visible2" 2670 unexported1 = "ignored2" 2671 2672 [nested3] 2673 exported1 = "visible3" 2674 unexported1 = "ignored3" 2675 2676 [[slice1]] 2677 exported1 = "visible3" 2678 2679 [[slice1]] 2680 exported1 = "visible4" 2681 2682 [[slice2]] 2683 exported1 = "visible5" 2684 ` 2685 2686 t.Run("unexported field should not be set from toml", func(t *testing.T) { 2687 var actual unexportedFieldPreservationTest 2688 err := Unmarshal([]byte(toml), &actual) 2689 2690 if err != nil { 2691 t.Fatal("did not expect an error") 2692 } 2693 2694 expect := unexportedFieldPreservationTest{ 2695 Exported: "visible", 2696 unexported: "", 2697 Nested1: unexportedFieldPreservationTestNested{"visible1", ""}, 2698 Nested2: &unexportedFieldPreservationTestNested{"visible2", ""}, 2699 Nested3: &unexportedFieldPreservationTestNested{"visible3", ""}, 2700 Slice1: []unexportedFieldPreservationTestNested{ 2701 {Exported1: "visible3"}, 2702 {Exported1: "visible4"}, 2703 }, 2704 Slice2: []*unexportedFieldPreservationTestNested{ 2705 {Exported1: "visible5"}, 2706 }, 2707 } 2708 2709 if !reflect.DeepEqual(actual, expect) { 2710 t.Fatalf("%+v did not equal %+v", actual, expect) 2711 } 2712 }) 2713 2714 t.Run("unexported field should be preserved", func(t *testing.T) { 2715 actual := unexportedFieldPreservationTest{ 2716 Exported: "foo", 2717 unexported: "bar", 2718 Nested1: unexportedFieldPreservationTestNested{"baz", "bax"}, 2719 Nested2: nil, 2720 Nested3: &unexportedFieldPreservationTestNested{"baz", "bax"}, 2721 } 2722 err := Unmarshal([]byte(toml), &actual) 2723 2724 if err != nil { 2725 t.Fatal("did not expect an error") 2726 } 2727 2728 expect := unexportedFieldPreservationTest{ 2729 Exported: "visible", 2730 unexported: "bar", 2731 Nested1: unexportedFieldPreservationTestNested{"visible1", "bax"}, 2732 Nested2: &unexportedFieldPreservationTestNested{"visible2", ""}, 2733 Nested3: &unexportedFieldPreservationTestNested{"visible3", "bax"}, 2734 Slice1: []unexportedFieldPreservationTestNested{ 2735 {Exported1: "visible3"}, 2736 {Exported1: "visible4"}, 2737 }, 2738 Slice2: []*unexportedFieldPreservationTestNested{ 2739 {Exported1: "visible5"}, 2740 }, 2741 } 2742 2743 if !reflect.DeepEqual(actual, expect) { 2744 t.Fatalf("%+v did not equal %+v", actual, expect) 2745 } 2746 }) 2747} 2748 2749func TestTreeMarshal(t *testing.T) { 2750 cases := [][]byte{ 2751 basicTestToml, 2752 marshalTestToml, 2753 emptyTestToml, 2754 pointerTestToml, 2755 } 2756 for _, expected := range cases { 2757 t.Run("", func(t *testing.T) { 2758 tree, err := LoadBytes(expected) 2759 if err != nil { 2760 t.Fatal(err) 2761 } 2762 result, err := tree.Marshal() 2763 if err != nil { 2764 t.Fatal(err) 2765 } 2766 if !bytes.Equal(result, expected) { 2767 t.Errorf("Bad marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expected, result) 2768 } 2769 }) 2770 } 2771} 2772 2773func TestMarshalArrays(t *testing.T) { 2774 cases := []struct { 2775 Data interface{} 2776 Expected string 2777 }{ 2778 { 2779 Data: struct { 2780 XY [2]int 2781 }{ 2782 XY: [2]int{1, 2}, 2783 }, 2784 Expected: `XY = [1, 2] 2785`, 2786 }, 2787 { 2788 Data: struct { 2789 XY [1][2]int 2790 }{ 2791 XY: [1][2]int{{1, 2}}, 2792 }, 2793 Expected: `XY = [[1, 2]] 2794`, 2795 }, 2796 { 2797 Data: struct { 2798 XY [1][]int 2799 }{ 2800 XY: [1][]int{{1, 2}}, 2801 }, 2802 Expected: `XY = [[1, 2]] 2803`, 2804 }, 2805 { 2806 Data: struct { 2807 XY [][2]int 2808 }{ 2809 XY: [][2]int{{1, 2}}, 2810 }, 2811 Expected: `XY = [[1, 2]] 2812`, 2813 }, 2814 } 2815 for _, tc := range cases { 2816 t.Run("", func(t *testing.T) { 2817 result, err := Marshal(tc.Data) 2818 if err != nil { 2819 t.Fatal(err) 2820 } 2821 if !bytes.Equal(result, []byte(tc.Expected)) { 2822 t.Errorf("Bad marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", []byte(tc.Expected), result) 2823 } 2824 }) 2825 } 2826} 2827 2828func TestUnmarshalLocalDate(t *testing.T) { 2829 t.Run("ToLocalDate", func(t *testing.T) { 2830 type dateStruct struct { 2831 Date LocalDate 2832 } 2833 2834 toml := `date = 1979-05-27` 2835 2836 var obj dateStruct 2837 2838 err := Unmarshal([]byte(toml), &obj) 2839 2840 if err != nil { 2841 t.Fatal(err) 2842 } 2843 2844 if obj.Date.Year != 1979 { 2845 t.Errorf("expected year 1979, got %d", obj.Date.Year) 2846 } 2847 if obj.Date.Month != 5 { 2848 t.Errorf("expected month 5, got %d", obj.Date.Month) 2849 } 2850 if obj.Date.Day != 27 { 2851 t.Errorf("expected day 27, got %d", obj.Date.Day) 2852 } 2853 }) 2854 2855 t.Run("ToLocalDate", func(t *testing.T) { 2856 type dateStruct struct { 2857 Date time.Time 2858 } 2859 2860 toml := `date = 1979-05-27` 2861 2862 var obj dateStruct 2863 2864 err := Unmarshal([]byte(toml), &obj) 2865 2866 if err != nil { 2867 t.Fatal(err) 2868 } 2869 2870 if obj.Date.Year() != 1979 { 2871 t.Errorf("expected year 1979, got %d", obj.Date.Year()) 2872 } 2873 if obj.Date.Month() != 5 { 2874 t.Errorf("expected month 5, got %d", obj.Date.Month()) 2875 } 2876 if obj.Date.Day() != 27 { 2877 t.Errorf("expected day 27, got %d", obj.Date.Day()) 2878 } 2879 }) 2880} 2881 2882func TestMarshalLocalDate(t *testing.T) { 2883 type dateStruct struct { 2884 Date LocalDate 2885 } 2886 2887 obj := dateStruct{Date: LocalDate{ 2888 Year: 1979, 2889 Month: 5, 2890 Day: 27, 2891 }} 2892 2893 b, err := Marshal(obj) 2894 2895 if err != nil { 2896 t.Fatalf("unexpected error: %v", err) 2897 } 2898 2899 got := string(b) 2900 expected := `Date = 1979-05-27 2901` 2902 2903 if got != expected { 2904 t.Errorf("expected '%s', got '%s'", expected, got) 2905 } 2906} 2907 2908func TestUnmarshalLocalDateTime(t *testing.T) { 2909 examples := []struct { 2910 name string 2911 in string 2912 out LocalDateTime 2913 }{ 2914 { 2915 name: "normal", 2916 in: "1979-05-27T07:32:00", 2917 out: LocalDateTime{ 2918 Date: LocalDate{ 2919 Year: 1979, 2920 Month: 5, 2921 Day: 27, 2922 }, 2923 Time: LocalTime{ 2924 Hour: 7, 2925 Minute: 32, 2926 Second: 0, 2927 Nanosecond: 0, 2928 }, 2929 }}, 2930 { 2931 name: "with nanoseconds", 2932 in: "1979-05-27T00:32:00.999999", 2933 out: LocalDateTime{ 2934 Date: LocalDate{ 2935 Year: 1979, 2936 Month: 5, 2937 Day: 27, 2938 }, 2939 Time: LocalTime{ 2940 Hour: 0, 2941 Minute: 32, 2942 Second: 0, 2943 Nanosecond: 999999000, 2944 }, 2945 }, 2946 }, 2947 } 2948 2949 for i, example := range examples { 2950 toml := fmt.Sprintf(`date = %s`, example.in) 2951 2952 t.Run(fmt.Sprintf("ToLocalDateTime_%d_%s", i, example.name), func(t *testing.T) { 2953 type dateStruct struct { 2954 Date LocalDateTime 2955 } 2956 2957 var obj dateStruct 2958 2959 err := Unmarshal([]byte(toml), &obj) 2960 2961 if err != nil { 2962 t.Fatal(err) 2963 } 2964 2965 if obj.Date != example.out { 2966 t.Errorf("expected '%s', got '%s'", example.out, obj.Date) 2967 } 2968 }) 2969 2970 t.Run(fmt.Sprintf("ToTime_%d_%s", i, example.name), func(t *testing.T) { 2971 type dateStruct struct { 2972 Date time.Time 2973 } 2974 2975 var obj dateStruct 2976 2977 err := Unmarshal([]byte(toml), &obj) 2978 2979 if err != nil { 2980 t.Fatal(err) 2981 } 2982 2983 if obj.Date.Year() != example.out.Date.Year { 2984 t.Errorf("expected year %d, got %d", example.out.Date.Year, obj.Date.Year()) 2985 } 2986 if obj.Date.Month() != example.out.Date.Month { 2987 t.Errorf("expected month %d, got %d", example.out.Date.Month, obj.Date.Month()) 2988 } 2989 if obj.Date.Day() != example.out.Date.Day { 2990 t.Errorf("expected day %d, got %d", example.out.Date.Day, obj.Date.Day()) 2991 } 2992 if obj.Date.Hour() != example.out.Time.Hour { 2993 t.Errorf("expected hour %d, got %d", example.out.Time.Hour, obj.Date.Hour()) 2994 } 2995 if obj.Date.Minute() != example.out.Time.Minute { 2996 t.Errorf("expected minute %d, got %d", example.out.Time.Minute, obj.Date.Minute()) 2997 } 2998 if obj.Date.Second() != example.out.Time.Second { 2999 t.Errorf("expected second %d, got %d", example.out.Time.Second, obj.Date.Second()) 3000 } 3001 if obj.Date.Nanosecond() != example.out.Time.Nanosecond { 3002 t.Errorf("expected nanoseconds %d, got %d", example.out.Time.Nanosecond, obj.Date.Nanosecond()) 3003 } 3004 }) 3005 } 3006} 3007 3008func TestMarshalLocalDateTime(t *testing.T) { 3009 type dateStruct struct { 3010 DateTime LocalDateTime 3011 } 3012 3013 examples := []struct { 3014 name string 3015 in LocalDateTime 3016 out string 3017 }{ 3018 { 3019 name: "normal", 3020 out: "DateTime = 1979-05-27T07:32:00\n", 3021 in: LocalDateTime{ 3022 Date: LocalDate{ 3023 Year: 1979, 3024 Month: 5, 3025 Day: 27, 3026 }, 3027 Time: LocalTime{ 3028 Hour: 7, 3029 Minute: 32, 3030 Second: 0, 3031 Nanosecond: 0, 3032 }, 3033 }}, 3034 { 3035 name: "with nanoseconds", 3036 out: "DateTime = 1979-05-27T00:32:00.999999000\n", 3037 in: LocalDateTime{ 3038 Date: LocalDate{ 3039 Year: 1979, 3040 Month: 5, 3041 Day: 27, 3042 }, 3043 Time: LocalTime{ 3044 Hour: 0, 3045 Minute: 32, 3046 Second: 0, 3047 Nanosecond: 999999000, 3048 }, 3049 }, 3050 }, 3051 } 3052 3053 for i, example := range examples { 3054 t.Run(fmt.Sprintf("%d_%s", i, example.name), func(t *testing.T) { 3055 obj := dateStruct{ 3056 DateTime: example.in, 3057 } 3058 b, err := Marshal(obj) 3059 3060 if err != nil { 3061 t.Fatalf("unexpected error: %v", err) 3062 } 3063 3064 got := string(b) 3065 3066 if got != example.out { 3067 t.Errorf("expected '%s', got '%s'", example.out, got) 3068 } 3069 }) 3070 } 3071} 3072 3073func TestUnmarshalLocalTime(t *testing.T) { 3074 examples := []struct { 3075 name string 3076 in string 3077 out LocalTime 3078 }{ 3079 { 3080 name: "normal", 3081 in: "07:32:00", 3082 out: LocalTime{ 3083 Hour: 7, 3084 Minute: 32, 3085 Second: 0, 3086 Nanosecond: 0, 3087 }, 3088 }, 3089 { 3090 name: "with nanoseconds", 3091 in: "00:32:00.999999", 3092 out: LocalTime{ 3093 Hour: 0, 3094 Minute: 32, 3095 Second: 0, 3096 Nanosecond: 999999000, 3097 }, 3098 }, 3099 } 3100 3101 for i, example := range examples { 3102 toml := fmt.Sprintf(`Time = %s`, example.in) 3103 3104 t.Run(fmt.Sprintf("ToLocalTime_%d_%s", i, example.name), func(t *testing.T) { 3105 type dateStruct struct { 3106 Time LocalTime 3107 } 3108 3109 var obj dateStruct 3110 3111 err := Unmarshal([]byte(toml), &obj) 3112 3113 if err != nil { 3114 t.Fatal(err) 3115 } 3116 3117 if obj.Time != example.out { 3118 t.Errorf("expected '%s', got '%s'", example.out, obj.Time) 3119 } 3120 }) 3121 } 3122} 3123 3124func TestMarshalLocalTime(t *testing.T) { 3125 type timeStruct struct { 3126 Time LocalTime 3127 } 3128 3129 examples := []struct { 3130 name string 3131 in LocalTime 3132 out string 3133 }{ 3134 { 3135 name: "normal", 3136 out: "Time = 07:32:00\n", 3137 in: LocalTime{ 3138 Hour: 7, 3139 Minute: 32, 3140 Second: 0, 3141 Nanosecond: 0, 3142 }}, 3143 { 3144 name: "with nanoseconds", 3145 out: "Time = 00:32:00.999999000\n", 3146 in: LocalTime{ 3147 Hour: 0, 3148 Minute: 32, 3149 Second: 0, 3150 Nanosecond: 999999000, 3151 }, 3152 }, 3153 } 3154 3155 for i, example := range examples { 3156 t.Run(fmt.Sprintf("%d_%s", i, example.name), func(t *testing.T) { 3157 obj := timeStruct{ 3158 Time: example.in, 3159 } 3160 b, err := Marshal(obj) 3161 3162 if err != nil { 3163 t.Fatalf("unexpected error: %v", err) 3164 } 3165 3166 got := string(b) 3167 3168 if got != example.out { 3169 t.Errorf("expected '%s', got '%s'", example.out, got) 3170 } 3171 }) 3172 } 3173} 3174 3175// test case for issue #339 3176func TestUnmarshalSameInnerField(t *testing.T) { 3177 type InterStruct2 struct { 3178 Test string 3179 Name string 3180 Age int 3181 } 3182 type Inter2 struct { 3183 Name string 3184 Age int 3185 InterStruct2 InterStruct2 3186 } 3187 type Server struct { 3188 Name string `toml:"name"` 3189 Inter2 Inter2 `toml:"inter2"` 3190 } 3191 3192 var server Server 3193 3194 if err := Unmarshal([]byte(`name = "123" 3195[inter2] 3196name = "inter2" 3197age = 222`), &server); err == nil { 3198 expected := Server{ 3199 Name: "123", 3200 Inter2: Inter2{ 3201 Name: "inter2", 3202 Age: 222, 3203 }, 3204 } 3205 if !reflect.DeepEqual(server, expected) { 3206 t.Errorf("Bad unmarshal: expected %v, got %v", expected, server) 3207 } 3208 } else { 3209 t.Fatalf("unexpected error: %v", err) 3210 } 3211} 3212 3213func TestMarshalInterface(t *testing.T) { 3214 type InnerStruct struct { 3215 InnerField string 3216 } 3217 3218 type OuterStruct struct { 3219 PrimitiveField interface{} 3220 ArrayField interface{} 3221 StructArrayField interface{} 3222 MapField map[string]interface{} 3223 StructField interface{} 3224 PointerField interface{} 3225 NilField interface{} 3226 InterfacePointerField *interface{} 3227 } 3228 3229 expected := []byte(`ArrayField = [1, 2, 3] 3230InterfacePointerField = "hello world" 3231PrimitiveField = "string" 3232 3233[MapField] 3234 key1 = "value1" 3235 key2 = false 3236 3237 [MapField.key3] 3238 InnerField = "value3" 3239 3240[PointerField] 3241 InnerField = "yyy" 3242 3243[[StructArrayField]] 3244 InnerField = "s1" 3245 3246[[StructArrayField]] 3247 InnerField = "s2" 3248 3249[StructField] 3250 InnerField = "xxx" 3251`) 3252 3253 var h interface{} = "hello world" 3254 if result, err := Marshal(OuterStruct{ 3255 "string", 3256 []int{1, 2, 3}, 3257 []InnerStruct{{"s1"}, {"s2"}}, 3258 map[string]interface{}{ 3259 "key1": "value1", 3260 "key2": false, 3261 "key3": InnerStruct{"value3"}, 3262 "nil value": nil, 3263 }, 3264 InnerStruct{ 3265 "xxx", 3266 }, 3267 &InnerStruct{ 3268 "yyy", 3269 }, 3270 nil, 3271 &h, 3272 }); err == nil { 3273 if !bytes.Equal(result, expected) { 3274 t.Errorf("Bad marshal: expected\n----\n%s\n----\ngot\n----\n%s\n----\n", expected, result) 3275 } 3276 } else { 3277 t.Fatal(err) 3278 } 3279} 3280 3281func TestUnmarshalToNilInterface(t *testing.T) { 3282 toml := []byte(` 3283PrimitiveField = "Hello" 3284ArrayField = [1,2,3] 3285InterfacePointerField = "World" 3286 3287[StructField] 3288Field1 = 123 3289Field2 = "Field2" 3290 3291[MapField] 3292MapField1 = [4,5,6] 3293MapField2 = {A = "A"} 3294MapField3 = false 3295 3296[[StructArrayField]] 3297Name = "Allen" 3298Age = 20 3299 3300[[StructArrayField]] 3301Name = "Jack" 3302Age = 23 3303`) 3304 3305 type OuterStruct struct { 3306 PrimitiveField interface{} 3307 ArrayField interface{} 3308 StructArrayField interface{} 3309 MapField map[string]interface{} 3310 StructField interface{} 3311 NilField interface{} 3312 InterfacePointerField *interface{} 3313 } 3314 3315 var s interface{} = "World" 3316 expected := OuterStruct{ 3317 PrimitiveField: "Hello", 3318 ArrayField: []interface{}{int64(1), int64(2), int64(3)}, 3319 StructField: map[string]interface{}{ 3320 "Field1": int64(123), 3321 "Field2": "Field2", 3322 }, 3323 MapField: map[string]interface{}{ 3324 "MapField1": []interface{}{int64(4), int64(5), int64(6)}, 3325 "MapField2": map[string]interface{}{ 3326 "A": "A", 3327 }, 3328 "MapField3": false, 3329 }, 3330 NilField: nil, 3331 InterfacePointerField: &s, 3332 StructArrayField: []map[string]interface{}{ 3333 { 3334 "Name": "Allen", 3335 "Age": int64(20), 3336 }, 3337 { 3338 "Name": "Jack", 3339 "Age": int64(23), 3340 }, 3341 }, 3342 } 3343 actual := OuterStruct{} 3344 if err := Unmarshal(toml, &actual); err == nil { 3345 if !reflect.DeepEqual(actual, expected) { 3346 t.Errorf("Bad unmarshal: expected %v, got %v", expected, actual) 3347 } 3348 } else { 3349 t.Fatal(err) 3350 } 3351} 3352 3353func TestUnmarshalToNonNilInterface(t *testing.T) { 3354 toml := []byte(` 3355PrimitiveField = "Allen" 3356ArrayField = [1,2,3] 3357 3358[StructField] 3359InnerField = "After1" 3360 3361[PointerField] 3362InnerField = "After2" 3363 3364[InterfacePointerField] 3365InnerField = "After" 3366 3367[MapField] 3368MapField1 = [4,5,6] 3369MapField2 = {A = "A"} 3370MapField3 = false 3371 3372[[StructArrayField]] 3373InnerField = "After3" 3374 3375[[StructArrayField]] 3376InnerField = "After4" 3377`) 3378 type InnerStruct struct { 3379 InnerField interface{} 3380 } 3381 3382 type OuterStruct struct { 3383 PrimitiveField interface{} 3384 ArrayField interface{} 3385 StructArrayField interface{} 3386 MapField map[string]interface{} 3387 StructField interface{} 3388 PointerField interface{} 3389 NilField interface{} 3390 InterfacePointerField *interface{} 3391 } 3392 3393 var s interface{} = InnerStruct{"After"} 3394 expected := OuterStruct{ 3395 PrimitiveField: "Allen", 3396 ArrayField: []int{1, 2, 3}, 3397 StructField: InnerStruct{InnerField: "After1"}, 3398 MapField: map[string]interface{}{ 3399 "MapField1": []interface{}{int64(4), int64(5), int64(6)}, 3400 "MapField2": map[string]interface{}{ 3401 "A": "A", 3402 }, 3403 "MapField3": false, 3404 }, 3405 PointerField: &InnerStruct{InnerField: "After2"}, 3406 NilField: nil, 3407 InterfacePointerField: &s, 3408 StructArrayField: []InnerStruct{ 3409 {InnerField: "After3"}, 3410 {InnerField: "After4"}, 3411 }, 3412 } 3413 actual := OuterStruct{ 3414 PrimitiveField: "aaa", 3415 ArrayField: []int{100, 200, 300, 400}, 3416 StructField: InnerStruct{InnerField: "Before1"}, 3417 MapField: map[string]interface{}{ 3418 "MapField1": []int{4, 5, 6}, 3419 "MapField2": map[string]string{ 3420 "B": "BBB", 3421 }, 3422 "MapField3": true, 3423 }, 3424 PointerField: &InnerStruct{InnerField: "Before2"}, 3425 NilField: nil, 3426 InterfacePointerField: &s, 3427 StructArrayField: []InnerStruct{ 3428 {InnerField: "Before3"}, 3429 {InnerField: "Before4"}, 3430 }, 3431 } 3432 if err := Unmarshal(toml, &actual); err == nil { 3433 if !reflect.DeepEqual(actual, expected) { 3434 t.Errorf("Bad unmarshal: expected %v, got %v", expected, actual) 3435 } 3436 } else { 3437 t.Fatal(err) 3438 } 3439} 3440 3441func TestUnmarshalEmbedTree(t *testing.T) { 3442 toml := []byte(` 3443OuterField1 = "Out" 3444OuterField2 = 1024 3445 3446[TreeField] 3447InnerField1 = "In" 3448InnerField2 = 2048 3449 3450 [TreeField.EmbedStruct] 3451 EmbedField = "Embed" 3452 3453`) 3454 type InnerStruct struct { 3455 InnerField1 string 3456 InnerField2 int 3457 EmbedStruct struct { 3458 EmbedField string 3459 } 3460 } 3461 3462 type OuterStruct struct { 3463 OuterField1 string 3464 OuterField2 int 3465 TreeField *Tree 3466 } 3467 3468 out := OuterStruct{} 3469 actual := InnerStruct{} 3470 expected := InnerStruct{ 3471 "In", 3472 2048, 3473 struct { 3474 EmbedField string 3475 }{ 3476 EmbedField: "Embed", 3477 }, 3478 } 3479 if err := Unmarshal(toml, &out); err != nil { 3480 t.Fatal(err) 3481 } 3482 if err := out.TreeField.Unmarshal(&actual); err != nil { 3483 t.Fatal(err) 3484 } 3485 3486 if !reflect.DeepEqual(actual, expected) { 3487 t.Errorf("Bad unmarshal: expected %v, got %v", expected, actual) 3488 } 3489} 3490 3491func TestMarshalNil(t *testing.T) { 3492 if _, err := Marshal(nil); err == nil { 3493 t.Errorf("Expected err from nil marshal") 3494 } 3495 if _, err := Marshal((*struct{})(nil)); err == nil { 3496 t.Errorf("Expected err from nil marshal") 3497 } 3498} 3499 3500func TestUnmarshalNil(t *testing.T) { 3501 if err := Unmarshal([]byte(`whatever = "whatever"`), nil); err == nil { 3502 t.Errorf("Expected err from nil marshal") 3503 } 3504 if err := Unmarshal([]byte(`whatever = "whatever"`), (*struct{})(nil)); err == nil { 3505 t.Errorf("Expected err from nil marshal") 3506 } 3507} 3508 3509var sliceTomlDemo = []byte(`str_slice = ["Howdy","Hey There"] 3510str_slice_ptr= ["Howdy","Hey There"] 3511int_slice=[1,2] 3512int_slice_ptr=[1,2] 3513[[struct_slice]] 3514String2="1" 3515[[struct_slice]] 3516String2="2" 3517[[struct_slice_ptr]] 3518String2="1" 3519[[struct_slice_ptr]] 3520String2="2" 3521`) 3522 3523type sliceStruct struct { 3524 Slice []string ` toml:"str_slice" ` 3525 SlicePtr *[]string ` toml:"str_slice_ptr" ` 3526 IntSlice []int ` toml:"int_slice" ` 3527 IntSlicePtr *[]int ` toml:"int_slice_ptr" ` 3528 StructSlice []basicMarshalTestSubStruct ` toml:"struct_slice" ` 3529 StructSlicePtr *[]basicMarshalTestSubStruct ` toml:"struct_slice_ptr" ` 3530} 3531 3532type arrayStruct struct { 3533 Slice [4]string ` toml:"str_slice" ` 3534 SlicePtr *[4]string ` toml:"str_slice_ptr" ` 3535 IntSlice [4]int ` toml:"int_slice" ` 3536 IntSlicePtr *[4]int ` toml:"int_slice_ptr" ` 3537 StructSlice [4]basicMarshalTestSubStruct ` toml:"struct_slice" ` 3538 StructSlicePtr *[4]basicMarshalTestSubStruct ` toml:"struct_slice_ptr" ` 3539} 3540 3541type arrayTooSmallStruct struct { 3542 Slice [1]string ` toml:"str_slice" ` 3543 StructSlice [1]basicMarshalTestSubStruct ` toml:"struct_slice" ` 3544} 3545 3546func TestUnmarshalSlice(t *testing.T) { 3547 tree, _ := LoadBytes(sliceTomlDemo) 3548 tree, _ = TreeFromMap(tree.ToMap()) 3549 3550 var actual sliceStruct 3551 err := tree.Unmarshal(&actual) 3552 if err != nil { 3553 t.Error("shound not err", err) 3554 } 3555 expected := sliceStruct{ 3556 Slice: []string{"Howdy", "Hey There"}, 3557 SlicePtr: &[]string{"Howdy", "Hey There"}, 3558 IntSlice: []int{1, 2}, 3559 IntSlicePtr: &[]int{1, 2}, 3560 StructSlice: []basicMarshalTestSubStruct{{"1"}, {"2"}}, 3561 StructSlicePtr: &[]basicMarshalTestSubStruct{{"1"}, {"2"}}, 3562 } 3563 if !reflect.DeepEqual(actual, expected) { 3564 t.Errorf("Bad unmarshal: expected %v, got %v", expected, actual) 3565 } 3566 3567} 3568 3569func TestUnmarshalSliceFail(t *testing.T) { 3570 tree, _ := TreeFromMap(map[string]interface{}{ 3571 "str_slice": []int{1, 2}, 3572 }) 3573 3574 var actual sliceStruct 3575 err := tree.Unmarshal(&actual) 3576 if err.Error() != "(0, 0): Can't convert 1(int64) to string" { 3577 t.Error("expect err:(0, 0): Can't convert 1(int64) to string but got ", err) 3578 } 3579} 3580 3581func TestUnmarshalSliceFail2(t *testing.T) { 3582 tree, _ := Load(`str_slice=[1,2]`) 3583 3584 var actual sliceStruct 3585 err := tree.Unmarshal(&actual) 3586 if err.Error() != "(1, 1): Can't convert 1(int64) to string" { 3587 t.Error("expect err:(1, 1): Can't convert 1(int64) to string but got ", err) 3588 } 3589 3590} 3591 3592func TestMarshalMixedTypeArray(t *testing.T) { 3593 type InnerStruct struct { 3594 IntField int 3595 StrField string 3596 } 3597 3598 type TestStruct struct { 3599 ArrayField []interface{} 3600 } 3601 3602 expected := []byte(`ArrayField = [3.14, 100, true, "hello world", { IntField = 100, StrField = "inner1" }, [{ IntField = 200, StrField = "inner2" }, { IntField = 300, StrField = "inner3" }]] 3603`) 3604 3605 if result, err := Marshal(TestStruct{ 3606 ArrayField: []interface{}{ 3607 3.14, 3608 100, 3609 true, 3610 "hello world", 3611 InnerStruct{ 3612 IntField: 100, 3613 StrField: "inner1", 3614 }, 3615 []InnerStruct{ 3616 {IntField: 200, StrField: "inner2"}, 3617 {IntField: 300, StrField: "inner3"}, 3618 }, 3619 }, 3620 }); err == nil { 3621 if !bytes.Equal(result, expected) { 3622 t.Errorf("Bad marshal: expected\n----\n%s\n----\ngot\n----\n%s\n----\n", expected, result) 3623 } 3624 } else { 3625 t.Fatal(err) 3626 } 3627} 3628 3629func TestUnmarshalMixedTypeArray(t *testing.T) { 3630 type TestStruct struct { 3631 ArrayField []interface{} 3632 } 3633 3634 toml := []byte(`ArrayField = [3.14,100,true,"hello world",{Field = "inner1"},[{Field = "inner2"},{Field = "inner3"}]] 3635`) 3636 3637 actual := TestStruct{} 3638 expected := TestStruct{ 3639 ArrayField: []interface{}{ 3640 3.14, 3641 int64(100), 3642 true, 3643 "hello world", 3644 map[string]interface{}{ 3645 "Field": "inner1", 3646 }, 3647 []map[string]interface{}{ 3648 {"Field": "inner2"}, 3649 {"Field": "inner3"}, 3650 }, 3651 }, 3652 } 3653 3654 if err := Unmarshal(toml, &actual); err == nil { 3655 if !reflect.DeepEqual(actual, expected) { 3656 t.Errorf("Bad unmarshal: expected %#v, got %#v", expected, actual) 3657 } 3658 } else { 3659 t.Fatal(err) 3660 } 3661} 3662 3663func TestUnmarshalArray(t *testing.T) { 3664 var tree *Tree 3665 var err error 3666 3667 tree, _ = LoadBytes(sliceTomlDemo) 3668 var actual1 arrayStruct 3669 err = tree.Unmarshal(&actual1) 3670 if err != nil { 3671 t.Error("shound not err", err) 3672 } 3673 3674 tree, _ = TreeFromMap(tree.ToMap()) 3675 var actual2 arrayStruct 3676 err = tree.Unmarshal(&actual2) 3677 if err != nil { 3678 t.Error("shound not err", err) 3679 } 3680 3681 expected := arrayStruct{ 3682 Slice: [4]string{"Howdy", "Hey There"}, 3683 SlicePtr: &[4]string{"Howdy", "Hey There"}, 3684 IntSlice: [4]int{1, 2}, 3685 IntSlicePtr: &[4]int{1, 2}, 3686 StructSlice: [4]basicMarshalTestSubStruct{{"1"}, {"2"}}, 3687 StructSlicePtr: &[4]basicMarshalTestSubStruct{{"1"}, {"2"}}, 3688 } 3689 if !reflect.DeepEqual(actual1, expected) { 3690 t.Errorf("Bad unmarshal: expected %v, got %v", expected, actual1) 3691 } 3692 if !reflect.DeepEqual(actual2, expected) { 3693 t.Errorf("Bad unmarshal: expected %v, got %v", expected, actual2) 3694 } 3695} 3696 3697func TestUnmarshalArrayFail(t *testing.T) { 3698 tree, _ := TreeFromMap(map[string]interface{}{ 3699 "str_slice": []string{"Howdy", "Hey There"}, 3700 }) 3701 3702 var actual arrayTooSmallStruct 3703 err := tree.Unmarshal(&actual) 3704 if err.Error() != "(0, 0): unmarshal: TOML array length (2) exceeds destination array length (1)" { 3705 t.Error("expect err:(0, 0): unmarshal: TOML array length (2) exceeds destination array length (1) but got ", err) 3706 } 3707} 3708 3709func TestUnmarshalArrayFail2(t *testing.T) { 3710 tree, _ := Load(`str_slice=["Howdy","Hey There"]`) 3711 3712 var actual arrayTooSmallStruct 3713 err := tree.Unmarshal(&actual) 3714 if err.Error() != "(1, 1): unmarshal: TOML array length (2) exceeds destination array length (1)" { 3715 t.Error("expect err:(1, 1): unmarshal: TOML array length (2) exceeds destination array length (1) but got ", err) 3716 } 3717} 3718 3719func TestUnmarshalArrayFail3(t *testing.T) { 3720 tree, _ := Load(`[[struct_slice]] 3721String2="1" 3722[[struct_slice]] 3723String2="2"`) 3724 3725 var actual arrayTooSmallStruct 3726 err := tree.Unmarshal(&actual) 3727 if err.Error() != "(3, 1): unmarshal: TOML array length (2) exceeds destination array length (1)" { 3728 t.Error("expect err:(3, 1): unmarshal: TOML array length (2) exceeds destination array length (1) but got ", err) 3729 } 3730} 3731 3732func TestDecoderStrict(t *testing.T) { 3733 input := ` 3734[decoded] 3735 key = "" 3736 3737[undecoded] 3738 key = "" 3739 3740 [undecoded.inner] 3741 key = "" 3742 3743 [[undecoded.array]] 3744 key = "" 3745 3746 [[undecoded.array]] 3747 key = "" 3748 3749` 3750 var doc struct { 3751 Decoded struct { 3752 Key string 3753 } 3754 } 3755 3756 expected := `undecoded keys: ["undecoded.array.0.key" "undecoded.array.1.key" "undecoded.inner.key" "undecoded.key"]` 3757 3758 err := NewDecoder(bytes.NewReader([]byte(input))).Strict(true).Decode(&doc) 3759 if err == nil { 3760 t.Error("expected error, got none") 3761 } else if err.Error() != expected { 3762 t.Errorf("expect err: %s, got: %s", expected, err.Error()) 3763 } 3764 3765 if err := NewDecoder(bytes.NewReader([]byte(input))).Decode(&doc); err != nil { 3766 t.Errorf("unexpected err: %s", err) 3767 } 3768 3769 var m map[string]interface{} 3770 if err := NewDecoder(bytes.NewReader([]byte(input))).Decode(&m); err != nil { 3771 t.Errorf("unexpected err: %s", err) 3772 } 3773} 3774 3775func TestDecoderStrictValid(t *testing.T) { 3776 input := ` 3777[decoded] 3778 key = "" 3779` 3780 var doc struct { 3781 Decoded struct { 3782 Key string 3783 } 3784 } 3785 3786 err := NewDecoder(bytes.NewReader([]byte(input))).Strict(true).Decode(&doc) 3787 if err != nil { 3788 t.Fatal("unexpected error:", err) 3789 } 3790} 3791 3792type docUnmarshalTOML struct { 3793 Decoded struct { 3794 Key string 3795 } 3796} 3797 3798func (d *docUnmarshalTOML) UnmarshalTOML(i interface{}) error { 3799 if iMap, ok := i.(map[string]interface{}); !ok { 3800 return fmt.Errorf("type assertion error: wants %T, have %T", map[string]interface{}{}, i) 3801 } else if key, ok := iMap["key"]; !ok { 3802 return fmt.Errorf("key '%s' not in map", "key") 3803 } else if keyString, ok := key.(string); !ok { 3804 return fmt.Errorf("type assertion error: wants %T, have %T", "", key) 3805 } else { 3806 d.Decoded.Key = keyString 3807 } 3808 return nil 3809} 3810 3811func TestDecoderStrictCustomUnmarshal(t *testing.T) { 3812 input := `key = "ok"` 3813 var doc docUnmarshalTOML 3814 err := NewDecoder(bytes.NewReader([]byte(input))).Strict(true).Decode(&doc) 3815 if err != nil { 3816 t.Fatal("unexpected error:", err) 3817 } 3818 if doc.Decoded.Key != "ok" { 3819 t.Errorf("Bad unmarshal: expected ok, got %v", doc.Decoded.Key) 3820 } 3821} 3822 3823type parent struct { 3824 Doc docUnmarshalTOML 3825 DocPointer *docUnmarshalTOML 3826} 3827 3828func TestCustomUnmarshal(t *testing.T) { 3829 input := ` 3830[Doc] 3831 key = "ok1" 3832[DocPointer] 3833 key = "ok2" 3834` 3835 3836 var d parent 3837 if err := Unmarshal([]byte(input), &d); err != nil { 3838 t.Fatalf("unexpected err: %s", err.Error()) 3839 } 3840 if d.Doc.Decoded.Key != "ok1" { 3841 t.Errorf("Bad unmarshal: expected ok, got %v", d.Doc.Decoded.Key) 3842 } 3843 if d.DocPointer.Decoded.Key != "ok2" { 3844 t.Errorf("Bad unmarshal: expected ok, got %v", d.DocPointer.Decoded.Key) 3845 } 3846} 3847 3848func TestCustomUnmarshalError(t *testing.T) { 3849 input := ` 3850[Doc] 3851 key = 1 3852[DocPointer] 3853 key = "ok2" 3854` 3855 3856 expected := "(2, 1): unmarshal toml: type assertion error: wants string, have int64" 3857 3858 var d parent 3859 err := Unmarshal([]byte(input), &d) 3860 if err == nil { 3861 t.Error("expected error, got none") 3862 } else if err.Error() != expected { 3863 t.Errorf("expect err: %s, got: %s", expected, err.Error()) 3864 } 3865} 3866 3867type intWrapper struct { 3868 Value int 3869} 3870 3871func (w *intWrapper) UnmarshalText(text []byte) error { 3872 var err error 3873 if w.Value, err = strconv.Atoi(string(text)); err == nil { 3874 return nil 3875 } 3876 if b, err := strconv.ParseBool(string(text)); err == nil { 3877 if b { 3878 w.Value = 1 3879 } 3880 return nil 3881 } 3882 if f, err := strconv.ParseFloat(string(text), 32); err == nil { 3883 w.Value = int(f) 3884 return nil 3885 } 3886 return fmt.Errorf("unsupported: %s", text) 3887} 3888 3889func TestTextUnmarshal(t *testing.T) { 3890 var doc struct { 3891 UnixTime intWrapper 3892 Version *intWrapper 3893 3894 Bool intWrapper 3895 Int intWrapper 3896 Float intWrapper 3897 } 3898 3899 input := ` 3900UnixTime = "12" 3901Version = "42" 3902Bool = true 3903Int = 21 3904Float = 2.0 3905` 3906 3907 if err := Unmarshal([]byte(input), &doc); err != nil { 3908 t.Fatalf("unexpected err: %s", err.Error()) 3909 } 3910 if doc.UnixTime.Value != 12 { 3911 t.Fatalf("expected UnixTime: 12 got: %d", doc.UnixTime.Value) 3912 } 3913 if doc.Version.Value != 42 { 3914 t.Fatalf("expected Version: 42 got: %d", doc.Version.Value) 3915 } 3916 if doc.Bool.Value != 1 { 3917 t.Fatalf("expected Bool: 1 got: %d", doc.Bool.Value) 3918 } 3919 if doc.Int.Value != 21 { 3920 t.Fatalf("expected Int: 21 got: %d", doc.Int.Value) 3921 } 3922 if doc.Float.Value != 2 { 3923 t.Fatalf("expected Float: 2 got: %d", doc.Float.Value) 3924 } 3925} 3926 3927func TestTextUnmarshalError(t *testing.T) { 3928 var doc struct { 3929 Failer intWrapper 3930 } 3931 3932 input := `Failer = "hello"` 3933 if err := Unmarshal([]byte(input), &doc); err == nil { 3934 t.Fatalf("expected err, got none") 3935 } 3936} 3937 3938// issue406 3939func TestPreserveNotEmptyField(t *testing.T) { 3940 toml := []byte(`Field1 = "ccc"`) 3941 type Inner struct { 3942 InnerField1 string 3943 InnerField2 int 3944 } 3945 type TestStruct struct { 3946 Field1 string 3947 Field2 int 3948 Field3 Inner 3949 } 3950 3951 actual := TestStruct{ 3952 "aaa", 3953 100, 3954 Inner{ 3955 "bbb", 3956 200, 3957 }, 3958 } 3959 3960 expected := TestStruct{ 3961 "ccc", 3962 100, 3963 Inner{ 3964 "bbb", 3965 200, 3966 }, 3967 } 3968 3969 err := Unmarshal(toml, &actual) 3970 if err != nil { 3971 t.Fatal(err) 3972 } 3973 3974 if !reflect.DeepEqual(actual, expected) { 3975 t.Errorf("Bad unmarshal: expected %+v, got %+v", expected, actual) 3976 } 3977} 3978 3979// github issue 432 3980func TestUnmarshalEmptyInterface(t *testing.T) { 3981 doc := []byte(`User = "pelletier"`) 3982 3983 var v interface{} 3984 3985 err := Unmarshal(doc, &v) 3986 if err != nil { 3987 t.Fatal(err) 3988 } 3989 3990 x, ok := v.(map[string]interface{}) 3991 if !ok { 3992 t.Fatal(err) 3993 } 3994 3995 if x["User"] != "pelletier" { 3996 t.Fatalf("expected User=pelletier, but got %v", x) 3997 } 3998} 3999 4000func TestUnmarshalEmptyInterfaceDeep(t *testing.T) { 4001 doc := []byte(` 4002User = "pelletier" 4003Age = 99 4004 4005[foo] 4006bar = 42 4007`) 4008 4009 var v interface{} 4010 4011 err := Unmarshal(doc, &v) 4012 if err != nil { 4013 t.Fatal(err) 4014 } 4015 4016 x, ok := v.(map[string]interface{}) 4017 if !ok { 4018 t.Fatal(err) 4019 } 4020 4021 expected := map[string]interface{}{ 4022 "User": "pelletier", 4023 "Age": 99, 4024 "foo": map[string]interface{}{ 4025 "bar": 42, 4026 }, 4027 } 4028 4029 reflect.DeepEqual(x, expected) 4030} 4031 4032type Config struct { 4033 Key string `toml:"key"` 4034 Obj Custom `toml:"obj"` 4035} 4036 4037type Custom struct { 4038 v string 4039} 4040 4041func (c *Custom) UnmarshalTOML(v interface{}) error { 4042 c.v = "called" 4043 return nil 4044} 4045 4046func TestGithubIssue431(t *testing.T) { 4047 doc := `key = "value"` 4048 tree, err := LoadBytes([]byte(doc)) 4049 if err != nil { 4050 t.Fatalf("unexpected error: %s", err) 4051 } 4052 4053 var c Config 4054 if err := tree.Unmarshal(&c); err != nil { 4055 t.Fatalf("unexpected error: %s", err) 4056 } 4057 4058 if c.Key != "value" { 4059 t.Errorf("expected c.Key='value', not '%s'", c.Key) 4060 } 4061 4062 if c.Obj.v == "called" { 4063 t.Errorf("UnmarshalTOML should not have been called") 4064 } 4065} 4066 4067type durationString struct { 4068 time.Duration 4069} 4070 4071func (d *durationString) UnmarshalTOML(v interface{}) error { 4072 d.Duration = 10 * time.Second 4073 return nil 4074} 4075 4076type config437Error struct { 4077} 4078 4079func (e *config437Error) UnmarshalTOML(v interface{}) error { 4080 return errors.New("expected") 4081} 4082 4083type config437 struct { 4084 HTTP struct { 4085 PingTimeout durationString `toml:"PingTimeout"` 4086 ErrorField config437Error 4087 } `toml:"HTTP"` 4088} 4089 4090func TestGithubIssue437(t *testing.T) { 4091 src := ` 4092[HTTP] 4093PingTimeout = "32m" 4094` 4095 cfg := &config437{} 4096 cfg.HTTP.PingTimeout = durationString{time.Second} 4097 4098 r := strings.NewReader(src) 4099 err := NewDecoder(r).Decode(cfg) 4100 if err != nil { 4101 t.Fatalf("unexpected errors %s", err) 4102 } 4103 expected := durationString{10 * time.Second} 4104 if cfg.HTTP.PingTimeout != expected { 4105 t.Fatalf("expected '%s', got '%s'", expected, cfg.HTTP.PingTimeout) 4106 } 4107} 4108 4109func TestLeafUnmarshalerError(t *testing.T) { 4110 src := ` 4111[HTTP] 4112ErrorField = "foo" 4113` 4114 cfg := &config437{} 4115 4116 r := strings.NewReader(src) 4117 err := NewDecoder(r).Decode(cfg) 4118 if err == nil { 4119 t.Fatalf("error was expected") 4120 } 4121} 4122