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