1package toml 2 3import ( 4 "fmt" 5 "math" 6 "reflect" 7 "testing" 8 "time" 9 10 "github.com/davecgh/go-spew/spew" 11) 12 13func assertSubTree(t *testing.T, path []string, tree *Tree, err error, ref map[string]interface{}) { 14 if err != nil { 15 t.Error("Non-nil error:", err.Error()) 16 return 17 } 18 for k, v := range ref { 19 nextPath := append(path, k) 20 t.Log("asserting path", nextPath) 21 // NOTE: directly access key instead of resolve by path 22 // NOTE: see TestSpecialKV 23 switch node := tree.GetPath([]string{k}).(type) { 24 case []*Tree: 25 t.Log("\tcomparing key", nextPath, "by array iteration") 26 for idx, item := range node { 27 assertSubTree(t, nextPath, item, err, v.([]map[string]interface{})[idx]) 28 } 29 case *Tree: 30 t.Log("\tcomparing key", nextPath, "by subtree assestion") 31 assertSubTree(t, nextPath, node, err, v.(map[string]interface{})) 32 default: 33 t.Log("\tcomparing key", nextPath, "by string representation because it's of type", reflect.TypeOf(node)) 34 if fmt.Sprintf("%v", node) != fmt.Sprintf("%v", v) { 35 t.Errorf("was expecting %v at %v but got %v", v, k, node) 36 } 37 } 38 } 39} 40 41func assertTree(t *testing.T, tree *Tree, err error, ref map[string]interface{}) { 42 t.Log("Asserting tree:\n", spew.Sdump(tree)) 43 assertSubTree(t, []string{}, tree, err, ref) 44 t.Log("Finished tree assertion.") 45} 46 47func TestCreateSubTree(t *testing.T) { 48 tree := newTree() 49 tree.createSubTree([]string{"a", "b", "c"}, Position{}) 50 tree.Set("a.b.c", 42) 51 if tree.Get("a.b.c") != 42 { 52 t.Fail() 53 } 54} 55 56func TestSimpleKV(t *testing.T) { 57 tree, err := Load("a = 42") 58 assertTree(t, tree, err, map[string]interface{}{ 59 "a": int64(42), 60 }) 61 62 tree, _ = Load("a = 42\nb = 21") 63 assertTree(t, tree, err, map[string]interface{}{ 64 "a": int64(42), 65 "b": int64(21), 66 }) 67} 68 69func TestNumberInKey(t *testing.T) { 70 tree, err := Load("hello2 = 42") 71 assertTree(t, tree, err, map[string]interface{}{ 72 "hello2": int64(42), 73 }) 74} 75 76func TestIncorrectKeyExtraSquareBracket(t *testing.T) { 77 _, err := Load(`[a]b] 78zyx = 42`) 79 if err == nil { 80 t.Error("Error should have been returned.") 81 } 82 if err.Error() != "(1, 4): parsing error: keys cannot contain ] character" { 83 t.Error("Bad error message:", err.Error()) 84 } 85} 86 87func TestSimpleNumbers(t *testing.T) { 88 tree, err := Load("a = +42\nb = -21\nc = +4.2\nd = -2.1") 89 assertTree(t, tree, err, map[string]interface{}{ 90 "a": int64(42), 91 "b": int64(-21), 92 "c": float64(4.2), 93 "d": float64(-2.1), 94 }) 95} 96 97func TestSpecialFloats(t *testing.T) { 98 tree, err := Load(` 99normalinf = inf 100plusinf = +inf 101minusinf = -inf 102normalnan = nan 103plusnan = +nan 104minusnan = -nan 105`) 106 assertTree(t, tree, err, map[string]interface{}{ 107 "normalinf": math.Inf(1), 108 "plusinf": math.Inf(1), 109 "minusinf": math.Inf(-1), 110 "normalnan": math.NaN(), 111 "plusnan": math.NaN(), 112 "minusnan": math.NaN(), 113 }) 114} 115 116func TestHexIntegers(t *testing.T) { 117 tree, err := Load(`a = 0xDEADBEEF`) 118 assertTree(t, tree, err, map[string]interface{}{"a": int64(3735928559)}) 119 120 tree, err = Load(`a = 0xdeadbeef`) 121 assertTree(t, tree, err, map[string]interface{}{"a": int64(3735928559)}) 122 123 tree, err = Load(`a = 0xdead_beef`) 124 assertTree(t, tree, err, map[string]interface{}{"a": int64(3735928559)}) 125 126 _, err = Load(`a = 0x_1`) 127 if err.Error() != "(1, 5): invalid use of _ in hex number" { 128 t.Error("Bad error message:", err.Error()) 129 } 130} 131 132func TestOctIntegers(t *testing.T) { 133 tree, err := Load(`a = 0o01234567`) 134 assertTree(t, tree, err, map[string]interface{}{"a": int64(342391)}) 135 136 tree, err = Load(`a = 0o755`) 137 assertTree(t, tree, err, map[string]interface{}{"a": int64(493)}) 138 139 _, err = Load(`a = 0o_1`) 140 if err.Error() != "(1, 5): invalid use of _ in number" { 141 t.Error("Bad error message:", err.Error()) 142 } 143} 144 145func TestBinIntegers(t *testing.T) { 146 tree, err := Load(`a = 0b11010110`) 147 assertTree(t, tree, err, map[string]interface{}{"a": int64(214)}) 148 149 _, err = Load(`a = 0b_1`) 150 if err.Error() != "(1, 5): invalid use of _ in number" { 151 t.Error("Bad error message:", err.Error()) 152 } 153} 154 155func TestBadIntegerBase(t *testing.T) { 156 _, err := Load(`a = 0k1`) 157 if err.Error() != "(1, 5): unknown number base: k. possible options are x (hex) o (octal) b (binary)" { 158 t.Error("Error should have been returned.") 159 } 160} 161 162func TestIntegerNoDigit(t *testing.T) { 163 _, err := Load(`a = 0b`) 164 if err.Error() != "(1, 5): number needs at least one digit" { 165 t.Error("Bad error message:", err.Error()) 166 } 167} 168 169func TestNumbersWithUnderscores(t *testing.T) { 170 tree, err := Load("a = 1_000") 171 assertTree(t, tree, err, map[string]interface{}{ 172 "a": int64(1000), 173 }) 174 175 tree, err = Load("a = 5_349_221") 176 assertTree(t, tree, err, map[string]interface{}{ 177 "a": int64(5349221), 178 }) 179 180 tree, err = Load("a = 1_2_3_4_5") 181 assertTree(t, tree, err, map[string]interface{}{ 182 "a": int64(12345), 183 }) 184 185 tree, err = Load("flt8 = 9_224_617.445_991_228_313") 186 assertTree(t, tree, err, map[string]interface{}{ 187 "flt8": float64(9224617.445991228313), 188 }) 189 190 tree, err = Load("flt9 = 1e1_00") 191 assertTree(t, tree, err, map[string]interface{}{ 192 "flt9": float64(1e100), 193 }) 194} 195 196func TestFloatsWithExponents(t *testing.T) { 197 tree, err := Load("a = 5e+22\nb = 5E+22\nc = -5e+22\nd = -5e-22\ne = 6.626e-34") 198 assertTree(t, tree, err, map[string]interface{}{ 199 "a": float64(5e+22), 200 "b": float64(5e+22), 201 "c": float64(-5e+22), 202 "d": float64(-5e-22), 203 "e": float64(6.626e-34), 204 }) 205} 206 207func TestSimpleDate(t *testing.T) { 208 tree, err := Load("a = 1979-05-27T07:32:00Z") 209 assertTree(t, tree, err, map[string]interface{}{ 210 "a": time.Date(1979, time.May, 27, 7, 32, 0, 0, time.UTC), 211 }) 212} 213 214func TestDateOffset(t *testing.T) { 215 tree, err := Load("a = 1979-05-27T00:32:00-07:00") 216 assertTree(t, tree, err, map[string]interface{}{ 217 "a": time.Date(1979, time.May, 27, 0, 32, 0, 0, time.FixedZone("", -7*60*60)), 218 }) 219} 220 221func TestDateNano(t *testing.T) { 222 tree, err := Load("a = 1979-05-27T00:32:00.999999999-07:00") 223 assertTree(t, tree, err, map[string]interface{}{ 224 "a": time.Date(1979, time.May, 27, 0, 32, 0, 999999999, time.FixedZone("", -7*60*60)), 225 }) 226} 227 228func TestLocalDateTime(t *testing.T) { 229 tree, err := Load("a = 1979-05-27T07:32:00") 230 assertTree(t, tree, err, map[string]interface{}{ 231 "a": LocalDateTime{ 232 Date: LocalDate{ 233 Year: 1979, 234 Month: 5, 235 Day: 27, 236 }, 237 Time: LocalTime{ 238 Hour: 7, 239 Minute: 32, 240 Second: 0, 241 Nanosecond: 0, 242 }, 243 }, 244 }) 245} 246 247func TestLocalDateTimeNano(t *testing.T) { 248 tree, err := Load("a = 1979-05-27T07:32:00.999999") 249 assertTree(t, tree, err, map[string]interface{}{ 250 "a": LocalDateTime{ 251 Date: LocalDate{ 252 Year: 1979, 253 Month: 5, 254 Day: 27, 255 }, 256 Time: LocalTime{ 257 Hour: 7, 258 Minute: 32, 259 Second: 0, 260 Nanosecond: 999999000, 261 }, 262 }, 263 }) 264} 265 266func TestLocalDate(t *testing.T) { 267 tree, err := Load("a = 1979-05-27") 268 assertTree(t, tree, err, map[string]interface{}{ 269 "a": LocalDate{ 270 Year: 1979, 271 Month: 5, 272 Day: 27, 273 }, 274 }) 275} 276 277func TestLocalTime(t *testing.T) { 278 tree, err := Load("a = 07:32:00") 279 assertTree(t, tree, err, map[string]interface{}{ 280 "a": LocalTime{ 281 Hour: 7, 282 Minute: 32, 283 Second: 0, 284 Nanosecond: 0, 285 }, 286 }) 287} 288 289func TestLocalTimeNano(t *testing.T) { 290 tree, err := Load("a = 00:32:00.999999") 291 assertTree(t, tree, err, map[string]interface{}{ 292 "a": LocalTime{ 293 Hour: 0, 294 Minute: 32, 295 Second: 0, 296 Nanosecond: 999999000, 297 }, 298 }) 299} 300 301func TestSimpleString(t *testing.T) { 302 tree, err := Load("a = \"hello world\"") 303 assertTree(t, tree, err, map[string]interface{}{ 304 "a": "hello world", 305 }) 306} 307 308func TestSpaceKey(t *testing.T) { 309 tree, err := Load("\"a b\" = \"hello world\"") 310 assertTree(t, tree, err, map[string]interface{}{ 311 "a b": "hello world", 312 }) 313} 314 315func TestDoubleQuotedKey(t *testing.T) { 316 tree, err := Load(` 317 "key" = "a" 318 "\t" = "b" 319 "\U0001F914" = "c" 320 "\u2764" = "d" 321 `) 322 assertTree(t, tree, err, map[string]interface{}{ 323 "key": "a", 324 "\t": "b", 325 "\U0001F914": "c", 326 "\u2764": "d", 327 }) 328} 329 330func TestSingleQuotedKey(t *testing.T) { 331 tree, err := Load(` 332 'key' = "a" 333 '\t' = "b" 334 '\U0001F914' = "c" 335 '\u2764' = "d" 336 `) 337 assertTree(t, tree, err, map[string]interface{}{ 338 `key`: "a", 339 `\t`: "b", 340 `\U0001F914`: "c", 341 `\u2764`: "d", 342 }) 343} 344 345func TestStringEscapables(t *testing.T) { 346 tree, err := Load("a = \"a \\n b\"") 347 assertTree(t, tree, err, map[string]interface{}{ 348 "a": "a \n b", 349 }) 350 351 tree, err = Load("a = \"a \\t b\"") 352 assertTree(t, tree, err, map[string]interface{}{ 353 "a": "a \t b", 354 }) 355 356 tree, err = Load("a = \"a \\r b\"") 357 assertTree(t, tree, err, map[string]interface{}{ 358 "a": "a \r b", 359 }) 360 361 tree, err = Load("a = \"a \\\\ b\"") 362 assertTree(t, tree, err, map[string]interface{}{ 363 "a": "a \\ b", 364 }) 365} 366 367func TestEmptyQuotedString(t *testing.T) { 368 tree, err := Load(`[""] 369"" = 1`) 370 assertTree(t, tree, err, map[string]interface{}{ 371 "": map[string]interface{}{ 372 "": int64(1), 373 }, 374 }) 375} 376 377func TestBools(t *testing.T) { 378 tree, err := Load("a = true\nb = false") 379 assertTree(t, tree, err, map[string]interface{}{ 380 "a": true, 381 "b": false, 382 }) 383} 384 385func TestNestedKeys(t *testing.T) { 386 tree, err := Load("[a.b.c]\nd = 42") 387 assertTree(t, tree, err, map[string]interface{}{ 388 "a": map[string]interface{}{ 389 "b": map[string]interface{}{ 390 "c": map[string]interface{}{ 391 "d": int64(42), 392 }, 393 }, 394 }, 395 }) 396} 397 398func TestNestedQuotedUnicodeKeys(t *testing.T) { 399 tree, err := Load("[ j . \"ʞ\" . l ]\nd = 42") 400 assertTree(t, tree, err, map[string]interface{}{ 401 "j": map[string]interface{}{ 402 "ʞ": map[string]interface{}{ 403 "l": map[string]interface{}{ 404 "d": int64(42), 405 }, 406 }, 407 }, 408 }) 409 410 tree, err = Load("[ g . h . i ]\nd = 42") 411 assertTree(t, tree, err, map[string]interface{}{ 412 "g": map[string]interface{}{ 413 "h": map[string]interface{}{ 414 "i": map[string]interface{}{ 415 "d": int64(42), 416 }, 417 }, 418 }, 419 }) 420 421 tree, err = Load("[ d.e.f ]\nk = 42") 422 assertTree(t, tree, err, map[string]interface{}{ 423 "d": map[string]interface{}{ 424 "e": map[string]interface{}{ 425 "f": map[string]interface{}{ 426 "k": int64(42), 427 }, 428 }, 429 }, 430 }) 431} 432 433func TestArrayOne(t *testing.T) { 434 tree, err := Load("a = [1]") 435 assertTree(t, tree, err, map[string]interface{}{ 436 "a": []int64{int64(1)}, 437 }) 438} 439 440func TestArrayZero(t *testing.T) { 441 tree, err := Load("a = []") 442 assertTree(t, tree, err, map[string]interface{}{ 443 "a": []interface{}{}, 444 }) 445} 446 447func TestArraySimple(t *testing.T) { 448 tree, err := Load("a = [42, 21, 10]") 449 assertTree(t, tree, err, map[string]interface{}{ 450 "a": []int64{int64(42), int64(21), int64(10)}, 451 }) 452 453 tree, _ = Load("a = [42, 21, 10,]") 454 assertTree(t, tree, err, map[string]interface{}{ 455 "a": []int64{int64(42), int64(21), int64(10)}, 456 }) 457} 458 459func TestArrayMultiline(t *testing.T) { 460 tree, err := Load("a = [42,\n21, 10,]") 461 assertTree(t, tree, err, map[string]interface{}{ 462 "a": []int64{int64(42), int64(21), int64(10)}, 463 }) 464} 465 466func TestArrayNested(t *testing.T) { 467 tree, err := Load("a = [[42, 21], [10]]") 468 assertTree(t, tree, err, map[string]interface{}{ 469 "a": [][]int64{{int64(42), int64(21)}, {int64(10)}}, 470 }) 471} 472 473func TestNestedArrayComment(t *testing.T) { 474 tree, err := Load(` 475someArray = [ 476# does not work 477["entry1"] 478]`) 479 assertTree(t, tree, err, map[string]interface{}{ 480 "someArray": [][]string{{"entry1"}}, 481 }) 482} 483 484func TestNestedEmptyArrays(t *testing.T) { 485 tree, err := Load("a = [[[]]]") 486 assertTree(t, tree, err, map[string]interface{}{ 487 "a": [][][]interface{}{{{}}}, 488 }) 489} 490 491func TestArrayNestedStrings(t *testing.T) { 492 tree, err := Load("data = [ [\"gamma\", \"delta\"], [\"Foo\"] ]") 493 assertTree(t, tree, err, map[string]interface{}{ 494 "data": [][]string{{"gamma", "delta"}, {"Foo"}}, 495 }) 496} 497 498func TestParseUnknownRvalue(t *testing.T) { 499 _, err := Load("a = !bssss") 500 if err == nil { 501 t.Error("Expecting a parse error") 502 } 503 504 _, err = Load("a = /b") 505 if err == nil { 506 t.Error("Expecting a parse error") 507 } 508} 509 510func TestMissingValue(t *testing.T) { 511 _, err := Load("a = ") 512 if err.Error() != "(1, 5): expecting a value" { 513 t.Error("Bad error message:", err.Error()) 514 } 515} 516 517func TestUnterminatedArray(t *testing.T) { 518 _, err := Load("a = [1,") 519 if err.Error() != "(1, 8): unterminated array" { 520 t.Error("Bad error message:", err.Error()) 521 } 522 523 _, err = Load("a = [1") 524 if err.Error() != "(1, 7): unterminated array" { 525 t.Error("Bad error message:", err.Error()) 526 } 527 528 _, err = Load("a = [1 2") 529 if err.Error() != "(1, 8): missing comma" { 530 t.Error("Bad error message:", err.Error()) 531 } 532} 533 534func TestNewlinesInArrays(t *testing.T) { 535 tree, err := Load("a = [1,\n2,\n3]") 536 assertTree(t, tree, err, map[string]interface{}{ 537 "a": []int64{int64(1), int64(2), int64(3)}, 538 }) 539} 540 541func TestArrayWithExtraComma(t *testing.T) { 542 tree, err := Load("a = [1,\n2,\n3,\n]") 543 assertTree(t, tree, err, map[string]interface{}{ 544 "a": []int64{int64(1), int64(2), int64(3)}, 545 }) 546} 547 548func TestArrayWithExtraCommaComment(t *testing.T) { 549 tree, err := Load("a = [1, # wow\n2, # such items\n3, # so array\n]") 550 assertTree(t, tree, err, map[string]interface{}{ 551 "a": []int64{int64(1), int64(2), int64(3)}, 552 }) 553} 554 555func TestSimpleInlineGroup(t *testing.T) { 556 tree, err := Load("key = {a = 42}") 557 assertTree(t, tree, err, map[string]interface{}{ 558 "key": map[string]interface{}{ 559 "a": int64(42), 560 }, 561 }) 562} 563 564func TestDoubleInlineGroup(t *testing.T) { 565 tree, err := Load("key = {a = 42, b = \"foo\"}") 566 assertTree(t, tree, err, map[string]interface{}{ 567 "key": map[string]interface{}{ 568 "a": int64(42), 569 "b": "foo", 570 }, 571 }) 572} 573 574func TestNestedInlineGroup(t *testing.T) { 575 tree, err := Load("out = {block0 = {x = 99, y = 100}, block1 = {p = \"999\", q = \"1000\"}}") 576 assertTree(t, tree, err, map[string]interface{}{ 577 "out": map[string]interface{}{ 578 "block0": map[string]interface{}{ 579 "x": int64(99), 580 "y": int64(100), 581 }, 582 "block1": map[string]interface{}{ 583 "p": "999", 584 "q": "1000", 585 }, 586 }, 587 }) 588} 589 590func TestArrayInNestedInlineGroup(t *testing.T) { 591 tree, err := Load(`image = {name = "xxx", palette = {id = 100, colors = ["red", "blue", "green"]}}`) 592 assertTree(t, tree, err, map[string]interface{}{ 593 "image": map[string]interface{}{ 594 "name": "xxx", 595 "palette": map[string]interface{}{ 596 "id": int64(100), 597 "colors": []string{ 598 "red", 599 "blue", 600 "green", 601 }, 602 }, 603 }, 604 }) 605} 606 607func TestExampleInlineGroup(t *testing.T) { 608 tree, err := Load(`name = { first = "Tom", last = "Preston-Werner" } 609point = { x = 1, y = 2 }`) 610 assertTree(t, tree, err, map[string]interface{}{ 611 "name": map[string]interface{}{ 612 "first": "Tom", 613 "last": "Preston-Werner", 614 }, 615 "point": map[string]interface{}{ 616 "x": int64(1), 617 "y": int64(2), 618 }, 619 }) 620} 621 622func TestInlineGroupBareKeysUnderscore(t *testing.T) { 623 tree, err := Load(`foo = { _bar = "buz" }`) 624 assertTree(t, tree, err, map[string]interface{}{ 625 "foo": map[string]interface{}{ 626 "_bar": "buz", 627 }, 628 }) 629} 630 631func TestInlineGroupBareKeysDash(t *testing.T) { 632 tree, err := Load(`foo = { -bar = "buz" }`) 633 assertTree(t, tree, err, map[string]interface{}{ 634 "foo": map[string]interface{}{ 635 "-bar": "buz", 636 }, 637 }) 638} 639 640func TestInlineGroupKeyQuoted(t *testing.T) { 641 tree, err := Load(`foo = { "bar" = "buz" }`) 642 assertTree(t, tree, err, map[string]interface{}{ 643 "foo": map[string]interface{}{ 644 "bar": "buz", 645 }, 646 }) 647} 648 649func TestExampleInlineGroupInArray(t *testing.T) { 650 tree, err := Load(`points = [{ x = 1, y = 2 }]`) 651 assertTree(t, tree, err, map[string]interface{}{ 652 "points": []map[string]interface{}{ 653 { 654 "x": int64(1), 655 "y": int64(2), 656 }, 657 }, 658 }) 659} 660 661func TestInlineTableUnterminated(t *testing.T) { 662 _, err := Load("foo = {") 663 if err.Error() != "(1, 8): unterminated inline table" { 664 t.Error("Bad error message:", err.Error()) 665 } 666} 667 668func TestInlineTableCommaExpected(t *testing.T) { 669 _, err := Load("foo = {hello = 53 test = foo}") 670 if err.Error() != "(1, 19): unexpected token type in inline table: no value can start with t" { 671 t.Error("Bad error message:", err.Error()) 672 } 673} 674 675func TestInlineTableCommaStart(t *testing.T) { 676 _, err := Load("foo = {, hello = 53}") 677 if err.Error() != "(1, 8): unexpected token type in inline table: keys cannot contain , character" { 678 t.Error("Bad error message:", err.Error()) 679 } 680} 681 682func TestInlineTableDoubleComma(t *testing.T) { 683 _, err := Load("foo = {hello = 53,, foo = 17}") 684 if err.Error() != "(1, 19): unexpected token type in inline table: keys cannot contain , character" { 685 t.Error("Bad error message:", err.Error()) 686 } 687} 688 689func TestInlineTableTrailingComma(t *testing.T) { 690 _, err := Load("foo = {hello = 53, foo = 17,}") 691 if err.Error() != "(1, 28): trailing comma at the end of inline table" { 692 t.Error("Bad error message:", err.Error()) 693 } 694} 695 696func TestAddKeyToInlineTable(t *testing.T) { 697 _, err := Load("type = { name = \"Nail\" }\ntype.edible = false") 698 if err.Error() != "(2, 1): could not add key or sub-table to exist inline table or its sub-table : type" { 699 t.Error("Bad error message:", err.Error()) 700 } 701} 702 703func TestAddSubTableToInlineTable(t *testing.T) { 704 _, err := Load("a = { b = \"c\" }\na.d.e = \"f\"") 705 if err.Error() != "(2, 1): could not add key or sub-table to exist inline table or its sub-table : a.d" { 706 t.Error("Bad error message:", err.Error()) 707 } 708} 709 710func TestAddKeyToSubTableOfInlineTable(t *testing.T) { 711 _, err := Load("a = { b = { c = \"d\" } }\na.b.e = \"f\"") 712 if err.Error() != "(2, 1): could not add key or sub-table to exist inline table or its sub-table : a.b" { 713 t.Error("Bad error message:", err.Error()) 714 } 715} 716 717func TestReDefineInlineTable(t *testing.T) { 718 _, err := Load("a = { b = \"c\" }\n[a]\n d = \"e\"") 719 if err.Error() != "(2, 2): could not re-define exist inline table or its sub-table : a" { 720 t.Error("Bad error message:", err.Error()) 721 } 722} 723 724func TestDuplicateGroups(t *testing.T) { 725 _, err := Load("[foo]\na=2\n[foo]b=3") 726 if err.Error() != "(3, 2): duplicated tables" { 727 t.Error("Bad error message:", err.Error()) 728 } 729} 730 731func TestDuplicateKeys(t *testing.T) { 732 _, err := Load("foo = 2\nfoo = 3") 733 if err.Error() != "(2, 1): The following key was defined twice: foo" { 734 t.Error("Bad error message:", err.Error()) 735 } 736} 737 738func TestEmptyIntermediateTable(t *testing.T) { 739 _, err := Load("[foo..bar]") 740 if err.Error() != "(1, 2): invalid table array key: expecting key part after dot" { 741 t.Error("Bad error message:", err.Error()) 742 } 743} 744 745func TestImplicitDeclarationBefore(t *testing.T) { 746 tree, err := Load("[a.b.c]\nanswer = 42\n[a]\nbetter = 43") 747 assertTree(t, tree, err, map[string]interface{}{ 748 "a": map[string]interface{}{ 749 "b": map[string]interface{}{ 750 "c": map[string]interface{}{ 751 "answer": int64(42), 752 }, 753 }, 754 "better": int64(43), 755 }, 756 }) 757} 758 759func TestFloatsWithoutLeadingZeros(t *testing.T) { 760 _, err := Load("a = .42") 761 if err.Error() != "(1, 5): cannot start float with a dot" { 762 t.Error("Bad error message:", err.Error()) 763 } 764 765 _, err = Load("a = -.42") 766 if err.Error() != "(1, 5): cannot start float with a dot" { 767 t.Error("Bad error message:", err.Error()) 768 } 769} 770 771func TestMissingFile(t *testing.T) { 772 _, err := LoadFile("foo.toml") 773 if err.Error() != "open foo.toml: no such file or directory" && 774 err.Error() != "open foo.toml: The system cannot find the file specified." { 775 t.Error("Bad error message:", err.Error()) 776 } 777} 778 779func TestParseFile(t *testing.T) { 780 tree, err := LoadFile("example.toml") 781 782 assertTree(t, tree, err, map[string]interface{}{ 783 "title": "TOML Example", 784 "owner": map[string]interface{}{ 785 "name": "Tom Preston-Werner", 786 "organization": "GitHub", 787 "bio": "GitHub Cofounder & CEO\nLikes tater tots and beer.", 788 "dob": time.Date(1979, time.May, 27, 7, 32, 0, 0, time.UTC), 789 }, 790 "database": map[string]interface{}{ 791 "server": "192.168.1.1", 792 "ports": []int64{8001, 8001, 8002}, 793 "connection_max": 5000, 794 "enabled": true, 795 }, 796 "servers": map[string]interface{}{ 797 "alpha": map[string]interface{}{ 798 "ip": "10.0.0.1", 799 "dc": "eqdc10", 800 }, 801 "beta": map[string]interface{}{ 802 "ip": "10.0.0.2", 803 "dc": "eqdc10", 804 }, 805 }, 806 "clients": map[string]interface{}{ 807 "data": []interface{}{ 808 []string{"gamma", "delta"}, 809 []int64{1, 2}, 810 }, 811 "score": 4e-08, 812 }, 813 }) 814} 815 816func TestParseFileCRLF(t *testing.T) { 817 tree, err := LoadFile("example-crlf.toml") 818 819 assertTree(t, tree, err, map[string]interface{}{ 820 "title": "TOML Example", 821 "owner": map[string]interface{}{ 822 "name": "Tom Preston-Werner", 823 "organization": "GitHub", 824 "bio": "GitHub Cofounder & CEO\nLikes tater tots and beer.", 825 "dob": time.Date(1979, time.May, 27, 7, 32, 0, 0, time.UTC), 826 }, 827 "database": map[string]interface{}{ 828 "server": "192.168.1.1", 829 "ports": []int64{8001, 8001, 8002}, 830 "connection_max": 5000, 831 "enabled": true, 832 }, 833 "servers": map[string]interface{}{ 834 "alpha": map[string]interface{}{ 835 "ip": "10.0.0.1", 836 "dc": "eqdc10", 837 }, 838 "beta": map[string]interface{}{ 839 "ip": "10.0.0.2", 840 "dc": "eqdc10", 841 }, 842 }, 843 "clients": map[string]interface{}{ 844 "data": []interface{}{ 845 []string{"gamma", "delta"}, 846 []int64{1, 2}, 847 }, 848 "score": 4e-08, 849 }, 850 }) 851} 852 853func TestParseKeyGroupArray(t *testing.T) { 854 tree, err := Load("[[foo.bar]] a = 42\n[[foo.bar]] a = 69") 855 assertTree(t, tree, err, map[string]interface{}{ 856 "foo": map[string]interface{}{ 857 "bar": []map[string]interface{}{ 858 {"a": int64(42)}, 859 {"a": int64(69)}, 860 }, 861 }, 862 }) 863} 864 865func TestParseKeyGroupArrayUnfinished(t *testing.T) { 866 _, err := Load("[[foo.bar]\na = 42") 867 if err.Error() != "(1, 10): was expecting token [[, but got unclosed table array key instead" { 868 t.Error("Bad error message:", err.Error()) 869 } 870 871 _, err = Load("[[foo.[bar]\na = 42") 872 if err.Error() != "(1, 3): unexpected token table array key cannot contain ']', was expecting a table array key" { 873 t.Error("Bad error message:", err.Error()) 874 } 875} 876 877func TestParseKeyGroupArrayQueryExample(t *testing.T) { 878 tree, err := Load(` 879 [[book]] 880 title = "The Stand" 881 author = "Stephen King" 882 [[book]] 883 title = "For Whom the Bell Tolls" 884 author = "Ernest Hemmingway" 885 [[book]] 886 title = "Neuromancer" 887 author = "William Gibson" 888 `) 889 890 assertTree(t, tree, err, map[string]interface{}{ 891 "book": []map[string]interface{}{ 892 {"title": "The Stand", "author": "Stephen King"}, 893 {"title": "For Whom the Bell Tolls", "author": "Ernest Hemmingway"}, 894 {"title": "Neuromancer", "author": "William Gibson"}, 895 }, 896 }) 897} 898 899func TestParseKeyGroupArraySpec(t *testing.T) { 900 tree, err := Load("[[fruit]]\n name=\"apple\"\n [fruit.physical]\n color=\"red\"\n shape=\"round\"\n [[fruit]]\n name=\"banana\"") 901 assertTree(t, tree, err, map[string]interface{}{ 902 "fruit": []map[string]interface{}{ 903 {"name": "apple", "physical": map[string]interface{}{"color": "red", "shape": "round"}}, 904 {"name": "banana"}, 905 }, 906 }) 907} 908 909func TestTomlValueStringRepresentation(t *testing.T) { 910 for idx, item := range []struct { 911 Value interface{} 912 Expect string 913 }{ 914 {int64(12345), "12345"}, 915 {uint64(50), "50"}, 916 {float64(123.45), "123.45"}, 917 {true, "true"}, 918 {"hello world", "\"hello world\""}, 919 {"\b\t\n\f\r\"\\", "\"\\b\\t\\n\\f\\r\\\"\\\\\""}, 920 {"\x05", "\"\\u0005\""}, 921 {time.Date(1979, time.May, 27, 7, 32, 0, 0, time.UTC), "1979-05-27T07:32:00Z"}, 922 {[]interface{}{"gamma", "delta"}, "[\"gamma\", \"delta\"]"}, 923 {nil, ""}, 924 } { 925 result, err := tomlValueStringRepresentation(item.Value, "", "", OrderAlphabetical, false) 926 if err != nil { 927 t.Errorf("Test %d - unexpected error: %s", idx, err) 928 } 929 if result != item.Expect { 930 t.Errorf("Test %d - got '%s', expected '%s'", idx, result, item.Expect) 931 } 932 } 933} 934 935func TestToStringMapStringString(t *testing.T) { 936 tree, err := TreeFromMap(map[string]interface{}{"m": map[string]interface{}{"v": "abc"}}) 937 if err != nil { 938 t.Fatalf("unexpected error: %s", err) 939 } 940 want := "\n[m]\n v = \"abc\"\n" 941 got := tree.String() 942 943 if got != want { 944 t.Errorf("want:\n%q\ngot:\n%q", want, got) 945 } 946} 947 948func assertPosition(t *testing.T, text string, ref map[string]Position) { 949 tree, err := Load(text) 950 if err != nil { 951 t.Errorf("Error loading document text: `%v`", text) 952 t.Errorf("Error: %v", err) 953 } 954 for path, pos := range ref { 955 testPos := tree.GetPosition(path) 956 if testPos.Invalid() { 957 t.Errorf("Failed to query tree path or path has invalid position: %s", path) 958 } else if pos != testPos { 959 t.Errorf("Expected position %v, got %v instead", pos, testPos) 960 } 961 } 962} 963 964func TestDocumentPositions(t *testing.T) { 965 assertPosition(t, 966 "[foo]\nbar=42\nbaz=69", 967 map[string]Position{ 968 "": {1, 1}, 969 "foo": {1, 1}, 970 "foo.bar": {2, 1}, 971 "foo.baz": {3, 1}, 972 }) 973} 974 975func TestDocumentPositionsWithSpaces(t *testing.T) { 976 assertPosition(t, 977 " [foo]\n bar=42\n baz=69", 978 map[string]Position{ 979 "": {1, 1}, 980 "foo": {1, 3}, 981 "foo.bar": {2, 3}, 982 "foo.baz": {3, 3}, 983 }) 984} 985 986func TestDocumentPositionsWithGroupArray(t *testing.T) { 987 assertPosition(t, 988 "[[foo]]\nbar=42\nbaz=69", 989 map[string]Position{ 990 "": {1, 1}, 991 "foo": {1, 1}, 992 "foo.bar": {2, 1}, 993 "foo.baz": {3, 1}, 994 }) 995} 996 997func TestNestedTreePosition(t *testing.T) { 998 assertPosition(t, 999 "[foo.bar]\na=42\nb=69", 1000 map[string]Position{ 1001 "": {1, 1}, 1002 "foo": {1, 1}, 1003 "foo.bar": {1, 1}, 1004 "foo.bar.a": {2, 1}, 1005 "foo.bar.b": {3, 1}, 1006 }) 1007} 1008 1009func TestInvalidGroupArray(t *testing.T) { 1010 _, err := Load("[table#key]\nanswer = 42") 1011 if err == nil { 1012 t.Error("Should error") 1013 } 1014 1015 _, err = Load("[foo.[bar]\na = 42") 1016 if err.Error() != "(1, 2): unexpected token table key cannot contain ']', was expecting a table key" { 1017 t.Error("Bad error message:", err.Error()) 1018 } 1019} 1020 1021func TestDoubleEqual(t *testing.T) { 1022 _, err := Load("foo= = 2") 1023 if err.Error() != "(1, 6): cannot have multiple equals for the same key" { 1024 t.Error("Bad error message:", err.Error()) 1025 } 1026} 1027 1028func TestGroupArrayReassign(t *testing.T) { 1029 _, err := Load("[hello]\n[[hello]]") 1030 if err.Error() != "(2, 3): key \"hello\" is already assigned and not of type table array" { 1031 t.Error("Bad error message:", err.Error()) 1032 } 1033} 1034 1035func TestInvalidFloatParsing(t *testing.T) { 1036 _, err := Load("a=1e_2") 1037 if err.Error() != "(1, 3): invalid use of _ in number" { 1038 t.Error("Bad error message:", err.Error()) 1039 } 1040 1041 _, err = Load("a=1e2_") 1042 if err.Error() != "(1, 3): invalid use of _ in number" { 1043 t.Error("Bad error message:", err.Error()) 1044 } 1045 1046 _, err = Load("a=1__2") 1047 if err.Error() != "(1, 3): invalid use of _ in number" { 1048 t.Error("Bad error message:", err.Error()) 1049 } 1050 1051 _, err = Load("a=_1_2") 1052 if err.Error() != "(1, 3): no value can start with _" { 1053 t.Error("Bad error message:", err.Error()) 1054 } 1055} 1056 1057func TestMapKeyIsNum(t *testing.T) { 1058 _, err := Load("table={2018=1,2019=2}") 1059 if err != nil { 1060 t.Error("should be passed") 1061 } 1062 _, err = Load(`table={"2018"=1,"2019"=2}`) 1063 if err != nil { 1064 t.Error("should be passed") 1065 } 1066} 1067 1068func TestInvalidKeyInlineTable(t *testing.T) { 1069 _, err := Load("table={invalid..key = 1}") 1070 if err.Error() != "(1, 8): invalid key: expecting key part after dot" { 1071 t.Error("Bad error message:", err.Error()) 1072 } 1073} 1074 1075func TestDottedKeys(t *testing.T) { 1076 tree, err := Load(` 1077name = "Orange" 1078physical.color = "orange" 1079physical.shape = "round" 1080site."google.com" = true`) 1081 1082 assertTree(t, tree, err, map[string]interface{}{ 1083 "name": "Orange", 1084 "physical": map[string]interface{}{ 1085 "color": "orange", 1086 "shape": "round", 1087 }, 1088 "site": map[string]interface{}{ 1089 "google.com": true, 1090 }, 1091 }) 1092} 1093 1094func TestInvalidDottedKeyEmptyGroup(t *testing.T) { 1095 _, err := Load(`a..b = true`) 1096 if err == nil { 1097 t.Fatal("should return an error") 1098 } 1099 if err.Error() != "(1, 1): invalid key: expecting key part after dot" { 1100 t.Fatalf("invalid error message: %s", err) 1101 } 1102} 1103 1104func TestAccidentalNewlines(t *testing.T) { 1105 expected := "The quick brown fox jumps over the lazy dog." 1106 tree, err := Load(`str1 = "The quick brown fox jumps over the lazy dog." 1107 1108str2 = """ 1109The quick brown \ 1110 1111 1112 fox jumps over \ 1113 the lazy dog.""" 1114 1115str3 = """\ 1116 The quick brown \` + " " + ` 1117 fox jumps over \` + " " + ` 1118 the lazy dog.\` + " " + ` 1119 """`) 1120 if err != nil { 1121 t.Fatalf("unexpected error: %v", err) 1122 } 1123 1124 got := tree.Get("str1") 1125 if got != expected { 1126 t.Errorf("expected '%s', got '%s'", expected, got) 1127 } 1128 1129 got = tree.Get("str2") 1130 if got != expected { 1131 t.Errorf("expected '%s', got '%s'", expected, got) 1132 } 1133 1134 got = tree.Get("str3") 1135 if got != expected { 1136 t.Errorf("expected '%s', got '%s'", expected, got) 1137 } 1138} 1139