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