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): unexpected token" { 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 TestSimpleString(t *testing.T) { 229 tree, err := Load("a = \"hello world\"") 230 assertTree(t, tree, err, map[string]interface{}{ 231 "a": "hello world", 232 }) 233} 234 235func TestSpaceKey(t *testing.T) { 236 tree, err := Load("\"a b\" = \"hello world\"") 237 assertTree(t, tree, err, map[string]interface{}{ 238 "a b": "hello world", 239 }) 240} 241 242func TestDoubleQuotedKey(t *testing.T) { 243 tree, err := Load(` 244 "key" = "a" 245 "\t" = "b" 246 "\U0001F914" = "c" 247 "\u2764" = "d" 248 `) 249 assertTree(t, tree, err, map[string]interface{}{ 250 "key": "a", 251 "\t": "b", 252 "\U0001F914": "c", 253 "\u2764": "d", 254 }) 255} 256 257func TestSingleQuotedKey(t *testing.T) { 258 tree, err := Load(` 259 'key' = "a" 260 '\t' = "b" 261 '\U0001F914' = "c" 262 '\u2764' = "d" 263 `) 264 assertTree(t, tree, err, map[string]interface{}{ 265 `key`: "a", 266 `\t`: "b", 267 `\U0001F914`: "c", 268 `\u2764`: "d", 269 }) 270} 271 272func TestStringEscapables(t *testing.T) { 273 tree, err := Load("a = \"a \\n b\"") 274 assertTree(t, tree, err, map[string]interface{}{ 275 "a": "a \n b", 276 }) 277 278 tree, err = Load("a = \"a \\t b\"") 279 assertTree(t, tree, err, map[string]interface{}{ 280 "a": "a \t b", 281 }) 282 283 tree, err = Load("a = \"a \\r b\"") 284 assertTree(t, tree, err, map[string]interface{}{ 285 "a": "a \r b", 286 }) 287 288 tree, err = Load("a = \"a \\\\ b\"") 289 assertTree(t, tree, err, map[string]interface{}{ 290 "a": "a \\ b", 291 }) 292} 293 294func TestEmptyQuotedString(t *testing.T) { 295 tree, err := Load(`[""] 296"" = 1`) 297 assertTree(t, tree, err, map[string]interface{}{ 298 "": map[string]interface{}{ 299 "": int64(1), 300 }, 301 }) 302} 303 304func TestBools(t *testing.T) { 305 tree, err := Load("a = true\nb = false") 306 assertTree(t, tree, err, map[string]interface{}{ 307 "a": true, 308 "b": false, 309 }) 310} 311 312func TestNestedKeys(t *testing.T) { 313 tree, err := Load("[a.b.c]\nd = 42") 314 assertTree(t, tree, err, map[string]interface{}{ 315 "a": map[string]interface{}{ 316 "b": map[string]interface{}{ 317 "c": map[string]interface{}{ 318 "d": int64(42), 319 }, 320 }, 321 }, 322 }) 323} 324 325func TestNestedQuotedUnicodeKeys(t *testing.T) { 326 tree, err := Load("[ j . \"ʞ\" . l ]\nd = 42") 327 assertTree(t, tree, err, map[string]interface{}{ 328 "j": map[string]interface{}{ 329 "ʞ": map[string]interface{}{ 330 "l": map[string]interface{}{ 331 "d": int64(42), 332 }, 333 }, 334 }, 335 }) 336 337 tree, err = Load("[ g . h . i ]\nd = 42") 338 assertTree(t, tree, err, map[string]interface{}{ 339 "g": map[string]interface{}{ 340 "h": map[string]interface{}{ 341 "i": map[string]interface{}{ 342 "d": int64(42), 343 }, 344 }, 345 }, 346 }) 347 348 tree, err = Load("[ d.e.f ]\nk = 42") 349 assertTree(t, tree, err, map[string]interface{}{ 350 "d": map[string]interface{}{ 351 "e": map[string]interface{}{ 352 "f": map[string]interface{}{ 353 "k": int64(42), 354 }, 355 }, 356 }, 357 }) 358} 359 360func TestArrayOne(t *testing.T) { 361 tree, err := Load("a = [1]") 362 assertTree(t, tree, err, map[string]interface{}{ 363 "a": []int64{int64(1)}, 364 }) 365} 366 367func TestArrayZero(t *testing.T) { 368 tree, err := Load("a = []") 369 assertTree(t, tree, err, map[string]interface{}{ 370 "a": []interface{}{}, 371 }) 372} 373 374func TestArraySimple(t *testing.T) { 375 tree, err := Load("a = [42, 21, 10]") 376 assertTree(t, tree, err, map[string]interface{}{ 377 "a": []int64{int64(42), int64(21), int64(10)}, 378 }) 379 380 tree, _ = Load("a = [42, 21, 10,]") 381 assertTree(t, tree, err, map[string]interface{}{ 382 "a": []int64{int64(42), int64(21), int64(10)}, 383 }) 384} 385 386func TestArrayMultiline(t *testing.T) { 387 tree, err := Load("a = [42,\n21, 10,]") 388 assertTree(t, tree, err, map[string]interface{}{ 389 "a": []int64{int64(42), int64(21), int64(10)}, 390 }) 391} 392 393func TestArrayNested(t *testing.T) { 394 tree, err := Load("a = [[42, 21], [10]]") 395 assertTree(t, tree, err, map[string]interface{}{ 396 "a": [][]int64{{int64(42), int64(21)}, {int64(10)}}, 397 }) 398} 399 400func TestNestedArrayComment(t *testing.T) { 401 tree, err := Load(` 402someArray = [ 403# does not work 404["entry1"] 405]`) 406 assertTree(t, tree, err, map[string]interface{}{ 407 "someArray": [][]string{{"entry1"}}, 408 }) 409} 410 411func TestNestedEmptyArrays(t *testing.T) { 412 tree, err := Load("a = [[[]]]") 413 assertTree(t, tree, err, map[string]interface{}{ 414 "a": [][][]interface{}{{{}}}, 415 }) 416} 417 418func TestArrayMixedTypes(t *testing.T) { 419 _, err := Load("a = [42, 16.0]") 420 if err.Error() != "(1, 10): mixed types in array" { 421 t.Error("Bad error message:", err.Error()) 422 } 423 424 _, err = Load("a = [42, \"hello\"]") 425 if err.Error() != "(1, 11): mixed types in array" { 426 t.Error("Bad error message:", err.Error()) 427 } 428} 429 430func TestArrayNestedStrings(t *testing.T) { 431 tree, err := Load("data = [ [\"gamma\", \"delta\"], [\"Foo\"] ]") 432 assertTree(t, tree, err, map[string]interface{}{ 433 "data": [][]string{{"gamma", "delta"}, {"Foo"}}, 434 }) 435} 436 437func TestParseUnknownRvalue(t *testing.T) { 438 _, err := Load("a = !bssss") 439 if err == nil { 440 t.Error("Expecting a parse error") 441 } 442 443 _, err = Load("a = /b") 444 if err == nil { 445 t.Error("Expecting a parse error") 446 } 447} 448 449func TestMissingValue(t *testing.T) { 450 _, err := Load("a = ") 451 if err.Error() != "(1, 5): expecting a value" { 452 t.Error("Bad error message:", err.Error()) 453 } 454} 455 456func TestUnterminatedArray(t *testing.T) { 457 _, err := Load("a = [1,") 458 if err.Error() != "(1, 8): unterminated array" { 459 t.Error("Bad error message:", err.Error()) 460 } 461 462 _, err = Load("a = [1") 463 if err.Error() != "(1, 7): unterminated array" { 464 t.Error("Bad error message:", err.Error()) 465 } 466 467 _, err = Load("a = [1 2") 468 if err.Error() != "(1, 8): missing comma" { 469 t.Error("Bad error message:", err.Error()) 470 } 471} 472 473func TestNewlinesInArrays(t *testing.T) { 474 tree, err := Load("a = [1,\n2,\n3]") 475 assertTree(t, tree, err, map[string]interface{}{ 476 "a": []int64{int64(1), int64(2), int64(3)}, 477 }) 478} 479 480func TestArrayWithExtraComma(t *testing.T) { 481 tree, err := Load("a = [1,\n2,\n3,\n]") 482 assertTree(t, tree, err, map[string]interface{}{ 483 "a": []int64{int64(1), int64(2), int64(3)}, 484 }) 485} 486 487func TestArrayWithExtraCommaComment(t *testing.T) { 488 tree, err := Load("a = [1, # wow\n2, # such items\n3, # so array\n]") 489 assertTree(t, tree, err, map[string]interface{}{ 490 "a": []int64{int64(1), int64(2), int64(3)}, 491 }) 492} 493 494func TestSimpleInlineGroup(t *testing.T) { 495 tree, err := Load("key = {a = 42}") 496 assertTree(t, tree, err, map[string]interface{}{ 497 "key": map[string]interface{}{ 498 "a": int64(42), 499 }, 500 }) 501} 502 503func TestDoubleInlineGroup(t *testing.T) { 504 tree, err := Load("key = {a = 42, b = \"foo\"}") 505 assertTree(t, tree, err, map[string]interface{}{ 506 "key": map[string]interface{}{ 507 "a": int64(42), 508 "b": "foo", 509 }, 510 }) 511} 512 513func TestExampleInlineGroup(t *testing.T) { 514 tree, err := Load(`name = { first = "Tom", last = "Preston-Werner" } 515point = { x = 1, y = 2 }`) 516 assertTree(t, tree, err, map[string]interface{}{ 517 "name": map[string]interface{}{ 518 "first": "Tom", 519 "last": "Preston-Werner", 520 }, 521 "point": map[string]interface{}{ 522 "x": int64(1), 523 "y": int64(2), 524 }, 525 }) 526} 527 528func TestExampleInlineGroupInArray(t *testing.T) { 529 tree, err := Load(`points = [{ x = 1, y = 2 }]`) 530 assertTree(t, tree, err, map[string]interface{}{ 531 "points": []map[string]interface{}{ 532 { 533 "x": int64(1), 534 "y": int64(2), 535 }, 536 }, 537 }) 538} 539 540func TestInlineTableUnterminated(t *testing.T) { 541 _, err := Load("foo = {") 542 if err.Error() != "(1, 8): unterminated inline table" { 543 t.Error("Bad error message:", err.Error()) 544 } 545} 546 547func TestInlineTableCommaExpected(t *testing.T) { 548 _, err := Load("foo = {hello = 53 test = foo}") 549 if err.Error() != "(1, 19): comma expected between fields in inline table" { 550 t.Error("Bad error message:", err.Error()) 551 } 552} 553 554func TestInlineTableCommaStart(t *testing.T) { 555 _, err := Load("foo = {, hello = 53}") 556 if err.Error() != "(1, 8): inline table cannot start with a comma" { 557 t.Error("Bad error message:", err.Error()) 558 } 559} 560 561func TestInlineTableDoubleComma(t *testing.T) { 562 _, err := Load("foo = {hello = 53,, foo = 17}") 563 if err.Error() != "(1, 19): need field between two commas in inline table" { 564 t.Error("Bad error message:", err.Error()) 565 } 566} 567 568func TestDuplicateGroups(t *testing.T) { 569 _, err := Load("[foo]\na=2\n[foo]b=3") 570 if err.Error() != "(3, 2): duplicated tables" { 571 t.Error("Bad error message:", err.Error()) 572 } 573} 574 575func TestDuplicateKeys(t *testing.T) { 576 _, err := Load("foo = 2\nfoo = 3") 577 if err.Error() != "(2, 1): The following key was defined twice: foo" { 578 t.Error("Bad error message:", err.Error()) 579 } 580} 581 582func TestEmptyIntermediateTable(t *testing.T) { 583 _, err := Load("[foo..bar]") 584 if err.Error() != "(1, 2): invalid table array key: empty table key" { 585 t.Error("Bad error message:", err.Error()) 586 } 587} 588 589func TestImplicitDeclarationBefore(t *testing.T) { 590 tree, err := Load("[a.b.c]\nanswer = 42\n[a]\nbetter = 43") 591 assertTree(t, tree, err, map[string]interface{}{ 592 "a": map[string]interface{}{ 593 "b": map[string]interface{}{ 594 "c": map[string]interface{}{ 595 "answer": int64(42), 596 }, 597 }, 598 "better": int64(43), 599 }, 600 }) 601} 602 603func TestFloatsWithoutLeadingZeros(t *testing.T) { 604 _, err := Load("a = .42") 605 if err.Error() != "(1, 5): cannot start float with a dot" { 606 t.Error("Bad error message:", err.Error()) 607 } 608 609 _, err = Load("a = -.42") 610 if err.Error() != "(1, 5): cannot start float with a dot" { 611 t.Error("Bad error message:", err.Error()) 612 } 613} 614 615func TestMissingFile(t *testing.T) { 616 _, err := LoadFile("foo.toml") 617 if err.Error() != "open foo.toml: no such file or directory" && 618 err.Error() != "open foo.toml: The system cannot find the file specified." { 619 t.Error("Bad error message:", err.Error()) 620 } 621} 622 623func TestParseFile(t *testing.T) { 624 tree, err := LoadFile("example.toml") 625 626 assertTree(t, tree, err, map[string]interface{}{ 627 "title": "TOML Example", 628 "owner": map[string]interface{}{ 629 "name": "Tom Preston-Werner", 630 "organization": "GitHub", 631 "bio": "GitHub Cofounder & CEO\nLikes tater tots and beer.", 632 "dob": time.Date(1979, time.May, 27, 7, 32, 0, 0, time.UTC), 633 }, 634 "database": map[string]interface{}{ 635 "server": "192.168.1.1", 636 "ports": []int64{8001, 8001, 8002}, 637 "connection_max": 5000, 638 "enabled": true, 639 }, 640 "servers": map[string]interface{}{ 641 "alpha": map[string]interface{}{ 642 "ip": "10.0.0.1", 643 "dc": "eqdc10", 644 }, 645 "beta": map[string]interface{}{ 646 "ip": "10.0.0.2", 647 "dc": "eqdc10", 648 }, 649 }, 650 "clients": map[string]interface{}{ 651 "data": []interface{}{ 652 []string{"gamma", "delta"}, 653 []int64{1, 2}, 654 }, 655 }, 656 }) 657} 658 659func TestParseFileCRLF(t *testing.T) { 660 tree, err := LoadFile("example-crlf.toml") 661 662 assertTree(t, tree, err, map[string]interface{}{ 663 "title": "TOML Example", 664 "owner": map[string]interface{}{ 665 "name": "Tom Preston-Werner", 666 "organization": "GitHub", 667 "bio": "GitHub Cofounder & CEO\nLikes tater tots and beer.", 668 "dob": time.Date(1979, time.May, 27, 7, 32, 0, 0, time.UTC), 669 }, 670 "database": map[string]interface{}{ 671 "server": "192.168.1.1", 672 "ports": []int64{8001, 8001, 8002}, 673 "connection_max": 5000, 674 "enabled": true, 675 }, 676 "servers": map[string]interface{}{ 677 "alpha": map[string]interface{}{ 678 "ip": "10.0.0.1", 679 "dc": "eqdc10", 680 }, 681 "beta": map[string]interface{}{ 682 "ip": "10.0.0.2", 683 "dc": "eqdc10", 684 }, 685 }, 686 "clients": map[string]interface{}{ 687 "data": []interface{}{ 688 []string{"gamma", "delta"}, 689 []int64{1, 2}, 690 }, 691 }, 692 }) 693} 694 695func TestParseKeyGroupArray(t *testing.T) { 696 tree, err := Load("[[foo.bar]] a = 42\n[[foo.bar]] a = 69") 697 assertTree(t, tree, err, map[string]interface{}{ 698 "foo": map[string]interface{}{ 699 "bar": []map[string]interface{}{ 700 {"a": int64(42)}, 701 {"a": int64(69)}, 702 }, 703 }, 704 }) 705} 706 707func TestParseKeyGroupArrayUnfinished(t *testing.T) { 708 _, err := Load("[[foo.bar]\na = 42") 709 if err.Error() != "(1, 10): was expecting token [[, but got unclosed table array key instead" { 710 t.Error("Bad error message:", err.Error()) 711 } 712 713 _, err = Load("[[foo.[bar]\na = 42") 714 if err.Error() != "(1, 3): unexpected token table array key cannot contain ']', was expecting a table array key" { 715 t.Error("Bad error message:", err.Error()) 716 } 717} 718 719func TestParseKeyGroupArrayQueryExample(t *testing.T) { 720 tree, err := Load(` 721 [[book]] 722 title = "The Stand" 723 author = "Stephen King" 724 [[book]] 725 title = "For Whom the Bell Tolls" 726 author = "Ernest Hemmingway" 727 [[book]] 728 title = "Neuromancer" 729 author = "William Gibson" 730 `) 731 732 assertTree(t, tree, err, map[string]interface{}{ 733 "book": []map[string]interface{}{ 734 {"title": "The Stand", "author": "Stephen King"}, 735 {"title": "For Whom the Bell Tolls", "author": "Ernest Hemmingway"}, 736 {"title": "Neuromancer", "author": "William Gibson"}, 737 }, 738 }) 739} 740 741func TestParseKeyGroupArraySpec(t *testing.T) { 742 tree, err := Load("[[fruit]]\n name=\"apple\"\n [fruit.physical]\n color=\"red\"\n shape=\"round\"\n [[fruit]]\n name=\"banana\"") 743 assertTree(t, tree, err, map[string]interface{}{ 744 "fruit": []map[string]interface{}{ 745 {"name": "apple", "physical": map[string]interface{}{"color": "red", "shape": "round"}}, 746 {"name": "banana"}, 747 }, 748 }) 749} 750 751func TestTomlValueStringRepresentation(t *testing.T) { 752 for idx, item := range []struct { 753 Value interface{} 754 Expect string 755 }{ 756 {int64(12345), "12345"}, 757 {uint64(50), "50"}, 758 {float64(123.45), "123.45"}, 759 {true, "true"}, 760 {"hello world", "\"hello world\""}, 761 {"\b\t\n\f\r\"\\", "\"\\b\\t\\n\\f\\r\\\"\\\\\""}, 762 {"\x05", "\"\\u0005\""}, 763 {time.Date(1979, time.May, 27, 7, 32, 0, 0, time.UTC), 764 "1979-05-27T07:32:00Z"}, 765 {[]interface{}{"gamma", "delta"}, 766 "[\"gamma\",\"delta\"]"}, 767 {nil, ""}, 768 } { 769 result, err := tomlValueStringRepresentation(item.Value, "", false) 770 if err != nil { 771 t.Errorf("Test %d - unexpected error: %s", idx, err) 772 } 773 if result != item.Expect { 774 t.Errorf("Test %d - got '%s', expected '%s'", idx, result, item.Expect) 775 } 776 } 777} 778 779func TestToStringMapStringString(t *testing.T) { 780 tree, err := TreeFromMap(map[string]interface{}{"m": map[string]interface{}{"v": "abc"}}) 781 if err != nil { 782 t.Fatalf("unexpected error: %s", err) 783 } 784 want := "\n[m]\n v = \"abc\"\n" 785 got := tree.String() 786 787 if got != want { 788 t.Errorf("want:\n%q\ngot:\n%q", want, got) 789 } 790} 791 792func assertPosition(t *testing.T, text string, ref map[string]Position) { 793 tree, err := Load(text) 794 if err != nil { 795 t.Errorf("Error loading document text: `%v`", text) 796 t.Errorf("Error: %v", err) 797 } 798 for path, pos := range ref { 799 testPos := tree.GetPosition(path) 800 if testPos.Invalid() { 801 t.Errorf("Failed to query tree path or path has invalid position: %s", path) 802 } else if pos != testPos { 803 t.Errorf("Expected position %v, got %v instead", pos, testPos) 804 } 805 } 806} 807 808func TestDocumentPositions(t *testing.T) { 809 assertPosition(t, 810 "[foo]\nbar=42\nbaz=69", 811 map[string]Position{ 812 "": {1, 1}, 813 "foo": {1, 1}, 814 "foo.bar": {2, 1}, 815 "foo.baz": {3, 1}, 816 }) 817} 818 819func TestDocumentPositionsWithSpaces(t *testing.T) { 820 assertPosition(t, 821 " [foo]\n bar=42\n baz=69", 822 map[string]Position{ 823 "": {1, 1}, 824 "foo": {1, 3}, 825 "foo.bar": {2, 3}, 826 "foo.baz": {3, 3}, 827 }) 828} 829 830func TestDocumentPositionsWithGroupArray(t *testing.T) { 831 assertPosition(t, 832 "[[foo]]\nbar=42\nbaz=69", 833 map[string]Position{ 834 "": {1, 1}, 835 "foo": {1, 1}, 836 "foo.bar": {2, 1}, 837 "foo.baz": {3, 1}, 838 }) 839} 840 841func TestNestedTreePosition(t *testing.T) { 842 assertPosition(t, 843 "[foo.bar]\na=42\nb=69", 844 map[string]Position{ 845 "": {1, 1}, 846 "foo": {1, 1}, 847 "foo.bar": {1, 1}, 848 "foo.bar.a": {2, 1}, 849 "foo.bar.b": {3, 1}, 850 }) 851} 852 853func TestInvalidGroupArray(t *testing.T) { 854 _, err := Load("[table#key]\nanswer = 42") 855 if err == nil { 856 t.Error("Should error") 857 } 858 859 _, err = Load("[foo.[bar]\na = 42") 860 if err.Error() != "(1, 2): unexpected token table key cannot contain ']', was expecting a table key" { 861 t.Error("Bad error message:", err.Error()) 862 } 863} 864 865func TestDoubleEqual(t *testing.T) { 866 _, err := Load("foo= = 2") 867 if err.Error() != "(1, 6): cannot have multiple equals for the same key" { 868 t.Error("Bad error message:", err.Error()) 869 } 870} 871 872func TestGroupArrayReassign(t *testing.T) { 873 _, err := Load("[hello]\n[[hello]]") 874 if err.Error() != "(2, 3): key \"hello\" is already assigned and not of type table array" { 875 t.Error("Bad error message:", err.Error()) 876 } 877} 878 879func TestInvalidFloatParsing(t *testing.T) { 880 _, err := Load("a=1e_2") 881 if err.Error() != "(1, 3): invalid use of _ in number" { 882 t.Error("Bad error message:", err.Error()) 883 } 884 885 _, err = Load("a=1e2_") 886 if err.Error() != "(1, 3): invalid use of _ in number" { 887 t.Error("Bad error message:", err.Error()) 888 } 889 890 _, err = Load("a=1__2") 891 if err.Error() != "(1, 3): invalid use of _ in number" { 892 t.Error("Bad error message:", err.Error()) 893 } 894 895 _, err = Load("a=_1_2") 896 if err.Error() != "(1, 3): cannot start number with underscore" { 897 t.Error("Bad error message:", err.Error()) 898 } 899} 900