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