1package toml 2 3import ( 4 "bytes" 5 "encoding/json" 6 "fmt" 7 "io/ioutil" 8 "os" 9 "reflect" 10 "strings" 11 "testing" 12 "time" 13) 14 15type basicMarshalTestStruct struct { 16 String string `toml:"Zstring"` 17 StringList []string `toml:"Ystrlist"` 18 Sub basicMarshalTestSubStruct `toml:"Xsubdoc"` 19 SubList []basicMarshalTestSubStruct `toml:"Wsublist"` 20} 21 22type basicMarshalTestSubStruct struct { 23 String2 string 24} 25 26var basicTestData = basicMarshalTestStruct{ 27 String: "Hello", 28 StringList: []string{"Howdy", "Hey There"}, 29 Sub: basicMarshalTestSubStruct{"One"}, 30 SubList: []basicMarshalTestSubStruct{{"Two"}, {"Three"}}, 31} 32 33var basicTestToml = []byte(`Ystrlist = ["Howdy","Hey There"] 34Zstring = "Hello" 35 36[[Wsublist]] 37 String2 = "Two" 38 39[[Wsublist]] 40 String2 = "Three" 41 42[Xsubdoc] 43 String2 = "One" 44`) 45 46var basicTestTomlOrdered = []byte(`Zstring = "Hello" 47Ystrlist = ["Howdy","Hey There"] 48 49[Xsubdoc] 50 String2 = "One" 51 52[[Wsublist]] 53 String2 = "Two" 54 55[[Wsublist]] 56 String2 = "Three" 57`) 58 59var marshalTestToml = []byte(`title = "TOML Marshal Testing" 60 61[basic] 62 bool = true 63 date = 1979-05-27T07:32:00Z 64 float = 123.4 65 float64 = 123.456782132399 66 int = 5000 67 string = "Bite me" 68 uint = 5001 69 70[basic_lists] 71 bools = [true,false,true] 72 dates = [1979-05-27T07:32:00Z,1980-05-27T07:32:00Z] 73 floats = [12.3,45.6,78.9] 74 ints = [8001,8001,8002] 75 strings = ["One","Two","Three"] 76 uints = [5002,5003] 77 78[basic_map] 79 one = "one" 80 two = "two" 81 82[subdoc] 83 84 [subdoc.first] 85 name = "First" 86 87 [subdoc.second] 88 name = "Second" 89 90[[subdoclist]] 91 name = "List.First" 92 93[[subdoclist]] 94 name = "List.Second" 95 96[[subdocptrs]] 97 name = "Second" 98`) 99 100var marshalOrderPreserveToml = []byte(`title = "TOML Marshal Testing" 101 102[basic_lists] 103 floats = [12.3,45.6,78.9] 104 bools = [true,false,true] 105 dates = [1979-05-27T07:32:00Z,1980-05-27T07:32:00Z] 106 ints = [8001,8001,8002] 107 uints = [5002,5003] 108 strings = ["One","Two","Three"] 109 110[[subdocptrs]] 111 name = "Second" 112 113[basic_map] 114 one = "one" 115 two = "two" 116 117[subdoc] 118 119 [subdoc.second] 120 name = "Second" 121 122 [subdoc.first] 123 name = "First" 124 125[basic] 126 uint = 5001 127 bool = true 128 float = 123.4 129 float64 = 123.456782132399 130 int = 5000 131 string = "Bite me" 132 date = 1979-05-27T07:32:00Z 133 134[[subdoclist]] 135 name = "List.First" 136 137[[subdoclist]] 138 name = "List.Second" 139`) 140 141var mashalOrderPreserveMapToml = []byte(`title = "TOML Marshal Testing" 142 143[basic_map] 144 one = "one" 145 two = "two" 146 147[long_map] 148 a7 = "1" 149 b3 = "2" 150 c8 = "3" 151 d4 = "4" 152 e6 = "5" 153 f5 = "6" 154 g10 = "7" 155 h1 = "8" 156 i2 = "9" 157 j9 = "10" 158`) 159 160func TestBasicMarshal(t *testing.T) { 161 result, err := Marshal(basicTestData) 162 if err != nil { 163 t.Fatal(err) 164 } 165 expected := basicTestToml 166 if !bytes.Equal(result, expected) { 167 t.Errorf("Bad marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expected, result) 168 } 169} 170 171func TestBasicMarshalOrdered(t *testing.T) { 172 var result bytes.Buffer 173 err := NewEncoder(&result).Order(OrderPreserve).Encode(basicTestData) 174 if err != nil { 175 t.Fatal(err) 176 } 177 expected := basicTestTomlOrdered 178 if !bytes.Equal(result.Bytes(), expected) { 179 t.Errorf("Bad marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expected, result.Bytes()) 180 } 181} 182 183func TestBasicMarshalWithPointer(t *testing.T) { 184 result, err := Marshal(&basicTestData) 185 if err != nil { 186 t.Fatal(err) 187 } 188 expected := basicTestToml 189 if !bytes.Equal(result, expected) { 190 t.Errorf("Bad marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expected, result) 191 } 192} 193 194func TestBasicMarshalOrderedWithPointer(t *testing.T) { 195 var result bytes.Buffer 196 err := NewEncoder(&result).Order(OrderPreserve).Encode(&basicTestData) 197 if err != nil { 198 t.Fatal(err) 199 } 200 expected := basicTestTomlOrdered 201 if !bytes.Equal(result.Bytes(), expected) { 202 t.Errorf("Bad marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expected, result.Bytes()) 203 } 204} 205 206func TestBasicUnmarshal(t *testing.T) { 207 result := basicMarshalTestStruct{} 208 err := Unmarshal(basicTestToml, &result) 209 expected := basicTestData 210 if err != nil { 211 t.Fatal(err) 212 } 213 if !reflect.DeepEqual(result, expected) { 214 t.Errorf("Bad unmarshal: expected %v, got %v", expected, result) 215 } 216} 217 218type testDoc struct { 219 Title string `toml:"title"` 220 BasicLists testDocBasicLists `toml:"basic_lists"` 221 SubDocPtrs []*testSubDoc `toml:"subdocptrs"` 222 BasicMap map[string]string `toml:"basic_map"` 223 Subdocs testDocSubs `toml:"subdoc"` 224 Basics testDocBasics `toml:"basic"` 225 SubDocList []testSubDoc `toml:"subdoclist"` 226 err int `toml:"shouldntBeHere"` 227 unexported int `toml:"shouldntBeHere"` 228 Unexported2 int `toml:"-"` 229} 230 231type testMapDoc struct { 232 Title string `toml:"title"` 233 BasicMap map[string]string `toml:"basic_map"` 234 LongMap map[string]string `toml:"long_map"` 235} 236 237type testDocBasics struct { 238 Uint uint `toml:"uint"` 239 Bool bool `toml:"bool"` 240 Float32 float32 `toml:"float"` 241 Float64 float64 `toml:"float64"` 242 Int int `toml:"int"` 243 String *string `toml:"string"` 244 Date time.Time `toml:"date"` 245 unexported int `toml:"shouldntBeHere"` 246} 247 248type testDocBasicLists struct { 249 Floats []*float32 `toml:"floats"` 250 Bools []bool `toml:"bools"` 251 Dates []time.Time `toml:"dates"` 252 Ints []int `toml:"ints"` 253 UInts []uint `toml:"uints"` 254 Strings []string `toml:"strings"` 255} 256 257type testDocSubs struct { 258 Second *testSubDoc `toml:"second"` 259 First testSubDoc `toml:"first"` 260} 261 262type testSubDoc struct { 263 Name string `toml:"name"` 264 unexported int `toml:"shouldntBeHere"` 265} 266 267var biteMe = "Bite me" 268var float1 float32 = 12.3 269var float2 float32 = 45.6 270var float3 float32 = 78.9 271var subdoc = testSubDoc{"Second", 0} 272 273var docData = testDoc{ 274 Title: "TOML Marshal Testing", 275 unexported: 0, 276 Unexported2: 0, 277 Basics: testDocBasics{ 278 Bool: true, 279 Date: time.Date(1979, 5, 27, 7, 32, 0, 0, time.UTC), 280 Float32: 123.4, 281 Float64: 123.456782132399, 282 Int: 5000, 283 Uint: 5001, 284 String: &biteMe, 285 unexported: 0, 286 }, 287 BasicLists: testDocBasicLists{ 288 Bools: []bool{true, false, true}, 289 Dates: []time.Time{ 290 time.Date(1979, 5, 27, 7, 32, 0, 0, time.UTC), 291 time.Date(1980, 5, 27, 7, 32, 0, 0, time.UTC), 292 }, 293 Floats: []*float32{&float1, &float2, &float3}, 294 Ints: []int{8001, 8001, 8002}, 295 Strings: []string{"One", "Two", "Three"}, 296 UInts: []uint{5002, 5003}, 297 }, 298 BasicMap: map[string]string{ 299 "one": "one", 300 "two": "two", 301 }, 302 Subdocs: testDocSubs{ 303 First: testSubDoc{"First", 0}, 304 Second: &subdoc, 305 }, 306 SubDocList: []testSubDoc{ 307 {"List.First", 0}, 308 {"List.Second", 0}, 309 }, 310 SubDocPtrs: []*testSubDoc{&subdoc}, 311} 312 313var mapTestDoc = testMapDoc{ 314 Title: "TOML Marshal Testing", 315 BasicMap: map[string]string{ 316 "one": "one", 317 "two": "two", 318 }, 319 LongMap: map[string]string{ 320 "h1": "8", 321 "i2": "9", 322 "b3": "2", 323 "d4": "4", 324 "f5": "6", 325 "e6": "5", 326 "a7": "1", 327 "c8": "3", 328 "j9": "10", 329 "g10": "7", 330 }, 331} 332 333func TestDocMarshal(t *testing.T) { 334 result, err := Marshal(docData) 335 if err != nil { 336 t.Fatal(err) 337 } 338 if !bytes.Equal(result, marshalTestToml) { 339 t.Errorf("Bad marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", marshalTestToml, result) 340 } 341} 342 343func TestDocMarshalOrdered(t *testing.T) { 344 var result bytes.Buffer 345 err := NewEncoder(&result).Order(OrderPreserve).Encode(docData) 346 if err != nil { 347 t.Fatal(err) 348 } 349 if !bytes.Equal(result.Bytes(), marshalOrderPreserveToml) { 350 t.Errorf("Bad marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", marshalOrderPreserveToml, result.Bytes()) 351 } 352} 353 354func TestDocMarshalMaps(t *testing.T) { 355 result, err := Marshal(mapTestDoc) 356 if err != nil { 357 t.Fatal(err) 358 } 359 if !bytes.Equal(result, mashalOrderPreserveMapToml) { 360 t.Errorf("Bad marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", mashalOrderPreserveMapToml, result) 361 } 362} 363 364func TestDocMarshalOrderedMaps(t *testing.T) { 365 var result bytes.Buffer 366 err := NewEncoder(&result).Order(OrderPreserve).Encode(mapTestDoc) 367 if err != nil { 368 t.Fatal(err) 369 } 370 if !bytes.Equal(result.Bytes(), mashalOrderPreserveMapToml) { 371 t.Errorf("Bad marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", mashalOrderPreserveMapToml, result.Bytes()) 372 } 373} 374 375func TestDocMarshalPointer(t *testing.T) { 376 result, err := Marshal(&docData) 377 if err != nil { 378 t.Fatal(err) 379 } 380 381 if !bytes.Equal(result, marshalTestToml) { 382 t.Errorf("Bad marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", marshalTestToml, result) 383 } 384} 385 386func TestDocUnmarshal(t *testing.T) { 387 result := testDoc{} 388 err := Unmarshal(marshalTestToml, &result) 389 expected := docData 390 if err != nil { 391 t.Fatal(err) 392 } 393 if !reflect.DeepEqual(result, expected) { 394 resStr, _ := json.MarshalIndent(result, "", " ") 395 expStr, _ := json.MarshalIndent(expected, "", " ") 396 t.Errorf("Bad unmarshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expStr, resStr) 397 } 398} 399 400func TestDocPartialUnmarshal(t *testing.T) { 401 file, err := ioutil.TempFile("", "test-*.toml") 402 if err != nil { 403 t.Fatal(err) 404 } 405 defer os.Remove(file.Name()) 406 407 err = ioutil.WriteFile(file.Name(), marshalTestToml, 0) 408 if err != nil { 409 t.Fatal(err) 410 } 411 412 tree, _ := LoadFile(file.Name()) 413 subTree := tree.Get("subdoc").(*Tree) 414 415 result := testDocSubs{} 416 err = subTree.Unmarshal(&result) 417 expected := docData.Subdocs 418 if err != nil { 419 t.Fatal(err) 420 } 421 if !reflect.DeepEqual(result, expected) { 422 resStr, _ := json.MarshalIndent(result, "", " ") 423 expStr, _ := json.MarshalIndent(expected, "", " ") 424 t.Errorf("Bad partial unmartial: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expStr, resStr) 425 } 426} 427 428type tomlTypeCheckTest struct { 429 name string 430 item interface{} 431 typ int //0=primitive, 1=otherslice, 2=treeslice, 3=tree 432} 433 434func TestTypeChecks(t *testing.T) { 435 tests := []tomlTypeCheckTest{ 436 {"bool", true, 0}, 437 {"bool", false, 0}, 438 {"int", int(2), 0}, 439 {"int8", int8(2), 0}, 440 {"int16", int16(2), 0}, 441 {"int32", int32(2), 0}, 442 {"int64", int64(2), 0}, 443 {"uint", uint(2), 0}, 444 {"uint8", uint8(2), 0}, 445 {"uint16", uint16(2), 0}, 446 {"uint32", uint32(2), 0}, 447 {"uint64", uint64(2), 0}, 448 {"float32", float32(3.14), 0}, 449 {"float64", float64(3.14), 0}, 450 {"string", "lorem ipsum", 0}, 451 {"time", time.Date(2015, 1, 1, 0, 0, 0, 0, time.UTC), 0}, 452 {"stringlist", []string{"hello", "hi"}, 1}, 453 {"stringlistptr", &[]string{"hello", "hi"}, 1}, 454 {"stringarray", [2]string{"hello", "hi"}, 1}, 455 {"stringarrayptr", &[2]string{"hello", "hi"}, 1}, 456 {"timelist", []time.Time{time.Date(2015, 1, 1, 0, 0, 0, 0, time.UTC)}, 1}, 457 {"timelistptr", &[]time.Time{time.Date(2015, 1, 1, 0, 0, 0, 0, time.UTC)}, 1}, 458 {"timearray", [1]time.Time{time.Date(2015, 1, 1, 0, 0, 0, 0, time.UTC)}, 1}, 459 {"timearrayptr", &[1]time.Time{time.Date(2015, 1, 1, 0, 0, 0, 0, time.UTC)}, 1}, 460 {"objectlist", []tomlTypeCheckTest{}, 2}, 461 {"objectlistptr", &[]tomlTypeCheckTest{}, 2}, 462 {"objectarray", [2]tomlTypeCheckTest{{}, {}}, 2}, 463 {"objectlistptr", &[2]tomlTypeCheckTest{{}, {}}, 2}, 464 {"object", tomlTypeCheckTest{}, 3}, 465 {"objectptr", &tomlTypeCheckTest{}, 3}, 466 } 467 468 for _, test := range tests { 469 expected := []bool{false, false, false, false} 470 expected[test.typ] = true 471 result := []bool{ 472 isPrimitive(reflect.TypeOf(test.item)), 473 isOtherSequence(reflect.TypeOf(test.item)), 474 isTreeSequence(reflect.TypeOf(test.item)), 475 isTree(reflect.TypeOf(test.item)), 476 } 477 if !reflect.DeepEqual(expected, result) { 478 t.Errorf("Bad type check on %q: expected %v, got %v", test.name, expected, result) 479 } 480 } 481} 482 483type unexportedMarshalTestStruct struct { 484 String string `toml:"string"` 485 StringList []string `toml:"strlist"` 486 Sub basicMarshalTestSubStruct `toml:"subdoc"` 487 SubList []basicMarshalTestSubStruct `toml:"sublist"` 488 unexported int `toml:"shouldntBeHere"` 489 Unexported2 int `toml:"-"` 490} 491 492var unexportedTestData = unexportedMarshalTestStruct{ 493 String: "Hello", 494 StringList: []string{"Howdy", "Hey There"}, 495 Sub: basicMarshalTestSubStruct{"One"}, 496 SubList: []basicMarshalTestSubStruct{{"Two"}, {"Three"}}, 497 unexported: 0, 498 Unexported2: 0, 499} 500 501var unexportedTestToml = []byte(`string = "Hello" 502strlist = ["Howdy","Hey There"] 503unexported = 1 504shouldntBeHere = 2 505 506[subdoc] 507 String2 = "One" 508 509[[sublist]] 510 String2 = "Two" 511 512[[sublist]] 513 String2 = "Three" 514`) 515 516func TestUnexportedUnmarshal(t *testing.T) { 517 result := unexportedMarshalTestStruct{} 518 err := Unmarshal(unexportedTestToml, &result) 519 expected := unexportedTestData 520 if err != nil { 521 t.Fatal(err) 522 } 523 if !reflect.DeepEqual(result, expected) { 524 t.Errorf("Bad unexported unmarshal: expected %v, got %v", expected, result) 525 } 526} 527 528type errStruct struct { 529 Bool bool `toml:"bool"` 530 Date time.Time `toml:"date"` 531 Float float64 `toml:"float"` 532 Int int16 `toml:"int"` 533 String *string `toml:"string"` 534} 535 536var errTomls = []string{ 537 "bool = truly\ndate = 1979-05-27T07:32:00Z\nfloat = 123.4\nint = 5000\nstring = \"Bite me\"", 538 "bool = true\ndate = 1979-05-27T07:3200Z\nfloat = 123.4\nint = 5000\nstring = \"Bite me\"", 539 "bool = true\ndate = 1979-05-27T07:32:00Z\nfloat = 123a4\nint = 5000\nstring = \"Bite me\"", 540 "bool = true\ndate = 1979-05-27T07:32:00Z\nfloat = 123.4\nint = j000\nstring = \"Bite me\"", 541 "bool = true\ndate = 1979-05-27T07:32:00Z\nfloat = 123.4\nint = 5000\nstring = Bite me", 542 "bool = true\ndate = 1979-05-27T07:32:00Z\nfloat = 123.4\nint = 5000\nstring = Bite me", 543 "bool = 1\ndate = 1979-05-27T07:32:00Z\nfloat = 123.4\nint = 5000\nstring = \"Bite me\"", 544 "bool = true\ndate = 1\nfloat = 123.4\nint = 5000\nstring = \"Bite me\"", 545 "bool = true\ndate = 1979-05-27T07:32:00Z\n\"sorry\"\nint = 5000\nstring = \"Bite me\"", 546 "bool = true\ndate = 1979-05-27T07:32:00Z\nfloat = 123.4\nint = \"sorry\"\nstring = \"Bite me\"", 547 "bool = true\ndate = 1979-05-27T07:32:00Z\nfloat = 123.4\nint = 5000\nstring = 1", 548} 549 550type mapErr struct { 551 Vals map[string]float64 552} 553 554type intErr struct { 555 Int1 int 556 Int2 int8 557 Int3 int16 558 Int4 int32 559 Int5 int64 560 UInt1 uint 561 UInt2 uint8 562 UInt3 uint16 563 UInt4 uint32 564 UInt5 uint64 565 Flt1 float32 566 Flt2 float64 567} 568 569var intErrTomls = []string{ 570 "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", 571 "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", 572 "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", 573 "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", 574 "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", 575 "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", 576 "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", 577 "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", 578 "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", 579 "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", 580 "Int1 = 1\nInt2 = 2\nInt3 = 3\nInt4 = 4\nInt5 = 5\nUInt1 = 1\nUInt2 = 2\nUInt3 = 3\nUInt4 = 4\nUInt5 = 5\nFlt1 = []\nFlt2 = 2.0", 581 "Int1 = 1\nInt2 = 2\nInt3 = 3\nInt4 = 4\nInt5 = 5\nUInt1 = 1\nUInt2 = 2\nUInt3 = 3\nUInt4 = 4\nUInt5 = 5\nFlt1 = 1.0\nFlt2 = []", 582} 583 584func TestErrUnmarshal(t *testing.T) { 585 for ind, toml := range errTomls { 586 result := errStruct{} 587 err := Unmarshal([]byte(toml), &result) 588 if err == nil { 589 t.Errorf("Expected err from case %d\n", ind) 590 } 591 } 592 result2 := mapErr{} 593 err := Unmarshal([]byte("[Vals]\nfred=\"1.2\""), &result2) 594 if err == nil { 595 t.Errorf("Expected err from map") 596 } 597 for ind, toml := range intErrTomls { 598 result3 := intErr{} 599 err := Unmarshal([]byte(toml), &result3) 600 if err == nil { 601 t.Errorf("Expected int err from case %d\n", ind) 602 } 603 } 604} 605 606type emptyMarshalTestStruct struct { 607 Title string `toml:"title"` 608 Bool bool `toml:"bool"` 609 Int int `toml:"int"` 610 String string `toml:"string"` 611 StringList []string `toml:"stringlist"` 612 Ptr *basicMarshalTestStruct `toml:"ptr"` 613 Map map[string]string `toml:"map"` 614} 615 616var emptyTestData = emptyMarshalTestStruct{ 617 Title: "Placeholder", 618 Bool: false, 619 Int: 0, 620 String: "", 621 StringList: []string{}, 622 Ptr: nil, 623 Map: map[string]string{}, 624} 625 626var emptyTestToml = []byte(`bool = false 627int = 0 628string = "" 629stringlist = [] 630title = "Placeholder" 631 632[map] 633`) 634 635type emptyMarshalTestStruct2 struct { 636 Title string `toml:"title"` 637 Bool bool `toml:"bool,omitempty"` 638 Int int `toml:"int, omitempty"` 639 String string `toml:"string,omitempty "` 640 StringList []string `toml:"stringlist,omitempty"` 641 Ptr *basicMarshalTestStruct `toml:"ptr,omitempty"` 642 Map map[string]string `toml:"map,omitempty"` 643} 644 645var emptyTestData2 = emptyMarshalTestStruct2{ 646 Title: "Placeholder", 647 Bool: false, 648 Int: 0, 649 String: "", 650 StringList: []string{}, 651 Ptr: nil, 652 Map: map[string]string{}, 653} 654 655var emptyTestToml2 = []byte(`title = "Placeholder" 656`) 657 658func TestEmptyMarshal(t *testing.T) { 659 result, err := Marshal(emptyTestData) 660 if err != nil { 661 t.Fatal(err) 662 } 663 expected := emptyTestToml 664 if !bytes.Equal(result, expected) { 665 t.Errorf("Bad empty marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expected, result) 666 } 667} 668 669func TestEmptyMarshalOmit(t *testing.T) { 670 result, err := Marshal(emptyTestData2) 671 if err != nil { 672 t.Fatal(err) 673 } 674 expected := emptyTestToml2 675 if !bytes.Equal(result, expected) { 676 t.Errorf("Bad empty omit marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expected, result) 677 } 678} 679 680func TestEmptyUnmarshal(t *testing.T) { 681 result := emptyMarshalTestStruct{} 682 err := Unmarshal(emptyTestToml, &result) 683 expected := emptyTestData 684 if err != nil { 685 t.Fatal(err) 686 } 687 if !reflect.DeepEqual(result, expected) { 688 t.Errorf("Bad empty unmarshal: expected %v, got %v", expected, result) 689 } 690} 691 692func TestEmptyUnmarshalOmit(t *testing.T) { 693 result := emptyMarshalTestStruct2{} 694 err := Unmarshal(emptyTestToml, &result) 695 expected := emptyTestData2 696 if err != nil { 697 t.Fatal(err) 698 } 699 if !reflect.DeepEqual(result, expected) { 700 t.Errorf("Bad empty omit unmarshal: expected %v, got %v", expected, result) 701 } 702} 703 704type pointerMarshalTestStruct struct { 705 Str *string 706 List *[]string 707 ListPtr *[]*string 708 Map *map[string]string 709 MapPtr *map[string]*string 710 EmptyStr *string 711 EmptyList *[]string 712 EmptyMap *map[string]string 713 DblPtr *[]*[]*string 714} 715 716var pointerStr = "Hello" 717var pointerList = []string{"Hello back"} 718var pointerListPtr = []*string{&pointerStr} 719var pointerMap = map[string]string{"response": "Goodbye"} 720var pointerMapPtr = map[string]*string{"alternate": &pointerStr} 721var pointerTestData = pointerMarshalTestStruct{ 722 Str: &pointerStr, 723 List: &pointerList, 724 ListPtr: &pointerListPtr, 725 Map: &pointerMap, 726 MapPtr: &pointerMapPtr, 727 EmptyStr: nil, 728 EmptyList: nil, 729 EmptyMap: nil, 730} 731 732var pointerTestToml = []byte(`List = ["Hello back"] 733ListPtr = ["Hello"] 734Str = "Hello" 735 736[Map] 737 response = "Goodbye" 738 739[MapPtr] 740 alternate = "Hello" 741`) 742 743func TestPointerMarshal(t *testing.T) { 744 result, err := Marshal(pointerTestData) 745 if err != nil { 746 t.Fatal(err) 747 } 748 expected := pointerTestToml 749 if !bytes.Equal(result, expected) { 750 t.Errorf("Bad pointer marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expected, result) 751 } 752} 753 754func TestPointerUnmarshal(t *testing.T) { 755 result := pointerMarshalTestStruct{} 756 err := Unmarshal(pointerTestToml, &result) 757 expected := pointerTestData 758 if err != nil { 759 t.Fatal(err) 760 } 761 if !reflect.DeepEqual(result, expected) { 762 t.Errorf("Bad pointer unmarshal: expected %v, got %v", expected, result) 763 } 764} 765 766func TestUnmarshalTypeMismatch(t *testing.T) { 767 result := pointerMarshalTestStruct{} 768 err := Unmarshal([]byte("List = 123"), &result) 769 if !strings.HasPrefix(err.Error(), "(1, 1): Can't convert 123(int64) to []string(slice)") { 770 t.Errorf("Type mismatch must be reported: got %v", err.Error()) 771 } 772} 773 774type nestedMarshalTestStruct struct { 775 String [][]string 776 //Struct [][]basicMarshalTestSubStruct 777 StringPtr *[]*[]*string 778 // StructPtr *[]*[]*basicMarshalTestSubStruct 779} 780 781var str1 = "Three" 782var str2 = "Four" 783var strPtr = []*string{&str1, &str2} 784var strPtr2 = []*[]*string{&strPtr} 785 786var nestedTestData = nestedMarshalTestStruct{ 787 String: [][]string{{"Five", "Six"}, {"One", "Two"}}, 788 StringPtr: &strPtr2, 789} 790 791var nestedTestToml = []byte(`String = [["Five","Six"],["One","Two"]] 792StringPtr = [["Three","Four"]] 793`) 794 795func TestNestedMarshal(t *testing.T) { 796 result, err := Marshal(nestedTestData) 797 if err != nil { 798 t.Fatal(err) 799 } 800 expected := nestedTestToml 801 if !bytes.Equal(result, expected) { 802 t.Errorf("Bad nested marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expected, result) 803 } 804} 805 806func TestNestedUnmarshal(t *testing.T) { 807 result := nestedMarshalTestStruct{} 808 err := Unmarshal(nestedTestToml, &result) 809 expected := nestedTestData 810 if err != nil { 811 t.Fatal(err) 812 } 813 if !reflect.DeepEqual(result, expected) { 814 t.Errorf("Bad nested unmarshal: expected %v, got %v", expected, result) 815 } 816} 817 818type customMarshalerParent struct { 819 Self customMarshaler `toml:"me"` 820 Friends []customMarshaler `toml:"friends"` 821} 822 823type customMarshaler struct { 824 FirsName string 825 LastName string 826} 827 828func (c customMarshaler) MarshalTOML() ([]byte, error) { 829 fullName := fmt.Sprintf("%s %s", c.FirsName, c.LastName) 830 return []byte(fullName), nil 831} 832 833var customMarshalerData = customMarshaler{FirsName: "Sally", LastName: "Fields"} 834var customMarshalerToml = []byte(`Sally Fields`) 835var nestedCustomMarshalerData = customMarshalerParent{ 836 Self: customMarshaler{FirsName: "Maiku", LastName: "Suteda"}, 837 Friends: []customMarshaler{customMarshalerData}, 838} 839var nestedCustomMarshalerToml = []byte(`friends = ["Sally Fields"] 840me = "Maiku Suteda" 841`) 842 843func TestCustomMarshaler(t *testing.T) { 844 result, err := Marshal(customMarshalerData) 845 if err != nil { 846 t.Fatal(err) 847 } 848 expected := customMarshalerToml 849 if !bytes.Equal(result, expected) { 850 t.Errorf("Bad custom marshaler: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expected, result) 851 } 852} 853 854func TestNestedCustomMarshaler(t *testing.T) { 855 result, err := Marshal(nestedCustomMarshalerData) 856 if err != nil { 857 t.Fatal(err) 858 } 859 expected := nestedCustomMarshalerToml 860 if !bytes.Equal(result, expected) { 861 t.Errorf("Bad nested custom marshaler: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expected, result) 862 } 863} 864 865var commentTestToml = []byte(` 866# it's a comment on type 867[postgres] 868 # isCommented = "dvalue" 869 noComment = "cvalue" 870 871 # A comment on AttrB with a 872 # break line 873 password = "bvalue" 874 875 # A comment on AttrA 876 user = "avalue" 877 878 [[postgres.My]] 879 880 # a comment on my on typeC 881 My = "Foo" 882 883 [[postgres.My]] 884 885 # a comment on my on typeC 886 My = "Baar" 887`) 888 889func TestMarshalComment(t *testing.T) { 890 type TypeC struct { 891 My string `comment:"a comment on my on typeC"` 892 } 893 type TypeB struct { 894 AttrA string `toml:"user" comment:"A comment on AttrA"` 895 AttrB string `toml:"password" comment:"A comment on AttrB with a\n break line"` 896 AttrC string `toml:"noComment"` 897 AttrD string `toml:"isCommented" commented:"true"` 898 My []TypeC 899 } 900 type TypeA struct { 901 TypeB TypeB `toml:"postgres" comment:"it's a comment on type"` 902 } 903 904 ta := []TypeC{{My: "Foo"}, {My: "Baar"}} 905 config := TypeA{TypeB{AttrA: "avalue", AttrB: "bvalue", AttrC: "cvalue", AttrD: "dvalue", My: ta}} 906 result, err := Marshal(config) 907 if err != nil { 908 t.Fatal(err) 909 } 910 expected := commentTestToml 911 if !bytes.Equal(result, expected) { 912 t.Errorf("Bad marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expected, result) 913 } 914} 915 916type mapsTestStruct struct { 917 Simple map[string]string 918 Paths map[string]string 919 Other map[string]float64 920 X struct { 921 Y struct { 922 Z map[string]bool 923 } 924 } 925} 926 927var mapsTestData = mapsTestStruct{ 928 Simple: map[string]string{ 929 "one plus one": "two", 930 "next": "three", 931 }, 932 Paths: map[string]string{ 933 "/this/is/a/path": "/this/is/also/a/path", 934 "/heloo.txt": "/tmp/lololo.txt", 935 }, 936 Other: map[string]float64{ 937 "testing": 3.9999, 938 }, 939 X: struct{ Y struct{ Z map[string]bool } }{ 940 Y: struct{ Z map[string]bool }{ 941 Z: map[string]bool{ 942 "is.Nested": true, 943 }, 944 }, 945 }, 946} 947var mapsTestToml = []byte(` 948[Other] 949 "testing" = 3.9999 950 951[Paths] 952 "/heloo.txt" = "/tmp/lololo.txt" 953 "/this/is/a/path" = "/this/is/also/a/path" 954 955[Simple] 956 "next" = "three" 957 "one plus one" = "two" 958 959[X] 960 961 [X.Y] 962 963 [X.Y.Z] 964 "is.Nested" = true 965`) 966 967func TestEncodeQuotedMapKeys(t *testing.T) { 968 var buf bytes.Buffer 969 if err := NewEncoder(&buf).QuoteMapKeys(true).Encode(mapsTestData); err != nil { 970 t.Fatal(err) 971 } 972 result := buf.Bytes() 973 expected := mapsTestToml 974 if !bytes.Equal(result, expected) { 975 t.Errorf("Bad maps marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expected, result) 976 } 977} 978 979func TestDecodeQuotedMapKeys(t *testing.T) { 980 result := mapsTestStruct{} 981 err := NewDecoder(bytes.NewBuffer(mapsTestToml)).Decode(&result) 982 expected := mapsTestData 983 if err != nil { 984 t.Fatal(err) 985 } 986 if !reflect.DeepEqual(result, expected) { 987 t.Errorf("Bad maps unmarshal: expected %v, got %v", expected, result) 988 } 989} 990 991type structArrayNoTag struct { 992 A struct { 993 B []int64 994 C []int64 995 } 996} 997 998func TestMarshalArray(t *testing.T) { 999 expected := []byte(` 1000[A] 1001 B = [1,2,3] 1002 C = [1] 1003`) 1004 1005 m := structArrayNoTag{ 1006 A: struct { 1007 B []int64 1008 C []int64 1009 }{ 1010 B: []int64{1, 2, 3}, 1011 C: []int64{1}, 1012 }, 1013 } 1014 1015 b, err := Marshal(m) 1016 1017 if err != nil { 1018 t.Fatal(err) 1019 } 1020 1021 if !bytes.Equal(b, expected) { 1022 t.Errorf("Bad arrays marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expected, b) 1023 } 1024} 1025 1026func TestMarshalArrayOnePerLine(t *testing.T) { 1027 expected := []byte(` 1028[A] 1029 B = [ 1030 1, 1031 2, 1032 3, 1033 ] 1034 C = [1] 1035`) 1036 1037 m := structArrayNoTag{ 1038 A: struct { 1039 B []int64 1040 C []int64 1041 }{ 1042 B: []int64{1, 2, 3}, 1043 C: []int64{1}, 1044 }, 1045 } 1046 1047 var buf bytes.Buffer 1048 encoder := NewEncoder(&buf).ArraysWithOneElementPerLine(true) 1049 err := encoder.Encode(m) 1050 1051 if err != nil { 1052 t.Fatal(err) 1053 } 1054 1055 b := buf.Bytes() 1056 1057 if !bytes.Equal(b, expected) { 1058 t.Errorf("Bad arrays marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expected, b) 1059 } 1060} 1061 1062var customTagTestToml = []byte(` 1063[postgres] 1064 password = "bvalue" 1065 user = "avalue" 1066 1067 [[postgres.My]] 1068 My = "Foo" 1069 1070 [[postgres.My]] 1071 My = "Baar" 1072`) 1073 1074func TestMarshalCustomTag(t *testing.T) { 1075 type TypeC struct { 1076 My string 1077 } 1078 type TypeB struct { 1079 AttrA string `file:"user"` 1080 AttrB string `file:"password"` 1081 My []TypeC 1082 } 1083 type TypeA struct { 1084 TypeB TypeB `file:"postgres"` 1085 } 1086 1087 ta := []TypeC{{My: "Foo"}, {My: "Baar"}} 1088 config := TypeA{TypeB{AttrA: "avalue", AttrB: "bvalue", My: ta}} 1089 var buf bytes.Buffer 1090 err := NewEncoder(&buf).SetTagName("file").Encode(config) 1091 if err != nil { 1092 t.Fatal(err) 1093 } 1094 expected := customTagTestToml 1095 result := buf.Bytes() 1096 if !bytes.Equal(result, expected) { 1097 t.Errorf("Bad marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expected, result) 1098 } 1099} 1100 1101var customCommentTagTestToml = []byte(` 1102# db connection 1103[postgres] 1104 1105 # db pass 1106 password = "bvalue" 1107 1108 # db user 1109 user = "avalue" 1110`) 1111 1112func TestMarshalCustomComment(t *testing.T) { 1113 type TypeB struct { 1114 AttrA string `toml:"user" descr:"db user"` 1115 AttrB string `toml:"password" descr:"db pass"` 1116 } 1117 type TypeA struct { 1118 TypeB TypeB `toml:"postgres" descr:"db connection"` 1119 } 1120 1121 config := TypeA{TypeB{AttrA: "avalue", AttrB: "bvalue"}} 1122 var buf bytes.Buffer 1123 err := NewEncoder(&buf).SetTagComment("descr").Encode(config) 1124 if err != nil { 1125 t.Fatal(err) 1126 } 1127 expected := customCommentTagTestToml 1128 result := buf.Bytes() 1129 if !bytes.Equal(result, expected) { 1130 t.Errorf("Bad marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expected, result) 1131 } 1132} 1133 1134var customCommentedTagTestToml = []byte(` 1135[postgres] 1136 # password = "bvalue" 1137 # user = "avalue" 1138`) 1139 1140func TestMarshalCustomCommented(t *testing.T) { 1141 type TypeB struct { 1142 AttrA string `toml:"user" disable:"true"` 1143 AttrB string `toml:"password" disable:"true"` 1144 } 1145 type TypeA struct { 1146 TypeB TypeB `toml:"postgres"` 1147 } 1148 1149 config := TypeA{TypeB{AttrA: "avalue", AttrB: "bvalue"}} 1150 var buf bytes.Buffer 1151 err := NewEncoder(&buf).SetTagCommented("disable").Encode(config) 1152 if err != nil { 1153 t.Fatal(err) 1154 } 1155 expected := customCommentedTagTestToml 1156 result := buf.Bytes() 1157 if !bytes.Equal(result, expected) { 1158 t.Errorf("Bad marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expected, result) 1159 } 1160} 1161 1162func TestMarshalDirectMultilineString(t *testing.T) { 1163 tree := newTree() 1164 tree.SetWithOptions("mykey", SetOptions{ 1165 Multiline: true, 1166 }, "my\x11multiline\nstring\ba\tb\fc\rd\"e\\!") 1167 result, err := tree.Marshal() 1168 if err != nil { 1169 t.Fatal("marshal should not error:", err) 1170 } 1171 expected := []byte("mykey = \"\"\"\nmy\\u0011multiline\nstring\\ba\tb\\fc\rd\"e\\!\"\"\"\n") 1172 if !bytes.Equal(result, expected) { 1173 t.Errorf("Bad marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expected, result) 1174 } 1175} 1176 1177var customMultilineTagTestToml = []byte(`int_slice = [ 1178 1, 1179 2, 1180 3, 1181] 1182`) 1183 1184func TestMarshalCustomMultiline(t *testing.T) { 1185 type TypeA struct { 1186 AttrA []int `toml:"int_slice" mltln:"true"` 1187 } 1188 1189 config := TypeA{AttrA: []int{1, 2, 3}} 1190 var buf bytes.Buffer 1191 err := NewEncoder(&buf).ArraysWithOneElementPerLine(true).SetTagMultiline("mltln").Encode(config) 1192 if err != nil { 1193 t.Fatal(err) 1194 } 1195 expected := customMultilineTagTestToml 1196 result := buf.Bytes() 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 1202var testDocBasicToml = []byte(` 1203[document] 1204 bool_val = true 1205 date_val = 1979-05-27T07:32:00Z 1206 float_val = 123.4 1207 int_val = 5000 1208 string_val = "Bite me" 1209 uint_val = 5001 1210`) 1211 1212type testDocCustomTag struct { 1213 Doc testDocBasicsCustomTag `file:"document"` 1214} 1215type testDocBasicsCustomTag struct { 1216 Bool bool `file:"bool_val"` 1217 Date time.Time `file:"date_val"` 1218 Float float32 `file:"float_val"` 1219 Int int `file:"int_val"` 1220 Uint uint `file:"uint_val"` 1221 String *string `file:"string_val"` 1222 unexported int `file:"shouldntBeHere"` 1223} 1224 1225var testDocCustomTagData = testDocCustomTag{ 1226 Doc: testDocBasicsCustomTag{ 1227 Bool: true, 1228 Date: time.Date(1979, 5, 27, 7, 32, 0, 0, time.UTC), 1229 Float: 123.4, 1230 Int: 5000, 1231 Uint: 5001, 1232 String: &biteMe, 1233 unexported: 0, 1234 }, 1235} 1236 1237func TestUnmarshalCustomTag(t *testing.T) { 1238 buf := bytes.NewBuffer(testDocBasicToml) 1239 1240 result := testDocCustomTag{} 1241 err := NewDecoder(buf).SetTagName("file").Decode(&result) 1242 if err != nil { 1243 t.Fatal(err) 1244 } 1245 expected := testDocCustomTagData 1246 if !reflect.DeepEqual(result, expected) { 1247 resStr, _ := json.MarshalIndent(result, "", " ") 1248 expStr, _ := json.MarshalIndent(expected, "", " ") 1249 t.Errorf("Bad unmarshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expStr, resStr) 1250 1251 } 1252} 1253 1254func TestUnmarshalMap(t *testing.T) { 1255 testToml := []byte(` 1256 a = 1 1257 b = 2 1258 c = 3 1259 `) 1260 var result map[string]int 1261 err := Unmarshal(testToml, &result) 1262 if err != nil { 1263 t.Errorf("Received unexpected error: %s", err) 1264 return 1265 } 1266 1267 expected := map[string]int{ 1268 "a": 1, 1269 "b": 2, 1270 "c": 3, 1271 } 1272 1273 if !reflect.DeepEqual(result, expected) { 1274 t.Errorf("Bad unmarshal: expected %v, got %v", expected, result) 1275 } 1276} 1277 1278func TestUnmarshalMapWithTypedKey(t *testing.T) { 1279 testToml := []byte(` 1280 a = 1 1281 b = 2 1282 c = 3 1283 `) 1284 1285 type letter string 1286 var result map[letter]int 1287 err := Unmarshal(testToml, &result) 1288 if err != nil { 1289 t.Errorf("Received unexpected error: %s", err) 1290 return 1291 } 1292 1293 expected := map[letter]int{ 1294 "a": 1, 1295 "b": 2, 1296 "c": 3, 1297 } 1298 1299 if !reflect.DeepEqual(result, expected) { 1300 t.Errorf("Bad unmarshal: expected %v, got %v", expected, result) 1301 } 1302} 1303 1304func TestUnmarshalNonPointer(t *testing.T) { 1305 a := 1 1306 err := Unmarshal([]byte{}, a) 1307 if err == nil { 1308 t.Fatal("unmarshal should err when given a non pointer") 1309 } 1310} 1311 1312func TestUnmarshalInvalidPointerKind(t *testing.T) { 1313 a := 1 1314 err := Unmarshal([]byte{}, &a) 1315 if err == nil { 1316 t.Fatal("unmarshal should err when given an invalid pointer type") 1317 } 1318} 1319 1320func TestMarshalSlice(t *testing.T) { 1321 m := make([]int, 1) 1322 m[0] = 1 1323 1324 var buf bytes.Buffer 1325 err := NewEncoder(&buf).Encode(&m) 1326 if err == nil { 1327 t.Error("expected error, got nil") 1328 return 1329 } 1330 if err.Error() != "Only pointer to struct can be marshaled to TOML" { 1331 t.Fail() 1332 } 1333} 1334 1335func TestMarshalSlicePointer(t *testing.T) { 1336 m := make([]int, 1) 1337 m[0] = 1 1338 1339 var buf bytes.Buffer 1340 err := NewEncoder(&buf).Encode(m) 1341 if err == nil { 1342 t.Error("expected error, got nil") 1343 return 1344 } 1345 if err.Error() != "Only a struct or map can be marshaled to TOML" { 1346 t.Fail() 1347 } 1348} 1349 1350type testDuration struct { 1351 Nanosec time.Duration `toml:"nanosec"` 1352 Microsec1 time.Duration `toml:"microsec1"` 1353 Microsec2 *time.Duration `toml:"microsec2"` 1354 Millisec time.Duration `toml:"millisec"` 1355 Sec time.Duration `toml:"sec"` 1356 Min time.Duration `toml:"min"` 1357 Hour time.Duration `toml:"hour"` 1358 Mixed time.Duration `toml:"mixed"` 1359 AString string `toml:"a_string"` 1360} 1361 1362var testDurationToml = []byte(` 1363nanosec = "1ns" 1364microsec1 = "1us" 1365microsec2 = "1µs" 1366millisec = "1ms" 1367sec = "1s" 1368min = "1m" 1369hour = "1h" 1370mixed = "1h1m1s1ms1µs1ns" 1371a_string = "15s" 1372`) 1373 1374func TestUnmarshalDuration(t *testing.T) { 1375 buf := bytes.NewBuffer(testDurationToml) 1376 1377 result := testDuration{} 1378 err := NewDecoder(buf).Decode(&result) 1379 if err != nil { 1380 t.Fatal(err) 1381 } 1382 ms := time.Duration(1) * time.Microsecond 1383 expected := testDuration{ 1384 Nanosec: 1, 1385 Microsec1: time.Microsecond, 1386 Microsec2: &ms, 1387 Millisec: time.Millisecond, 1388 Sec: time.Second, 1389 Min: time.Minute, 1390 Hour: time.Hour, 1391 Mixed: time.Hour + 1392 time.Minute + 1393 time.Second + 1394 time.Millisecond + 1395 time.Microsecond + 1396 time.Nanosecond, 1397 AString: "15s", 1398 } 1399 if !reflect.DeepEqual(result, expected) { 1400 resStr, _ := json.MarshalIndent(result, "", " ") 1401 expStr, _ := json.MarshalIndent(expected, "", " ") 1402 t.Errorf("Bad unmarshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expStr, resStr) 1403 1404 } 1405} 1406 1407var testDurationToml2 = []byte(`a_string = "15s" 1408hour = "1h0m0s" 1409microsec1 = "1µs" 1410microsec2 = "1µs" 1411millisec = "1ms" 1412min = "1m0s" 1413mixed = "1h1m1.001001001s" 1414nanosec = "1ns" 1415sec = "1s" 1416`) 1417 1418func TestMarshalDuration(t *testing.T) { 1419 ms := time.Duration(1) * time.Microsecond 1420 data := testDuration{ 1421 Nanosec: 1, 1422 Microsec1: time.Microsecond, 1423 Microsec2: &ms, 1424 Millisec: time.Millisecond, 1425 Sec: time.Second, 1426 Min: time.Minute, 1427 Hour: time.Hour, 1428 Mixed: time.Hour + 1429 time.Minute + 1430 time.Second + 1431 time.Millisecond + 1432 time.Microsecond + 1433 time.Nanosecond, 1434 AString: "15s", 1435 } 1436 1437 var buf bytes.Buffer 1438 err := NewEncoder(&buf).Encode(data) 1439 if err != nil { 1440 t.Fatal(err) 1441 } 1442 expected := testDurationToml2 1443 result := buf.Bytes() 1444 if !bytes.Equal(result, expected) { 1445 t.Errorf("Bad marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expected, result) 1446 } 1447} 1448 1449type testBadDuration struct { 1450 Val time.Duration `toml:"val"` 1451} 1452 1453var testBadDurationToml = []byte(`val = "1z"`) 1454 1455func TestUnmarshalBadDuration(t *testing.T) { 1456 buf := bytes.NewBuffer(testBadDurationToml) 1457 1458 result := testBadDuration{} 1459 err := NewDecoder(buf).Decode(&result) 1460 if err == nil { 1461 t.Fatal() 1462 } 1463 if err.Error() != "(1, 1): Can't convert 1z(string) to time.Duration. time: unknown unit z in duration 1z" { 1464 t.Fatalf("unexpected error: %s", err) 1465 } 1466} 1467 1468var testCamelCaseKeyToml = []byte(`fooBar = 10`) 1469 1470func TestUnmarshalCamelCaseKey(t *testing.T) { 1471 var x struct { 1472 FooBar int 1473 B int 1474 } 1475 1476 if err := Unmarshal(testCamelCaseKeyToml, &x); err != nil { 1477 t.Fatal(err) 1478 } 1479 1480 if x.FooBar != 10 { 1481 t.Fatal("Did not set camelCase'd key") 1482 } 1483} 1484 1485func TestUnmarshalDefault(t *testing.T) { 1486 var doc struct { 1487 StringField string `default:"a"` 1488 BoolField bool `default:"true"` 1489 IntField int `default:"1"` 1490 Int64Field int64 `default:"2"` 1491 Float64Field float64 `default:"3.1"` 1492 } 1493 1494 err := Unmarshal([]byte(``), &doc) 1495 if err != nil { 1496 t.Fatal(err) 1497 } 1498 if doc.BoolField != true { 1499 t.Errorf("BoolField should be true, not %t", doc.BoolField) 1500 } 1501 if doc.StringField != "a" { 1502 t.Errorf("StringField should be \"a\", not %s", doc.StringField) 1503 } 1504 if doc.IntField != 1 { 1505 t.Errorf("IntField should be 1, not %d", doc.IntField) 1506 } 1507 if doc.Int64Field != 2 { 1508 t.Errorf("Int64Field should be 2, not %d", doc.Int64Field) 1509 } 1510 if doc.Float64Field != 3.1 { 1511 t.Errorf("Float64Field should be 3.1, not %f", doc.Float64Field) 1512 } 1513} 1514 1515func TestUnmarshalDefaultFailureBool(t *testing.T) { 1516 var doc struct { 1517 Field bool `default:"blah"` 1518 } 1519 1520 err := Unmarshal([]byte(``), &doc) 1521 if err == nil { 1522 t.Fatal("should error") 1523 } 1524} 1525 1526func TestUnmarshalDefaultFailureInt(t *testing.T) { 1527 var doc struct { 1528 Field int `default:"blah"` 1529 } 1530 1531 err := Unmarshal([]byte(``), &doc) 1532 if err == nil { 1533 t.Fatal("should error") 1534 } 1535} 1536 1537func TestUnmarshalDefaultFailureInt64(t *testing.T) { 1538 var doc struct { 1539 Field int64 `default:"blah"` 1540 } 1541 1542 err := Unmarshal([]byte(``), &doc) 1543 if err == nil { 1544 t.Fatal("should error") 1545 } 1546} 1547 1548func TestUnmarshalDefaultFailureFloat64(t *testing.T) { 1549 var doc struct { 1550 Field float64 `default:"blah"` 1551 } 1552 1553 err := Unmarshal([]byte(``), &doc) 1554 if err == nil { 1555 t.Fatal("should error") 1556 } 1557} 1558 1559func TestUnmarshalDefaultFailureUnsupported(t *testing.T) { 1560 var doc struct { 1561 Field struct{} `default:"blah"` 1562 } 1563 1564 err := Unmarshal([]byte(``), &doc) 1565 if err == nil { 1566 t.Fatal("should error") 1567 } 1568} 1569 1570func TestUnmarshalNestedAnonymousStructs(t *testing.T) { 1571 type Nested struct { 1572 Value string `toml:"nested_field"` 1573 } 1574 type Deep struct { 1575 Nested 1576 } 1577 type Document struct { 1578 Deep 1579 Value string `toml:"own_field"` 1580 } 1581 1582 var doc Document 1583 1584 err := Unmarshal([]byte(`nested_field = "nested value"`+"\n"+`own_field = "own value"`), &doc) 1585 if err != nil { 1586 t.Fatal("should not error") 1587 } 1588 if doc.Value != "own value" || doc.Nested.Value != "nested value" { 1589 t.Fatal("unexpected values") 1590 } 1591} 1592 1593func TestUnmarshalNestedAnonymousStructs_Controversial(t *testing.T) { 1594 type Nested struct { 1595 Value string `toml:"nested"` 1596 } 1597 type Deep struct { 1598 Nested 1599 } 1600 type Document struct { 1601 Deep 1602 Value string `toml:"own"` 1603 } 1604 1605 var doc Document 1606 1607 err := Unmarshal([]byte(`nested = "nested value"`+"\n"+`own = "own value"`), &doc) 1608 if err == nil { 1609 t.Fatal("should error") 1610 } 1611} 1612 1613type unexportedFieldPreservationTest struct { 1614 Exported string `toml:"exported"` 1615 unexported string 1616 Nested1 unexportedFieldPreservationTestNested `toml:"nested1"` 1617 Nested2 *unexportedFieldPreservationTestNested `toml:"nested2"` 1618 Nested3 *unexportedFieldPreservationTestNested `toml:"nested3"` 1619 Slice1 []unexportedFieldPreservationTestNested `toml:"slice1"` 1620 Slice2 []*unexportedFieldPreservationTestNested `toml:"slice2"` 1621} 1622 1623type unexportedFieldPreservationTestNested struct { 1624 Exported1 string `toml:"exported1"` 1625 unexported1 string 1626} 1627 1628func TestUnmarshalPreservesUnexportedFields(t *testing.T) { 1629 toml := ` 1630 exported = "visible" 1631 unexported = "ignored" 1632 1633 [nested1] 1634 exported1 = "visible1" 1635 unexported1 = "ignored1" 1636 1637 [nested2] 1638 exported1 = "visible2" 1639 unexported1 = "ignored2" 1640 1641 [nested3] 1642 exported1 = "visible3" 1643 unexported1 = "ignored3" 1644 1645 [[slice1]] 1646 exported1 = "visible3" 1647 1648 [[slice1]] 1649 exported1 = "visible4" 1650 1651 [[slice2]] 1652 exported1 = "visible5" 1653 ` 1654 1655 t.Run("unexported field should not be set from toml", func(t *testing.T) { 1656 var actual unexportedFieldPreservationTest 1657 err := Unmarshal([]byte(toml), &actual) 1658 1659 if err != nil { 1660 t.Fatal("did not expect an error") 1661 } 1662 1663 expect := unexportedFieldPreservationTest{ 1664 Exported: "visible", 1665 unexported: "", 1666 Nested1: unexportedFieldPreservationTestNested{"visible1", ""}, 1667 Nested2: &unexportedFieldPreservationTestNested{"visible2", ""}, 1668 Nested3: &unexportedFieldPreservationTestNested{"visible3", ""}, 1669 Slice1: []unexportedFieldPreservationTestNested{ 1670 {Exported1: "visible3"}, 1671 {Exported1: "visible4"}, 1672 }, 1673 Slice2: []*unexportedFieldPreservationTestNested{ 1674 {Exported1: "visible5"}, 1675 }, 1676 } 1677 1678 if !reflect.DeepEqual(actual, expect) { 1679 t.Fatalf("%+v did not equal %+v", actual, expect) 1680 } 1681 }) 1682 1683 t.Run("unexported field should be preserved", func(t *testing.T) { 1684 actual := unexportedFieldPreservationTest{ 1685 Exported: "foo", 1686 unexported: "bar", 1687 Nested1: unexportedFieldPreservationTestNested{"baz", "bax"}, 1688 Nested2: nil, 1689 Nested3: &unexportedFieldPreservationTestNested{"baz", "bax"}, 1690 } 1691 err := Unmarshal([]byte(toml), &actual) 1692 1693 if err != nil { 1694 t.Fatal("did not expect an error") 1695 } 1696 1697 expect := unexportedFieldPreservationTest{ 1698 Exported: "visible", 1699 unexported: "bar", 1700 Nested1: unexportedFieldPreservationTestNested{"visible1", "bax"}, 1701 Nested2: &unexportedFieldPreservationTestNested{"visible2", ""}, 1702 Nested3: &unexportedFieldPreservationTestNested{"visible3", "bax"}, 1703 Slice1: []unexportedFieldPreservationTestNested{ 1704 {Exported1: "visible3"}, 1705 {Exported1: "visible4"}, 1706 }, 1707 Slice2: []*unexportedFieldPreservationTestNested{ 1708 {Exported1: "visible5"}, 1709 }, 1710 } 1711 1712 if !reflect.DeepEqual(actual, expect) { 1713 t.Fatalf("%+v did not equal %+v", actual, expect) 1714 } 1715 }) 1716} 1717 1718func TestTreeMarshal(t *testing.T) { 1719 cases := [][]byte{ 1720 basicTestToml, 1721 marshalTestToml, 1722 emptyTestToml, 1723 pointerTestToml, 1724 } 1725 for _, expected := range cases { 1726 t.Run("", func(t *testing.T) { 1727 tree, err := LoadBytes(expected) 1728 if err != nil { 1729 t.Fatal(err) 1730 } 1731 result, err := tree.Marshal() 1732 if err != nil { 1733 t.Fatal(err) 1734 } 1735 if !bytes.Equal(result, expected) { 1736 t.Errorf("Bad marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expected, result) 1737 } 1738 }) 1739 } 1740} 1741 1742func TestMarshalArrays(t *testing.T) { 1743 cases := []struct { 1744 Data interface{} 1745 Expected string 1746 }{ 1747 { 1748 Data: struct { 1749 XY [2]int 1750 }{ 1751 XY: [2]int{1, 2}, 1752 }, 1753 Expected: `XY = [1,2] 1754`, 1755 }, 1756 { 1757 Data: struct { 1758 XY [1][2]int 1759 }{ 1760 XY: [1][2]int{{1, 2}}, 1761 }, 1762 Expected: `XY = [[1,2]] 1763`, 1764 }, 1765 { 1766 Data: struct { 1767 XY [1][]int 1768 }{ 1769 XY: [1][]int{{1, 2}}, 1770 }, 1771 Expected: `XY = [[1,2]] 1772`, 1773 }, 1774 { 1775 Data: struct { 1776 XY [][2]int 1777 }{ 1778 XY: [][2]int{{1, 2}}, 1779 }, 1780 Expected: `XY = [[1,2]] 1781`, 1782 }, 1783 } 1784 for _, tc := range cases { 1785 t.Run("", func(t *testing.T) { 1786 result, err := Marshal(tc.Data) 1787 if err != nil { 1788 t.Fatal(err) 1789 } 1790 if !bytes.Equal(result, []byte(tc.Expected)) { 1791 t.Errorf("Bad marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", []byte(tc.Expected), result) 1792 } 1793 }) 1794 } 1795} 1796 1797func TestUnmarshalLocalDate(t *testing.T) { 1798 t.Run("ToLocalDate", func(t *testing.T) { 1799 type dateStruct struct { 1800 Date LocalDate 1801 } 1802 1803 toml := `date = 1979-05-27` 1804 1805 var obj dateStruct 1806 1807 err := Unmarshal([]byte(toml), &obj) 1808 1809 if err != nil { 1810 t.Fatal(err) 1811 } 1812 1813 if obj.Date.Year != 1979 { 1814 t.Errorf("expected year 1979, got %d", obj.Date.Year) 1815 } 1816 if obj.Date.Month != 5 { 1817 t.Errorf("expected month 5, got %d", obj.Date.Month) 1818 } 1819 if obj.Date.Day != 27 { 1820 t.Errorf("expected day 27, got %d", obj.Date.Day) 1821 } 1822 }) 1823 1824 t.Run("ToLocalDate", func(t *testing.T) { 1825 type dateStruct struct { 1826 Date time.Time 1827 } 1828 1829 toml := `date = 1979-05-27` 1830 1831 var obj dateStruct 1832 1833 err := Unmarshal([]byte(toml), &obj) 1834 1835 if err != nil { 1836 t.Fatal(err) 1837 } 1838 1839 if obj.Date.Year() != 1979 { 1840 t.Errorf("expected year 1979, got %d", obj.Date.Year()) 1841 } 1842 if obj.Date.Month() != 5 { 1843 t.Errorf("expected month 5, got %d", obj.Date.Month()) 1844 } 1845 if obj.Date.Day() != 27 { 1846 t.Errorf("expected day 27, got %d", obj.Date.Day()) 1847 } 1848 }) 1849} 1850 1851func TestMarshalLocalDate(t *testing.T) { 1852 type dateStruct struct { 1853 Date LocalDate 1854 } 1855 1856 obj := dateStruct{Date: LocalDate{ 1857 Year: 1979, 1858 Month: 5, 1859 Day: 27, 1860 }} 1861 1862 b, err := Marshal(obj) 1863 1864 if err != nil { 1865 t.Fatalf("unexpected error: %v", err) 1866 } 1867 1868 got := string(b) 1869 expected := `Date = 1979-05-27 1870` 1871 1872 if got != expected { 1873 t.Errorf("expected '%s', got '%s'", expected, got) 1874 } 1875} 1876 1877func TestUnmarshalLocalDateTime(t *testing.T) { 1878 examples := []struct { 1879 name string 1880 in string 1881 out LocalDateTime 1882 }{ 1883 { 1884 name: "normal", 1885 in: "1979-05-27T07:32:00", 1886 out: LocalDateTime{ 1887 Date: LocalDate{ 1888 Year: 1979, 1889 Month: 5, 1890 Day: 27, 1891 }, 1892 Time: LocalTime{ 1893 Hour: 7, 1894 Minute: 32, 1895 Second: 0, 1896 Nanosecond: 0, 1897 }, 1898 }}, 1899 { 1900 name: "with nanoseconds", 1901 in: "1979-05-27T00:32:00.999999", 1902 out: LocalDateTime{ 1903 Date: LocalDate{ 1904 Year: 1979, 1905 Month: 5, 1906 Day: 27, 1907 }, 1908 Time: LocalTime{ 1909 Hour: 0, 1910 Minute: 32, 1911 Second: 0, 1912 Nanosecond: 999999000, 1913 }, 1914 }, 1915 }, 1916 } 1917 1918 for i, example := range examples { 1919 toml := fmt.Sprintf(`date = %s`, example.in) 1920 1921 t.Run(fmt.Sprintf("ToLocalDateTime_%d_%s", i, example.name), func(t *testing.T) { 1922 type dateStruct struct { 1923 Date LocalDateTime 1924 } 1925 1926 var obj dateStruct 1927 1928 err := Unmarshal([]byte(toml), &obj) 1929 1930 if err != nil { 1931 t.Fatal(err) 1932 } 1933 1934 if obj.Date != example.out { 1935 t.Errorf("expected '%s', got '%s'", example.out, obj.Date) 1936 } 1937 }) 1938 1939 t.Run(fmt.Sprintf("ToTime_%d_%s", i, example.name), func(t *testing.T) { 1940 type dateStruct struct { 1941 Date time.Time 1942 } 1943 1944 var obj dateStruct 1945 1946 err := Unmarshal([]byte(toml), &obj) 1947 1948 if err != nil { 1949 t.Fatal(err) 1950 } 1951 1952 if obj.Date.Year() != example.out.Date.Year { 1953 t.Errorf("expected year %d, got %d", example.out.Date.Year, obj.Date.Year()) 1954 } 1955 if obj.Date.Month() != example.out.Date.Month { 1956 t.Errorf("expected month %d, got %d", example.out.Date.Month, obj.Date.Month()) 1957 } 1958 if obj.Date.Day() != example.out.Date.Day { 1959 t.Errorf("expected day %d, got %d", example.out.Date.Day, obj.Date.Day()) 1960 } 1961 if obj.Date.Hour() != example.out.Time.Hour { 1962 t.Errorf("expected hour %d, got %d", example.out.Time.Hour, obj.Date.Hour()) 1963 } 1964 if obj.Date.Minute() != example.out.Time.Minute { 1965 t.Errorf("expected minute %d, got %d", example.out.Time.Minute, obj.Date.Minute()) 1966 } 1967 if obj.Date.Second() != example.out.Time.Second { 1968 t.Errorf("expected second %d, got %d", example.out.Time.Second, obj.Date.Second()) 1969 } 1970 if obj.Date.Nanosecond() != example.out.Time.Nanosecond { 1971 t.Errorf("expected nanoseconds %d, got %d", example.out.Time.Nanosecond, obj.Date.Nanosecond()) 1972 } 1973 }) 1974 } 1975} 1976 1977func TestMarshalLocalDateTime(t *testing.T) { 1978 type dateStruct struct { 1979 DateTime LocalDateTime 1980 } 1981 1982 examples := []struct { 1983 name string 1984 in LocalDateTime 1985 out string 1986 }{ 1987 { 1988 name: "normal", 1989 out: "DateTime = 1979-05-27T07:32:00\n", 1990 in: LocalDateTime{ 1991 Date: LocalDate{ 1992 Year: 1979, 1993 Month: 5, 1994 Day: 27, 1995 }, 1996 Time: LocalTime{ 1997 Hour: 7, 1998 Minute: 32, 1999 Second: 0, 2000 Nanosecond: 0, 2001 }, 2002 }}, 2003 { 2004 name: "with nanoseconds", 2005 out: "DateTime = 1979-05-27T00:32:00.999999000\n", 2006 in: LocalDateTime{ 2007 Date: LocalDate{ 2008 Year: 1979, 2009 Month: 5, 2010 Day: 27, 2011 }, 2012 Time: LocalTime{ 2013 Hour: 0, 2014 Minute: 32, 2015 Second: 0, 2016 Nanosecond: 999999000, 2017 }, 2018 }, 2019 }, 2020 } 2021 2022 for i, example := range examples { 2023 t.Run(fmt.Sprintf("%d_%s", i, example.name), func(t *testing.T) { 2024 obj := dateStruct{ 2025 DateTime: example.in, 2026 } 2027 b, err := Marshal(obj) 2028 2029 if err != nil { 2030 t.Fatalf("unexpected error: %v", err) 2031 } 2032 2033 got := string(b) 2034 2035 if got != example.out { 2036 t.Errorf("expected '%s', got '%s'", example.out, got) 2037 } 2038 }) 2039 } 2040} 2041 2042func TestUnmarshalLocalTime(t *testing.T) { 2043 examples := []struct { 2044 name string 2045 in string 2046 out LocalTime 2047 }{ 2048 { 2049 name: "normal", 2050 in: "07:32:00", 2051 out: LocalTime{ 2052 Hour: 7, 2053 Minute: 32, 2054 Second: 0, 2055 Nanosecond: 0, 2056 }, 2057 }, 2058 { 2059 name: "with nanoseconds", 2060 in: "00:32:00.999999", 2061 out: LocalTime{ 2062 Hour: 0, 2063 Minute: 32, 2064 Second: 0, 2065 Nanosecond: 999999000, 2066 }, 2067 }, 2068 } 2069 2070 for i, example := range examples { 2071 toml := fmt.Sprintf(`Time = %s`, example.in) 2072 2073 t.Run(fmt.Sprintf("ToLocalTime_%d_%s", i, example.name), func(t *testing.T) { 2074 type dateStruct struct { 2075 Time LocalTime 2076 } 2077 2078 var obj dateStruct 2079 2080 err := Unmarshal([]byte(toml), &obj) 2081 2082 if err != nil { 2083 t.Fatal(err) 2084 } 2085 2086 if obj.Time != example.out { 2087 t.Errorf("expected '%s', got '%s'", example.out, obj.Time) 2088 } 2089 }) 2090 } 2091} 2092 2093func TestMarshalLocalTime(t *testing.T) { 2094 type timeStruct struct { 2095 Time LocalTime 2096 } 2097 2098 examples := []struct { 2099 name string 2100 in LocalTime 2101 out string 2102 }{ 2103 { 2104 name: "normal", 2105 out: "Time = 07:32:00\n", 2106 in: LocalTime{ 2107 Hour: 7, 2108 Minute: 32, 2109 Second: 0, 2110 Nanosecond: 0, 2111 }}, 2112 { 2113 name: "with nanoseconds", 2114 out: "Time = 00:32:00.999999000\n", 2115 in: LocalTime{ 2116 Hour: 0, 2117 Minute: 32, 2118 Second: 0, 2119 Nanosecond: 999999000, 2120 }, 2121 }, 2122 } 2123 2124 for i, example := range examples { 2125 t.Run(fmt.Sprintf("%d_%s", i, example.name), func(t *testing.T) { 2126 obj := timeStruct{ 2127 Time: example.in, 2128 } 2129 b, err := Marshal(obj) 2130 2131 if err != nil { 2132 t.Fatalf("unexpected error: %v", err) 2133 } 2134 2135 got := string(b) 2136 2137 if got != example.out { 2138 t.Errorf("expected '%s', got '%s'", example.out, got) 2139 } 2140 }) 2141 } 2142} 2143