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() 2198 } 2199 if err.Error() != "(1, 1): Can't convert 1z(string) to time.Duration. time: unknown unit z in duration 1z" { 2200 t.Fatalf("unexpected error: %s", err) 2201 } 2202} 2203 2204var testCamelCaseKeyToml = []byte(`fooBar = 10`) 2205 2206func TestUnmarshalCamelCaseKey(t *testing.T) { 2207 var x struct { 2208 FooBar int 2209 B int 2210 } 2211 2212 if err := Unmarshal(testCamelCaseKeyToml, &x); err != nil { 2213 t.Fatal(err) 2214 } 2215 2216 if x.FooBar != 10 { 2217 t.Fatal("Did not set camelCase'd key") 2218 } 2219} 2220 2221func TestUnmarshalNegativeUint(t *testing.T) { 2222 type check struct{ U uint } 2223 2224 tree, _ := Load("u = -1") 2225 err := tree.Unmarshal(&check{}) 2226 if err.Error() != "(1, 1): -1(int64) is negative so does not fit in uint" { 2227 t.Error("expect err:(1, 1): -1(int64) is negative so does not fit in uint but got:", err) 2228 } 2229} 2230 2231func TestUnmarshalCheckConversionFloatInt(t *testing.T) { 2232 type conversionCheck struct { 2233 U uint 2234 I int 2235 F float64 2236 } 2237 2238 treeU, _ := Load("u = 1e300") 2239 treeI, _ := Load("i = 1e300") 2240 treeF, _ := Load("f = 9223372036854775806") 2241 2242 errU := treeU.Unmarshal(&conversionCheck{}) 2243 errI := treeI.Unmarshal(&conversionCheck{}) 2244 errF := treeF.Unmarshal(&conversionCheck{}) 2245 2246 if errU.Error() != "(1, 1): Can't convert 1e+300(float64) to uint" { 2247 t.Error("expect err:(1, 1): Can't convert 1e+300(float64) to uint but got:", errU) 2248 } 2249 if errI.Error() != "(1, 1): Can't convert 1e+300(float64) to int" { 2250 t.Error("expect err:(1, 1): Can't convert 1e+300(float64) to int but got:", errI) 2251 } 2252 if errF.Error() != "(1, 1): Can't convert 9223372036854775806(int64) to float64" { 2253 t.Error("expect err:(1, 1): Can't convert 9223372036854775806(int64) to float64 but got:", errF) 2254 } 2255} 2256 2257func TestUnmarshalOverflow(t *testing.T) { 2258 type overflow struct { 2259 U8 uint8 2260 I8 int8 2261 F32 float32 2262 } 2263 2264 treeU8, _ := Load("u8 = 300") 2265 treeI8, _ := Load("i8 = 300") 2266 treeF32, _ := Load("f32 = 1e300") 2267 2268 errU8 := treeU8.Unmarshal(&overflow{}) 2269 errI8 := treeI8.Unmarshal(&overflow{}) 2270 errF32 := treeF32.Unmarshal(&overflow{}) 2271 2272 if errU8.Error() != "(1, 1): 300(int64) would overflow uint8" { 2273 t.Error("expect err:(1, 1): 300(int64) would overflow uint8 but got:", errU8) 2274 } 2275 if errI8.Error() != "(1, 1): 300(int64) would overflow int8" { 2276 t.Error("expect err:(1, 1): 300(int64) would overflow int8 but got:", errI8) 2277 } 2278 if errF32.Error() != "(1, 1): 1e+300(float64) would overflow float32" { 2279 t.Error("expect err:(1, 1): 1e+300(float64) would overflow float32 but got:", errF32) 2280 } 2281} 2282 2283func TestUnmarshalDefault(t *testing.T) { 2284 type EmbeddedStruct struct { 2285 StringField string `default:"c"` 2286 } 2287 2288 type aliasUint uint 2289 2290 var doc struct { 2291 StringField string `default:"a"` 2292 BoolField bool `default:"true"` 2293 UintField uint `default:"1"` 2294 Uint8Field uint8 `default:"8"` 2295 Uint16Field uint16 `default:"16"` 2296 Uint32Field uint32 `default:"32"` 2297 Uint64Field uint64 `default:"64"` 2298 IntField int `default:"-1"` 2299 Int8Field int8 `default:"-8"` 2300 Int16Field int16 `default:"-16"` 2301 Int32Field int32 `default:"-32"` 2302 Int64Field int64 `default:"-64"` 2303 Float32Field float32 `default:"32.1"` 2304 Float64Field float64 `default:"64.1"` 2305 NonEmbeddedStruct struct { 2306 StringField string `default:"b"` 2307 } 2308 EmbeddedStruct 2309 AliasUintField aliasUint `default:"1000"` 2310 } 2311 2312 err := Unmarshal([]byte(``), &doc) 2313 if err != nil { 2314 t.Fatal(err) 2315 } 2316 if doc.BoolField != true { 2317 t.Errorf("BoolField should be true, not %t", doc.BoolField) 2318 } 2319 if doc.StringField != "a" { 2320 t.Errorf("StringField should be \"a\", not %s", doc.StringField) 2321 } 2322 if doc.UintField != 1 { 2323 t.Errorf("UintField should be 1, not %d", doc.UintField) 2324 } 2325 if doc.Uint8Field != 8 { 2326 t.Errorf("Uint8Field should be 8, not %d", doc.Uint8Field) 2327 } 2328 if doc.Uint16Field != 16 { 2329 t.Errorf("Uint16Field should be 16, not %d", doc.Uint16Field) 2330 } 2331 if doc.Uint32Field != 32 { 2332 t.Errorf("Uint32Field should be 32, not %d", doc.Uint32Field) 2333 } 2334 if doc.Uint64Field != 64 { 2335 t.Errorf("Uint64Field should be 64, not %d", doc.Uint64Field) 2336 } 2337 if doc.IntField != -1 { 2338 t.Errorf("IntField should be -1, not %d", doc.IntField) 2339 } 2340 if doc.Int8Field != -8 { 2341 t.Errorf("Int8Field should be -8, not %d", doc.Int8Field) 2342 } 2343 if doc.Int16Field != -16 { 2344 t.Errorf("Int16Field should be -16, not %d", doc.Int16Field) 2345 } 2346 if doc.Int32Field != -32 { 2347 t.Errorf("Int32Field should be -32, not %d", doc.Int32Field) 2348 } 2349 if doc.Int64Field != -64 { 2350 t.Errorf("Int64Field should be -64, not %d", doc.Int64Field) 2351 } 2352 if doc.Float32Field != 32.1 { 2353 t.Errorf("Float32Field should be 32.1, not %f", doc.Float32Field) 2354 } 2355 if doc.Float64Field != 64.1 { 2356 t.Errorf("Float64Field should be 64.1, not %f", doc.Float64Field) 2357 } 2358 if doc.NonEmbeddedStruct.StringField != "b" { 2359 t.Errorf("StringField should be \"b\", not %s", doc.NonEmbeddedStruct.StringField) 2360 } 2361 if doc.EmbeddedStruct.StringField != "c" { 2362 t.Errorf("StringField should be \"c\", not %s", doc.EmbeddedStruct.StringField) 2363 } 2364 if doc.AliasUintField != 1000 { 2365 t.Errorf("AliasUintField should be 1000, not %d", doc.AliasUintField) 2366 } 2367} 2368 2369func TestUnmarshalDefaultFailureBool(t *testing.T) { 2370 var doc struct { 2371 Field bool `default:"blah"` 2372 } 2373 2374 err := Unmarshal([]byte(``), &doc) 2375 if err == nil { 2376 t.Fatal("should error") 2377 } 2378} 2379 2380func TestUnmarshalDefaultFailureInt(t *testing.T) { 2381 var doc struct { 2382 Field int `default:"blah"` 2383 } 2384 2385 err := Unmarshal([]byte(``), &doc) 2386 if err == nil { 2387 t.Fatal("should error") 2388 } 2389} 2390 2391func TestUnmarshalDefaultFailureInt64(t *testing.T) { 2392 var doc struct { 2393 Field int64 `default:"blah"` 2394 } 2395 2396 err := Unmarshal([]byte(``), &doc) 2397 if err == nil { 2398 t.Fatal("should error") 2399 } 2400} 2401 2402func TestUnmarshalDefaultFailureFloat64(t *testing.T) { 2403 var doc struct { 2404 Field float64 `default:"blah"` 2405 } 2406 2407 err := Unmarshal([]byte(``), &doc) 2408 if err == nil { 2409 t.Fatal("should error") 2410 } 2411} 2412 2413func TestUnmarshalDefaultFailureUnsupported(t *testing.T) { 2414 var doc struct { 2415 Field struct{} `default:"blah"` 2416 } 2417 2418 err := Unmarshal([]byte(``), &doc) 2419 if err == nil { 2420 t.Fatal("should error") 2421 } 2422} 2423 2424func TestMarshalNestedAnonymousStructs(t *testing.T) { 2425 type Embedded struct { 2426 Value string `toml:"value"` 2427 Top struct { 2428 Value string `toml:"value"` 2429 } `toml:"top"` 2430 } 2431 2432 type Named struct { 2433 Value string `toml:"value"` 2434 } 2435 2436 var doc struct { 2437 Embedded 2438 Named `toml:"named"` 2439 Anonymous struct { 2440 Value string `toml:"value"` 2441 } `toml:"anonymous"` 2442 } 2443 2444 expected := `value = "" 2445 2446[anonymous] 2447 value = "" 2448 2449[named] 2450 value = "" 2451 2452[top] 2453 value = "" 2454` 2455 2456 result, err := Marshal(doc) 2457 if err != nil { 2458 t.Fatalf("unexpected error: %s", err.Error()) 2459 } 2460 if !bytes.Equal(result, []byte(expected)) { 2461 t.Errorf("Bad marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expected, string(result)) 2462 } 2463} 2464 2465func TestEncoderPromoteNestedAnonymousStructs(t *testing.T) { 2466 type Embedded struct { 2467 Value string `toml:"value"` 2468 } 2469 2470 var doc struct { 2471 Embedded 2472 } 2473 2474 expected := ` 2475[Embedded] 2476 value = "" 2477` 2478 var buf bytes.Buffer 2479 if err := NewEncoder(&buf).PromoteAnonymous(true).Encode(doc); err != nil { 2480 t.Fatalf("unexpected error: %s", err.Error()) 2481 } 2482 if !bytes.Equal(buf.Bytes(), []byte(expected)) { 2483 t.Errorf("Bad marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expected, buf.String()) 2484 } 2485} 2486 2487func TestMarshalNestedAnonymousStructs_DuplicateField(t *testing.T) { 2488 type Embedded struct { 2489 Value string `toml:"value"` 2490 Top struct { 2491 Value string `toml:"value"` 2492 } `toml:"top"` 2493 } 2494 2495 var doc struct { 2496 Value string `toml:"value"` 2497 Embedded 2498 } 2499 doc.Embedded.Value = "shadowed" 2500 doc.Value = "shadows" 2501 2502 expected := `value = "shadows" 2503 2504[top] 2505 value = "" 2506` 2507 2508 result, err := Marshal(doc) 2509 if err != nil { 2510 t.Fatalf("unexpected error: %s", err.Error()) 2511 } 2512 if !bytes.Equal(result, []byte(expected)) { 2513 t.Errorf("Bad marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expected, string(result)) 2514 } 2515} 2516 2517func TestUnmarshalNestedAnonymousStructs(t *testing.T) { 2518 type Nested struct { 2519 Value string `toml:"nested_field"` 2520 } 2521 type Deep struct { 2522 Nested 2523 } 2524 type Document struct { 2525 Deep 2526 Value string `toml:"own_field"` 2527 } 2528 2529 var doc Document 2530 2531 err := Unmarshal([]byte(`nested_field = "nested value"`+"\n"+`own_field = "own value"`), &doc) 2532 if err != nil { 2533 t.Fatal("should not error") 2534 } 2535 if doc.Value != "own value" || doc.Nested.Value != "nested value" { 2536 t.Fatal("unexpected values") 2537 } 2538} 2539 2540func TestUnmarshalNestedAnonymousStructs_Controversial(t *testing.T) { 2541 type Nested struct { 2542 Value string `toml:"nested"` 2543 } 2544 type Deep struct { 2545 Nested 2546 } 2547 type Document struct { 2548 Deep 2549 Value string `toml:"own"` 2550 } 2551 2552 var doc Document 2553 2554 err := Unmarshal([]byte(`nested = "nested value"`+"\n"+`own = "own value"`), &doc) 2555 if err == nil { 2556 t.Fatal("should error") 2557 } 2558} 2559 2560type unexportedFieldPreservationTest struct { 2561 Exported string `toml:"exported"` 2562 unexported string 2563 Nested1 unexportedFieldPreservationTestNested `toml:"nested1"` 2564 Nested2 *unexportedFieldPreservationTestNested `toml:"nested2"` 2565 Nested3 *unexportedFieldPreservationTestNested `toml:"nested3"` 2566 Slice1 []unexportedFieldPreservationTestNested `toml:"slice1"` 2567 Slice2 []*unexportedFieldPreservationTestNested `toml:"slice2"` 2568} 2569 2570type unexportedFieldPreservationTestNested struct { 2571 Exported1 string `toml:"exported1"` 2572 unexported1 string 2573} 2574 2575func TestUnmarshalPreservesUnexportedFields(t *testing.T) { 2576 toml := ` 2577 exported = "visible" 2578 unexported = "ignored" 2579 2580 [nested1] 2581 exported1 = "visible1" 2582 unexported1 = "ignored1" 2583 2584 [nested2] 2585 exported1 = "visible2" 2586 unexported1 = "ignored2" 2587 2588 [nested3] 2589 exported1 = "visible3" 2590 unexported1 = "ignored3" 2591 2592 [[slice1]] 2593 exported1 = "visible3" 2594 2595 [[slice1]] 2596 exported1 = "visible4" 2597 2598 [[slice2]] 2599 exported1 = "visible5" 2600 ` 2601 2602 t.Run("unexported field should not be set from toml", func(t *testing.T) { 2603 var actual unexportedFieldPreservationTest 2604 err := Unmarshal([]byte(toml), &actual) 2605 2606 if err != nil { 2607 t.Fatal("did not expect an error") 2608 } 2609 2610 expect := unexportedFieldPreservationTest{ 2611 Exported: "visible", 2612 unexported: "", 2613 Nested1: unexportedFieldPreservationTestNested{"visible1", ""}, 2614 Nested2: &unexportedFieldPreservationTestNested{"visible2", ""}, 2615 Nested3: &unexportedFieldPreservationTestNested{"visible3", ""}, 2616 Slice1: []unexportedFieldPreservationTestNested{ 2617 {Exported1: "visible3"}, 2618 {Exported1: "visible4"}, 2619 }, 2620 Slice2: []*unexportedFieldPreservationTestNested{ 2621 {Exported1: "visible5"}, 2622 }, 2623 } 2624 2625 if !reflect.DeepEqual(actual, expect) { 2626 t.Fatalf("%+v did not equal %+v", actual, expect) 2627 } 2628 }) 2629 2630 t.Run("unexported field should be preserved", func(t *testing.T) { 2631 actual := unexportedFieldPreservationTest{ 2632 Exported: "foo", 2633 unexported: "bar", 2634 Nested1: unexportedFieldPreservationTestNested{"baz", "bax"}, 2635 Nested2: nil, 2636 Nested3: &unexportedFieldPreservationTestNested{"baz", "bax"}, 2637 } 2638 err := Unmarshal([]byte(toml), &actual) 2639 2640 if err != nil { 2641 t.Fatal("did not expect an error") 2642 } 2643 2644 expect := unexportedFieldPreservationTest{ 2645 Exported: "visible", 2646 unexported: "bar", 2647 Nested1: unexportedFieldPreservationTestNested{"visible1", "bax"}, 2648 Nested2: &unexportedFieldPreservationTestNested{"visible2", ""}, 2649 Nested3: &unexportedFieldPreservationTestNested{"visible3", "bax"}, 2650 Slice1: []unexportedFieldPreservationTestNested{ 2651 {Exported1: "visible3"}, 2652 {Exported1: "visible4"}, 2653 }, 2654 Slice2: []*unexportedFieldPreservationTestNested{ 2655 {Exported1: "visible5"}, 2656 }, 2657 } 2658 2659 if !reflect.DeepEqual(actual, expect) { 2660 t.Fatalf("%+v did not equal %+v", actual, expect) 2661 } 2662 }) 2663} 2664 2665func TestTreeMarshal(t *testing.T) { 2666 cases := [][]byte{ 2667 basicTestToml, 2668 marshalTestToml, 2669 emptyTestToml, 2670 pointerTestToml, 2671 } 2672 for _, expected := range cases { 2673 t.Run("", func(t *testing.T) { 2674 tree, err := LoadBytes(expected) 2675 if err != nil { 2676 t.Fatal(err) 2677 } 2678 result, err := tree.Marshal() 2679 if err != nil { 2680 t.Fatal(err) 2681 } 2682 if !bytes.Equal(result, expected) { 2683 t.Errorf("Bad marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expected, result) 2684 } 2685 }) 2686 } 2687} 2688 2689func TestMarshalArrays(t *testing.T) { 2690 cases := []struct { 2691 Data interface{} 2692 Expected string 2693 }{ 2694 { 2695 Data: struct { 2696 XY [2]int 2697 }{ 2698 XY: [2]int{1, 2}, 2699 }, 2700 Expected: `XY = [1, 2] 2701`, 2702 }, 2703 { 2704 Data: struct { 2705 XY [1][2]int 2706 }{ 2707 XY: [1][2]int{{1, 2}}, 2708 }, 2709 Expected: `XY = [[1, 2]] 2710`, 2711 }, 2712 { 2713 Data: struct { 2714 XY [1][]int 2715 }{ 2716 XY: [1][]int{{1, 2}}, 2717 }, 2718 Expected: `XY = [[1, 2]] 2719`, 2720 }, 2721 { 2722 Data: struct { 2723 XY [][2]int 2724 }{ 2725 XY: [][2]int{{1, 2}}, 2726 }, 2727 Expected: `XY = [[1, 2]] 2728`, 2729 }, 2730 } 2731 for _, tc := range cases { 2732 t.Run("", func(t *testing.T) { 2733 result, err := Marshal(tc.Data) 2734 if err != nil { 2735 t.Fatal(err) 2736 } 2737 if !bytes.Equal(result, []byte(tc.Expected)) { 2738 t.Errorf("Bad marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", []byte(tc.Expected), result) 2739 } 2740 }) 2741 } 2742} 2743 2744func TestUnmarshalLocalDate(t *testing.T) { 2745 t.Run("ToLocalDate", func(t *testing.T) { 2746 type dateStruct struct { 2747 Date LocalDate 2748 } 2749 2750 toml := `date = 1979-05-27` 2751 2752 var obj dateStruct 2753 2754 err := Unmarshal([]byte(toml), &obj) 2755 2756 if err != nil { 2757 t.Fatal(err) 2758 } 2759 2760 if obj.Date.Year != 1979 { 2761 t.Errorf("expected year 1979, got %d", obj.Date.Year) 2762 } 2763 if obj.Date.Month != 5 { 2764 t.Errorf("expected month 5, got %d", obj.Date.Month) 2765 } 2766 if obj.Date.Day != 27 { 2767 t.Errorf("expected day 27, got %d", obj.Date.Day) 2768 } 2769 }) 2770 2771 t.Run("ToLocalDate", func(t *testing.T) { 2772 type dateStruct struct { 2773 Date time.Time 2774 } 2775 2776 toml := `date = 1979-05-27` 2777 2778 var obj dateStruct 2779 2780 err := Unmarshal([]byte(toml), &obj) 2781 2782 if err != nil { 2783 t.Fatal(err) 2784 } 2785 2786 if obj.Date.Year() != 1979 { 2787 t.Errorf("expected year 1979, got %d", obj.Date.Year()) 2788 } 2789 if obj.Date.Month() != 5 { 2790 t.Errorf("expected month 5, got %d", obj.Date.Month()) 2791 } 2792 if obj.Date.Day() != 27 { 2793 t.Errorf("expected day 27, got %d", obj.Date.Day()) 2794 } 2795 }) 2796} 2797 2798func TestMarshalLocalDate(t *testing.T) { 2799 type dateStruct struct { 2800 Date LocalDate 2801 } 2802 2803 obj := dateStruct{Date: LocalDate{ 2804 Year: 1979, 2805 Month: 5, 2806 Day: 27, 2807 }} 2808 2809 b, err := Marshal(obj) 2810 2811 if err != nil { 2812 t.Fatalf("unexpected error: %v", err) 2813 } 2814 2815 got := string(b) 2816 expected := `Date = 1979-05-27 2817` 2818 2819 if got != expected { 2820 t.Errorf("expected '%s', got '%s'", expected, got) 2821 } 2822} 2823 2824func TestUnmarshalLocalDateTime(t *testing.T) { 2825 examples := []struct { 2826 name string 2827 in string 2828 out LocalDateTime 2829 }{ 2830 { 2831 name: "normal", 2832 in: "1979-05-27T07:32:00", 2833 out: LocalDateTime{ 2834 Date: LocalDate{ 2835 Year: 1979, 2836 Month: 5, 2837 Day: 27, 2838 }, 2839 Time: LocalTime{ 2840 Hour: 7, 2841 Minute: 32, 2842 Second: 0, 2843 Nanosecond: 0, 2844 }, 2845 }}, 2846 { 2847 name: "with nanoseconds", 2848 in: "1979-05-27T00:32:00.999999", 2849 out: LocalDateTime{ 2850 Date: LocalDate{ 2851 Year: 1979, 2852 Month: 5, 2853 Day: 27, 2854 }, 2855 Time: LocalTime{ 2856 Hour: 0, 2857 Minute: 32, 2858 Second: 0, 2859 Nanosecond: 999999000, 2860 }, 2861 }, 2862 }, 2863 } 2864 2865 for i, example := range examples { 2866 toml := fmt.Sprintf(`date = %s`, example.in) 2867 2868 t.Run(fmt.Sprintf("ToLocalDateTime_%d_%s", i, example.name), func(t *testing.T) { 2869 type dateStruct struct { 2870 Date LocalDateTime 2871 } 2872 2873 var obj dateStruct 2874 2875 err := Unmarshal([]byte(toml), &obj) 2876 2877 if err != nil { 2878 t.Fatal(err) 2879 } 2880 2881 if obj.Date != example.out { 2882 t.Errorf("expected '%s', got '%s'", example.out, obj.Date) 2883 } 2884 }) 2885 2886 t.Run(fmt.Sprintf("ToTime_%d_%s", i, example.name), func(t *testing.T) { 2887 type dateStruct struct { 2888 Date time.Time 2889 } 2890 2891 var obj dateStruct 2892 2893 err := Unmarshal([]byte(toml), &obj) 2894 2895 if err != nil { 2896 t.Fatal(err) 2897 } 2898 2899 if obj.Date.Year() != example.out.Date.Year { 2900 t.Errorf("expected year %d, got %d", example.out.Date.Year, obj.Date.Year()) 2901 } 2902 if obj.Date.Month() != example.out.Date.Month { 2903 t.Errorf("expected month %d, got %d", example.out.Date.Month, obj.Date.Month()) 2904 } 2905 if obj.Date.Day() != example.out.Date.Day { 2906 t.Errorf("expected day %d, got %d", example.out.Date.Day, obj.Date.Day()) 2907 } 2908 if obj.Date.Hour() != example.out.Time.Hour { 2909 t.Errorf("expected hour %d, got %d", example.out.Time.Hour, obj.Date.Hour()) 2910 } 2911 if obj.Date.Minute() != example.out.Time.Minute { 2912 t.Errorf("expected minute %d, got %d", example.out.Time.Minute, obj.Date.Minute()) 2913 } 2914 if obj.Date.Second() != example.out.Time.Second { 2915 t.Errorf("expected second %d, got %d", example.out.Time.Second, obj.Date.Second()) 2916 } 2917 if obj.Date.Nanosecond() != example.out.Time.Nanosecond { 2918 t.Errorf("expected nanoseconds %d, got %d", example.out.Time.Nanosecond, obj.Date.Nanosecond()) 2919 } 2920 }) 2921 } 2922} 2923 2924func TestMarshalLocalDateTime(t *testing.T) { 2925 type dateStruct struct { 2926 DateTime LocalDateTime 2927 } 2928 2929 examples := []struct { 2930 name string 2931 in LocalDateTime 2932 out string 2933 }{ 2934 { 2935 name: "normal", 2936 out: "DateTime = 1979-05-27T07:32:00\n", 2937 in: LocalDateTime{ 2938 Date: LocalDate{ 2939 Year: 1979, 2940 Month: 5, 2941 Day: 27, 2942 }, 2943 Time: LocalTime{ 2944 Hour: 7, 2945 Minute: 32, 2946 Second: 0, 2947 Nanosecond: 0, 2948 }, 2949 }}, 2950 { 2951 name: "with nanoseconds", 2952 out: "DateTime = 1979-05-27T00:32:00.999999000\n", 2953 in: LocalDateTime{ 2954 Date: LocalDate{ 2955 Year: 1979, 2956 Month: 5, 2957 Day: 27, 2958 }, 2959 Time: LocalTime{ 2960 Hour: 0, 2961 Minute: 32, 2962 Second: 0, 2963 Nanosecond: 999999000, 2964 }, 2965 }, 2966 }, 2967 } 2968 2969 for i, example := range examples { 2970 t.Run(fmt.Sprintf("%d_%s", i, example.name), func(t *testing.T) { 2971 obj := dateStruct{ 2972 DateTime: example.in, 2973 } 2974 b, err := Marshal(obj) 2975 2976 if err != nil { 2977 t.Fatalf("unexpected error: %v", err) 2978 } 2979 2980 got := string(b) 2981 2982 if got != example.out { 2983 t.Errorf("expected '%s', got '%s'", example.out, got) 2984 } 2985 }) 2986 } 2987} 2988 2989func TestUnmarshalLocalTime(t *testing.T) { 2990 examples := []struct { 2991 name string 2992 in string 2993 out LocalTime 2994 }{ 2995 { 2996 name: "normal", 2997 in: "07:32:00", 2998 out: LocalTime{ 2999 Hour: 7, 3000 Minute: 32, 3001 Second: 0, 3002 Nanosecond: 0, 3003 }, 3004 }, 3005 { 3006 name: "with nanoseconds", 3007 in: "00:32:00.999999", 3008 out: LocalTime{ 3009 Hour: 0, 3010 Minute: 32, 3011 Second: 0, 3012 Nanosecond: 999999000, 3013 }, 3014 }, 3015 } 3016 3017 for i, example := range examples { 3018 toml := fmt.Sprintf(`Time = %s`, example.in) 3019 3020 t.Run(fmt.Sprintf("ToLocalTime_%d_%s", i, example.name), func(t *testing.T) { 3021 type dateStruct struct { 3022 Time LocalTime 3023 } 3024 3025 var obj dateStruct 3026 3027 err := Unmarshal([]byte(toml), &obj) 3028 3029 if err != nil { 3030 t.Fatal(err) 3031 } 3032 3033 if obj.Time != example.out { 3034 t.Errorf("expected '%s', got '%s'", example.out, obj.Time) 3035 } 3036 }) 3037 } 3038} 3039 3040func TestMarshalLocalTime(t *testing.T) { 3041 type timeStruct struct { 3042 Time LocalTime 3043 } 3044 3045 examples := []struct { 3046 name string 3047 in LocalTime 3048 out string 3049 }{ 3050 { 3051 name: "normal", 3052 out: "Time = 07:32:00\n", 3053 in: LocalTime{ 3054 Hour: 7, 3055 Minute: 32, 3056 Second: 0, 3057 Nanosecond: 0, 3058 }}, 3059 { 3060 name: "with nanoseconds", 3061 out: "Time = 00:32:00.999999000\n", 3062 in: LocalTime{ 3063 Hour: 0, 3064 Minute: 32, 3065 Second: 0, 3066 Nanosecond: 999999000, 3067 }, 3068 }, 3069 } 3070 3071 for i, example := range examples { 3072 t.Run(fmt.Sprintf("%d_%s", i, example.name), func(t *testing.T) { 3073 obj := timeStruct{ 3074 Time: example.in, 3075 } 3076 b, err := Marshal(obj) 3077 3078 if err != nil { 3079 t.Fatalf("unexpected error: %v", err) 3080 } 3081 3082 got := string(b) 3083 3084 if got != example.out { 3085 t.Errorf("expected '%s', got '%s'", example.out, got) 3086 } 3087 }) 3088 } 3089} 3090 3091// test case for issue #339 3092func TestUnmarshalSameInnerField(t *testing.T) { 3093 type InterStruct2 struct { 3094 Test string 3095 Name string 3096 Age int 3097 } 3098 type Inter2 struct { 3099 Name string 3100 Age int 3101 InterStruct2 InterStruct2 3102 } 3103 type Server struct { 3104 Name string `toml:"name"` 3105 Inter2 Inter2 `toml:"inter2"` 3106 } 3107 3108 var server Server 3109 3110 if err := Unmarshal([]byte(`name = "123" 3111[inter2] 3112name = "inter2" 3113age = 222`), &server); err == nil { 3114 expected := Server{ 3115 Name: "123", 3116 Inter2: Inter2{ 3117 Name: "inter2", 3118 Age: 222, 3119 }, 3120 } 3121 if !reflect.DeepEqual(server, expected) { 3122 t.Errorf("Bad unmarshal: expected %v, got %v", expected, server) 3123 } 3124 } else { 3125 t.Fatalf("unexpected error: %v", err) 3126 } 3127} 3128 3129func TestMarshalInterface(t *testing.T) { 3130 type InnerStruct struct { 3131 InnerField string 3132 } 3133 3134 type OuterStruct struct { 3135 PrimitiveField interface{} 3136 ArrayField interface{} 3137 StructArrayField interface{} 3138 MapField map[string]interface{} 3139 StructField interface{} 3140 PointerField interface{} 3141 NilField interface{} 3142 InterfacePointerField *interface{} 3143 } 3144 3145 expected := []byte(`ArrayField = [1, 2, 3] 3146InterfacePointerField = "hello world" 3147PrimitiveField = "string" 3148 3149[MapField] 3150 key1 = "value1" 3151 key2 = false 3152 3153 [MapField.key3] 3154 InnerField = "value3" 3155 3156[PointerField] 3157 InnerField = "yyy" 3158 3159[[StructArrayField]] 3160 InnerField = "s1" 3161 3162[[StructArrayField]] 3163 InnerField = "s2" 3164 3165[StructField] 3166 InnerField = "xxx" 3167`) 3168 3169 var h interface{} = "hello world" 3170 if result, err := Marshal(OuterStruct{ 3171 "string", 3172 []int{1, 2, 3}, 3173 []InnerStruct{{"s1"}, {"s2"}}, 3174 map[string]interface{}{ 3175 "key1": "value1", 3176 "key2": false, 3177 "key3": InnerStruct{"value3"}, 3178 "nil value": nil, 3179 }, 3180 InnerStruct{ 3181 "xxx", 3182 }, 3183 &InnerStruct{ 3184 "yyy", 3185 }, 3186 nil, 3187 &h, 3188 }); err == nil { 3189 if !bytes.Equal(result, expected) { 3190 t.Errorf("Bad marshal: expected\n----\n%s\n----\ngot\n----\n%s\n----\n", expected, result) 3191 } 3192 } else { 3193 t.Fatal(err) 3194 } 3195} 3196 3197func TestUnmarshalToNilInterface(t *testing.T) { 3198 toml := []byte(` 3199PrimitiveField = "Hello" 3200ArrayField = [1,2,3] 3201InterfacePointerField = "World" 3202 3203[StructField] 3204Field1 = 123 3205Field2 = "Field2" 3206 3207[MapField] 3208MapField1 = [4,5,6] 3209MapField2 = {A = "A"} 3210MapField3 = false 3211 3212[[StructArrayField]] 3213Name = "Allen" 3214Age = 20 3215 3216[[StructArrayField]] 3217Name = "Jack" 3218Age = 23 3219`) 3220 3221 type OuterStruct struct { 3222 PrimitiveField interface{} 3223 ArrayField interface{} 3224 StructArrayField interface{} 3225 MapField map[string]interface{} 3226 StructField interface{} 3227 NilField interface{} 3228 InterfacePointerField *interface{} 3229 } 3230 3231 var s interface{} = "World" 3232 expected := OuterStruct{ 3233 PrimitiveField: "Hello", 3234 ArrayField: []interface{}{int64(1), int64(2), int64(3)}, 3235 StructField: map[string]interface{}{ 3236 "Field1": int64(123), 3237 "Field2": "Field2", 3238 }, 3239 MapField: map[string]interface{}{ 3240 "MapField1": []interface{}{int64(4), int64(5), int64(6)}, 3241 "MapField2": map[string]interface{}{ 3242 "A": "A", 3243 }, 3244 "MapField3": false, 3245 }, 3246 NilField: nil, 3247 InterfacePointerField: &s, 3248 StructArrayField: []map[string]interface{}{ 3249 { 3250 "Name": "Allen", 3251 "Age": int64(20), 3252 }, 3253 { 3254 "Name": "Jack", 3255 "Age": int64(23), 3256 }, 3257 }, 3258 } 3259 actual := OuterStruct{} 3260 if err := Unmarshal(toml, &actual); err == nil { 3261 if !reflect.DeepEqual(actual, expected) { 3262 t.Errorf("Bad unmarshal: expected %v, got %v", expected, actual) 3263 } 3264 } else { 3265 t.Fatal(err) 3266 } 3267} 3268 3269func TestUnmarshalToNonNilInterface(t *testing.T) { 3270 toml := []byte(` 3271PrimitiveField = "Allen" 3272ArrayField = [1,2,3] 3273 3274[StructField] 3275InnerField = "After1" 3276 3277[PointerField] 3278InnerField = "After2" 3279 3280[InterfacePointerField] 3281InnerField = "After" 3282 3283[MapField] 3284MapField1 = [4,5,6] 3285MapField2 = {A = "A"} 3286MapField3 = false 3287 3288[[StructArrayField]] 3289InnerField = "After3" 3290 3291[[StructArrayField]] 3292InnerField = "After4" 3293`) 3294 type InnerStruct struct { 3295 InnerField interface{} 3296 } 3297 3298 type OuterStruct struct { 3299 PrimitiveField interface{} 3300 ArrayField interface{} 3301 StructArrayField interface{} 3302 MapField map[string]interface{} 3303 StructField interface{} 3304 PointerField interface{} 3305 NilField interface{} 3306 InterfacePointerField *interface{} 3307 } 3308 3309 var s interface{} = InnerStruct{"After"} 3310 expected := OuterStruct{ 3311 PrimitiveField: "Allen", 3312 ArrayField: []int{1, 2, 3}, 3313 StructField: InnerStruct{InnerField: "After1"}, 3314 MapField: map[string]interface{}{ 3315 "MapField1": []interface{}{int64(4), int64(5), int64(6)}, 3316 "MapField2": map[string]interface{}{ 3317 "A": "A", 3318 }, 3319 "MapField3": false, 3320 }, 3321 PointerField: &InnerStruct{InnerField: "After2"}, 3322 NilField: nil, 3323 InterfacePointerField: &s, 3324 StructArrayField: []InnerStruct{ 3325 {InnerField: "After3"}, 3326 {InnerField: "After4"}, 3327 }, 3328 } 3329 actual := OuterStruct{ 3330 PrimitiveField: "aaa", 3331 ArrayField: []int{100, 200, 300, 400}, 3332 StructField: InnerStruct{InnerField: "Before1"}, 3333 MapField: map[string]interface{}{ 3334 "MapField1": []int{4, 5, 6}, 3335 "MapField2": map[string]string{ 3336 "B": "BBB", 3337 }, 3338 "MapField3": true, 3339 }, 3340 PointerField: &InnerStruct{InnerField: "Before2"}, 3341 NilField: nil, 3342 InterfacePointerField: &s, 3343 StructArrayField: []InnerStruct{ 3344 {InnerField: "Before3"}, 3345 {InnerField: "Before4"}, 3346 }, 3347 } 3348 if err := Unmarshal(toml, &actual); err == nil { 3349 if !reflect.DeepEqual(actual, expected) { 3350 t.Errorf("Bad unmarshal: expected %v, got %v", expected, actual) 3351 } 3352 } else { 3353 t.Fatal(err) 3354 } 3355} 3356 3357func TestUnmarshalEmbedTree(t *testing.T) { 3358 toml := []byte(` 3359OuterField1 = "Out" 3360OuterField2 = 1024 3361 3362[TreeField] 3363InnerField1 = "In" 3364InnerField2 = 2048 3365 3366 [TreeField.EmbedStruct] 3367 EmbedField = "Embed" 3368 3369`) 3370 type InnerStruct struct { 3371 InnerField1 string 3372 InnerField2 int 3373 EmbedStruct struct { 3374 EmbedField string 3375 } 3376 } 3377 3378 type OuterStruct struct { 3379 OuterField1 string 3380 OuterField2 int 3381 TreeField *Tree 3382 } 3383 3384 out := OuterStruct{} 3385 actual := InnerStruct{} 3386 expected := InnerStruct{ 3387 "In", 3388 2048, 3389 struct { 3390 EmbedField string 3391 }{ 3392 EmbedField: "Embed", 3393 }, 3394 } 3395 if err := Unmarshal(toml, &out); err != nil { 3396 t.Fatal(err) 3397 } 3398 if err := out.TreeField.Unmarshal(&actual); err != nil { 3399 t.Fatal(err) 3400 } 3401 3402 if !reflect.DeepEqual(actual, expected) { 3403 t.Errorf("Bad unmarshal: expected %v, got %v", expected, actual) 3404 } 3405} 3406 3407func TestMarshalNil(t *testing.T) { 3408 if _, err := Marshal(nil); err == nil { 3409 t.Errorf("Expected err from nil marshal") 3410 } 3411 if _, err := Marshal((*struct{})(nil)); err == nil { 3412 t.Errorf("Expected err from nil marshal") 3413 } 3414} 3415 3416func TestUnmarshalNil(t *testing.T) { 3417 if err := Unmarshal([]byte(`whatever = "whatever"`), nil); err == nil { 3418 t.Errorf("Expected err from nil marshal") 3419 } 3420 if err := Unmarshal([]byte(`whatever = "whatever"`), (*struct{})(nil)); err == nil { 3421 t.Errorf("Expected err from nil marshal") 3422 } 3423} 3424 3425var sliceTomlDemo = []byte(`str_slice = ["Howdy","Hey There"] 3426str_slice_ptr= ["Howdy","Hey There"] 3427int_slice=[1,2] 3428int_slice_ptr=[1,2] 3429[[struct_slice]] 3430String2="1" 3431[[struct_slice]] 3432String2="2" 3433[[struct_slice_ptr]] 3434String2="1" 3435[[struct_slice_ptr]] 3436String2="2" 3437`) 3438 3439type sliceStruct struct { 3440 Slice []string ` toml:"str_slice" ` 3441 SlicePtr *[]string ` toml:"str_slice_ptr" ` 3442 IntSlice []int ` toml:"int_slice" ` 3443 IntSlicePtr *[]int ` toml:"int_slice_ptr" ` 3444 StructSlice []basicMarshalTestSubStruct ` toml:"struct_slice" ` 3445 StructSlicePtr *[]basicMarshalTestSubStruct ` toml:"struct_slice_ptr" ` 3446} 3447 3448type arrayStruct struct { 3449 Slice [4]string ` toml:"str_slice" ` 3450 SlicePtr *[4]string ` toml:"str_slice_ptr" ` 3451 IntSlice [4]int ` toml:"int_slice" ` 3452 IntSlicePtr *[4]int ` toml:"int_slice_ptr" ` 3453 StructSlice [4]basicMarshalTestSubStruct ` toml:"struct_slice" ` 3454 StructSlicePtr *[4]basicMarshalTestSubStruct ` toml:"struct_slice_ptr" ` 3455} 3456 3457type arrayTooSmallStruct struct { 3458 Slice [1]string ` toml:"str_slice" ` 3459 StructSlice [1]basicMarshalTestSubStruct ` toml:"struct_slice" ` 3460} 3461 3462func TestUnmarshalSlice(t *testing.T) { 3463 tree, _ := LoadBytes(sliceTomlDemo) 3464 tree, _ = TreeFromMap(tree.ToMap()) 3465 3466 var actual sliceStruct 3467 err := tree.Unmarshal(&actual) 3468 if err != nil { 3469 t.Error("shound not err", err) 3470 } 3471 expected := sliceStruct{ 3472 Slice: []string{"Howdy", "Hey There"}, 3473 SlicePtr: &[]string{"Howdy", "Hey There"}, 3474 IntSlice: []int{1, 2}, 3475 IntSlicePtr: &[]int{1, 2}, 3476 StructSlice: []basicMarshalTestSubStruct{{"1"}, {"2"}}, 3477 StructSlicePtr: &[]basicMarshalTestSubStruct{{"1"}, {"2"}}, 3478 } 3479 if !reflect.DeepEqual(actual, expected) { 3480 t.Errorf("Bad unmarshal: expected %v, got %v", expected, actual) 3481 } 3482 3483} 3484 3485func TestUnmarshalSliceFail(t *testing.T) { 3486 tree, _ := TreeFromMap(map[string]interface{}{ 3487 "str_slice": []int{1, 2}, 3488 }) 3489 3490 var actual sliceStruct 3491 err := tree.Unmarshal(&actual) 3492 if err.Error() != "(0, 0): Can't convert 1(int64) to string" { 3493 t.Error("expect err:(0, 0): Can't convert 1(int64) to string but got ", err) 3494 } 3495} 3496 3497func TestUnmarshalSliceFail2(t *testing.T) { 3498 tree, _ := Load(`str_slice=[1,2]`) 3499 3500 var actual sliceStruct 3501 err := tree.Unmarshal(&actual) 3502 if err.Error() != "(1, 1): Can't convert 1(int64) to string" { 3503 t.Error("expect err:(1, 1): Can't convert 1(int64) to string but got ", err) 3504 } 3505 3506} 3507 3508func TestMarshalMixedTypeArray(t *testing.T) { 3509 type InnerStruct struct { 3510 IntField int 3511 StrField string 3512 } 3513 3514 type TestStruct struct { 3515 ArrayField []interface{} 3516 } 3517 3518 expected := []byte(`ArrayField = [3.14, 100, true, "hello world", { IntField = 100, StrField = "inner1" }, [{ IntField = 200, StrField = "inner2" }, { IntField = 300, StrField = "inner3" }]] 3519`) 3520 3521 if result, err := Marshal(TestStruct{ 3522 ArrayField: []interface{}{ 3523 3.14, 3524 100, 3525 true, 3526 "hello world", 3527 InnerStruct{ 3528 IntField: 100, 3529 StrField: "inner1", 3530 }, 3531 []InnerStruct{ 3532 {IntField: 200, StrField: "inner2"}, 3533 {IntField: 300, StrField: "inner3"}, 3534 }, 3535 }, 3536 }); err == nil { 3537 if !bytes.Equal(result, expected) { 3538 t.Errorf("Bad marshal: expected\n----\n%s\n----\ngot\n----\n%s\n----\n", expected, result) 3539 } 3540 } else { 3541 t.Fatal(err) 3542 } 3543} 3544 3545func TestUnmarshalMixedTypeArray(t *testing.T) { 3546 type TestStruct struct { 3547 ArrayField []interface{} 3548 } 3549 3550 toml := []byte(`ArrayField = [3.14,100,true,"hello world",{Field = "inner1"},[{Field = "inner2"},{Field = "inner3"}]] 3551`) 3552 3553 actual := TestStruct{} 3554 expected := TestStruct{ 3555 ArrayField: []interface{}{ 3556 3.14, 3557 int64(100), 3558 true, 3559 "hello world", 3560 map[string]interface{}{ 3561 "Field": "inner1", 3562 }, 3563 []map[string]interface{}{ 3564 {"Field": "inner2"}, 3565 {"Field": "inner3"}, 3566 }, 3567 }, 3568 } 3569 3570 if err := Unmarshal(toml, &actual); err == nil { 3571 if !reflect.DeepEqual(actual, expected) { 3572 t.Errorf("Bad unmarshal: expected %#v, got %#v", expected, actual) 3573 } 3574 } else { 3575 t.Fatal(err) 3576 } 3577} 3578 3579func TestUnmarshalArray(t *testing.T) { 3580 var tree *Tree 3581 var err error 3582 3583 tree, _ = LoadBytes(sliceTomlDemo) 3584 var actual1 arrayStruct 3585 err = tree.Unmarshal(&actual1) 3586 if err != nil { 3587 t.Error("shound not err", err) 3588 } 3589 3590 tree, _ = TreeFromMap(tree.ToMap()) 3591 var actual2 arrayStruct 3592 err = tree.Unmarshal(&actual2) 3593 if err != nil { 3594 t.Error("shound not err", err) 3595 } 3596 3597 expected := arrayStruct{ 3598 Slice: [4]string{"Howdy", "Hey There"}, 3599 SlicePtr: &[4]string{"Howdy", "Hey There"}, 3600 IntSlice: [4]int{1, 2}, 3601 IntSlicePtr: &[4]int{1, 2}, 3602 StructSlice: [4]basicMarshalTestSubStruct{{"1"}, {"2"}}, 3603 StructSlicePtr: &[4]basicMarshalTestSubStruct{{"1"}, {"2"}}, 3604 } 3605 if !reflect.DeepEqual(actual1, expected) { 3606 t.Errorf("Bad unmarshal: expected %v, got %v", expected, actual1) 3607 } 3608 if !reflect.DeepEqual(actual2, expected) { 3609 t.Errorf("Bad unmarshal: expected %v, got %v", expected, actual2) 3610 } 3611} 3612 3613func TestUnmarshalArrayFail(t *testing.T) { 3614 tree, _ := TreeFromMap(map[string]interface{}{ 3615 "str_slice": []string{"Howdy", "Hey There"}, 3616 }) 3617 3618 var actual arrayTooSmallStruct 3619 err := tree.Unmarshal(&actual) 3620 if err.Error() != "(0, 0): unmarshal: TOML array length (2) exceeds destination array length (1)" { 3621 t.Error("expect err:(0, 0): unmarshal: TOML array length (2) exceeds destination array length (1) but got ", err) 3622 } 3623} 3624 3625func TestUnmarshalArrayFail2(t *testing.T) { 3626 tree, _ := Load(`str_slice=["Howdy","Hey There"]`) 3627 3628 var actual arrayTooSmallStruct 3629 err := tree.Unmarshal(&actual) 3630 if err.Error() != "(1, 1): unmarshal: TOML array length (2) exceeds destination array length (1)" { 3631 t.Error("expect err:(1, 1): unmarshal: TOML array length (2) exceeds destination array length (1) but got ", err) 3632 } 3633} 3634 3635func TestUnmarshalArrayFail3(t *testing.T) { 3636 tree, _ := Load(`[[struct_slice]] 3637String2="1" 3638[[struct_slice]] 3639String2="2"`) 3640 3641 var actual arrayTooSmallStruct 3642 err := tree.Unmarshal(&actual) 3643 if err.Error() != "(3, 1): unmarshal: TOML array length (2) exceeds destination array length (1)" { 3644 t.Error("expect err:(3, 1): unmarshal: TOML array length (2) exceeds destination array length (1) but got ", err) 3645 } 3646} 3647 3648func TestDecoderStrict(t *testing.T) { 3649 input := ` 3650[decoded] 3651 key = "" 3652 3653[undecoded] 3654 key = "" 3655 3656 [undecoded.inner] 3657 key = "" 3658 3659 [[undecoded.array]] 3660 key = "" 3661 3662 [[undecoded.array]] 3663 key = "" 3664 3665` 3666 var doc struct { 3667 Decoded struct { 3668 Key string 3669 } 3670 } 3671 3672 expected := `undecoded keys: ["undecoded.array.0.key" "undecoded.array.1.key" "undecoded.inner.key" "undecoded.key"]` 3673 3674 err := NewDecoder(bytes.NewReader([]byte(input))).Strict(true).Decode(&doc) 3675 if err == nil { 3676 t.Error("expected error, got none") 3677 } else if err.Error() != expected { 3678 t.Errorf("expect err: %s, got: %s", expected, err.Error()) 3679 } 3680 3681 if err := NewDecoder(bytes.NewReader([]byte(input))).Decode(&doc); err != nil { 3682 t.Errorf("unexpected err: %s", err) 3683 } 3684 3685 var m map[string]interface{} 3686 if err := NewDecoder(bytes.NewReader([]byte(input))).Decode(&m); err != nil { 3687 t.Errorf("unexpected err: %s", err) 3688 } 3689} 3690 3691func TestDecoderStrictValid(t *testing.T) { 3692 input := ` 3693[decoded] 3694 key = "" 3695` 3696 var doc struct { 3697 Decoded struct { 3698 Key string 3699 } 3700 } 3701 3702 err := NewDecoder(bytes.NewReader([]byte(input))).Strict(true).Decode(&doc) 3703 if err != nil { 3704 t.Fatal("unexpected error:", err) 3705 } 3706} 3707 3708type docUnmarshalTOML struct { 3709 Decoded struct { 3710 Key string 3711 } 3712} 3713 3714func (d *docUnmarshalTOML) UnmarshalTOML(i interface{}) error { 3715 if iMap, ok := i.(map[string]interface{}); !ok { 3716 return fmt.Errorf("type assertion error: wants %T, have %T", map[string]interface{}{}, i) 3717 } else if key, ok := iMap["key"]; !ok { 3718 return fmt.Errorf("key '%s' not in map", "key") 3719 } else if keyString, ok := key.(string); !ok { 3720 return fmt.Errorf("type assertion error: wants %T, have %T", "", key) 3721 } else { 3722 d.Decoded.Key = keyString 3723 } 3724 return nil 3725} 3726 3727func TestDecoderStrictCustomUnmarshal(t *testing.T) { 3728 input := `key = "ok"` 3729 var doc docUnmarshalTOML 3730 err := NewDecoder(bytes.NewReader([]byte(input))).Strict(true).Decode(&doc) 3731 if err != nil { 3732 t.Fatal("unexpected error:", err) 3733 } 3734 if doc.Decoded.Key != "ok" { 3735 t.Errorf("Bad unmarshal: expected ok, got %v", doc.Decoded.Key) 3736 } 3737} 3738 3739type parent struct { 3740 Doc docUnmarshalTOML 3741 DocPointer *docUnmarshalTOML 3742} 3743 3744func TestCustomUnmarshal(t *testing.T) { 3745 input := ` 3746[Doc] 3747 key = "ok1" 3748[DocPointer] 3749 key = "ok2" 3750` 3751 3752 var d parent 3753 if err := Unmarshal([]byte(input), &d); err != nil { 3754 t.Fatalf("unexpected err: %s", err.Error()) 3755 } 3756 if d.Doc.Decoded.Key != "ok1" { 3757 t.Errorf("Bad unmarshal: expected ok, got %v", d.Doc.Decoded.Key) 3758 } 3759 if d.DocPointer.Decoded.Key != "ok2" { 3760 t.Errorf("Bad unmarshal: expected ok, got %v", d.DocPointer.Decoded.Key) 3761 } 3762} 3763 3764func TestCustomUnmarshalError(t *testing.T) { 3765 input := ` 3766[Doc] 3767 key = 1 3768[DocPointer] 3769 key = "ok2" 3770` 3771 3772 expected := "(2, 1): unmarshal toml: type assertion error: wants string, have int64" 3773 3774 var d parent 3775 err := Unmarshal([]byte(input), &d) 3776 if err == nil { 3777 t.Error("expected error, got none") 3778 } else if err.Error() != expected { 3779 t.Errorf("expect err: %s, got: %s", expected, err.Error()) 3780 } 3781} 3782 3783type intWrapper struct { 3784 Value int 3785} 3786 3787func (w *intWrapper) UnmarshalText(text []byte) error { 3788 var err error 3789 if w.Value, err = strconv.Atoi(string(text)); err == nil { 3790 return nil 3791 } 3792 if b, err := strconv.ParseBool(string(text)); err == nil { 3793 if b { 3794 w.Value = 1 3795 } 3796 return nil 3797 } 3798 if f, err := strconv.ParseFloat(string(text), 32); err == nil { 3799 w.Value = int(f) 3800 return nil 3801 } 3802 return fmt.Errorf("unsupported: %s", text) 3803} 3804 3805func TestTextUnmarshal(t *testing.T) { 3806 var doc struct { 3807 UnixTime intWrapper 3808 Version *intWrapper 3809 3810 Bool intWrapper 3811 Int intWrapper 3812 Float intWrapper 3813 } 3814 3815 input := ` 3816UnixTime = "12" 3817Version = "42" 3818Bool = true 3819Int = 21 3820Float = 2.0 3821` 3822 3823 if err := Unmarshal([]byte(input), &doc); err != nil { 3824 t.Fatalf("unexpected err: %s", err.Error()) 3825 } 3826 if doc.UnixTime.Value != 12 { 3827 t.Fatalf("expected UnixTime: 12 got: %d", doc.UnixTime.Value) 3828 } 3829 if doc.Version.Value != 42 { 3830 t.Fatalf("expected Version: 42 got: %d", doc.Version.Value) 3831 } 3832 if doc.Bool.Value != 1 { 3833 t.Fatalf("expected Bool: 1 got: %d", doc.Bool.Value) 3834 } 3835 if doc.Int.Value != 21 { 3836 t.Fatalf("expected Int: 21 got: %d", doc.Int.Value) 3837 } 3838 if doc.Float.Value != 2 { 3839 t.Fatalf("expected Float: 2 got: %d", doc.Float.Value) 3840 } 3841} 3842 3843func TestTextUnmarshalError(t *testing.T) { 3844 var doc struct { 3845 Failer intWrapper 3846 } 3847 3848 input := `Failer = "hello"` 3849 if err := Unmarshal([]byte(input), &doc); err == nil { 3850 t.Fatalf("expected err, got none") 3851 } 3852} 3853 3854// issue406 3855func TestPreserveNotEmptyField(t *testing.T) { 3856 toml := []byte(`Field1 = "ccc"`) 3857 type Inner struct { 3858 InnerField1 string 3859 InnerField2 int 3860 } 3861 type TestStruct struct { 3862 Field1 string 3863 Field2 int 3864 Field3 Inner 3865 } 3866 3867 actual := TestStruct{ 3868 "aaa", 3869 100, 3870 Inner{ 3871 "bbb", 3872 200, 3873 }, 3874 } 3875 3876 expected := TestStruct{ 3877 "ccc", 3878 100, 3879 Inner{ 3880 "bbb", 3881 200, 3882 }, 3883 } 3884 3885 err := Unmarshal(toml, &actual) 3886 if err != nil { 3887 t.Fatal(err) 3888 } 3889 3890 if !reflect.DeepEqual(actual, expected) { 3891 t.Errorf("Bad unmarshal: expected %+v, got %+v", expected, actual) 3892 } 3893} 3894