9 "github.com/davecgh/go-spew/spew"
12 func assertSubTree(t *testing.T, path []string, tree *Tree, err error, ref map[string]interface{}) {
14 t.Error("Non-nil error:", err.Error())
17 for k, v := range ref {
18 nextPath := append(path, k)
19 t.Log("asserting path", nextPath)
20 // NOTE: directly access key instead of resolve by path
21 // NOTE: see TestSpecialKV
22 switch node := tree.GetPath([]string{k}).(type) {
24 t.Log("\tcomparing key", nextPath, "by array iteration")
25 for idx, item := range node {
26 assertSubTree(t, nextPath, item, err, v.([]map[string]interface{})[idx])
29 t.Log("\tcomparing key", nextPath, "by subtree assestion")
30 assertSubTree(t, nextPath, node, err, v.(map[string]interface{}))
32 t.Log("\tcomparing key", nextPath, "by string representation because it's of type", reflect.TypeOf(node))
33 if fmt.Sprintf("%v", node) != fmt.Sprintf("%v", v) {
34 t.Errorf("was expecting %v at %v but got %v", v, k, node)
40 func assertTree(t *testing.T, tree *Tree, err error, ref map[string]interface{}) {
41 t.Log("Asserting tree:\n", spew.Sdump(tree))
42 assertSubTree(t, []string{}, tree, err, ref)
43 t.Log("Finished tree assertion.")
46 func TestCreateSubTree(t *testing.T) {
48 tree.createSubTree([]string{"a", "b", "c"}, Position{})
49 tree.Set("a.b.c", "", false, 42)
50 if tree.Get("a.b.c") != 42 {
55 func TestSimpleKV(t *testing.T) {
56 tree, err := Load("a = 42")
57 assertTree(t, tree, err, map[string]interface{}{
61 tree, _ = Load("a = 42\nb = 21")
62 assertTree(t, tree, err, map[string]interface{}{
68 func TestNumberInKey(t *testing.T) {
69 tree, err := Load("hello2 = 42")
70 assertTree(t, tree, err, map[string]interface{}{
75 func TestSimpleNumbers(t *testing.T) {
76 tree, err := Load("a = +42\nb = -21\nc = +4.2\nd = -2.1")
77 assertTree(t, tree, err, map[string]interface{}{
85 func TestNumbersWithUnderscores(t *testing.T) {
86 tree, err := Load("a = 1_000")
87 assertTree(t, tree, err, map[string]interface{}{
91 tree, err = Load("a = 5_349_221")
92 assertTree(t, tree, err, map[string]interface{}{
96 tree, err = Load("a = 1_2_3_4_5")
97 assertTree(t, tree, err, map[string]interface{}{
101 tree, err = Load("flt8 = 9_224_617.445_991_228_313")
102 assertTree(t, tree, err, map[string]interface{}{
103 "flt8": float64(9224617.445991228313),
106 tree, err = Load("flt9 = 1e1_00")
107 assertTree(t, tree, err, map[string]interface{}{
108 "flt9": float64(1e100),
112 func TestFloatsWithExponents(t *testing.T) {
113 tree, err := Load("a = 5e+22\nb = 5E+22\nc = -5e+22\nd = -5e-22\ne = 6.626e-34")
114 assertTree(t, tree, err, map[string]interface{}{
117 "c": float64(-5e+22),
118 "d": float64(-5e-22),
119 "e": float64(6.626e-34),
123 func TestSimpleDate(t *testing.T) {
124 tree, err := Load("a = 1979-05-27T07:32:00Z")
125 assertTree(t, tree, err, map[string]interface{}{
126 "a": time.Date(1979, time.May, 27, 7, 32, 0, 0, time.UTC),
130 func TestDateOffset(t *testing.T) {
131 tree, err := Load("a = 1979-05-27T00:32:00-07:00")
132 assertTree(t, tree, err, map[string]interface{}{
133 "a": time.Date(1979, time.May, 27, 0, 32, 0, 0, time.FixedZone("", -7*60*60)),
137 func TestDateNano(t *testing.T) {
138 tree, err := Load("a = 1979-05-27T00:32:00.999999999-07:00")
139 assertTree(t, tree, err, map[string]interface{}{
140 "a": time.Date(1979, time.May, 27, 0, 32, 0, 999999999, time.FixedZone("", -7*60*60)),
144 func TestSimpleString(t *testing.T) {
145 tree, err := Load("a = \"hello world\"")
146 assertTree(t, tree, err, map[string]interface{}{
151 func TestSpaceKey(t *testing.T) {
152 tree, err := Load("\"a b\" = \"hello world\"")
153 assertTree(t, tree, err, map[string]interface{}{
154 "a b": "hello world",
158 func TestStringEscapables(t *testing.T) {
159 tree, err := Load("a = \"a \\n b\"")
160 assertTree(t, tree, err, map[string]interface{}{
164 tree, err = Load("a = \"a \\t b\"")
165 assertTree(t, tree, err, map[string]interface{}{
169 tree, err = Load("a = \"a \\r b\"")
170 assertTree(t, tree, err, map[string]interface{}{
174 tree, err = Load("a = \"a \\\\ b\"")
175 assertTree(t, tree, err, map[string]interface{}{
180 func TestEmptyQuotedString(t *testing.T) {
181 tree, err := Load(`[""]
183 assertTree(t, tree, err, map[string]interface{}{
184 "": map[string]interface{}{
190 func TestBools(t *testing.T) {
191 tree, err := Load("a = true\nb = false")
192 assertTree(t, tree, err, map[string]interface{}{
198 func TestNestedKeys(t *testing.T) {
199 tree, err := Load("[a.b.c]\nd = 42")
200 assertTree(t, tree, err, map[string]interface{}{
201 "a": map[string]interface{}{
202 "b": map[string]interface{}{
203 "c": map[string]interface{}{
211 func TestNestedQuotedUnicodeKeys(t *testing.T) {
212 tree, err := Load("[ j . \"Êž\" . l ]\nd = 42")
213 assertTree(t, tree, err, map[string]interface{}{
214 "j": map[string]interface{}{
215 "Êž": map[string]interface{}{
216 "l": map[string]interface{}{
223 tree, err = Load("[ g . h . i ]\nd = 42")
224 assertTree(t, tree, err, map[string]interface{}{
225 "g": map[string]interface{}{
226 "h": map[string]interface{}{
227 "i": map[string]interface{}{
234 tree, err = Load("[ d.e.f ]\nk = 42")
235 assertTree(t, tree, err, map[string]interface{}{
236 "d": map[string]interface{}{
237 "e": map[string]interface{}{
238 "f": map[string]interface{}{
246 func TestArrayOne(t *testing.T) {
247 tree, err := Load("a = [1]")
248 assertTree(t, tree, err, map[string]interface{}{
249 "a": []int64{int64(1)},
253 func TestArrayZero(t *testing.T) {
254 tree, err := Load("a = []")
255 assertTree(t, tree, err, map[string]interface{}{
256 "a": []interface{}{},
260 func TestArraySimple(t *testing.T) {
261 tree, err := Load("a = [42, 21, 10]")
262 assertTree(t, tree, err, map[string]interface{}{
263 "a": []int64{int64(42), int64(21), int64(10)},
266 tree, _ = Load("a = [42, 21, 10,]")
267 assertTree(t, tree, err, map[string]interface{}{
268 "a": []int64{int64(42), int64(21), int64(10)},
272 func TestArrayMultiline(t *testing.T) {
273 tree, err := Load("a = [42,\n21, 10,]")
274 assertTree(t, tree, err, map[string]interface{}{
275 "a": []int64{int64(42), int64(21), int64(10)},
279 func TestArrayNested(t *testing.T) {
280 tree, err := Load("a = [[42, 21], [10]]")
281 assertTree(t, tree, err, map[string]interface{}{
282 "a": [][]int64{{int64(42), int64(21)}, {int64(10)}},
286 func TestNestedArrayComment(t *testing.T) {
292 assertTree(t, tree, err, map[string]interface{}{
293 "someArray": [][]string{{"entry1"}},
297 func TestNestedEmptyArrays(t *testing.T) {
298 tree, err := Load("a = [[[]]]")
299 assertTree(t, tree, err, map[string]interface{}{
300 "a": [][][]interface{}{{{}}},
304 func TestArrayMixedTypes(t *testing.T) {
305 _, err := Load("a = [42, 16.0]")
306 if err.Error() != "(1, 10): mixed types in array" {
307 t.Error("Bad error message:", err.Error())
310 _, err = Load("a = [42, \"hello\"]")
311 if err.Error() != "(1, 11): mixed types in array" {
312 t.Error("Bad error message:", err.Error())
316 func TestArrayNestedStrings(t *testing.T) {
317 tree, err := Load("data = [ [\"gamma\", \"delta\"], [\"Foo\"] ]")
318 assertTree(t, tree, err, map[string]interface{}{
319 "data": [][]string{{"gamma", "delta"}, {"Foo"}},
323 func TestParseUnknownRvalue(t *testing.T) {
324 _, err := Load("a = !bssss")
326 t.Error("Expecting a parse error")
329 _, err = Load("a = /b")
331 t.Error("Expecting a parse error")
335 func TestMissingValue(t *testing.T) {
336 _, err := Load("a = ")
337 if err.Error() != "(1, 5): expecting a value" {
338 t.Error("Bad error message:", err.Error())
342 func TestUnterminatedArray(t *testing.T) {
343 _, err := Load("a = [1,")
344 if err.Error() != "(1, 8): unterminated array" {
345 t.Error("Bad error message:", err.Error())
348 _, err = Load("a = [1")
349 if err.Error() != "(1, 7): unterminated array" {
350 t.Error("Bad error message:", err.Error())
353 _, err = Load("a = [1 2")
354 if err.Error() != "(1, 8): missing comma" {
355 t.Error("Bad error message:", err.Error())
359 func TestNewlinesInArrays(t *testing.T) {
360 tree, err := Load("a = [1,\n2,\n3]")
361 assertTree(t, tree, err, map[string]interface{}{
362 "a": []int64{int64(1), int64(2), int64(3)},
366 func TestArrayWithExtraComma(t *testing.T) {
367 tree, err := Load("a = [1,\n2,\n3,\n]")
368 assertTree(t, tree, err, map[string]interface{}{
369 "a": []int64{int64(1), int64(2), int64(3)},
373 func TestArrayWithExtraCommaComment(t *testing.T) {
374 tree, err := Load("a = [1, # wow\n2, # such items\n3, # so array\n]")
375 assertTree(t, tree, err, map[string]interface{}{
376 "a": []int64{int64(1), int64(2), int64(3)},
380 func TestSimpleInlineGroup(t *testing.T) {
381 tree, err := Load("key = {a = 42}")
382 assertTree(t, tree, err, map[string]interface{}{
383 "key": map[string]interface{}{
389 func TestDoubleInlineGroup(t *testing.T) {
390 tree, err := Load("key = {a = 42, b = \"foo\"}")
391 assertTree(t, tree, err, map[string]interface{}{
392 "key": map[string]interface{}{
399 func TestExampleInlineGroup(t *testing.T) {
400 tree, err := Load(`name = { first = "Tom", last = "Preston-Werner" }
401 point = { x = 1, y = 2 }`)
402 assertTree(t, tree, err, map[string]interface{}{
403 "name": map[string]interface{}{
405 "last": "Preston-Werner",
407 "point": map[string]interface{}{
414 func TestExampleInlineGroupInArray(t *testing.T) {
415 tree, err := Load(`points = [{ x = 1, y = 2 }]`)
416 assertTree(t, tree, err, map[string]interface{}{
417 "points": []map[string]interface{}{
426 func TestInlineTableUnterminated(t *testing.T) {
427 _, err := Load("foo = {")
428 if err.Error() != "(1, 8): unterminated inline table" {
429 t.Error("Bad error message:", err.Error())
433 func TestInlineTableCommaExpected(t *testing.T) {
434 _, err := Load("foo = {hello = 53 test = foo}")
435 if err.Error() != "(1, 19): comma expected between fields in inline table" {
436 t.Error("Bad error message:", err.Error())
440 func TestInlineTableCommaStart(t *testing.T) {
441 _, err := Load("foo = {, hello = 53}")
442 if err.Error() != "(1, 8): inline table cannot start with a comma" {
443 t.Error("Bad error message:", err.Error())
447 func TestInlineTableDoubleComma(t *testing.T) {
448 _, err := Load("foo = {hello = 53,, foo = 17}")
449 if err.Error() != "(1, 19): need field between two commas in inline table" {
450 t.Error("Bad error message:", err.Error())
454 func TestDuplicateGroups(t *testing.T) {
455 _, err := Load("[foo]\na=2\n[foo]b=3")
456 if err.Error() != "(3, 2): duplicated tables" {
457 t.Error("Bad error message:", err.Error())
461 func TestDuplicateKeys(t *testing.T) {
462 _, err := Load("foo = 2\nfoo = 3")
463 if err.Error() != "(2, 1): The following key was defined twice: foo" {
464 t.Error("Bad error message:", err.Error())
468 func TestEmptyIntermediateTable(t *testing.T) {
469 _, err := Load("[foo..bar]")
470 if err.Error() != "(1, 2): invalid table array key: empty table key" {
471 t.Error("Bad error message:", err.Error())
475 func TestImplicitDeclarationBefore(t *testing.T) {
476 tree, err := Load("[a.b.c]\nanswer = 42\n[a]\nbetter = 43")
477 assertTree(t, tree, err, map[string]interface{}{
478 "a": map[string]interface{}{
479 "b": map[string]interface{}{
480 "c": map[string]interface{}{
489 func TestFloatsWithoutLeadingZeros(t *testing.T) {
490 _, err := Load("a = .42")
491 if err.Error() != "(1, 5): cannot start float with a dot" {
492 t.Error("Bad error message:", err.Error())
495 _, err = Load("a = -.42")
496 if err.Error() != "(1, 5): cannot start float with a dot" {
497 t.Error("Bad error message:", err.Error())
501 func TestMissingFile(t *testing.T) {
502 _, err := LoadFile("foo.toml")
503 if err.Error() != "open foo.toml: no such file or directory" &&
504 err.Error() != "open foo.toml: The system cannot find the file specified." {
505 t.Error("Bad error message:", err.Error())
509 func TestParseFile(t *testing.T) {
510 tree, err := LoadFile("example.toml")
512 assertTree(t, tree, err, map[string]interface{}{
513 "title": "TOML Example",
514 "owner": map[string]interface{}{
515 "name": "Tom Preston-Werner",
516 "organization": "GitHub",
517 "bio": "GitHub Cofounder & CEO\nLikes tater tots and beer.",
518 "dob": time.Date(1979, time.May, 27, 7, 32, 0, 0, time.UTC),
520 "database": map[string]interface{}{
521 "server": "192.168.1.1",
522 "ports": []int64{8001, 8001, 8002},
523 "connection_max": 5000,
526 "servers": map[string]interface{}{
527 "alpha": map[string]interface{}{
531 "beta": map[string]interface{}{
536 "clients": map[string]interface{}{
537 "data": []interface{}{
538 []string{"gamma", "delta"},
545 func TestParseFileCRLF(t *testing.T) {
546 tree, err := LoadFile("example-crlf.toml")
548 assertTree(t, tree, err, map[string]interface{}{
549 "title": "TOML Example",
550 "owner": map[string]interface{}{
551 "name": "Tom Preston-Werner",
552 "organization": "GitHub",
553 "bio": "GitHub Cofounder & CEO\nLikes tater tots and beer.",
554 "dob": time.Date(1979, time.May, 27, 7, 32, 0, 0, time.UTC),
556 "database": map[string]interface{}{
557 "server": "192.168.1.1",
558 "ports": []int64{8001, 8001, 8002},
559 "connection_max": 5000,
562 "servers": map[string]interface{}{
563 "alpha": map[string]interface{}{
567 "beta": map[string]interface{}{
572 "clients": map[string]interface{}{
573 "data": []interface{}{
574 []string{"gamma", "delta"},
581 func TestParseKeyGroupArray(t *testing.T) {
582 tree, err := Load("[[foo.bar]] a = 42\n[[foo.bar]] a = 69")
583 assertTree(t, tree, err, map[string]interface{}{
584 "foo": map[string]interface{}{
585 "bar": []map[string]interface{}{
593 func TestParseKeyGroupArrayUnfinished(t *testing.T) {
594 _, err := Load("[[foo.bar]\na = 42")
595 if err.Error() != "(1, 10): was expecting token [[, but got unclosed table array key instead" {
596 t.Error("Bad error message:", err.Error())
599 _, err = Load("[[foo.[bar]\na = 42")
600 if err.Error() != "(1, 3): unexpected token table array key cannot contain ']', was expecting a table array key" {
601 t.Error("Bad error message:", err.Error())
605 func TestParseKeyGroupArrayQueryExample(t *testing.T) {
609 author = "Stephen King"
611 title = "For Whom the Bell Tolls"
612 author = "Ernest Hemmingway"
614 title = "Neuromancer"
615 author = "William Gibson"
618 assertTree(t, tree, err, map[string]interface{}{
619 "book": []map[string]interface{}{
620 {"title": "The Stand", "author": "Stephen King"},
621 {"title": "For Whom the Bell Tolls", "author": "Ernest Hemmingway"},
622 {"title": "Neuromancer", "author": "William Gibson"},
627 func TestParseKeyGroupArraySpec(t *testing.T) {
628 tree, err := Load("[[fruit]]\n name=\"apple\"\n [fruit.physical]\n color=\"red\"\n shape=\"round\"\n [[fruit]]\n name=\"banana\"")
629 assertTree(t, tree, err, map[string]interface{}{
630 "fruit": []map[string]interface{}{
631 {"name": "apple", "physical": map[string]interface{}{"color": "red", "shape": "round"}},
637 func TestTomlValueStringRepresentation(t *testing.T) {
638 for idx, item := range []struct {
642 {int64(12345), "12345"},
644 {float64(123.45), "123.45"},
645 {bool(true), "true"},
646 {"hello world", "\"hello world\""},
647 {"\b\t\n\f\r\"\\", "\"\\b\\t\\n\\f\\r\\\"\\\\\""},
648 {"\x05", "\"\\u0005\""},
649 {time.Date(1979, time.May, 27, 7, 32, 0, 0, time.UTC),
650 "1979-05-27T07:32:00Z"},
651 {[]interface{}{"gamma", "delta"},
652 "[\"gamma\",\"delta\"]"},
655 result, err := tomlValueStringRepresentation(item.Value)
657 t.Errorf("Test %d - unexpected error: %s", idx, err)
659 if result != item.Expect {
660 t.Errorf("Test %d - got '%s', expected '%s'", idx, result, item.Expect)
665 func TestToStringMapStringString(t *testing.T) {
666 tree, err := TreeFromMap(map[string]interface{}{"m": map[string]interface{}{"v": "abc"}})
668 t.Fatalf("unexpected error: %s", err)
670 want := "\n[m]\n v = \"abc\"\n"
674 t.Errorf("want:\n%q\ngot:\n%q", want, got)
678 func assertPosition(t *testing.T, text string, ref map[string]Position) {
679 tree, err := Load(text)
681 t.Errorf("Error loading document text: `%v`", text)
682 t.Errorf("Error: %v", err)
684 for path, pos := range ref {
685 testPos := tree.GetPosition(path)
686 if testPos.Invalid() {
687 t.Errorf("Failed to query tree path or path has invalid position: %s", path)
688 } else if pos != testPos {
689 t.Errorf("Expected position %v, got %v instead", pos, testPos)
694 func TestDocumentPositions(t *testing.T) {
696 "[foo]\nbar=42\nbaz=69",
705 func TestDocumentPositionsWithSpaces(t *testing.T) {
707 " [foo]\n bar=42\n baz=69",
716 func TestDocumentPositionsWithGroupArray(t *testing.T) {
718 "[[foo]]\nbar=42\nbaz=69",
727 func TestNestedTreePosition(t *testing.T) {
729 "[foo.bar]\na=42\nb=69",
739 func TestInvalidGroupArray(t *testing.T) {
740 _, err := Load("[table#key]\nanswer = 42")
742 t.Error("Should error")
745 _, err = Load("[foo.[bar]\na = 42")
746 if err.Error() != "(1, 2): unexpected token table key cannot contain ']', was expecting a table key" {
747 t.Error("Bad error message:", err.Error())
751 func TestDoubleEqual(t *testing.T) {
752 _, err := Load("foo= = 2")
753 if err.Error() != "(1, 6): cannot have multiple equals for the same key" {
754 t.Error("Bad error message:", err.Error())
758 func TestGroupArrayReassign(t *testing.T) {
759 _, err := Load("[hello]\n[[hello]]")
760 if err.Error() != "(2, 3): key \"hello\" is already assigned and not of type table array" {
761 t.Error("Bad error message:", err.Error())
765 func TestInvalidFloatParsing(t *testing.T) {
766 _, err := Load("a=1e_2")
767 if err.Error() != "(1, 3): invalid use of _ in number" {
768 t.Error("Bad error message:", err.Error())
771 _, err = Load("a=1e2_")
772 if err.Error() != "(1, 3): invalid use of _ in number" {
773 t.Error("Bad error message:", err.Error())
776 _, err = Load("a=1__2")
777 if err.Error() != "(1, 3): invalid use of _ in number" {
778 t.Error("Bad error message:", err.Error())
781 _, err = Load("a=_1_2")
782 if err.Error() != "(1, 3): cannot start number with underscore" {
783 t.Error("Bad error message:", err.Error())