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