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