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