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