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 246func TestLocalDateTimeNano(t *testing.T) { 247 tree, err := Load("a = 1979-05-27T07:32:00.999999") 248 assertTree(t, tree, err, map[string]interface{}{ 249 "a": LocalDateTime{ 250 Date: LocalDate{ 251 Year: 1979, 252 Month: 5, 253 Day: 27, 254 }, 255 Time: LocalTime{ 256 Hour: 7, 257 Minute: 32, 258 Second: 0, 259 Nanosecond: 999999000, 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 TestLocalTime(t *testing.T) { 276 tree, err := Load("a = 07:32:00") 277 assertTree(t, tree, err, map[string]interface{}{ 278 "a": LocalTime{ 279 Hour: 7, 280 Minute: 32, 281 Second: 0, 282 Nanosecond: 0, 283 }, 284 }) 285} 286 287func TestLocalTimeNano(t *testing.T) { 288 tree, err := Load("a = 00:32:00.999999") 289 assertTree(t, tree, err, map[string]interface{}{ 290 "a": LocalTime{ 291 Hour: 0, 292 Minute: 32, 293 Second: 0, 294 Nanosecond: 999999000, 295 }, 296 }) 297} 298 299func TestSimpleString(t *testing.T) { 300 tree, err := Load("a = \"hello world\"") 301 assertTree(t, tree, err, map[string]interface{}{ 302 "a": "hello world", 303 }) 304} 305 306func TestSpaceKey(t *testing.T) { 307 tree, err := Load("\"a b\" = \"hello world\"") 308 assertTree(t, tree, err, map[string]interface{}{ 309 "a b": "hello world", 310 }) 311} 312 313func TestDoubleQuotedKey(t *testing.T) { 314 tree, err := Load(` 315 "key" = "a" 316 "\t" = "b" 317 "\U0001F914" = "c" 318 "\u2764" = "d" 319 `) 320 assertTree(t, tree, err, map[string]interface{}{ 321 "key": "a", 322 "\t": "b", 323 "\U0001F914": "c", 324 "\u2764": "d", 325 }) 326} 327 328func TestSingleQuotedKey(t *testing.T) { 329 tree, err := Load(` 330 'key' = "a" 331 '\t' = "b" 332 '\U0001F914' = "c" 333 '\u2764' = "d" 334 `) 335 assertTree(t, tree, err, map[string]interface{}{ 336 `key`: "a", 337 `\t`: "b", 338 `\U0001F914`: "c", 339 `\u2764`: "d", 340 }) 341} 342 343func TestStringEscapables(t *testing.T) { 344 tree, err := Load("a = \"a \\n b\"") 345 assertTree(t, tree, err, map[string]interface{}{ 346 "a": "a \n b", 347 }) 348 349 tree, err = Load("a = \"a \\t b\"") 350 assertTree(t, tree, err, map[string]interface{}{ 351 "a": "a \t b", 352 }) 353 354 tree, err = Load("a = \"a \\r b\"") 355 assertTree(t, tree, err, map[string]interface{}{ 356 "a": "a \r b", 357 }) 358 359 tree, err = Load("a = \"a \\\\ b\"") 360 assertTree(t, tree, err, map[string]interface{}{ 361 "a": "a \\ b", 362 }) 363} 364 365func TestEmptyQuotedString(t *testing.T) { 366 tree, err := Load(`[""] 367"" = 1`) 368 assertTree(t, tree, err, map[string]interface{}{ 369 "": map[string]interface{}{ 370 "": int64(1), 371 }, 372 }) 373} 374 375func TestBools(t *testing.T) { 376 tree, err := Load("a = true\nb = false") 377 assertTree(t, tree, err, map[string]interface{}{ 378 "a": true, 379 "b": false, 380 }) 381} 382 383func TestNestedKeys(t *testing.T) { 384 tree, err := Load("[a.b.c]\nd = 42") 385 assertTree(t, tree, err, map[string]interface{}{ 386 "a": map[string]interface{}{ 387 "b": map[string]interface{}{ 388 "c": map[string]interface{}{ 389 "d": int64(42), 390 }, 391 }, 392 }, 393 }) 394} 395 396func TestNestedQuotedUnicodeKeys(t *testing.T) { 397 tree, err := Load("[ j . \"ʞ\" . l ]\nd = 42") 398 assertTree(t, tree, err, map[string]interface{}{ 399 "j": map[string]interface{}{ 400 "ʞ": map[string]interface{}{ 401 "l": map[string]interface{}{ 402 "d": int64(42), 403 }, 404 }, 405 }, 406 }) 407 408 tree, err = Load("[ g . h . i ]\nd = 42") 409 assertTree(t, tree, err, map[string]interface{}{ 410 "g": map[string]interface{}{ 411 "h": map[string]interface{}{ 412 "i": map[string]interface{}{ 413 "d": int64(42), 414 }, 415 }, 416 }, 417 }) 418 419 tree, err = Load("[ d.e.f ]\nk = 42") 420 assertTree(t, tree, err, map[string]interface{}{ 421 "d": map[string]interface{}{ 422 "e": map[string]interface{}{ 423 "f": map[string]interface{}{ 424 "k": int64(42), 425 }, 426 }, 427 }, 428 }) 429} 430 431func TestArrayOne(t *testing.T) { 432 tree, err := Load("a = [1]") 433 assertTree(t, tree, err, map[string]interface{}{ 434 "a": []int64{int64(1)}, 435 }) 436} 437 438func TestArrayZero(t *testing.T) { 439 tree, err := Load("a = []") 440 assertTree(t, tree, err, map[string]interface{}{ 441 "a": []interface{}{}, 442 }) 443} 444 445func TestArraySimple(t *testing.T) { 446 tree, err := Load("a = [42, 21, 10]") 447 assertTree(t, tree, err, map[string]interface{}{ 448 "a": []int64{int64(42), int64(21), int64(10)}, 449 }) 450 451 tree, _ = Load("a = [42, 21, 10,]") 452 assertTree(t, tree, err, map[string]interface{}{ 453 "a": []int64{int64(42), int64(21), int64(10)}, 454 }) 455} 456 457func TestArrayMultiline(t *testing.T) { 458 tree, err := Load("a = [42,\n21, 10,]") 459 assertTree(t, tree, err, map[string]interface{}{ 460 "a": []int64{int64(42), int64(21), int64(10)}, 461 }) 462} 463 464func TestArrayNested(t *testing.T) { 465 tree, err := Load("a = [[42, 21], [10]]") 466 assertTree(t, tree, err, map[string]interface{}{ 467 "a": [][]int64{{int64(42), int64(21)}, {int64(10)}}, 468 }) 469} 470 471func TestNestedArrayComment(t *testing.T) { 472 tree, err := Load(` 473someArray = [ 474# does not work 475["entry1"] 476]`) 477 assertTree(t, tree, err, map[string]interface{}{ 478 "someArray": [][]string{{"entry1"}}, 479 }) 480} 481 482func TestNestedEmptyArrays(t *testing.T) { 483 tree, err := Load("a = [[[]]]") 484 assertTree(t, tree, err, map[string]interface{}{ 485 "a": [][][]interface{}{{{}}}, 486 }) 487} 488 489func TestArrayMixedTypes(t *testing.T) { 490 _, err := Load("a = [42, 16.0]") 491 if err.Error() != "(1, 10): mixed types in array" { 492 t.Error("Bad error message:", err.Error()) 493 } 494 495 _, err = Load("a = [42, \"hello\"]") 496 if err.Error() != "(1, 11): mixed types in array" { 497 t.Error("Bad error message:", err.Error()) 498 } 499} 500 501func TestArrayNestedStrings(t *testing.T) { 502 tree, err := Load("data = [ [\"gamma\", \"delta\"], [\"Foo\"] ]") 503 assertTree(t, tree, err, map[string]interface{}{ 504 "data": [][]string{{"gamma", "delta"}, {"Foo"}}, 505 }) 506} 507 508func TestParseUnknownRvalue(t *testing.T) { 509 _, err := Load("a = !bssss") 510 if err == nil { 511 t.Error("Expecting a parse error") 512 } 513 514 _, err = Load("a = /b") 515 if err == nil { 516 t.Error("Expecting a parse error") 517 } 518} 519 520func TestMissingValue(t *testing.T) { 521 _, err := Load("a = ") 522 if err.Error() != "(1, 5): expecting a value" { 523 t.Error("Bad error message:", err.Error()) 524 } 525} 526 527func TestUnterminatedArray(t *testing.T) { 528 _, err := Load("a = [1,") 529 if err.Error() != "(1, 8): unterminated array" { 530 t.Error("Bad error message:", err.Error()) 531 } 532 533 _, err = Load("a = [1") 534 if err.Error() != "(1, 7): unterminated array" { 535 t.Error("Bad error message:", err.Error()) 536 } 537 538 _, err = Load("a = [1 2") 539 if err.Error() != "(1, 8): missing comma" { 540 t.Error("Bad error message:", err.Error()) 541 } 542} 543 544func TestNewlinesInArrays(t *testing.T) { 545 tree, err := Load("a = [1,\n2,\n3]") 546 assertTree(t, tree, err, map[string]interface{}{ 547 "a": []int64{int64(1), int64(2), int64(3)}, 548 }) 549} 550 551func TestArrayWithExtraComma(t *testing.T) { 552 tree, err := Load("a = [1,\n2,\n3,\n]") 553 assertTree(t, tree, err, map[string]interface{}{ 554 "a": []int64{int64(1), int64(2), int64(3)}, 555 }) 556} 557 558func TestArrayWithExtraCommaComment(t *testing.T) { 559 tree, err := Load("a = [1, # wow\n2, # such items\n3, # so array\n]") 560 assertTree(t, tree, err, map[string]interface{}{ 561 "a": []int64{int64(1), int64(2), int64(3)}, 562 }) 563} 564 565func TestSimpleInlineGroup(t *testing.T) { 566 tree, err := Load("key = {a = 42}") 567 assertTree(t, tree, err, map[string]interface{}{ 568 "key": map[string]interface{}{ 569 "a": int64(42), 570 }, 571 }) 572} 573 574func TestDoubleInlineGroup(t *testing.T) { 575 tree, err := Load("key = {a = 42, b = \"foo\"}") 576 assertTree(t, tree, err, map[string]interface{}{ 577 "key": map[string]interface{}{ 578 "a": int64(42), 579 "b": "foo", 580 }, 581 }) 582} 583 584func TestExampleInlineGroup(t *testing.T) { 585 tree, err := Load(`name = { first = "Tom", last = "Preston-Werner" } 586point = { x = 1, y = 2 }`) 587 assertTree(t, tree, err, map[string]interface{}{ 588 "name": map[string]interface{}{ 589 "first": "Tom", 590 "last": "Preston-Werner", 591 }, 592 "point": map[string]interface{}{ 593 "x": int64(1), 594 "y": int64(2), 595 }, 596 }) 597} 598 599func TestInlineGroupBareKeysUnderscore(t *testing.T) { 600 tree, err := Load(`foo = { _bar = "buz" }`) 601 assertTree(t, tree, err, map[string]interface{}{ 602 "foo": map[string]interface{}{ 603 "_bar": "buz", 604 }, 605 }) 606} 607 608func TestInlineGroupBareKeysDash(t *testing.T) { 609 tree, err := Load(`foo = { -bar = "buz" }`) 610 assertTree(t, tree, err, map[string]interface{}{ 611 "foo": map[string]interface{}{ 612 "-bar": "buz", 613 }, 614 }) 615} 616 617func TestInlineGroupKeyQuoted(t *testing.T) { 618 tree, err := Load(`foo = { "bar" = "buz" }`) 619 assertTree(t, tree, err, map[string]interface{}{ 620 "foo": map[string]interface{}{ 621 "bar": "buz", 622 }, 623 }) 624} 625 626func TestExampleInlineGroupInArray(t *testing.T) { 627 tree, err := Load(`points = [{ x = 1, y = 2 }]`) 628 assertTree(t, tree, err, map[string]interface{}{ 629 "points": []map[string]interface{}{ 630 { 631 "x": int64(1), 632 "y": int64(2), 633 }, 634 }, 635 }) 636} 637 638func TestInlineTableUnterminated(t *testing.T) { 639 _, err := Load("foo = {") 640 if err.Error() != "(1, 8): unterminated inline table" { 641 t.Error("Bad error message:", err.Error()) 642 } 643} 644 645func TestInlineTableCommaExpected(t *testing.T) { 646 _, err := Load("foo = {hello = 53 test = foo}") 647 if err.Error() != "(1, 19): comma expected between fields in inline table" { 648 t.Error("Bad error message:", err.Error()) 649 } 650} 651 652func TestInlineTableCommaStart(t *testing.T) { 653 _, err := Load("foo = {, hello = 53}") 654 if err.Error() != "(1, 8): unexpected token type in inline table: keys cannot contain , character" { 655 t.Error("Bad error message:", err.Error()) 656 } 657} 658 659func TestInlineTableDoubleComma(t *testing.T) { 660 _, err := Load("foo = {hello = 53,, foo = 17}") 661 if err.Error() != "(1, 19): need field between two commas in inline table" { 662 t.Error("Bad error message:", err.Error()) 663 } 664} 665 666func TestDuplicateGroups(t *testing.T) { 667 _, err := Load("[foo]\na=2\n[foo]b=3") 668 if err.Error() != "(3, 2): duplicated tables" { 669 t.Error("Bad error message:", err.Error()) 670 } 671} 672 673func TestDuplicateKeys(t *testing.T) { 674 _, err := Load("foo = 2\nfoo = 3") 675 if err.Error() != "(2, 1): The following key was defined twice: foo" { 676 t.Error("Bad error message:", err.Error()) 677 } 678} 679 680func TestEmptyIntermediateTable(t *testing.T) { 681 _, err := Load("[foo..bar]") 682 if err.Error() != "(1, 2): invalid table array key: expecting key part after dot" { 683 t.Error("Bad error message:", err.Error()) 684 } 685} 686 687func TestImplicitDeclarationBefore(t *testing.T) { 688 tree, err := Load("[a.b.c]\nanswer = 42\n[a]\nbetter = 43") 689 assertTree(t, tree, err, map[string]interface{}{ 690 "a": map[string]interface{}{ 691 "b": map[string]interface{}{ 692 "c": map[string]interface{}{ 693 "answer": int64(42), 694 }, 695 }, 696 "better": int64(43), 697 }, 698 }) 699} 700 701func TestFloatsWithoutLeadingZeros(t *testing.T) { 702 _, err := Load("a = .42") 703 if err.Error() != "(1, 5): cannot start float with a dot" { 704 t.Error("Bad error message:", err.Error()) 705 } 706 707 _, err = Load("a = -.42") 708 if err.Error() != "(1, 5): cannot start float with a dot" { 709 t.Error("Bad error message:", err.Error()) 710 } 711} 712 713func TestMissingFile(t *testing.T) { 714 _, err := LoadFile("foo.toml") 715 if err.Error() != "open foo.toml: no such file or directory" && 716 err.Error() != "open foo.toml: The system cannot find the file specified." { 717 t.Error("Bad error message:", err.Error()) 718 } 719} 720 721func TestParseFile(t *testing.T) { 722 tree, err := LoadFile("example.toml") 723 724 assertTree(t, tree, err, map[string]interface{}{ 725 "title": "TOML Example", 726 "owner": map[string]interface{}{ 727 "name": "Tom Preston-Werner", 728 "organization": "GitHub", 729 "bio": "GitHub Cofounder & CEO\nLikes tater tots and beer.", 730 "dob": time.Date(1979, time.May, 27, 7, 32, 0, 0, time.UTC), 731 }, 732 "database": map[string]interface{}{ 733 "server": "192.168.1.1", 734 "ports": []int64{8001, 8001, 8002}, 735 "connection_max": 5000, 736 "enabled": true, 737 }, 738 "servers": map[string]interface{}{ 739 "alpha": map[string]interface{}{ 740 "ip": "10.0.0.1", 741 "dc": "eqdc10", 742 }, 743 "beta": map[string]interface{}{ 744 "ip": "10.0.0.2", 745 "dc": "eqdc10", 746 }, 747 }, 748 "clients": map[string]interface{}{ 749 "data": []interface{}{ 750 []string{"gamma", "delta"}, 751 []int64{1, 2}, 752 }, 753 }, 754 }) 755} 756 757func TestParseFileCRLF(t *testing.T) { 758 tree, err := LoadFile("example-crlf.toml") 759 760 assertTree(t, tree, err, map[string]interface{}{ 761 "title": "TOML Example", 762 "owner": map[string]interface{}{ 763 "name": "Tom Preston-Werner", 764 "organization": "GitHub", 765 "bio": "GitHub Cofounder & CEO\nLikes tater tots and beer.", 766 "dob": time.Date(1979, time.May, 27, 7, 32, 0, 0, time.UTC), 767 }, 768 "database": map[string]interface{}{ 769 "server": "192.168.1.1", 770 "ports": []int64{8001, 8001, 8002}, 771 "connection_max": 5000, 772 "enabled": true, 773 }, 774 "servers": map[string]interface{}{ 775 "alpha": map[string]interface{}{ 776 "ip": "10.0.0.1", 777 "dc": "eqdc10", 778 }, 779 "beta": map[string]interface{}{ 780 "ip": "10.0.0.2", 781 "dc": "eqdc10", 782 }, 783 }, 784 "clients": map[string]interface{}{ 785 "data": []interface{}{ 786 []string{"gamma", "delta"}, 787 []int64{1, 2}, 788 }, 789 }, 790 }) 791} 792 793func TestParseKeyGroupArray(t *testing.T) { 794 tree, err := Load("[[foo.bar]] a = 42\n[[foo.bar]] a = 69") 795 assertTree(t, tree, err, map[string]interface{}{ 796 "foo": map[string]interface{}{ 797 "bar": []map[string]interface{}{ 798 {"a": int64(42)}, 799 {"a": int64(69)}, 800 }, 801 }, 802 }) 803} 804 805func TestParseKeyGroupArrayUnfinished(t *testing.T) { 806 _, err := Load("[[foo.bar]\na = 42") 807 if err.Error() != "(1, 10): was expecting token [[, but got unclosed table array key instead" { 808 t.Error("Bad error message:", err.Error()) 809 } 810 811 _, err = Load("[[foo.[bar]\na = 42") 812 if err.Error() != "(1, 3): unexpected token table array key cannot contain ']', was expecting a table array key" { 813 t.Error("Bad error message:", err.Error()) 814 } 815} 816 817func TestParseKeyGroupArrayQueryExample(t *testing.T) { 818 tree, err := Load(` 819 [[book]] 820 title = "The Stand" 821 author = "Stephen King" 822 [[book]] 823 title = "For Whom the Bell Tolls" 824 author = "Ernest Hemmingway" 825 [[book]] 826 title = "Neuromancer" 827 author = "William Gibson" 828 `) 829 830 assertTree(t, tree, err, map[string]interface{}{ 831 "book": []map[string]interface{}{ 832 {"title": "The Stand", "author": "Stephen King"}, 833 {"title": "For Whom the Bell Tolls", "author": "Ernest Hemmingway"}, 834 {"title": "Neuromancer", "author": "William Gibson"}, 835 }, 836 }) 837} 838 839func TestParseKeyGroupArraySpec(t *testing.T) { 840 tree, err := Load("[[fruit]]\n name=\"apple\"\n [fruit.physical]\n color=\"red\"\n shape=\"round\"\n [[fruit]]\n name=\"banana\"") 841 assertTree(t, tree, err, map[string]interface{}{ 842 "fruit": []map[string]interface{}{ 843 {"name": "apple", "physical": map[string]interface{}{"color": "red", "shape": "round"}}, 844 {"name": "banana"}, 845 }, 846 }) 847} 848 849func TestTomlValueStringRepresentation(t *testing.T) { 850 for idx, item := range []struct { 851 Value interface{} 852 Expect string 853 }{ 854 {int64(12345), "12345"}, 855 {uint64(50), "50"}, 856 {float64(123.45), "123.45"}, 857 {true, "true"}, 858 {"hello world", "\"hello world\""}, 859 {"\b\t\n\f\r\"\\", "\"\\b\\t\\n\\f\\r\\\"\\\\\""}, 860 {"\x05", "\"\\u0005\""}, 861 {time.Date(1979, time.May, 27, 7, 32, 0, 0, time.UTC), 862 "1979-05-27T07:32:00Z"}, 863 {[]interface{}{"gamma", "delta"}, 864 "[\"gamma\",\"delta\"]"}, 865 {nil, ""}, 866 } { 867 result, err := tomlValueStringRepresentation(item.Value, "", false) 868 if err != nil { 869 t.Errorf("Test %d - unexpected error: %s", idx, err) 870 } 871 if result != item.Expect { 872 t.Errorf("Test %d - got '%s', expected '%s'", idx, result, item.Expect) 873 } 874 } 875} 876 877func TestToStringMapStringString(t *testing.T) { 878 tree, err := TreeFromMap(map[string]interface{}{"m": map[string]interface{}{"v": "abc"}}) 879 if err != nil { 880 t.Fatalf("unexpected error: %s", err) 881 } 882 want := "\n[m]\n v = \"abc\"\n" 883 got := tree.String() 884 885 if got != want { 886 t.Errorf("want:\n%q\ngot:\n%q", want, got) 887 } 888} 889 890func assertPosition(t *testing.T, text string, ref map[string]Position) { 891 tree, err := Load(text) 892 if err != nil { 893 t.Errorf("Error loading document text: `%v`", text) 894 t.Errorf("Error: %v", err) 895 } 896 for path, pos := range ref { 897 testPos := tree.GetPosition(path) 898 if testPos.Invalid() { 899 t.Errorf("Failed to query tree path or path has invalid position: %s", path) 900 } else if pos != testPos { 901 t.Errorf("Expected position %v, got %v instead", pos, testPos) 902 } 903 } 904} 905 906func TestDocumentPositions(t *testing.T) { 907 assertPosition(t, 908 "[foo]\nbar=42\nbaz=69", 909 map[string]Position{ 910 "": {1, 1}, 911 "foo": {1, 1}, 912 "foo.bar": {2, 1}, 913 "foo.baz": {3, 1}, 914 }) 915} 916 917func TestDocumentPositionsWithSpaces(t *testing.T) { 918 assertPosition(t, 919 " [foo]\n bar=42\n baz=69", 920 map[string]Position{ 921 "": {1, 1}, 922 "foo": {1, 3}, 923 "foo.bar": {2, 3}, 924 "foo.baz": {3, 3}, 925 }) 926} 927 928func TestDocumentPositionsWithGroupArray(t *testing.T) { 929 assertPosition(t, 930 "[[foo]]\nbar=42\nbaz=69", 931 map[string]Position{ 932 "": {1, 1}, 933 "foo": {1, 1}, 934 "foo.bar": {2, 1}, 935 "foo.baz": {3, 1}, 936 }) 937} 938 939func TestNestedTreePosition(t *testing.T) { 940 assertPosition(t, 941 "[foo.bar]\na=42\nb=69", 942 map[string]Position{ 943 "": {1, 1}, 944 "foo": {1, 1}, 945 "foo.bar": {1, 1}, 946 "foo.bar.a": {2, 1}, 947 "foo.bar.b": {3, 1}, 948 }) 949} 950 951func TestInvalidGroupArray(t *testing.T) { 952 _, err := Load("[table#key]\nanswer = 42") 953 if err == nil { 954 t.Error("Should error") 955 } 956 957 _, err = Load("[foo.[bar]\na = 42") 958 if err.Error() != "(1, 2): unexpected token table key cannot contain ']', was expecting a table key" { 959 t.Error("Bad error message:", err.Error()) 960 } 961} 962 963func TestDoubleEqual(t *testing.T) { 964 _, err := Load("foo= = 2") 965 if err.Error() != "(1, 6): cannot have multiple equals for the same key" { 966 t.Error("Bad error message:", err.Error()) 967 } 968} 969 970func TestGroupArrayReassign(t *testing.T) { 971 _, err := Load("[hello]\n[[hello]]") 972 if err.Error() != "(2, 3): key \"hello\" is already assigned and not of type table array" { 973 t.Error("Bad error message:", err.Error()) 974 } 975} 976 977func TestInvalidFloatParsing(t *testing.T) { 978 _, err := Load("a=1e_2") 979 if err.Error() != "(1, 3): invalid use of _ in number" { 980 t.Error("Bad error message:", err.Error()) 981 } 982 983 _, err = Load("a=1e2_") 984 if err.Error() != "(1, 3): invalid use of _ in number" { 985 t.Error("Bad error message:", err.Error()) 986 } 987 988 _, err = Load("a=1__2") 989 if err.Error() != "(1, 3): invalid use of _ in number" { 990 t.Error("Bad error message:", err.Error()) 991 } 992 993 _, err = Load("a=_1_2") 994 if err.Error() != "(1, 3): cannot start number with underscore" { 995 t.Error("Bad error message:", err.Error()) 996 } 997} 998 999func TestMapKeyIsNum(t *testing.T) { 1000 _, err := Load("table={2018=1,2019=2}") 1001 if err != nil { 1002 t.Error("should be passed") 1003 } 1004 _, err = Load(`table={"2018"=1,"2019"=2}`) 1005 if err != nil { 1006 t.Error("should be passed") 1007 } 1008} 1009 1010func TestInvalidKeyInlineTable(t *testing.T) { 1011 _, err := Load("table={invalid..key = 1}") 1012 if err.Error() != "(1, 8): invalid key: expecting key part after dot" { 1013 t.Error("Bad error message:", err.Error()) 1014 } 1015} 1016 1017func TestDottedKeys(t *testing.T) { 1018 tree, err := Load(` 1019name = "Orange" 1020physical.color = "orange" 1021physical.shape = "round" 1022site."google.com" = true`) 1023 1024 assertTree(t, tree, err, map[string]interface{}{ 1025 "name": "Orange", 1026 "physical": map[string]interface{}{ 1027 "color": "orange", 1028 "shape": "round", 1029 }, 1030 "site": map[string]interface{}{ 1031 "google.com": true, 1032 }, 1033 }) 1034} 1035 1036func TestInvalidDottedKeyEmptyGroup(t *testing.T) { 1037 _, err := Load(`a..b = true`) 1038 if err == nil { 1039 t.Fatal("should return an error") 1040 } 1041 if err.Error() != "(1, 1): invalid key: expecting key part after dot" { 1042 t.Fatalf("invalid error message: %s", err) 1043 } 1044} 1045 1046func TestAccidentalNewlines(t *testing.T) { 1047 expected := "The quick brown fox jumps over the lazy dog." 1048 tree, err := Load(`str1 = "The quick brown fox jumps over the lazy dog." 1049 1050str2 = """ 1051The quick brown \ 1052 1053 1054 fox jumps over \ 1055 the lazy dog.""" 1056 1057str3 = """\ 1058 The quick brown \ 1059 fox jumps over \ 1060 the lazy dog.\ 1061 """`) 1062 1063 if err != nil { 1064 t.Fatalf("unexpected error: %v", err) 1065 } 1066 1067 got := tree.Get("str1") 1068 if got != expected { 1069 t.Errorf("expected '%s', got '%s'", expected, got) 1070 } 1071 1072 got = tree.Get("str2") 1073 if got != expected { 1074 t.Errorf("expected '%s', got '%s'", expected, got) 1075 } 1076 1077 got = tree.Get("str3") 1078 if got != expected { 1079 t.Errorf("expected '%s', got '%s'", expected, got) 1080 } 1081} 1082