1package toml
2
3import (
4	"bytes"
5	"encoding/json"
6	"fmt"
7	"io/ioutil"
8	"os"
9	"reflect"
10	"strconv"
11	"strings"
12	"testing"
13	"time"
14)
15
16type basicMarshalTestStruct struct {
17	String     string   `toml:"Zstring"`
18	StringList []string `toml:"Ystrlist"`
19	BasicMarshalTestSubAnonymousStruct
20	Sub     basicMarshalTestSubStruct   `toml:"Xsubdoc"`
21	SubList []basicMarshalTestSubStruct `toml:"Wsublist"`
22}
23
24type basicMarshalTestSubStruct struct {
25	String2 string
26}
27
28type BasicMarshalTestSubAnonymousStruct struct {
29	String3 string
30}
31
32var basicTestData = basicMarshalTestStruct{
33	String:                             "Hello",
34	StringList:                         []string{"Howdy", "Hey There"},
35	BasicMarshalTestSubAnonymousStruct: BasicMarshalTestSubAnonymousStruct{"One"},
36	Sub:                                basicMarshalTestSubStruct{"Two"},
37	SubList:                            []basicMarshalTestSubStruct{{"Three"}, {"Four"}},
38}
39
40var basicTestToml = []byte(`String3 = "One"
41Ystrlist = ["Howdy", "Hey There"]
42Zstring = "Hello"
43
44[[Wsublist]]
45  String2 = "Three"
46
47[[Wsublist]]
48  String2 = "Four"
49
50[Xsubdoc]
51  String2 = "Two"
52`)
53
54var basicTestTomlCustomIndentation = []byte(`String3 = "One"
55Ystrlist = ["Howdy", "Hey There"]
56Zstring = "Hello"
57
58[[Wsublist]]
59	String2 = "Three"
60
61[[Wsublist]]
62	String2 = "Four"
63
64[Xsubdoc]
65	String2 = "Two"
66`)
67
68var basicTestTomlOrdered = []byte(`Zstring = "Hello"
69Ystrlist = ["Howdy", "Hey There"]
70String3 = "One"
71
72[Xsubdoc]
73  String2 = "Two"
74
75[[Wsublist]]
76  String2 = "Three"
77
78[[Wsublist]]
79  String2 = "Four"
80`)
81
82var marshalTestToml = []byte(`title = "TOML Marshal Testing"
83
84[basic]
85  bool = true
86  date = 1979-05-27T07:32:00Z
87  float = 123.4
88  float64 = 123.456782132399
89  int = 5000
90  string = "Bite me"
91  uint = 5001
92
93[basic_lists]
94  bools = [true, false, true]
95  dates = [1979-05-27T07:32:00Z, 1980-05-27T07:32:00Z]
96  floats = [12.3, 45.6, 78.9]
97  ints = [8001, 8001, 8002]
98  strings = ["One", "Two", "Three"]
99  uints = [5002, 5003]
100
101[basic_map]
102  one = "one"
103  two = "two"
104
105[subdoc]
106
107  [subdoc.first]
108    name = "First"
109
110  [subdoc.second]
111    name = "Second"
112
113[[subdoclist]]
114  name = "List.First"
115
116[[subdoclist]]
117  name = "List.Second"
118
119[[subdocptrs]]
120  name = "Second"
121`)
122
123var marshalOrderPreserveToml = []byte(`title = "TOML Marshal Testing"
124
125[basic_lists]
126  floats = [12.3, 45.6, 78.9]
127  bools = [true, false, true]
128  dates = [1979-05-27T07:32:00Z, 1980-05-27T07:32:00Z]
129  ints = [8001, 8001, 8002]
130  uints = [5002, 5003]
131  strings = ["One", "Two", "Three"]
132
133[[subdocptrs]]
134  name = "Second"
135
136[basic_map]
137  one = "one"
138  two = "two"
139
140[subdoc]
141
142  [subdoc.second]
143    name = "Second"
144
145  [subdoc.first]
146    name = "First"
147
148[basic]
149  uint = 5001
150  bool = true
151  float = 123.4
152  float64 = 123.456782132399
153  int = 5000
154  string = "Bite me"
155  date = 1979-05-27T07:32:00Z
156
157[[subdoclist]]
158  name = "List.First"
159
160[[subdoclist]]
161  name = "List.Second"
162`)
163
164var mashalOrderPreserveMapToml = []byte(`title = "TOML Marshal Testing"
165
166[basic_map]
167  one = "one"
168  two = "two"
169
170[long_map]
171  a7 = "1"
172  b3 = "2"
173  c8 = "3"
174  d4 = "4"
175  e6 = "5"
176  f5 = "6"
177  g10 = "7"
178  h1 = "8"
179  i2 = "9"
180  j9 = "10"
181`)
182
183type Conf struct {
184	Name  string
185	Age   int
186	Inter interface{}
187}
188
189type NestedStruct struct {
190	FirstName string
191	LastName  string
192	Age       int
193}
194
195var doc = []byte(`Name = "rui"
196Age = 18
197
198[Inter]
199  FirstName = "wang"
200  LastName = "jl"
201  Age = 100`)
202
203func TestInterface(t *testing.T) {
204	var config Conf
205	config.Inter = &NestedStruct{}
206	err := Unmarshal(doc, &config)
207	expected := Conf{
208		Name: "rui",
209		Age:  18,
210		Inter: &NestedStruct{
211			FirstName: "wang",
212			LastName:  "jl",
213			Age:       100,
214		},
215	}
216	if err != nil || !reflect.DeepEqual(config, expected) {
217		t.Errorf("Bad unmarshal: expected %v, got %v", expected, config)
218	}
219}
220
221func TestBasicMarshal(t *testing.T) {
222	result, err := Marshal(basicTestData)
223	if err != nil {
224		t.Fatal(err)
225	}
226	expected := basicTestToml
227	if !bytes.Equal(result, expected) {
228		t.Errorf("Bad marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expected, result)
229	}
230}
231
232func TestBasicMarshalCustomIndentation(t *testing.T) {
233	var result bytes.Buffer
234	err := NewEncoder(&result).Indentation("\t").Encode(basicTestData)
235	if err != nil {
236		t.Fatal(err)
237	}
238	expected := basicTestTomlCustomIndentation
239	if !bytes.Equal(result.Bytes(), expected) {
240		t.Errorf("Bad marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expected, result.Bytes())
241	}
242}
243
244func TestBasicMarshalWrongIndentation(t *testing.T) {
245	var result bytes.Buffer
246	err := NewEncoder(&result).Indentation("  \n").Encode(basicTestData)
247	if err.Error() != "invalid indentation: must only contains space or tab characters" {
248		t.Error("expect err:invalid indentation: must only contains space or tab characters but got:", err)
249	}
250}
251
252func TestBasicMarshalOrdered(t *testing.T) {
253	var result bytes.Buffer
254	err := NewEncoder(&result).Order(OrderPreserve).Encode(basicTestData)
255	if err != nil {
256		t.Fatal(err)
257	}
258	expected := basicTestTomlOrdered
259	if !bytes.Equal(result.Bytes(), expected) {
260		t.Errorf("Bad marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expected, result.Bytes())
261	}
262}
263
264func TestBasicMarshalWithPointer(t *testing.T) {
265	result, err := Marshal(&basicTestData)
266	if err != nil {
267		t.Fatal(err)
268	}
269	expected := basicTestToml
270	if !bytes.Equal(result, expected) {
271		t.Errorf("Bad marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expected, result)
272	}
273}
274
275func TestBasicMarshalOrderedWithPointer(t *testing.T) {
276	var result bytes.Buffer
277	err := NewEncoder(&result).Order(OrderPreserve).Encode(&basicTestData)
278	if err != nil {
279		t.Fatal(err)
280	}
281	expected := basicTestTomlOrdered
282	if !bytes.Equal(result.Bytes(), expected) {
283		t.Errorf("Bad marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expected, result.Bytes())
284	}
285}
286
287func TestBasicUnmarshal(t *testing.T) {
288	result := basicMarshalTestStruct{}
289	err := Unmarshal(basicTestToml, &result)
290	expected := basicTestData
291	if err != nil {
292		t.Fatal(err)
293	}
294	if !reflect.DeepEqual(result, expected) {
295		t.Errorf("Bad unmarshal: expected %v, got %v", expected, result)
296	}
297}
298
299type quotedKeyMarshalTestStruct struct {
300	String  string                      `toml:"Z.string-àéù"`
301	Float   float64                     `toml:"Yfloat-��"`
302	Sub     basicMarshalTestSubStruct   `toml:"Xsubdoc-àéù"`
303	SubList []basicMarshalTestSubStruct `toml:"W.sublist-��"`
304}
305
306var quotedKeyMarshalTestData = quotedKeyMarshalTestStruct{
307	String:  "Hello",
308	Float:   3.5,
309	Sub:     basicMarshalTestSubStruct{"One"},
310	SubList: []basicMarshalTestSubStruct{{"Two"}, {"Three"}},
311}
312
313var quotedKeyMarshalTestToml = []byte(`"Yfloat-��" = 3.5
314"Z.string-àéù" = "Hello"
315
316[["W.sublist-��"]]
317  String2 = "Two"
318
319[["W.sublist-��"]]
320  String2 = "Three"
321
322["Xsubdoc-àéù"]
323  String2 = "One"
324`)
325
326func TestBasicMarshalQuotedKey(t *testing.T) {
327	result, err := Marshal(quotedKeyMarshalTestData)
328	if err != nil {
329		t.Fatal(err)
330	}
331	expected := quotedKeyMarshalTestToml
332	if !bytes.Equal(result, expected) {
333		t.Errorf("Bad marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expected, result)
334	}
335}
336
337func TestBasicUnmarshalQuotedKey(t *testing.T) {
338	tree, err := LoadBytes(quotedKeyMarshalTestToml)
339	if err != nil {
340		t.Fatal(err)
341	}
342
343	var q quotedKeyMarshalTestStruct
344	tree.Unmarshal(&q)
345	fmt.Println(q)
346
347	if !reflect.DeepEqual(quotedKeyMarshalTestData, q) {
348		t.Errorf("Bad unmarshal: expected\n-----\n%v\n-----\ngot\n-----\n%v\n-----\n", quotedKeyMarshalTestData, q)
349	}
350}
351
352type testDoc struct {
353	Title       string            `toml:"title"`
354	BasicLists  testDocBasicLists `toml:"basic_lists"`
355	SubDocPtrs  []*testSubDoc     `toml:"subdocptrs"`
356	BasicMap    map[string]string `toml:"basic_map"`
357	Subdocs     testDocSubs       `toml:"subdoc"`
358	Basics      testDocBasics     `toml:"basic"`
359	SubDocList  []testSubDoc      `toml:"subdoclist"`
360	err         int               `toml:"shouldntBeHere"`
361	unexported  int               `toml:"shouldntBeHere"`
362	Unexported2 int               `toml:"-"`
363}
364
365type testMapDoc struct {
366	Title    string            `toml:"title"`
367	BasicMap map[string]string `toml:"basic_map"`
368	LongMap  map[string]string `toml:"long_map"`
369}
370
371type testDocBasics struct {
372	Uint       uint      `toml:"uint"`
373	Bool       bool      `toml:"bool"`
374	Float32    float32   `toml:"float"`
375	Float64    float64   `toml:"float64"`
376	Int        int       `toml:"int"`
377	String     *string   `toml:"string"`
378	Date       time.Time `toml:"date"`
379	unexported int       `toml:"shouldntBeHere"`
380}
381
382type testDocBasicLists struct {
383	Floats  []*float32  `toml:"floats"`
384	Bools   []bool      `toml:"bools"`
385	Dates   []time.Time `toml:"dates"`
386	Ints    []int       `toml:"ints"`
387	UInts   []uint      `toml:"uints"`
388	Strings []string    `toml:"strings"`
389}
390
391type testDocSubs struct {
392	Second *testSubDoc `toml:"second"`
393	First  testSubDoc  `toml:"first"`
394}
395
396type testSubDoc struct {
397	Name       string `toml:"name"`
398	unexported int    `toml:"shouldntBeHere"`
399}
400
401var biteMe = "Bite me"
402var float1 float32 = 12.3
403var float2 float32 = 45.6
404var float3 float32 = 78.9
405var subdoc = testSubDoc{"Second", 0}
406
407var docData = testDoc{
408	Title:       "TOML Marshal Testing",
409	unexported:  0,
410	Unexported2: 0,
411	Basics: testDocBasics{
412		Bool:       true,
413		Date:       time.Date(1979, 5, 27, 7, 32, 0, 0, time.UTC),
414		Float32:    123.4,
415		Float64:    123.456782132399,
416		Int:        5000,
417		Uint:       5001,
418		String:     &biteMe,
419		unexported: 0,
420	},
421	BasicLists: testDocBasicLists{
422		Bools: []bool{true, false, true},
423		Dates: []time.Time{
424			time.Date(1979, 5, 27, 7, 32, 0, 0, time.UTC),
425			time.Date(1980, 5, 27, 7, 32, 0, 0, time.UTC),
426		},
427		Floats:  []*float32{&float1, &float2, &float3},
428		Ints:    []int{8001, 8001, 8002},
429		Strings: []string{"One", "Two", "Three"},
430		UInts:   []uint{5002, 5003},
431	},
432	BasicMap: map[string]string{
433		"one": "one",
434		"two": "two",
435	},
436	Subdocs: testDocSubs{
437		First:  testSubDoc{"First", 0},
438		Second: &subdoc,
439	},
440	SubDocList: []testSubDoc{
441		{"List.First", 0},
442		{"List.Second", 0},
443	},
444	SubDocPtrs: []*testSubDoc{&subdoc},
445}
446
447var mapTestDoc = testMapDoc{
448	Title: "TOML Marshal Testing",
449	BasicMap: map[string]string{
450		"one": "one",
451		"two": "two",
452	},
453	LongMap: map[string]string{
454		"h1":  "8",
455		"i2":  "9",
456		"b3":  "2",
457		"d4":  "4",
458		"f5":  "6",
459		"e6":  "5",
460		"a7":  "1",
461		"c8":  "3",
462		"j9":  "10",
463		"g10": "7",
464	},
465}
466
467func TestDocMarshal(t *testing.T) {
468	result, err := Marshal(docData)
469	if err != nil {
470		t.Fatal(err)
471	}
472	if !bytes.Equal(result, marshalTestToml) {
473		t.Errorf("Bad marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", marshalTestToml, result)
474	}
475}
476
477func TestDocMarshalOrdered(t *testing.T) {
478	var result bytes.Buffer
479	err := NewEncoder(&result).Order(OrderPreserve).Encode(docData)
480	if err != nil {
481		t.Fatal(err)
482	}
483	if !bytes.Equal(result.Bytes(), marshalOrderPreserveToml) {
484		t.Errorf("Bad marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", marshalOrderPreserveToml, result.Bytes())
485	}
486}
487
488func TestDocMarshalMaps(t *testing.T) {
489	result, err := Marshal(mapTestDoc)
490	if err != nil {
491		t.Fatal(err)
492	}
493	if !bytes.Equal(result, mashalOrderPreserveMapToml) {
494		t.Errorf("Bad marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", mashalOrderPreserveMapToml, result)
495	}
496}
497
498func TestDocMarshalOrderedMaps(t *testing.T) {
499	var result bytes.Buffer
500	err := NewEncoder(&result).Order(OrderPreserve).Encode(mapTestDoc)
501	if err != nil {
502		t.Fatal(err)
503	}
504	if !bytes.Equal(result.Bytes(), mashalOrderPreserveMapToml) {
505		t.Errorf("Bad marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", mashalOrderPreserveMapToml, result.Bytes())
506	}
507}
508
509func TestDocMarshalPointer(t *testing.T) {
510	result, err := Marshal(&docData)
511	if err != nil {
512		t.Fatal(err)
513	}
514
515	if !bytes.Equal(result, marshalTestToml) {
516		t.Errorf("Bad marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", marshalTestToml, result)
517	}
518}
519
520func TestDocUnmarshal(t *testing.T) {
521	result := testDoc{}
522	err := Unmarshal(marshalTestToml, &result)
523	expected := docData
524	if err != nil {
525		t.Fatal(err)
526	}
527	if !reflect.DeepEqual(result, expected) {
528		resStr, _ := json.MarshalIndent(result, "", "  ")
529		expStr, _ := json.MarshalIndent(expected, "", "  ")
530		t.Errorf("Bad unmarshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expStr, resStr)
531	}
532}
533
534func TestDocPartialUnmarshal(t *testing.T) {
535	file, err := ioutil.TempFile("", "test-*.toml")
536	if err != nil {
537		t.Fatal(err)
538	}
539	defer os.Remove(file.Name())
540
541	err = ioutil.WriteFile(file.Name(), marshalTestToml, 0)
542	if err != nil {
543		t.Fatal(err)
544	}
545
546	tree, _ := LoadFile(file.Name())
547	subTree := tree.Get("subdoc").(*Tree)
548
549	result := testDocSubs{}
550	err = subTree.Unmarshal(&result)
551	expected := docData.Subdocs
552	if err != nil {
553		t.Fatal(err)
554	}
555	if !reflect.DeepEqual(result, expected) {
556		resStr, _ := json.MarshalIndent(result, "", "  ")
557		expStr, _ := json.MarshalIndent(expected, "", "  ")
558		t.Errorf("Bad partial unmartial: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expStr, resStr)
559	}
560}
561
562type tomlTypeCheckTest struct {
563	name string
564	item interface{}
565	typ  int //0=primitive, 1=otherslice, 2=treeslice, 3=tree
566}
567
568func TestTypeChecks(t *testing.T) {
569	tests := []tomlTypeCheckTest{
570		{"bool", true, 0},
571		{"bool", false, 0},
572		{"int", int(2), 0},
573		{"int8", int8(2), 0},
574		{"int16", int16(2), 0},
575		{"int32", int32(2), 0},
576		{"int64", int64(2), 0},
577		{"uint", uint(2), 0},
578		{"uint8", uint8(2), 0},
579		{"uint16", uint16(2), 0},
580		{"uint32", uint32(2), 0},
581		{"uint64", uint64(2), 0},
582		{"float32", float32(3.14), 0},
583		{"float64", float64(3.14), 0},
584		{"string", "lorem ipsum", 0},
585		{"time", time.Date(2015, 1, 1, 0, 0, 0, 0, time.UTC), 0},
586		{"stringlist", []string{"hello", "hi"}, 1},
587		{"stringlistptr", &[]string{"hello", "hi"}, 1},
588		{"stringarray", [2]string{"hello", "hi"}, 1},
589		{"stringarrayptr", &[2]string{"hello", "hi"}, 1},
590		{"timelist", []time.Time{time.Date(2015, 1, 1, 0, 0, 0, 0, time.UTC)}, 1},
591		{"timelistptr", &[]time.Time{time.Date(2015, 1, 1, 0, 0, 0, 0, time.UTC)}, 1},
592		{"timearray", [1]time.Time{time.Date(2015, 1, 1, 0, 0, 0, 0, time.UTC)}, 1},
593		{"timearrayptr", &[1]time.Time{time.Date(2015, 1, 1, 0, 0, 0, 0, time.UTC)}, 1},
594		{"objectlist", []tomlTypeCheckTest{}, 2},
595		{"objectlistptr", &[]tomlTypeCheckTest{}, 2},
596		{"objectarray", [2]tomlTypeCheckTest{{}, {}}, 2},
597		{"objectlistptr", &[2]tomlTypeCheckTest{{}, {}}, 2},
598		{"object", tomlTypeCheckTest{}, 3},
599		{"objectptr", &tomlTypeCheckTest{}, 3},
600	}
601
602	for _, test := range tests {
603		expected := []bool{false, false, false, false}
604		expected[test.typ] = true
605		result := []bool{
606			isPrimitive(reflect.TypeOf(test.item)),
607			isOtherSequence(reflect.TypeOf(test.item)),
608			isTreeSequence(reflect.TypeOf(test.item)),
609			isTree(reflect.TypeOf(test.item)),
610		}
611		if !reflect.DeepEqual(expected, result) {
612			t.Errorf("Bad type check on %q: expected %v, got %v", test.name, expected, result)
613		}
614	}
615}
616
617type unexportedMarshalTestStruct struct {
618	String      string                      `toml:"string"`
619	StringList  []string                    `toml:"strlist"`
620	Sub         basicMarshalTestSubStruct   `toml:"subdoc"`
621	SubList     []basicMarshalTestSubStruct `toml:"sublist"`
622	unexported  int                         `toml:"shouldntBeHere"`
623	Unexported2 int                         `toml:"-"`
624}
625
626var unexportedTestData = unexportedMarshalTestStruct{
627	String:      "Hello",
628	StringList:  []string{"Howdy", "Hey There"},
629	Sub:         basicMarshalTestSubStruct{"One"},
630	SubList:     []basicMarshalTestSubStruct{{"Two"}, {"Three"}},
631	unexported:  0,
632	Unexported2: 0,
633}
634
635var unexportedTestToml = []byte(`string = "Hello"
636strlist = ["Howdy","Hey There"]
637unexported = 1
638shouldntBeHere = 2
639
640[subdoc]
641  String2 = "One"
642
643[[sublist]]
644  String2 = "Two"
645
646[[sublist]]
647  String2 = "Three"
648`)
649
650func TestUnexportedUnmarshal(t *testing.T) {
651	result := unexportedMarshalTestStruct{}
652	err := Unmarshal(unexportedTestToml, &result)
653	expected := unexportedTestData
654	if err != nil {
655		t.Fatal(err)
656	}
657	if !reflect.DeepEqual(result, expected) {
658		t.Errorf("Bad unexported unmarshal: expected %v, got %v", expected, result)
659	}
660}
661
662type errStruct struct {
663	Bool   bool      `toml:"bool"`
664	Date   time.Time `toml:"date"`
665	Float  float64   `toml:"float"`
666	Int    int16     `toml:"int"`
667	String *string   `toml:"string"`
668}
669
670var errTomls = []string{
671	"bool = truly\ndate = 1979-05-27T07:32:00Z\nfloat = 123.4\nint = 5000\nstring = \"Bite me\"",
672	"bool = true\ndate = 1979-05-27T07:3200Z\nfloat = 123.4\nint = 5000\nstring = \"Bite me\"",
673	"bool = true\ndate = 1979-05-27T07:32:00Z\nfloat = 123a4\nint = 5000\nstring = \"Bite me\"",
674	"bool = true\ndate = 1979-05-27T07:32:00Z\nfloat = 123.4\nint = j000\nstring = \"Bite me\"",
675	"bool = true\ndate = 1979-05-27T07:32:00Z\nfloat = 123.4\nint = 5000\nstring = Bite me",
676	"bool = true\ndate = 1979-05-27T07:32:00Z\nfloat = 123.4\nint = 5000\nstring = Bite me",
677	"bool = 1\ndate = 1979-05-27T07:32:00Z\nfloat = 123.4\nint = 5000\nstring = \"Bite me\"",
678	"bool = true\ndate = 1\nfloat = 123.4\nint = 5000\nstring = \"Bite me\"",
679	"bool = true\ndate = 1979-05-27T07:32:00Z\n\"sorry\"\nint = 5000\nstring = \"Bite me\"",
680	"bool = true\ndate = 1979-05-27T07:32:00Z\nfloat = 123.4\nint = \"sorry\"\nstring = \"Bite me\"",
681	"bool = true\ndate = 1979-05-27T07:32:00Z\nfloat = 123.4\nint = 5000\nstring = 1",
682}
683
684type mapErr struct {
685	Vals map[string]float64
686}
687
688type intErr struct {
689	Int1  int
690	Int2  int8
691	Int3  int16
692	Int4  int32
693	Int5  int64
694	UInt1 uint
695	UInt2 uint8
696	UInt3 uint16
697	UInt4 uint32
698	UInt5 uint64
699	Flt1  float32
700	Flt2  float64
701}
702
703var intErrTomls = []string{
704	"Int1 = []\nInt2 = 2\nInt3 = 3\nInt4 = 4\nInt5 = 5\nUInt1 = 1\nUInt2 = 2\nUInt3 = 3\nUInt4 = 4\nUInt5 = 5\nFlt1 = 1.0\nFlt2 = 2.0",
705	"Int1 = 1\nInt2 = []\nInt3 = 3\nInt4 = 4\nInt5 = 5\nUInt1 = 1\nUInt2 = 2\nUInt3 = 3\nUInt4 = 4\nUInt5 = 5\nFlt1 = 1.0\nFlt2 = 2.0",
706	"Int1 = 1\nInt2 = 2\nInt3 = []\nInt4 = 4\nInt5 = 5\nUInt1 = 1\nUInt2 = 2\nUInt3 = 3\nUInt4 = 4\nUInt5 = 5\nFlt1 = 1.0\nFlt2 = 2.0",
707	"Int1 = 1\nInt2 = 2\nInt3 = 3\nInt4 = []\nInt5 = 5\nUInt1 = 1\nUInt2 = 2\nUInt3 = 3\nUInt4 = 4\nUInt5 = 5\nFlt1 = 1.0\nFlt2 = 2.0",
708	"Int1 = 1\nInt2 = 2\nInt3 = 3\nInt4 = 4\nInt5 = []\nUInt1 = 1\nUInt2 = 2\nUInt3 = 3\nUInt4 = 4\nUInt5 = 5\nFlt1 = 1.0\nFlt2 = 2.0",
709	"Int1 = 1\nInt2 = 2\nInt3 = 3\nInt4 = 4\nInt5 = 5\nUInt1 = []\nUInt2 = 2\nUInt3 = 3\nUInt4 = 4\nUInt5 = 5\nFlt1 = 1.0\nFlt2 = 2.0",
710	"Int1 = 1\nInt2 = 2\nInt3 = 3\nInt4 = 4\nInt5 = 5\nUInt1 = 1\nUInt2 = []\nUInt3 = 3\nUInt4 = 4\nUInt5 = 5\nFlt1 = 1.0\nFlt2 = 2.0",
711	"Int1 = 1\nInt2 = 2\nInt3 = 3\nInt4 = 4\nInt5 = 5\nUInt1 = 1\nUInt2 = 2\nUInt3 = []\nUInt4 = 4\nUInt5 = 5\nFlt1 = 1.0\nFlt2 = 2.0",
712	"Int1 = 1\nInt2 = 2\nInt3 = 3\nInt4 = 4\nInt5 = 5\nUInt1 = 1\nUInt2 = 2\nUInt3 = 3\nUInt4 = []\nUInt5 = 5\nFlt1 = 1.0\nFlt2 = 2.0",
713	"Int1 = 1\nInt2 = 2\nInt3 = 3\nInt4 = 4\nInt5 = 5\nUInt1 = 1\nUInt2 = 2\nUInt3 = 3\nUInt4 = 4\nUInt5 = []\nFlt1 = 1.0\nFlt2 = 2.0",
714	"Int1 = 1\nInt2 = 2\nInt3 = 3\nInt4 = 4\nInt5 = 5\nUInt1 = 1\nUInt2 = 2\nUInt3 = 3\nUInt4 = 4\nUInt5 = 5\nFlt1 = []\nFlt2 = 2.0",
715	"Int1 = 1\nInt2 = 2\nInt3 = 3\nInt4 = 4\nInt5 = 5\nUInt1 = 1\nUInt2 = 2\nUInt3 = 3\nUInt4 = 4\nUInt5 = 5\nFlt1 = 1.0\nFlt2 = []",
716}
717
718func TestErrUnmarshal(t *testing.T) {
719	for ind, toml := range errTomls {
720		result := errStruct{}
721		err := Unmarshal([]byte(toml), &result)
722		if err == nil {
723			t.Errorf("Expected err from case %d\n", ind)
724		}
725	}
726	result2 := mapErr{}
727	err := Unmarshal([]byte("[Vals]\nfred=\"1.2\""), &result2)
728	if err == nil {
729		t.Errorf("Expected err from map")
730	}
731	for ind, toml := range intErrTomls {
732		result3 := intErr{}
733		err := Unmarshal([]byte(toml), &result3)
734		if err == nil {
735			t.Errorf("Expected int err from case %d\n", ind)
736		}
737	}
738}
739
740type emptyMarshalTestStruct struct {
741	Title      string                  `toml:"title"`
742	Bool       bool                    `toml:"bool"`
743	Int        int                     `toml:"int"`
744	String     string                  `toml:"string"`
745	StringList []string                `toml:"stringlist"`
746	Ptr        *basicMarshalTestStruct `toml:"ptr"`
747	Map        map[string]string       `toml:"map"`
748}
749
750var emptyTestData = emptyMarshalTestStruct{
751	Title:      "Placeholder",
752	Bool:       false,
753	Int:        0,
754	String:     "",
755	StringList: []string{},
756	Ptr:        nil,
757	Map:        map[string]string{},
758}
759
760var emptyTestToml = []byte(`bool = false
761int = 0
762string = ""
763stringlist = []
764title = "Placeholder"
765
766[map]
767`)
768
769type emptyMarshalTestStruct2 struct {
770	Title      string                  `toml:"title"`
771	Bool       bool                    `toml:"bool,omitempty"`
772	Int        int                     `toml:"int, omitempty"`
773	String     string                  `toml:"string,omitempty "`
774	StringList []string                `toml:"stringlist,omitempty"`
775	Ptr        *basicMarshalTestStruct `toml:"ptr,omitempty"`
776	Map        map[string]string       `toml:"map,omitempty"`
777}
778
779var emptyTestData2 = emptyMarshalTestStruct2{
780	Title:      "Placeholder",
781	Bool:       false,
782	Int:        0,
783	String:     "",
784	StringList: []string{},
785	Ptr:        nil,
786	Map:        map[string]string{},
787}
788
789var emptyTestToml2 = []byte(`title = "Placeholder"
790`)
791
792func TestEmptyMarshal(t *testing.T) {
793	result, err := Marshal(emptyTestData)
794	if err != nil {
795		t.Fatal(err)
796	}
797	expected := emptyTestToml
798	if !bytes.Equal(result, expected) {
799		t.Errorf("Bad empty marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expected, result)
800	}
801}
802
803func TestEmptyMarshalOmit(t *testing.T) {
804	result, err := Marshal(emptyTestData2)
805	if err != nil {
806		t.Fatal(err)
807	}
808	expected := emptyTestToml2
809	if !bytes.Equal(result, expected) {
810		t.Errorf("Bad empty omit marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expected, result)
811	}
812}
813
814func TestEmptyUnmarshal(t *testing.T) {
815	result := emptyMarshalTestStruct{}
816	err := Unmarshal(emptyTestToml, &result)
817	expected := emptyTestData
818	if err != nil {
819		t.Fatal(err)
820	}
821	if !reflect.DeepEqual(result, expected) {
822		t.Errorf("Bad empty unmarshal: expected %v, got %v", expected, result)
823	}
824}
825
826func TestEmptyUnmarshalOmit(t *testing.T) {
827	result := emptyMarshalTestStruct2{}
828	err := Unmarshal(emptyTestToml, &result)
829	expected := emptyTestData2
830	if err != nil {
831		t.Fatal(err)
832	}
833	if !reflect.DeepEqual(result, expected) {
834		t.Errorf("Bad empty omit unmarshal: expected %v, got %v", expected, result)
835	}
836}
837
838type pointerMarshalTestStruct struct {
839	Str       *string
840	List      *[]string
841	ListPtr   *[]*string
842	Map       *map[string]string
843	MapPtr    *map[string]*string
844	EmptyStr  *string
845	EmptyList *[]string
846	EmptyMap  *map[string]string
847	DblPtr    *[]*[]*string
848}
849
850var pointerStr = "Hello"
851var pointerList = []string{"Hello back"}
852var pointerListPtr = []*string{&pointerStr}
853var pointerMap = map[string]string{"response": "Goodbye"}
854var pointerMapPtr = map[string]*string{"alternate": &pointerStr}
855var pointerTestData = pointerMarshalTestStruct{
856	Str:       &pointerStr,
857	List:      &pointerList,
858	ListPtr:   &pointerListPtr,
859	Map:       &pointerMap,
860	MapPtr:    &pointerMapPtr,
861	EmptyStr:  nil,
862	EmptyList: nil,
863	EmptyMap:  nil,
864}
865
866var pointerTestToml = []byte(`List = ["Hello back"]
867ListPtr = ["Hello"]
868Str = "Hello"
869
870[Map]
871  response = "Goodbye"
872
873[MapPtr]
874  alternate = "Hello"
875`)
876
877func TestPointerMarshal(t *testing.T) {
878	result, err := Marshal(pointerTestData)
879	if err != nil {
880		t.Fatal(err)
881	}
882	expected := pointerTestToml
883	if !bytes.Equal(result, expected) {
884		t.Errorf("Bad pointer marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expected, result)
885	}
886}
887
888func TestPointerUnmarshal(t *testing.T) {
889	result := pointerMarshalTestStruct{}
890	err := Unmarshal(pointerTestToml, &result)
891	expected := pointerTestData
892	if err != nil {
893		t.Fatal(err)
894	}
895	if !reflect.DeepEqual(result, expected) {
896		t.Errorf("Bad pointer unmarshal: expected %v, got %v", expected, result)
897	}
898}
899
900func TestUnmarshalTypeMismatch(t *testing.T) {
901	result := pointerMarshalTestStruct{}
902	err := Unmarshal([]byte("List = 123"), &result)
903	if !strings.HasPrefix(err.Error(), "(1, 1): Can't convert 123(int64) to []string(slice)") {
904		t.Errorf("Type mismatch must be reported: got %v", err.Error())
905	}
906}
907
908type nestedMarshalTestStruct struct {
909	String [][]string
910	//Struct [][]basicMarshalTestSubStruct
911	StringPtr *[]*[]*string
912	// StructPtr *[]*[]*basicMarshalTestSubStruct
913}
914
915var str1 = "Three"
916var str2 = "Four"
917var strPtr = []*string{&str1, &str2}
918var strPtr2 = []*[]*string{&strPtr}
919
920var nestedTestData = nestedMarshalTestStruct{
921	String:    [][]string{{"Five", "Six"}, {"One", "Two"}},
922	StringPtr: &strPtr2,
923}
924
925var nestedTestToml = []byte(`String = [["Five", "Six"], ["One", "Two"]]
926StringPtr = [["Three", "Four"]]
927`)
928
929func TestNestedMarshal(t *testing.T) {
930	result, err := Marshal(nestedTestData)
931	if err != nil {
932		t.Fatal(err)
933	}
934	expected := nestedTestToml
935	if !bytes.Equal(result, expected) {
936		t.Errorf("Bad nested marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expected, result)
937	}
938}
939
940func TestNestedUnmarshal(t *testing.T) {
941	result := nestedMarshalTestStruct{}
942	err := Unmarshal(nestedTestToml, &result)
943	expected := nestedTestData
944	if err != nil {
945		t.Fatal(err)
946	}
947	if !reflect.DeepEqual(result, expected) {
948		t.Errorf("Bad nested unmarshal: expected %v, got %v", expected, result)
949	}
950}
951
952type customMarshalerParent struct {
953	Self    customMarshaler   `toml:"me"`
954	Friends []customMarshaler `toml:"friends"`
955}
956
957type customMarshaler struct {
958	FirstName string
959	LastName  string
960}
961
962func (c customMarshaler) MarshalTOML() ([]byte, error) {
963	fullName := fmt.Sprintf("%s %s", c.FirstName, c.LastName)
964	return []byte(fullName), nil
965}
966
967var customMarshalerData = customMarshaler{FirstName: "Sally", LastName: "Fields"}
968var customMarshalerToml = []byte(`Sally Fields`)
969var nestedCustomMarshalerData = customMarshalerParent{
970	Self:    customMarshaler{FirstName: "Maiku", LastName: "Suteda"},
971	Friends: []customMarshaler{customMarshalerData},
972}
973var nestedCustomMarshalerToml = []byte(`friends = ["Sally Fields"]
974me = "Maiku Suteda"
975`)
976var nestedCustomMarshalerTomlForUnmarshal = []byte(`[friends]
977FirstName = "Sally"
978LastName = "Fields"`)
979
980func TestCustomMarshaler(t *testing.T) {
981	result, err := Marshal(customMarshalerData)
982	if err != nil {
983		t.Fatal(err)
984	}
985	expected := customMarshalerToml
986	if !bytes.Equal(result, expected) {
987		t.Errorf("Bad custom marshaler: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expected, result)
988	}
989}
990
991type IntOrString string
992
993func (x *IntOrString) MarshalTOML() ([]byte, error) {
994	s := *(*string)(x)
995	_, err := strconv.Atoi(s)
996	if err != nil {
997		return []byte(fmt.Sprintf(`"%s"`, s)), nil
998	}
999	return []byte(s), nil
1000}
1001
1002func TestNestedCustomMarshaler(t *testing.T) {
1003	num := IntOrString("100")
1004	str := IntOrString("hello")
1005	var parent = struct {
1006		IntField    *IntOrString `toml:"int"`
1007		StringField *IntOrString `toml:"string"`
1008	}{
1009		&num,
1010		&str,
1011	}
1012
1013	result, err := Marshal(parent)
1014	if err != nil {
1015		t.Fatal(err)
1016	}
1017	expected := `int = 100
1018string = "hello"
1019`
1020	if !bytes.Equal(result, []byte(expected)) {
1021		t.Errorf("Bad nested text marshaler: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expected, result)
1022	}
1023}
1024
1025type textMarshaler struct {
1026	FirstName string
1027	LastName  string
1028}
1029
1030func (m textMarshaler) MarshalText() ([]byte, error) {
1031	fullName := fmt.Sprintf("%s %s", m.FirstName, m.LastName)
1032	return []byte(fullName), nil
1033}
1034
1035func TestTextMarshaler(t *testing.T) {
1036	m := textMarshaler{FirstName: "Sally", LastName: "Fields"}
1037
1038	result, err := Marshal(m)
1039	if err != nil {
1040		t.Fatal(err)
1041	}
1042	expected := `Sally Fields`
1043	if !bytes.Equal(result, []byte(expected)) {
1044		t.Errorf("Bad text marshaler: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expected, result)
1045	}
1046}
1047
1048func TestUnmarshalTextMarshaler(t *testing.T) {
1049	var nested = struct {
1050		Friends textMarshaler `toml:"friends"`
1051	}{}
1052
1053	var expected = struct {
1054		Friends textMarshaler `toml:"friends"`
1055	}{
1056		Friends: textMarshaler{FirstName: "Sally", LastName: "Fields"},
1057	}
1058
1059	err := Unmarshal(nestedCustomMarshalerTomlForUnmarshal, &nested)
1060	if err != nil {
1061		t.Fatal(err)
1062	}
1063	if !reflect.DeepEqual(nested, expected) {
1064		t.Errorf("Bad unmarshal: expected %v, got %v", expected, nested)
1065	}
1066}
1067
1068func TestNestedTextMarshaler(t *testing.T) {
1069	var parent = struct {
1070		Self     textMarshaler   `toml:"me"`
1071		Friends  []textMarshaler `toml:"friends"`
1072		Stranger *textMarshaler  `toml:"stranger"`
1073	}{
1074		Self:     textMarshaler{FirstName: "Maiku", LastName: "Suteda"},
1075		Friends:  []textMarshaler{textMarshaler{FirstName: "Sally", LastName: "Fields"}},
1076		Stranger: &textMarshaler{FirstName: "Earl", LastName: "Henson"},
1077	}
1078
1079	result, err := Marshal(parent)
1080	if err != nil {
1081		t.Fatal(err)
1082	}
1083	expected := `friends = ["Sally Fields"]
1084me = "Maiku Suteda"
1085stranger = "Earl Henson"
1086`
1087	if !bytes.Equal(result, []byte(expected)) {
1088		t.Errorf("Bad nested text marshaler: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expected, result)
1089	}
1090}
1091
1092type precedentMarshaler struct {
1093	FirstName string
1094	LastName  string
1095}
1096
1097func (m precedentMarshaler) MarshalText() ([]byte, error) {
1098	return []byte("shadowed"), nil
1099}
1100
1101func (m precedentMarshaler) MarshalTOML() ([]byte, error) {
1102	fullName := fmt.Sprintf("%s %s", m.FirstName, m.LastName)
1103	return []byte(fullName), nil
1104}
1105
1106func TestPrecedentMarshaler(t *testing.T) {
1107	m := textMarshaler{FirstName: "Sally", LastName: "Fields"}
1108
1109	result, err := Marshal(m)
1110	if err != nil {
1111		t.Fatal(err)
1112	}
1113	expected := `Sally Fields`
1114	if !bytes.Equal(result, []byte(expected)) {
1115		t.Errorf("Bad text marshaler: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expected, result)
1116	}
1117}
1118
1119type customPointerMarshaler struct {
1120	FirstName string
1121	LastName  string
1122}
1123
1124func (m *customPointerMarshaler) MarshalTOML() ([]byte, error) {
1125	return []byte(`"hidden"`), nil
1126}
1127
1128type textPointerMarshaler struct {
1129	FirstName string
1130	LastName  string
1131}
1132
1133func (m *textPointerMarshaler) MarshalText() ([]byte, error) {
1134	return []byte("hidden"), nil
1135}
1136
1137func TestPointerMarshaler(t *testing.T) {
1138	var parent = struct {
1139		Self     customPointerMarshaler  `toml:"me"`
1140		Stranger *customPointerMarshaler `toml:"stranger"`
1141		Friend   textPointerMarshaler    `toml:"friend"`
1142		Fiend    *textPointerMarshaler   `toml:"fiend"`
1143	}{
1144		Self:     customPointerMarshaler{FirstName: "Maiku", LastName: "Suteda"},
1145		Stranger: &customPointerMarshaler{FirstName: "Earl", LastName: "Henson"},
1146		Friend:   textPointerMarshaler{FirstName: "Sally", LastName: "Fields"},
1147		Fiend:    &textPointerMarshaler{FirstName: "Casper", LastName: "Snider"},
1148	}
1149
1150	result, err := Marshal(parent)
1151	if err != nil {
1152		t.Fatal(err)
1153	}
1154	expected := `fiend = "hidden"
1155stranger = "hidden"
1156
1157[friend]
1158  FirstName = "Sally"
1159  LastName = "Fields"
1160
1161[me]
1162  FirstName = "Maiku"
1163  LastName = "Suteda"
1164`
1165	if !bytes.Equal(result, []byte(expected)) {
1166		t.Errorf("Bad nested text marshaler: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expected, result)
1167	}
1168}
1169
1170func TestPointerCustomMarshalerSequence(t *testing.T) {
1171	var customPointerMarshalerSlice *[]*customPointerMarshaler
1172	var customPointerMarshalerArray *[2]*customPointerMarshaler
1173
1174	if !isCustomMarshalerSequence(reflect.TypeOf(customPointerMarshalerSlice)) {
1175		t.Errorf("error: should be a sequence of custom marshaler interfaces")
1176	}
1177	if !isCustomMarshalerSequence(reflect.TypeOf(customPointerMarshalerArray)) {
1178		t.Errorf("error: should be a sequence of custom marshaler interfaces")
1179	}
1180}
1181
1182func TestPointerTextMarshalerSequence(t *testing.T) {
1183	var textPointerMarshalerSlice *[]*textPointerMarshaler
1184	var textPointerMarshalerArray *[2]*textPointerMarshaler
1185
1186	if !isTextMarshalerSequence(reflect.TypeOf(textPointerMarshalerSlice)) {
1187		t.Errorf("error: should be a sequence of text marshaler interfaces")
1188	}
1189	if !isTextMarshalerSequence(reflect.TypeOf(textPointerMarshalerArray)) {
1190		t.Errorf("error: should be a sequence of text marshaler interfaces")
1191	}
1192}
1193
1194var commentTestToml = []byte(`
1195# it's a comment on type
1196[postgres]
1197  # isCommented = "dvalue"
1198  noComment = "cvalue"
1199
1200  # A comment on AttrB with a
1201  # break line
1202  password = "bvalue"
1203
1204  # A comment on AttrA
1205  user = "avalue"
1206
1207  [[postgres.My]]
1208
1209    # a comment on my on typeC
1210    My = "Foo"
1211
1212  [[postgres.My]]
1213
1214    # a comment on my on typeC
1215    My = "Baar"
1216`)
1217
1218func TestMarshalComment(t *testing.T) {
1219	type TypeC struct {
1220		My string `comment:"a comment on my on typeC"`
1221	}
1222	type TypeB struct {
1223		AttrA string `toml:"user" comment:"A comment on AttrA"`
1224		AttrB string `toml:"password" comment:"A comment on AttrB with a\n break line"`
1225		AttrC string `toml:"noComment"`
1226		AttrD string `toml:"isCommented" commented:"true"`
1227		My    []TypeC
1228	}
1229	type TypeA struct {
1230		TypeB TypeB `toml:"postgres" comment:"it's a comment on type"`
1231	}
1232
1233	ta := []TypeC{{My: "Foo"}, {My: "Baar"}}
1234	config := TypeA{TypeB{AttrA: "avalue", AttrB: "bvalue", AttrC: "cvalue", AttrD: "dvalue", My: ta}}
1235	result, err := Marshal(config)
1236	if err != nil {
1237		t.Fatal(err)
1238	}
1239	expected := commentTestToml
1240	if !bytes.Equal(result, expected) {
1241		t.Errorf("Bad marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expected, result)
1242	}
1243}
1244
1245func TestMarshalMultilineCommented(t *testing.T) {
1246	expectedToml := []byte(`# MultilineArray = [
1247  # 100,
1248  # 200,
1249  # 300,
1250# ]
1251# MultilineNestedArray = [
1252  # [
1253  # "a",
1254  # "b",
1255  # "c",
1256# ],
1257  # [
1258  # "d",
1259  # "e",
1260  # "f",
1261# ],
1262# ]
1263# MultilineString = """
1264# I
1265# am
1266# Allen"""
1267NonCommented = "Not commented line"
1268`)
1269	type StructWithMultiline struct {
1270		NonCommented         string
1271		MultilineString      string     `commented:"true" multiline:"true"`
1272		MultilineArray       []int      `commented:"true"`
1273		MultilineNestedArray [][]string `commented:"true"`
1274	}
1275
1276	var buf bytes.Buffer
1277	enc := NewEncoder(&buf)
1278	if err := enc.ArraysWithOneElementPerLine(true).Encode(StructWithMultiline{
1279		NonCommented:    "Not commented line",
1280		MultilineString: "I\nam\nAllen",
1281		MultilineArray:  []int{100, 200, 300},
1282		MultilineNestedArray: [][]string{
1283			{"a", "b", "c"},
1284			{"d", "e", "f"},
1285		},
1286	}); err == nil {
1287		result := buf.Bytes()
1288		if !bytes.Equal(result, expectedToml) {
1289			t.Errorf("Bad marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expectedToml, result)
1290		}
1291	} else {
1292		t.Fatal(err)
1293	}
1294}
1295
1296func TestMarshalNonPrimitiveTypeCommented(t *testing.T) {
1297	expectedToml := []byte(`
1298# [CommentedMapField]
1299
1300  # [CommentedMapField.CommentedMapField1]
1301    # SingleLineString = "This line should be commented out"
1302
1303  # [CommentedMapField.CommentedMapField2]
1304    # SingleLineString = "This line should be commented out"
1305
1306# [CommentedStructField]
1307
1308  # [CommentedStructField.CommentedStructField]
1309    # MultilineArray = [
1310      # 1,
1311      # 2,
1312    # ]
1313    # MultilineNestedArray = [
1314      # [
1315      # 10,
1316      # 20,
1317    # ],
1318      # [
1319      # 100,
1320      # 200,
1321    # ],
1322    # ]
1323    # MultilineString = """
1324# This line
1325# should be
1326# commented out"""
1327
1328  # [CommentedStructField.NotCommentedStructField]
1329    # MultilineArray = [
1330      # 1,
1331      # 2,
1332    # ]
1333    # MultilineNestedArray = [
1334      # [
1335      # 10,
1336      # 20,
1337    # ],
1338      # [
1339      # 100,
1340      # 200,
1341    # ],
1342    # ]
1343    # MultilineString = """
1344# This line
1345# should be
1346# commented out"""
1347
1348[NotCommentedStructField]
1349
1350  # [NotCommentedStructField.CommentedStructField]
1351    # MultilineArray = [
1352      # 1,
1353      # 2,
1354    # ]
1355    # MultilineNestedArray = [
1356      # [
1357      # 10,
1358      # 20,
1359    # ],
1360      # [
1361      # 100,
1362      # 200,
1363    # ],
1364    # ]
1365    # MultilineString = """
1366# This line
1367# should be
1368# commented out"""
1369
1370  [NotCommentedStructField.NotCommentedStructField]
1371    MultilineArray = [
1372      3,
1373      4,
1374    ]
1375    MultilineNestedArray = [
1376      [
1377      30,
1378      40,
1379    ],
1380      [
1381      300,
1382      400,
1383    ],
1384    ]
1385    MultilineString = """
1386This line
1387should NOT be
1388commented out"""
1389`)
1390	type InnerStruct struct {
1391		MultilineString      string `multiline:"true"`
1392		MultilineArray       []int
1393		MultilineNestedArray [][]int
1394	}
1395	type MiddleStruct struct {
1396		NotCommentedStructField InnerStruct
1397		CommentedStructField    InnerStruct `commented:"true"`
1398	}
1399	type OuterStruct struct {
1400		CommentedStructField    MiddleStruct `commented:"true"`
1401		NotCommentedStructField MiddleStruct
1402		CommentedMapField       map[string]struct{ SingleLineString string } `commented:"true"`
1403	}
1404
1405	commentedTestStruct := OuterStruct{
1406		CommentedStructField: MiddleStruct{
1407			NotCommentedStructField: InnerStruct{
1408				MultilineString:      "This line\nshould be\ncommented out",
1409				MultilineArray:       []int{1, 2},
1410				MultilineNestedArray: [][]int{{10, 20}, {100, 200}},
1411			},
1412			CommentedStructField: InnerStruct{
1413				MultilineString:      "This line\nshould be\ncommented out",
1414				MultilineArray:       []int{1, 2},
1415				MultilineNestedArray: [][]int{{10, 20}, {100, 200}},
1416			},
1417		},
1418		NotCommentedStructField: MiddleStruct{
1419			NotCommentedStructField: InnerStruct{
1420				MultilineString:      "This line\nshould NOT be\ncommented out",
1421				MultilineArray:       []int{3, 4},
1422				MultilineNestedArray: [][]int{{30, 40}, {300, 400}},
1423			},
1424			CommentedStructField: InnerStruct{
1425				MultilineString:      "This line\nshould be\ncommented out",
1426				MultilineArray:       []int{1, 2},
1427				MultilineNestedArray: [][]int{{10, 20}, {100, 200}},
1428			},
1429		},
1430		CommentedMapField: map[string]struct{ SingleLineString string }{
1431			"CommentedMapField1": {
1432				SingleLineString: "This line should be commented out",
1433			},
1434			"CommentedMapField2": {
1435				SingleLineString: "This line should be commented out",
1436			},
1437		},
1438	}
1439
1440	var buf bytes.Buffer
1441	enc := NewEncoder(&buf)
1442	if err := enc.ArraysWithOneElementPerLine(true).Encode(commentedTestStruct); err == nil {
1443		result := buf.Bytes()
1444		if !bytes.Equal(result, expectedToml) {
1445			t.Errorf("Bad marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expectedToml, result)
1446		}
1447	} else {
1448		t.Fatal(err)
1449	}
1450}
1451
1452type mapsTestStruct struct {
1453	Simple map[string]string
1454	Paths  map[string]string
1455	Other  map[string]float64
1456	X      struct {
1457		Y struct {
1458			Z map[string]bool
1459		}
1460	}
1461}
1462
1463var mapsTestData = mapsTestStruct{
1464	Simple: map[string]string{
1465		"one plus one": "two",
1466		"next":         "three",
1467	},
1468	Paths: map[string]string{
1469		"/this/is/a/path": "/this/is/also/a/path",
1470		"/heloo.txt":      "/tmp/lololo.txt",
1471	},
1472	Other: map[string]float64{
1473		"testing": 3.9999,
1474	},
1475	X: struct{ Y struct{ Z map[string]bool } }{
1476		Y: struct{ Z map[string]bool }{
1477			Z: map[string]bool{
1478				"is.Nested": true,
1479			},
1480		},
1481	},
1482}
1483var mapsTestToml = []byte(`
1484[Other]
1485  "testing" = 3.9999
1486
1487[Paths]
1488  "/heloo.txt" = "/tmp/lololo.txt"
1489  "/this/is/a/path" = "/this/is/also/a/path"
1490
1491[Simple]
1492  "next" = "three"
1493  "one plus one" = "two"
1494
1495[X]
1496
1497  [X.Y]
1498
1499    [X.Y.Z]
1500      "is.Nested" = true
1501`)
1502
1503func TestEncodeQuotedMapKeys(t *testing.T) {
1504	var buf bytes.Buffer
1505	if err := NewEncoder(&buf).QuoteMapKeys(true).Encode(mapsTestData); err != nil {
1506		t.Fatal(err)
1507	}
1508	result := buf.Bytes()
1509	expected := mapsTestToml
1510	if !bytes.Equal(result, expected) {
1511		t.Errorf("Bad maps marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expected, result)
1512	}
1513}
1514
1515func TestDecodeQuotedMapKeys(t *testing.T) {
1516	result := mapsTestStruct{}
1517	err := NewDecoder(bytes.NewBuffer(mapsTestToml)).Decode(&result)
1518	expected := mapsTestData
1519	if err != nil {
1520		t.Fatal(err)
1521	}
1522	if !reflect.DeepEqual(result, expected) {
1523		t.Errorf("Bad maps unmarshal: expected %v, got %v", expected, result)
1524	}
1525}
1526
1527type structArrayNoTag struct {
1528	A struct {
1529		B []int64
1530		C []int64
1531	}
1532}
1533
1534func TestMarshalArray(t *testing.T) {
1535	expected := []byte(`
1536[A]
1537  B = [1, 2, 3]
1538  C = [1]
1539`)
1540
1541	m := structArrayNoTag{
1542		A: struct {
1543			B []int64
1544			C []int64
1545		}{
1546			B: []int64{1, 2, 3},
1547			C: []int64{1},
1548		},
1549	}
1550
1551	b, err := Marshal(m)
1552
1553	if err != nil {
1554		t.Fatal(err)
1555	}
1556
1557	if !bytes.Equal(b, expected) {
1558		t.Errorf("Bad arrays marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expected, b)
1559	}
1560}
1561
1562func TestMarshalArrayOnePerLine(t *testing.T) {
1563	expected := []byte(`
1564[A]
1565  B = [
1566    1,
1567    2,
1568    3,
1569  ]
1570  C = [1]
1571`)
1572
1573	m := structArrayNoTag{
1574		A: struct {
1575			B []int64
1576			C []int64
1577		}{
1578			B: []int64{1, 2, 3},
1579			C: []int64{1},
1580		},
1581	}
1582
1583	var buf bytes.Buffer
1584	encoder := NewEncoder(&buf).ArraysWithOneElementPerLine(true)
1585	err := encoder.Encode(m)
1586
1587	if err != nil {
1588		t.Fatal(err)
1589	}
1590
1591	b := buf.Bytes()
1592
1593	if !bytes.Equal(b, expected) {
1594		t.Errorf("Bad arrays marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expected, b)
1595	}
1596}
1597
1598var customTagTestToml = []byte(`
1599[postgres]
1600  password = "bvalue"
1601  user = "avalue"
1602
1603  [[postgres.My]]
1604    My = "Foo"
1605
1606  [[postgres.My]]
1607    My = "Baar"
1608`)
1609
1610func TestMarshalCustomTag(t *testing.T) {
1611	type TypeC struct {
1612		My string
1613	}
1614	type TypeB struct {
1615		AttrA string `file:"user"`
1616		AttrB string `file:"password"`
1617		My    []TypeC
1618	}
1619	type TypeA struct {
1620		TypeB TypeB `file:"postgres"`
1621	}
1622
1623	ta := []TypeC{{My: "Foo"}, {My: "Baar"}}
1624	config := TypeA{TypeB{AttrA: "avalue", AttrB: "bvalue", My: ta}}
1625	var buf bytes.Buffer
1626	err := NewEncoder(&buf).SetTagName("file").Encode(config)
1627	if err != nil {
1628		t.Fatal(err)
1629	}
1630	expected := customTagTestToml
1631	result := buf.Bytes()
1632	if !bytes.Equal(result, expected) {
1633		t.Errorf("Bad marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expected, result)
1634	}
1635}
1636
1637var customCommentTagTestToml = []byte(`
1638# db connection
1639[postgres]
1640
1641  # db pass
1642  password = "bvalue"
1643
1644  # db user
1645  user = "avalue"
1646`)
1647
1648func TestMarshalCustomComment(t *testing.T) {
1649	type TypeB struct {
1650		AttrA string `toml:"user" descr:"db user"`
1651		AttrB string `toml:"password" descr:"db pass"`
1652	}
1653	type TypeA struct {
1654		TypeB TypeB `toml:"postgres" descr:"db connection"`
1655	}
1656
1657	config := TypeA{TypeB{AttrA: "avalue", AttrB: "bvalue"}}
1658	var buf bytes.Buffer
1659	err := NewEncoder(&buf).SetTagComment("descr").Encode(config)
1660	if err != nil {
1661		t.Fatal(err)
1662	}
1663	expected := customCommentTagTestToml
1664	result := buf.Bytes()
1665	if !bytes.Equal(result, expected) {
1666		t.Errorf("Bad marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expected, result)
1667	}
1668}
1669
1670var customCommentedTagTestToml = []byte(`
1671[postgres]
1672  # password = "bvalue"
1673  # user = "avalue"
1674`)
1675
1676func TestMarshalCustomCommented(t *testing.T) {
1677	type TypeB struct {
1678		AttrA string `toml:"user" disable:"true"`
1679		AttrB string `toml:"password" disable:"true"`
1680	}
1681	type TypeA struct {
1682		TypeB TypeB `toml:"postgres"`
1683	}
1684
1685	config := TypeA{TypeB{AttrA: "avalue", AttrB: "bvalue"}}
1686	var buf bytes.Buffer
1687	err := NewEncoder(&buf).SetTagCommented("disable").Encode(config)
1688	if err != nil {
1689		t.Fatal(err)
1690	}
1691	expected := customCommentedTagTestToml
1692	result := buf.Bytes()
1693	if !bytes.Equal(result, expected) {
1694		t.Errorf("Bad marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expected, result)
1695	}
1696}
1697
1698func TestMarshalDirectMultilineString(t *testing.T) {
1699	tree := newTree()
1700	tree.SetWithOptions("mykey", SetOptions{
1701		Multiline: true,
1702	}, "my\x11multiline\nstring\ba\tb\fc\rd\"e\\!")
1703	result, err := tree.Marshal()
1704	if err != nil {
1705		t.Fatal("marshal should not error:", err)
1706	}
1707	expected := []byte("mykey = \"\"\"\nmy\\u0011multiline\nstring\\ba\tb\\fc\rd\"e\\!\"\"\"\n")
1708	if !bytes.Equal(result, expected) {
1709		t.Errorf("Bad marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expected, result)
1710	}
1711}
1712
1713func TestUnmarshalTabInStringAndQuotedKey(t *testing.T) {
1714	type Test struct {
1715		Field1 string `toml:"Fie	ld1"`
1716		Field2 string
1717	}
1718
1719	type TestCase struct {
1720		desc     string
1721		input    []byte
1722		expected Test
1723	}
1724
1725	testCases := []TestCase{
1726		{
1727			desc:  "multiline string with tab",
1728			input: []byte("Field2 = \"\"\"\nhello\tworld\"\"\""),
1729			expected: Test{
1730				Field2: "hello\tworld",
1731			},
1732		},
1733		{
1734			desc:  "quoted key with tab",
1735			input: []byte("\"Fie\tld1\" = \"key with tab\""),
1736			expected: Test{
1737				Field1: "key with tab",
1738			},
1739		},
1740		{
1741			desc:  "basic string tab",
1742			input: []byte("Field2 = \"hello\tworld\""),
1743			expected: Test{
1744				Field2: "hello\tworld",
1745			},
1746		},
1747	}
1748
1749	for i := range testCases {
1750		result := Test{}
1751		err := Unmarshal(testCases[i].input, &result)
1752		if err != nil {
1753			t.Errorf("%s test error:%v", testCases[i].desc, err)
1754			continue
1755		}
1756
1757		if !reflect.DeepEqual(result, testCases[i].expected) {
1758			t.Errorf("%s test error: expected\n-----\n%+v\n-----\ngot\n-----\n%+v\n-----\n",
1759				testCases[i].desc, testCases[i].expected, result)
1760		}
1761	}
1762}
1763
1764var customMultilineTagTestToml = []byte(`int_slice = [
1765  1,
1766  2,
1767  3,
1768]
1769`)
1770
1771func TestMarshalCustomMultiline(t *testing.T) {
1772	type TypeA struct {
1773		AttrA []int `toml:"int_slice" mltln:"true"`
1774	}
1775
1776	config := TypeA{AttrA: []int{1, 2, 3}}
1777	var buf bytes.Buffer
1778	err := NewEncoder(&buf).ArraysWithOneElementPerLine(true).SetTagMultiline("mltln").Encode(config)
1779	if err != nil {
1780		t.Fatal(err)
1781	}
1782	expected := customMultilineTagTestToml
1783	result := buf.Bytes()
1784	if !bytes.Equal(result, expected) {
1785		t.Errorf("Bad marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expected, result)
1786	}
1787}
1788
1789func TestMultilineWithAdjacentQuotationMarks(t *testing.T) {
1790	type testStruct struct {
1791		Str string `multiline:"true"`
1792	}
1793	type testCase struct {
1794		expected []byte
1795		data     testStruct
1796	}
1797
1798	testCases := []testCase{
1799		{
1800			expected: []byte(`Str = """
1801hello\""""
1802`),
1803			data: testStruct{
1804				Str: "hello\"",
1805			},
1806		},
1807		{
1808			expected: []byte(`Str = """
1809""\"""\"""\""""
1810`),
1811			data: testStruct{
1812				Str: "\"\"\"\"\"\"\"\"\"",
1813			},
1814		},
1815	}
1816	for i := range testCases {
1817		result, err := Marshal(testCases[i].data)
1818		if err != nil {
1819			t.Fatal(err)
1820		}
1821
1822		if !bytes.Equal(result, testCases[i].expected) {
1823			t.Errorf("Bad marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n",
1824				testCases[i].expected, result)
1825		} else {
1826			var data testStruct
1827			if err = Unmarshal(result, &data); err != nil {
1828				t.Fatal(err)
1829			}
1830			if data.Str != testCases[i].data.Str {
1831				t.Errorf("Round trip test fail: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n",
1832					testCases[i].data.Str, data.Str)
1833			}
1834		}
1835	}
1836}
1837
1838func TestMarshalEmbedTree(t *testing.T) {
1839	expected := []byte(`OuterField1 = "Out"
1840OuterField2 = 1024
1841
1842[TreeField]
1843  InnerField1 = "In"
1844  InnerField2 = 2048
1845
1846  [TreeField.EmbedStruct]
1847    EmbedField = "Embed"
1848`)
1849	type InnerStruct struct {
1850		InnerField1 string
1851		InnerField2 int
1852		EmbedStruct struct {
1853			EmbedField string
1854		}
1855	}
1856
1857	type OuterStruct struct {
1858		OuterField1 string
1859		OuterField2 int
1860		TreeField   *Tree
1861	}
1862
1863	tree, err := Load(`
1864InnerField1 = "In"
1865InnerField2 = 2048
1866
1867[EmbedStruct]
1868	EmbedField = "Embed"
1869`)
1870	if err != nil {
1871		t.Fatal(err)
1872	}
1873
1874	out := OuterStruct{
1875		"Out",
1876		1024,
1877		tree,
1878	}
1879	actual, _ := Marshal(out)
1880
1881	if !bytes.Equal(actual, expected) {
1882		t.Errorf("Bad marshal: expected %s, got %s", expected, actual)
1883	}
1884}
1885
1886var testDocBasicToml = []byte(`
1887[document]
1888  bool_val = true
1889  date_val = 1979-05-27T07:32:00Z
1890  float_val = 123.4
1891  int_val = 5000
1892  string_val = "Bite me"
1893  uint_val = 5001
1894`)
1895
1896type testDocCustomTag struct {
1897	Doc testDocBasicsCustomTag `file:"document"`
1898}
1899type testDocBasicsCustomTag struct {
1900	Bool       bool      `file:"bool_val"`
1901	Date       time.Time `file:"date_val"`
1902	Float      float32   `file:"float_val"`
1903	Int        int       `file:"int_val"`
1904	Uint       uint      `file:"uint_val"`
1905	String     *string   `file:"string_val"`
1906	unexported int       `file:"shouldntBeHere"`
1907}
1908
1909var testDocCustomTagData = testDocCustomTag{
1910	Doc: testDocBasicsCustomTag{
1911		Bool:       true,
1912		Date:       time.Date(1979, 5, 27, 7, 32, 0, 0, time.UTC),
1913		Float:      123.4,
1914		Int:        5000,
1915		Uint:       5001,
1916		String:     &biteMe,
1917		unexported: 0,
1918	},
1919}
1920
1921func TestUnmarshalCustomTag(t *testing.T) {
1922	buf := bytes.NewBuffer(testDocBasicToml)
1923
1924	result := testDocCustomTag{}
1925	err := NewDecoder(buf).SetTagName("file").Decode(&result)
1926	if err != nil {
1927		t.Fatal(err)
1928	}
1929	expected := testDocCustomTagData
1930	if !reflect.DeepEqual(result, expected) {
1931		resStr, _ := json.MarshalIndent(result, "", "  ")
1932		expStr, _ := json.MarshalIndent(expected, "", "  ")
1933		t.Errorf("Bad unmarshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expStr, resStr)
1934
1935	}
1936}
1937
1938func TestUnmarshalMap(t *testing.T) {
1939	testToml := []byte(`
1940		a = 1
1941		b = 2
1942		c = 3
1943		`)
1944	var result map[string]int
1945	err := Unmarshal(testToml, &result)
1946	if err != nil {
1947		t.Errorf("Received unexpected error: %s", err)
1948		return
1949	}
1950
1951	expected := map[string]int{
1952		"a": 1,
1953		"b": 2,
1954		"c": 3,
1955	}
1956
1957	if !reflect.DeepEqual(result, expected) {
1958		t.Errorf("Bad unmarshal: expected %v, got %v", expected, result)
1959	}
1960}
1961
1962func TestUnmarshalMapWithTypedKey(t *testing.T) {
1963	testToml := []byte(`
1964		a = 1
1965		b = 2
1966		c = 3
1967		`)
1968
1969	type letter string
1970	var result map[letter]int
1971	err := Unmarshal(testToml, &result)
1972	if err != nil {
1973		t.Errorf("Received unexpected error: %s", err)
1974		return
1975	}
1976
1977	expected := map[letter]int{
1978		"a": 1,
1979		"b": 2,
1980		"c": 3,
1981	}
1982
1983	if !reflect.DeepEqual(result, expected) {
1984		t.Errorf("Bad unmarshal: expected %v, got %v", expected, result)
1985	}
1986}
1987
1988func TestUnmarshalNonPointer(t *testing.T) {
1989	a := 1
1990	err := Unmarshal([]byte{}, a)
1991	if err == nil {
1992		t.Fatal("unmarshal should err when given a non pointer")
1993	}
1994}
1995
1996func TestUnmarshalInvalidPointerKind(t *testing.T) {
1997	a := 1
1998	err := Unmarshal([]byte{}, &a)
1999	if err == nil {
2000		t.Fatal("unmarshal should err when given an invalid pointer type")
2001	}
2002}
2003
2004func TestMarshalSlice(t *testing.T) {
2005	m := make([]int, 1)
2006	m[0] = 1
2007
2008	var buf bytes.Buffer
2009	err := NewEncoder(&buf).Encode(&m)
2010	if err == nil {
2011		t.Error("expected error, got nil")
2012		return
2013	}
2014	if err.Error() != "Only pointer to struct can be marshaled to TOML" {
2015		t.Fail()
2016	}
2017}
2018
2019func TestMarshalSlicePointer(t *testing.T) {
2020	m := make([]int, 1)
2021	m[0] = 1
2022
2023	var buf bytes.Buffer
2024	err := NewEncoder(&buf).Encode(m)
2025	if err == nil {
2026		t.Error("expected error, got nil")
2027		return
2028	}
2029	if err.Error() != "Only a struct or map can be marshaled to TOML" {
2030		t.Fail()
2031	}
2032}
2033
2034func TestMarshalNestedArrayInlineTables(t *testing.T) {
2035	type table struct {
2036		Value1 int `toml:"ZValue1"`
2037		Value2 int `toml:"YValue2"`
2038		Value3 int `toml:"XValue3"`
2039	}
2040
2041	type nestedTable struct {
2042		Table table
2043	}
2044
2045	nestedArray := struct {
2046		Simple        [][]table
2047		SimplePointer *[]*[]table
2048		Nested        [][]nestedTable
2049		NestedPointer *[]*[]nestedTable
2050	}{
2051		Simple:        [][]table{{{Value1: 1}, {Value1: 10}}},
2052		SimplePointer: &[]*[]table{{{Value2: 2}}},
2053		Nested:        [][]nestedTable{{{Table: table{Value3: 3}}}},
2054		NestedPointer: &[]*[]nestedTable{{{Table: table{Value3: -3}}}},
2055	}
2056
2057	expectedPreserve := `Simple = [[{ ZValue1 = 1, YValue2 = 0, XValue3 = 0 }, { ZValue1 = 10, YValue2 = 0, XValue3 = 0 }]]
2058SimplePointer = [[{ ZValue1 = 0, YValue2 = 2, XValue3 = 0 }]]
2059Nested = [[{ Table = { ZValue1 = 0, YValue2 = 0, XValue3 = 3 } }]]
2060NestedPointer = [[{ Table = { ZValue1 = 0, YValue2 = 0, XValue3 = -3 } }]]
2061`
2062
2063	expectedAlphabetical := `Nested = [[{ Table = { XValue3 = 3, YValue2 = 0, ZValue1 = 0 } }]]
2064NestedPointer = [[{ Table = { XValue3 = -3, YValue2 = 0, ZValue1 = 0 } }]]
2065Simple = [[{ XValue3 = 0, YValue2 = 0, ZValue1 = 1 }, { XValue3 = 0, YValue2 = 0, ZValue1 = 10 }]]
2066SimplePointer = [[{ XValue3 = 0, YValue2 = 2, ZValue1 = 0 }]]
2067`
2068
2069	var bufPreserve bytes.Buffer
2070	if err := NewEncoder(&bufPreserve).Order(OrderPreserve).Encode(nestedArray); err != nil {
2071		t.Fatalf("unexpected error: %s", err.Error())
2072	}
2073	if !bytes.Equal(bufPreserve.Bytes(), []byte(expectedPreserve)) {
2074		t.Errorf("Bad marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expectedPreserve, bufPreserve.String())
2075	}
2076
2077	var bufAlphabetical bytes.Buffer
2078	if err := NewEncoder(&bufAlphabetical).Order(OrderAlphabetical).Encode(nestedArray); err != nil {
2079		t.Fatalf("unexpected error: %s", err.Error())
2080	}
2081	if !bytes.Equal(bufAlphabetical.Bytes(), []byte(expectedAlphabetical)) {
2082		t.Errorf("Bad marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expectedAlphabetical, bufAlphabetical.String())
2083	}
2084}
2085
2086type testDuration struct {
2087	Nanosec   time.Duration  `toml:"nanosec"`
2088	Microsec1 time.Duration  `toml:"microsec1"`
2089	Microsec2 *time.Duration `toml:"microsec2"`
2090	Millisec  time.Duration  `toml:"millisec"`
2091	Sec       time.Duration  `toml:"sec"`
2092	Min       time.Duration  `toml:"min"`
2093	Hour      time.Duration  `toml:"hour"`
2094	Mixed     time.Duration  `toml:"mixed"`
2095	AString   string         `toml:"a_string"`
2096}
2097
2098var testDurationToml = []byte(`
2099nanosec = "1ns"
2100microsec1 = "1us"
2101microsec2 = "1µs"
2102millisec = "1ms"
2103sec = "1s"
2104min = "1m"
2105hour = "1h"
2106mixed = "1h1m1s1ms1µs1ns"
2107a_string = "15s"
2108`)
2109
2110func TestUnmarshalDuration(t *testing.T) {
2111	buf := bytes.NewBuffer(testDurationToml)
2112
2113	result := testDuration{}
2114	err := NewDecoder(buf).Decode(&result)
2115	if err != nil {
2116		t.Fatal(err)
2117	}
2118	ms := time.Duration(1) * time.Microsecond
2119	expected := testDuration{
2120		Nanosec:   1,
2121		Microsec1: time.Microsecond,
2122		Microsec2: &ms,
2123		Millisec:  time.Millisecond,
2124		Sec:       time.Second,
2125		Min:       time.Minute,
2126		Hour:      time.Hour,
2127		Mixed: time.Hour +
2128			time.Minute +
2129			time.Second +
2130			time.Millisecond +
2131			time.Microsecond +
2132			time.Nanosecond,
2133		AString: "15s",
2134	}
2135	if !reflect.DeepEqual(result, expected) {
2136		resStr, _ := json.MarshalIndent(result, "", "  ")
2137		expStr, _ := json.MarshalIndent(expected, "", "  ")
2138		t.Errorf("Bad unmarshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expStr, resStr)
2139
2140	}
2141}
2142
2143var testDurationToml2 = []byte(`a_string = "15s"
2144hour = "1h0m0s"
2145microsec1 = "1µs"
2146microsec2 = "1µs"
2147millisec = "1ms"
2148min = "1m0s"
2149mixed = "1h1m1.001001001s"
2150nanosec = "1ns"
2151sec = "1s"
2152`)
2153
2154func TestMarshalDuration(t *testing.T) {
2155	ms := time.Duration(1) * time.Microsecond
2156	data := testDuration{
2157		Nanosec:   1,
2158		Microsec1: time.Microsecond,
2159		Microsec2: &ms,
2160		Millisec:  time.Millisecond,
2161		Sec:       time.Second,
2162		Min:       time.Minute,
2163		Hour:      time.Hour,
2164		Mixed: time.Hour +
2165			time.Minute +
2166			time.Second +
2167			time.Millisecond +
2168			time.Microsecond +
2169			time.Nanosecond,
2170		AString: "15s",
2171	}
2172
2173	var buf bytes.Buffer
2174	err := NewEncoder(&buf).Encode(data)
2175	if err != nil {
2176		t.Fatal(err)
2177	}
2178	expected := testDurationToml2
2179	result := buf.Bytes()
2180	if !bytes.Equal(result, expected) {
2181		t.Errorf("Bad marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expected, result)
2182	}
2183}
2184
2185type testBadDuration struct {
2186	Val time.Duration `toml:"val"`
2187}
2188
2189var testBadDurationToml = []byte(`val = "1z"`)
2190
2191func TestUnmarshalBadDuration(t *testing.T) {
2192	buf := bytes.NewBuffer(testBadDurationToml)
2193
2194	result := testBadDuration{}
2195	err := NewDecoder(buf).Decode(&result)
2196	if err == nil {
2197		t.Fatal()
2198	}
2199	if err.Error() != "(1, 1): Can't convert 1z(string) to time.Duration. time: unknown unit z in duration 1z" {
2200		t.Fatalf("unexpected error: %s", err)
2201	}
2202}
2203
2204var testCamelCaseKeyToml = []byte(`fooBar = 10`)
2205
2206func TestUnmarshalCamelCaseKey(t *testing.T) {
2207	var x struct {
2208		FooBar int
2209		B      int
2210	}
2211
2212	if err := Unmarshal(testCamelCaseKeyToml, &x); err != nil {
2213		t.Fatal(err)
2214	}
2215
2216	if x.FooBar != 10 {
2217		t.Fatal("Did not set camelCase'd key")
2218	}
2219}
2220
2221func TestUnmarshalNegativeUint(t *testing.T) {
2222	type check struct{ U uint }
2223
2224	tree, _ := Load("u = -1")
2225	err := tree.Unmarshal(&check{})
2226	if err.Error() != "(1, 1): -1(int64) is negative so does not fit in uint" {
2227		t.Error("expect err:(1, 1): -1(int64) is negative so does not fit in uint but got:", err)
2228	}
2229}
2230
2231func TestUnmarshalCheckConversionFloatInt(t *testing.T) {
2232	type conversionCheck struct {
2233		U uint
2234		I int
2235		F float64
2236	}
2237
2238	treeU, _ := Load("u = 1e300")
2239	treeI, _ := Load("i = 1e300")
2240	treeF, _ := Load("f = 9223372036854775806")
2241
2242	errU := treeU.Unmarshal(&conversionCheck{})
2243	errI := treeI.Unmarshal(&conversionCheck{})
2244	errF := treeF.Unmarshal(&conversionCheck{})
2245
2246	if errU.Error() != "(1, 1): Can't convert 1e+300(float64) to uint" {
2247		t.Error("expect err:(1, 1): Can't convert 1e+300(float64) to uint but got:", errU)
2248	}
2249	if errI.Error() != "(1, 1): Can't convert 1e+300(float64) to int" {
2250		t.Error("expect err:(1, 1): Can't convert 1e+300(float64) to int but got:", errI)
2251	}
2252	if errF.Error() != "(1, 1): Can't convert 9223372036854775806(int64) to float64" {
2253		t.Error("expect err:(1, 1): Can't convert 9223372036854775806(int64) to float64 but got:", errF)
2254	}
2255}
2256
2257func TestUnmarshalOverflow(t *testing.T) {
2258	type overflow struct {
2259		U8  uint8
2260		I8  int8
2261		F32 float32
2262	}
2263
2264	treeU8, _ := Load("u8 = 300")
2265	treeI8, _ := Load("i8 = 300")
2266	treeF32, _ := Load("f32 = 1e300")
2267
2268	errU8 := treeU8.Unmarshal(&overflow{})
2269	errI8 := treeI8.Unmarshal(&overflow{})
2270	errF32 := treeF32.Unmarshal(&overflow{})
2271
2272	if errU8.Error() != "(1, 1): 300(int64) would overflow uint8" {
2273		t.Error("expect err:(1, 1): 300(int64) would overflow uint8 but got:", errU8)
2274	}
2275	if errI8.Error() != "(1, 1): 300(int64) would overflow int8" {
2276		t.Error("expect err:(1, 1): 300(int64) would overflow int8 but got:", errI8)
2277	}
2278	if errF32.Error() != "(1, 1): 1e+300(float64) would overflow float32" {
2279		t.Error("expect err:(1, 1): 1e+300(float64) would overflow float32 but got:", errF32)
2280	}
2281}
2282
2283func TestUnmarshalDefault(t *testing.T) {
2284	type EmbeddedStruct struct {
2285		StringField string `default:"c"`
2286	}
2287
2288	type aliasUint uint
2289
2290	var doc struct {
2291		StringField       string  `default:"a"`
2292		BoolField         bool    `default:"true"`
2293		UintField         uint    `default:"1"`
2294		Uint8Field        uint8   `default:"8"`
2295		Uint16Field       uint16  `default:"16"`
2296		Uint32Field       uint32  `default:"32"`
2297		Uint64Field       uint64  `default:"64"`
2298		IntField          int     `default:"-1"`
2299		Int8Field         int8    `default:"-8"`
2300		Int16Field        int16   `default:"-16"`
2301		Int32Field        int32   `default:"-32"`
2302		Int64Field        int64   `default:"-64"`
2303		Float32Field      float32 `default:"32.1"`
2304		Float64Field      float64 `default:"64.1"`
2305		NonEmbeddedStruct struct {
2306			StringField string `default:"b"`
2307		}
2308		EmbeddedStruct
2309		AliasUintField aliasUint `default:"1000"`
2310	}
2311
2312	err := Unmarshal([]byte(``), &doc)
2313	if err != nil {
2314		t.Fatal(err)
2315	}
2316	if doc.BoolField != true {
2317		t.Errorf("BoolField should be true, not %t", doc.BoolField)
2318	}
2319	if doc.StringField != "a" {
2320		t.Errorf("StringField should be \"a\", not %s", doc.StringField)
2321	}
2322	if doc.UintField != 1 {
2323		t.Errorf("UintField should be 1, not %d", doc.UintField)
2324	}
2325	if doc.Uint8Field != 8 {
2326		t.Errorf("Uint8Field should be 8, not %d", doc.Uint8Field)
2327	}
2328	if doc.Uint16Field != 16 {
2329		t.Errorf("Uint16Field should be 16, not %d", doc.Uint16Field)
2330	}
2331	if doc.Uint32Field != 32 {
2332		t.Errorf("Uint32Field should be 32, not %d", doc.Uint32Field)
2333	}
2334	if doc.Uint64Field != 64 {
2335		t.Errorf("Uint64Field should be 64, not %d", doc.Uint64Field)
2336	}
2337	if doc.IntField != -1 {
2338		t.Errorf("IntField should be -1, not %d", doc.IntField)
2339	}
2340	if doc.Int8Field != -8 {
2341		t.Errorf("Int8Field should be -8, not %d", doc.Int8Field)
2342	}
2343	if doc.Int16Field != -16 {
2344		t.Errorf("Int16Field should be -16, not %d", doc.Int16Field)
2345	}
2346	if doc.Int32Field != -32 {
2347		t.Errorf("Int32Field should be -32, not %d", doc.Int32Field)
2348	}
2349	if doc.Int64Field != -64 {
2350		t.Errorf("Int64Field should be -64, not %d", doc.Int64Field)
2351	}
2352	if doc.Float32Field != 32.1 {
2353		t.Errorf("Float32Field should be 32.1, not %f", doc.Float32Field)
2354	}
2355	if doc.Float64Field != 64.1 {
2356		t.Errorf("Float64Field should be 64.1, not %f", doc.Float64Field)
2357	}
2358	if doc.NonEmbeddedStruct.StringField != "b" {
2359		t.Errorf("StringField should be \"b\", not %s", doc.NonEmbeddedStruct.StringField)
2360	}
2361	if doc.EmbeddedStruct.StringField != "c" {
2362		t.Errorf("StringField should be \"c\", not %s", doc.EmbeddedStruct.StringField)
2363	}
2364	if doc.AliasUintField != 1000 {
2365		t.Errorf("AliasUintField should be 1000, not %d", doc.AliasUintField)
2366	}
2367}
2368
2369func TestUnmarshalDefaultFailureBool(t *testing.T) {
2370	var doc struct {
2371		Field bool `default:"blah"`
2372	}
2373
2374	err := Unmarshal([]byte(``), &doc)
2375	if err == nil {
2376		t.Fatal("should error")
2377	}
2378}
2379
2380func TestUnmarshalDefaultFailureInt(t *testing.T) {
2381	var doc struct {
2382		Field int `default:"blah"`
2383	}
2384
2385	err := Unmarshal([]byte(``), &doc)
2386	if err == nil {
2387		t.Fatal("should error")
2388	}
2389}
2390
2391func TestUnmarshalDefaultFailureInt64(t *testing.T) {
2392	var doc struct {
2393		Field int64 `default:"blah"`
2394	}
2395
2396	err := Unmarshal([]byte(``), &doc)
2397	if err == nil {
2398		t.Fatal("should error")
2399	}
2400}
2401
2402func TestUnmarshalDefaultFailureFloat64(t *testing.T) {
2403	var doc struct {
2404		Field float64 `default:"blah"`
2405	}
2406
2407	err := Unmarshal([]byte(``), &doc)
2408	if err == nil {
2409		t.Fatal("should error")
2410	}
2411}
2412
2413func TestUnmarshalDefaultFailureUnsupported(t *testing.T) {
2414	var doc struct {
2415		Field struct{} `default:"blah"`
2416	}
2417
2418	err := Unmarshal([]byte(``), &doc)
2419	if err == nil {
2420		t.Fatal("should error")
2421	}
2422}
2423
2424func TestMarshalNestedAnonymousStructs(t *testing.T) {
2425	type Embedded struct {
2426		Value string `toml:"value"`
2427		Top   struct {
2428			Value string `toml:"value"`
2429		} `toml:"top"`
2430	}
2431
2432	type Named struct {
2433		Value string `toml:"value"`
2434	}
2435
2436	var doc struct {
2437		Embedded
2438		Named     `toml:"named"`
2439		Anonymous struct {
2440			Value string `toml:"value"`
2441		} `toml:"anonymous"`
2442	}
2443
2444	expected := `value = ""
2445
2446[anonymous]
2447  value = ""
2448
2449[named]
2450  value = ""
2451
2452[top]
2453  value = ""
2454`
2455
2456	result, err := Marshal(doc)
2457	if err != nil {
2458		t.Fatalf("unexpected error: %s", err.Error())
2459	}
2460	if !bytes.Equal(result, []byte(expected)) {
2461		t.Errorf("Bad marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expected, string(result))
2462	}
2463}
2464
2465func TestEncoderPromoteNestedAnonymousStructs(t *testing.T) {
2466	type Embedded struct {
2467		Value string `toml:"value"`
2468	}
2469
2470	var doc struct {
2471		Embedded
2472	}
2473
2474	expected := `
2475[Embedded]
2476  value = ""
2477`
2478	var buf bytes.Buffer
2479	if err := NewEncoder(&buf).PromoteAnonymous(true).Encode(doc); err != nil {
2480		t.Fatalf("unexpected error: %s", err.Error())
2481	}
2482	if !bytes.Equal(buf.Bytes(), []byte(expected)) {
2483		t.Errorf("Bad marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expected, buf.String())
2484	}
2485}
2486
2487func TestMarshalNestedAnonymousStructs_DuplicateField(t *testing.T) {
2488	type Embedded struct {
2489		Value string `toml:"value"`
2490		Top   struct {
2491			Value string `toml:"value"`
2492		} `toml:"top"`
2493	}
2494
2495	var doc struct {
2496		Value string `toml:"value"`
2497		Embedded
2498	}
2499	doc.Embedded.Value = "shadowed"
2500	doc.Value = "shadows"
2501
2502	expected := `value = "shadows"
2503
2504[top]
2505  value = ""
2506`
2507
2508	result, err := Marshal(doc)
2509	if err != nil {
2510		t.Fatalf("unexpected error: %s", err.Error())
2511	}
2512	if !bytes.Equal(result, []byte(expected)) {
2513		t.Errorf("Bad marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expected, string(result))
2514	}
2515}
2516
2517func TestUnmarshalNestedAnonymousStructs(t *testing.T) {
2518	type Nested struct {
2519		Value string `toml:"nested_field"`
2520	}
2521	type Deep struct {
2522		Nested
2523	}
2524	type Document struct {
2525		Deep
2526		Value string `toml:"own_field"`
2527	}
2528
2529	var doc Document
2530
2531	err := Unmarshal([]byte(`nested_field = "nested value"`+"\n"+`own_field = "own value"`), &doc)
2532	if err != nil {
2533		t.Fatal("should not error")
2534	}
2535	if doc.Value != "own value" || doc.Nested.Value != "nested value" {
2536		t.Fatal("unexpected values")
2537	}
2538}
2539
2540func TestUnmarshalNestedAnonymousStructs_Controversial(t *testing.T) {
2541	type Nested struct {
2542		Value string `toml:"nested"`
2543	}
2544	type Deep struct {
2545		Nested
2546	}
2547	type Document struct {
2548		Deep
2549		Value string `toml:"own"`
2550	}
2551
2552	var doc Document
2553
2554	err := Unmarshal([]byte(`nested = "nested value"`+"\n"+`own = "own value"`), &doc)
2555	if err == nil {
2556		t.Fatal("should error")
2557	}
2558}
2559
2560type unexportedFieldPreservationTest struct {
2561	Exported   string `toml:"exported"`
2562	unexported string
2563	Nested1    unexportedFieldPreservationTestNested    `toml:"nested1"`
2564	Nested2    *unexportedFieldPreservationTestNested   `toml:"nested2"`
2565	Nested3    *unexportedFieldPreservationTestNested   `toml:"nested3"`
2566	Slice1     []unexportedFieldPreservationTestNested  `toml:"slice1"`
2567	Slice2     []*unexportedFieldPreservationTestNested `toml:"slice2"`
2568}
2569
2570type unexportedFieldPreservationTestNested struct {
2571	Exported1   string `toml:"exported1"`
2572	unexported1 string
2573}
2574
2575func TestUnmarshalPreservesUnexportedFields(t *testing.T) {
2576	toml := `
2577	exported = "visible"
2578	unexported = "ignored"
2579
2580	[nested1]
2581	exported1 = "visible1"
2582	unexported1 = "ignored1"
2583
2584	[nested2]
2585	exported1 = "visible2"
2586	unexported1 = "ignored2"
2587
2588	[nested3]
2589	exported1 = "visible3"
2590	unexported1 = "ignored3"
2591
2592	[[slice1]]
2593	exported1 = "visible3"
2594
2595	[[slice1]]
2596	exported1 = "visible4"
2597
2598	[[slice2]]
2599	exported1 = "visible5"
2600	`
2601
2602	t.Run("unexported field should not be set from toml", func(t *testing.T) {
2603		var actual unexportedFieldPreservationTest
2604		err := Unmarshal([]byte(toml), &actual)
2605
2606		if err != nil {
2607			t.Fatal("did not expect an error")
2608		}
2609
2610		expect := unexportedFieldPreservationTest{
2611			Exported:   "visible",
2612			unexported: "",
2613			Nested1:    unexportedFieldPreservationTestNested{"visible1", ""},
2614			Nested2:    &unexportedFieldPreservationTestNested{"visible2", ""},
2615			Nested3:    &unexportedFieldPreservationTestNested{"visible3", ""},
2616			Slice1: []unexportedFieldPreservationTestNested{
2617				{Exported1: "visible3"},
2618				{Exported1: "visible4"},
2619			},
2620			Slice2: []*unexportedFieldPreservationTestNested{
2621				{Exported1: "visible5"},
2622			},
2623		}
2624
2625		if !reflect.DeepEqual(actual, expect) {
2626			t.Fatalf("%+v did not equal %+v", actual, expect)
2627		}
2628	})
2629
2630	t.Run("unexported field should be preserved", func(t *testing.T) {
2631		actual := unexportedFieldPreservationTest{
2632			Exported:   "foo",
2633			unexported: "bar",
2634			Nested1:    unexportedFieldPreservationTestNested{"baz", "bax"},
2635			Nested2:    nil,
2636			Nested3:    &unexportedFieldPreservationTestNested{"baz", "bax"},
2637		}
2638		err := Unmarshal([]byte(toml), &actual)
2639
2640		if err != nil {
2641			t.Fatal("did not expect an error")
2642		}
2643
2644		expect := unexportedFieldPreservationTest{
2645			Exported:   "visible",
2646			unexported: "bar",
2647			Nested1:    unexportedFieldPreservationTestNested{"visible1", "bax"},
2648			Nested2:    &unexportedFieldPreservationTestNested{"visible2", ""},
2649			Nested3:    &unexportedFieldPreservationTestNested{"visible3", "bax"},
2650			Slice1: []unexportedFieldPreservationTestNested{
2651				{Exported1: "visible3"},
2652				{Exported1: "visible4"},
2653			},
2654			Slice2: []*unexportedFieldPreservationTestNested{
2655				{Exported1: "visible5"},
2656			},
2657		}
2658
2659		if !reflect.DeepEqual(actual, expect) {
2660			t.Fatalf("%+v did not equal %+v", actual, expect)
2661		}
2662	})
2663}
2664
2665func TestTreeMarshal(t *testing.T) {
2666	cases := [][]byte{
2667		basicTestToml,
2668		marshalTestToml,
2669		emptyTestToml,
2670		pointerTestToml,
2671	}
2672	for _, expected := range cases {
2673		t.Run("", func(t *testing.T) {
2674			tree, err := LoadBytes(expected)
2675			if err != nil {
2676				t.Fatal(err)
2677			}
2678			result, err := tree.Marshal()
2679			if err != nil {
2680				t.Fatal(err)
2681			}
2682			if !bytes.Equal(result, expected) {
2683				t.Errorf("Bad marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expected, result)
2684			}
2685		})
2686	}
2687}
2688
2689func TestMarshalArrays(t *testing.T) {
2690	cases := []struct {
2691		Data     interface{}
2692		Expected string
2693	}{
2694		{
2695			Data: struct {
2696				XY [2]int
2697			}{
2698				XY: [2]int{1, 2},
2699			},
2700			Expected: `XY = [1, 2]
2701`,
2702		},
2703		{
2704			Data: struct {
2705				XY [1][2]int
2706			}{
2707				XY: [1][2]int{{1, 2}},
2708			},
2709			Expected: `XY = [[1, 2]]
2710`,
2711		},
2712		{
2713			Data: struct {
2714				XY [1][]int
2715			}{
2716				XY: [1][]int{{1, 2}},
2717			},
2718			Expected: `XY = [[1, 2]]
2719`,
2720		},
2721		{
2722			Data: struct {
2723				XY [][2]int
2724			}{
2725				XY: [][2]int{{1, 2}},
2726			},
2727			Expected: `XY = [[1, 2]]
2728`,
2729		},
2730	}
2731	for _, tc := range cases {
2732		t.Run("", func(t *testing.T) {
2733			result, err := Marshal(tc.Data)
2734			if err != nil {
2735				t.Fatal(err)
2736			}
2737			if !bytes.Equal(result, []byte(tc.Expected)) {
2738				t.Errorf("Bad marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", []byte(tc.Expected), result)
2739			}
2740		})
2741	}
2742}
2743
2744func TestUnmarshalLocalDate(t *testing.T) {
2745	t.Run("ToLocalDate", func(t *testing.T) {
2746		type dateStruct struct {
2747			Date LocalDate
2748		}
2749
2750		toml := `date = 1979-05-27`
2751
2752		var obj dateStruct
2753
2754		err := Unmarshal([]byte(toml), &obj)
2755
2756		if err != nil {
2757			t.Fatal(err)
2758		}
2759
2760		if obj.Date.Year != 1979 {
2761			t.Errorf("expected year 1979, got %d", obj.Date.Year)
2762		}
2763		if obj.Date.Month != 5 {
2764			t.Errorf("expected month 5, got %d", obj.Date.Month)
2765		}
2766		if obj.Date.Day != 27 {
2767			t.Errorf("expected day 27, got %d", obj.Date.Day)
2768		}
2769	})
2770
2771	t.Run("ToLocalDate", func(t *testing.T) {
2772		type dateStruct struct {
2773			Date time.Time
2774		}
2775
2776		toml := `date = 1979-05-27`
2777
2778		var obj dateStruct
2779
2780		err := Unmarshal([]byte(toml), &obj)
2781
2782		if err != nil {
2783			t.Fatal(err)
2784		}
2785
2786		if obj.Date.Year() != 1979 {
2787			t.Errorf("expected year 1979, got %d", obj.Date.Year())
2788		}
2789		if obj.Date.Month() != 5 {
2790			t.Errorf("expected month 5, got %d", obj.Date.Month())
2791		}
2792		if obj.Date.Day() != 27 {
2793			t.Errorf("expected day 27, got %d", obj.Date.Day())
2794		}
2795	})
2796}
2797
2798func TestMarshalLocalDate(t *testing.T) {
2799	type dateStruct struct {
2800		Date LocalDate
2801	}
2802
2803	obj := dateStruct{Date: LocalDate{
2804		Year:  1979,
2805		Month: 5,
2806		Day:   27,
2807	}}
2808
2809	b, err := Marshal(obj)
2810
2811	if err != nil {
2812		t.Fatalf("unexpected error: %v", err)
2813	}
2814
2815	got := string(b)
2816	expected := `Date = 1979-05-27
2817`
2818
2819	if got != expected {
2820		t.Errorf("expected '%s', got '%s'", expected, got)
2821	}
2822}
2823
2824func TestUnmarshalLocalDateTime(t *testing.T) {
2825	examples := []struct {
2826		name string
2827		in   string
2828		out  LocalDateTime
2829	}{
2830		{
2831			name: "normal",
2832			in:   "1979-05-27T07:32:00",
2833			out: LocalDateTime{
2834				Date: LocalDate{
2835					Year:  1979,
2836					Month: 5,
2837					Day:   27,
2838				},
2839				Time: LocalTime{
2840					Hour:       7,
2841					Minute:     32,
2842					Second:     0,
2843					Nanosecond: 0,
2844				},
2845			}},
2846		{
2847			name: "with nanoseconds",
2848			in:   "1979-05-27T00:32:00.999999",
2849			out: LocalDateTime{
2850				Date: LocalDate{
2851					Year:  1979,
2852					Month: 5,
2853					Day:   27,
2854				},
2855				Time: LocalTime{
2856					Hour:       0,
2857					Minute:     32,
2858					Second:     0,
2859					Nanosecond: 999999000,
2860				},
2861			},
2862		},
2863	}
2864
2865	for i, example := range examples {
2866		toml := fmt.Sprintf(`date = %s`, example.in)
2867
2868		t.Run(fmt.Sprintf("ToLocalDateTime_%d_%s", i, example.name), func(t *testing.T) {
2869			type dateStruct struct {
2870				Date LocalDateTime
2871			}
2872
2873			var obj dateStruct
2874
2875			err := Unmarshal([]byte(toml), &obj)
2876
2877			if err != nil {
2878				t.Fatal(err)
2879			}
2880
2881			if obj.Date != example.out {
2882				t.Errorf("expected '%s', got '%s'", example.out, obj.Date)
2883			}
2884		})
2885
2886		t.Run(fmt.Sprintf("ToTime_%d_%s", i, example.name), func(t *testing.T) {
2887			type dateStruct struct {
2888				Date time.Time
2889			}
2890
2891			var obj dateStruct
2892
2893			err := Unmarshal([]byte(toml), &obj)
2894
2895			if err != nil {
2896				t.Fatal(err)
2897			}
2898
2899			if obj.Date.Year() != example.out.Date.Year {
2900				t.Errorf("expected year %d, got %d", example.out.Date.Year, obj.Date.Year())
2901			}
2902			if obj.Date.Month() != example.out.Date.Month {
2903				t.Errorf("expected month %d, got %d", example.out.Date.Month, obj.Date.Month())
2904			}
2905			if obj.Date.Day() != example.out.Date.Day {
2906				t.Errorf("expected day %d, got %d", example.out.Date.Day, obj.Date.Day())
2907			}
2908			if obj.Date.Hour() != example.out.Time.Hour {
2909				t.Errorf("expected hour %d, got %d", example.out.Time.Hour, obj.Date.Hour())
2910			}
2911			if obj.Date.Minute() != example.out.Time.Minute {
2912				t.Errorf("expected minute %d, got %d", example.out.Time.Minute, obj.Date.Minute())
2913			}
2914			if obj.Date.Second() != example.out.Time.Second {
2915				t.Errorf("expected second %d, got %d", example.out.Time.Second, obj.Date.Second())
2916			}
2917			if obj.Date.Nanosecond() != example.out.Time.Nanosecond {
2918				t.Errorf("expected nanoseconds %d, got %d", example.out.Time.Nanosecond, obj.Date.Nanosecond())
2919			}
2920		})
2921	}
2922}
2923
2924func TestMarshalLocalDateTime(t *testing.T) {
2925	type dateStruct struct {
2926		DateTime LocalDateTime
2927	}
2928
2929	examples := []struct {
2930		name string
2931		in   LocalDateTime
2932		out  string
2933	}{
2934		{
2935			name: "normal",
2936			out:  "DateTime = 1979-05-27T07:32:00\n",
2937			in: LocalDateTime{
2938				Date: LocalDate{
2939					Year:  1979,
2940					Month: 5,
2941					Day:   27,
2942				},
2943				Time: LocalTime{
2944					Hour:       7,
2945					Minute:     32,
2946					Second:     0,
2947					Nanosecond: 0,
2948				},
2949			}},
2950		{
2951			name: "with nanoseconds",
2952			out:  "DateTime = 1979-05-27T00:32:00.999999000\n",
2953			in: LocalDateTime{
2954				Date: LocalDate{
2955					Year:  1979,
2956					Month: 5,
2957					Day:   27,
2958				},
2959				Time: LocalTime{
2960					Hour:       0,
2961					Minute:     32,
2962					Second:     0,
2963					Nanosecond: 999999000,
2964				},
2965			},
2966		},
2967	}
2968
2969	for i, example := range examples {
2970		t.Run(fmt.Sprintf("%d_%s", i, example.name), func(t *testing.T) {
2971			obj := dateStruct{
2972				DateTime: example.in,
2973			}
2974			b, err := Marshal(obj)
2975
2976			if err != nil {
2977				t.Fatalf("unexpected error: %v", err)
2978			}
2979
2980			got := string(b)
2981
2982			if got != example.out {
2983				t.Errorf("expected '%s', got '%s'", example.out, got)
2984			}
2985		})
2986	}
2987}
2988
2989func TestUnmarshalLocalTime(t *testing.T) {
2990	examples := []struct {
2991		name string
2992		in   string
2993		out  LocalTime
2994	}{
2995		{
2996			name: "normal",
2997			in:   "07:32:00",
2998			out: LocalTime{
2999				Hour:       7,
3000				Minute:     32,
3001				Second:     0,
3002				Nanosecond: 0,
3003			},
3004		},
3005		{
3006			name: "with nanoseconds",
3007			in:   "00:32:00.999999",
3008			out: LocalTime{
3009				Hour:       0,
3010				Minute:     32,
3011				Second:     0,
3012				Nanosecond: 999999000,
3013			},
3014		},
3015	}
3016
3017	for i, example := range examples {
3018		toml := fmt.Sprintf(`Time = %s`, example.in)
3019
3020		t.Run(fmt.Sprintf("ToLocalTime_%d_%s", i, example.name), func(t *testing.T) {
3021			type dateStruct struct {
3022				Time LocalTime
3023			}
3024
3025			var obj dateStruct
3026
3027			err := Unmarshal([]byte(toml), &obj)
3028
3029			if err != nil {
3030				t.Fatal(err)
3031			}
3032
3033			if obj.Time != example.out {
3034				t.Errorf("expected '%s', got '%s'", example.out, obj.Time)
3035			}
3036		})
3037	}
3038}
3039
3040func TestMarshalLocalTime(t *testing.T) {
3041	type timeStruct struct {
3042		Time LocalTime
3043	}
3044
3045	examples := []struct {
3046		name string
3047		in   LocalTime
3048		out  string
3049	}{
3050		{
3051			name: "normal",
3052			out:  "Time = 07:32:00\n",
3053			in: LocalTime{
3054				Hour:       7,
3055				Minute:     32,
3056				Second:     0,
3057				Nanosecond: 0,
3058			}},
3059		{
3060			name: "with nanoseconds",
3061			out:  "Time = 00:32:00.999999000\n",
3062			in: LocalTime{
3063				Hour:       0,
3064				Minute:     32,
3065				Second:     0,
3066				Nanosecond: 999999000,
3067			},
3068		},
3069	}
3070
3071	for i, example := range examples {
3072		t.Run(fmt.Sprintf("%d_%s", i, example.name), func(t *testing.T) {
3073			obj := timeStruct{
3074				Time: example.in,
3075			}
3076			b, err := Marshal(obj)
3077
3078			if err != nil {
3079				t.Fatalf("unexpected error: %v", err)
3080			}
3081
3082			got := string(b)
3083
3084			if got != example.out {
3085				t.Errorf("expected '%s', got '%s'", example.out, got)
3086			}
3087		})
3088	}
3089}
3090
3091// test case for issue #339
3092func TestUnmarshalSameInnerField(t *testing.T) {
3093	type InterStruct2 struct {
3094		Test string
3095		Name string
3096		Age  int
3097	}
3098	type Inter2 struct {
3099		Name         string
3100		Age          int
3101		InterStruct2 InterStruct2
3102	}
3103	type Server struct {
3104		Name   string `toml:"name"`
3105		Inter2 Inter2 `toml:"inter2"`
3106	}
3107
3108	var server Server
3109
3110	if err := Unmarshal([]byte(`name = "123"
3111[inter2]
3112name = "inter2"
3113age = 222`), &server); err == nil {
3114		expected := Server{
3115			Name: "123",
3116			Inter2: Inter2{
3117				Name: "inter2",
3118				Age:  222,
3119			},
3120		}
3121		if !reflect.DeepEqual(server, expected) {
3122			t.Errorf("Bad unmarshal: expected %v, got %v", expected, server)
3123		}
3124	} else {
3125		t.Fatalf("unexpected error: %v", err)
3126	}
3127}
3128
3129func TestMarshalInterface(t *testing.T) {
3130	type InnerStruct struct {
3131		InnerField string
3132	}
3133
3134	type OuterStruct struct {
3135		PrimitiveField        interface{}
3136		ArrayField            interface{}
3137		StructArrayField      interface{}
3138		MapField              map[string]interface{}
3139		StructField           interface{}
3140		PointerField          interface{}
3141		NilField              interface{}
3142		InterfacePointerField *interface{}
3143	}
3144
3145	expected := []byte(`ArrayField = [1, 2, 3]
3146InterfacePointerField = "hello world"
3147PrimitiveField = "string"
3148
3149[MapField]
3150  key1 = "value1"
3151  key2 = false
3152
3153  [MapField.key3]
3154    InnerField = "value3"
3155
3156[PointerField]
3157  InnerField = "yyy"
3158
3159[[StructArrayField]]
3160  InnerField = "s1"
3161
3162[[StructArrayField]]
3163  InnerField = "s2"
3164
3165[StructField]
3166  InnerField = "xxx"
3167`)
3168
3169	var h interface{} = "hello world"
3170	if result, err := Marshal(OuterStruct{
3171		"string",
3172		[]int{1, 2, 3},
3173		[]InnerStruct{{"s1"}, {"s2"}},
3174		map[string]interface{}{
3175			"key1":      "value1",
3176			"key2":      false,
3177			"key3":      InnerStruct{"value3"},
3178			"nil value": nil,
3179		},
3180		InnerStruct{
3181			"xxx",
3182		},
3183		&InnerStruct{
3184			"yyy",
3185		},
3186		nil,
3187		&h,
3188	}); err == nil {
3189		if !bytes.Equal(result, expected) {
3190			t.Errorf("Bad marshal: expected\n----\n%s\n----\ngot\n----\n%s\n----\n", expected, result)
3191		}
3192	} else {
3193		t.Fatal(err)
3194	}
3195}
3196
3197func TestUnmarshalToNilInterface(t *testing.T) {
3198	toml := []byte(`
3199PrimitiveField = "Hello"
3200ArrayField = [1,2,3]
3201InterfacePointerField = "World"
3202
3203[StructField]
3204Field1 = 123
3205Field2 = "Field2"
3206
3207[MapField]
3208MapField1 = [4,5,6]
3209MapField2 = {A = "A"}
3210MapField3 = false
3211
3212[[StructArrayField]]
3213Name = "Allen"
3214Age = 20
3215
3216[[StructArrayField]]
3217Name = "Jack"
3218Age = 23
3219`)
3220
3221	type OuterStruct struct {
3222		PrimitiveField        interface{}
3223		ArrayField            interface{}
3224		StructArrayField      interface{}
3225		MapField              map[string]interface{}
3226		StructField           interface{}
3227		NilField              interface{}
3228		InterfacePointerField *interface{}
3229	}
3230
3231	var s interface{} = "World"
3232	expected := OuterStruct{
3233		PrimitiveField: "Hello",
3234		ArrayField:     []interface{}{int64(1), int64(2), int64(3)},
3235		StructField: map[string]interface{}{
3236			"Field1": int64(123),
3237			"Field2": "Field2",
3238		},
3239		MapField: map[string]interface{}{
3240			"MapField1": []interface{}{int64(4), int64(5), int64(6)},
3241			"MapField2": map[string]interface{}{
3242				"A": "A",
3243			},
3244			"MapField3": false,
3245		},
3246		NilField:              nil,
3247		InterfacePointerField: &s,
3248		StructArrayField: []map[string]interface{}{
3249			{
3250				"Name": "Allen",
3251				"Age":  int64(20),
3252			},
3253			{
3254				"Name": "Jack",
3255				"Age":  int64(23),
3256			},
3257		},
3258	}
3259	actual := OuterStruct{}
3260	if err := Unmarshal(toml, &actual); err == nil {
3261		if !reflect.DeepEqual(actual, expected) {
3262			t.Errorf("Bad unmarshal: expected %v, got %v", expected, actual)
3263		}
3264	} else {
3265		t.Fatal(err)
3266	}
3267}
3268
3269func TestUnmarshalToNonNilInterface(t *testing.T) {
3270	toml := []byte(`
3271PrimitiveField = "Allen"
3272ArrayField = [1,2,3]
3273
3274[StructField]
3275InnerField = "After1"
3276
3277[PointerField]
3278InnerField = "After2"
3279
3280[InterfacePointerField]
3281InnerField = "After"
3282
3283[MapField]
3284MapField1 = [4,5,6]
3285MapField2 = {A = "A"}
3286MapField3 = false
3287
3288[[StructArrayField]]
3289InnerField = "After3"
3290
3291[[StructArrayField]]
3292InnerField = "After4"
3293`)
3294	type InnerStruct struct {
3295		InnerField interface{}
3296	}
3297
3298	type OuterStruct struct {
3299		PrimitiveField        interface{}
3300		ArrayField            interface{}
3301		StructArrayField      interface{}
3302		MapField              map[string]interface{}
3303		StructField           interface{}
3304		PointerField          interface{}
3305		NilField              interface{}
3306		InterfacePointerField *interface{}
3307	}
3308
3309	var s interface{} = InnerStruct{"After"}
3310	expected := OuterStruct{
3311		PrimitiveField: "Allen",
3312		ArrayField:     []int{1, 2, 3},
3313		StructField:    InnerStruct{InnerField: "After1"},
3314		MapField: map[string]interface{}{
3315			"MapField1": []interface{}{int64(4), int64(5), int64(6)},
3316			"MapField2": map[string]interface{}{
3317				"A": "A",
3318			},
3319			"MapField3": false,
3320		},
3321		PointerField:          &InnerStruct{InnerField: "After2"},
3322		NilField:              nil,
3323		InterfacePointerField: &s,
3324		StructArrayField: []InnerStruct{
3325			{InnerField: "After3"},
3326			{InnerField: "After4"},
3327		},
3328	}
3329	actual := OuterStruct{
3330		PrimitiveField: "aaa",
3331		ArrayField:     []int{100, 200, 300, 400},
3332		StructField:    InnerStruct{InnerField: "Before1"},
3333		MapField: map[string]interface{}{
3334			"MapField1": []int{4, 5, 6},
3335			"MapField2": map[string]string{
3336				"B": "BBB",
3337			},
3338			"MapField3": true,
3339		},
3340		PointerField:          &InnerStruct{InnerField: "Before2"},
3341		NilField:              nil,
3342		InterfacePointerField: &s,
3343		StructArrayField: []InnerStruct{
3344			{InnerField: "Before3"},
3345			{InnerField: "Before4"},
3346		},
3347	}
3348	if err := Unmarshal(toml, &actual); err == nil {
3349		if !reflect.DeepEqual(actual, expected) {
3350			t.Errorf("Bad unmarshal: expected %v, got %v", expected, actual)
3351		}
3352	} else {
3353		t.Fatal(err)
3354	}
3355}
3356
3357func TestUnmarshalEmbedTree(t *testing.T) {
3358	toml := []byte(`
3359OuterField1 = "Out"
3360OuterField2 = 1024
3361
3362[TreeField]
3363InnerField1 = "In"
3364InnerField2 = 2048
3365
3366	[TreeField.EmbedStruct]
3367		EmbedField = "Embed"
3368
3369`)
3370	type InnerStruct struct {
3371		InnerField1 string
3372		InnerField2 int
3373		EmbedStruct struct {
3374			EmbedField string
3375		}
3376	}
3377
3378	type OuterStruct struct {
3379		OuterField1 string
3380		OuterField2 int
3381		TreeField   *Tree
3382	}
3383
3384	out := OuterStruct{}
3385	actual := InnerStruct{}
3386	expected := InnerStruct{
3387		"In",
3388		2048,
3389		struct {
3390			EmbedField string
3391		}{
3392			EmbedField: "Embed",
3393		},
3394	}
3395	if err := Unmarshal(toml, &out); err != nil {
3396		t.Fatal(err)
3397	}
3398	if err := out.TreeField.Unmarshal(&actual); err != nil {
3399		t.Fatal(err)
3400	}
3401
3402	if !reflect.DeepEqual(actual, expected) {
3403		t.Errorf("Bad unmarshal: expected %v, got %v", expected, actual)
3404	}
3405}
3406
3407func TestMarshalNil(t *testing.T) {
3408	if _, err := Marshal(nil); err == nil {
3409		t.Errorf("Expected err from nil marshal")
3410	}
3411	if _, err := Marshal((*struct{})(nil)); err == nil {
3412		t.Errorf("Expected err from nil marshal")
3413	}
3414}
3415
3416func TestUnmarshalNil(t *testing.T) {
3417	if err := Unmarshal([]byte(`whatever = "whatever"`), nil); err == nil {
3418		t.Errorf("Expected err from nil marshal")
3419	}
3420	if err := Unmarshal([]byte(`whatever = "whatever"`), (*struct{})(nil)); err == nil {
3421		t.Errorf("Expected err from nil marshal")
3422	}
3423}
3424
3425var sliceTomlDemo = []byte(`str_slice = ["Howdy","Hey There"]
3426str_slice_ptr= ["Howdy","Hey There"]
3427int_slice=[1,2]
3428int_slice_ptr=[1,2]
3429[[struct_slice]]
3430String2="1"
3431[[struct_slice]]
3432String2="2"
3433[[struct_slice_ptr]]
3434String2="1"
3435[[struct_slice_ptr]]
3436String2="2"
3437`)
3438
3439type sliceStruct struct {
3440	Slice          []string                     `  toml:"str_slice"  `
3441	SlicePtr       *[]string                    `  toml:"str_slice_ptr"  `
3442	IntSlice       []int                        `  toml:"int_slice"  `
3443	IntSlicePtr    *[]int                       `  toml:"int_slice_ptr"  `
3444	StructSlice    []basicMarshalTestSubStruct  `  toml:"struct_slice"  `
3445	StructSlicePtr *[]basicMarshalTestSubStruct `  toml:"struct_slice_ptr"  `
3446}
3447
3448type arrayStruct struct {
3449	Slice          [4]string                     `  toml:"str_slice"  `
3450	SlicePtr       *[4]string                    `  toml:"str_slice_ptr"  `
3451	IntSlice       [4]int                        `  toml:"int_slice"  `
3452	IntSlicePtr    *[4]int                       `  toml:"int_slice_ptr"  `
3453	StructSlice    [4]basicMarshalTestSubStruct  `  toml:"struct_slice"  `
3454	StructSlicePtr *[4]basicMarshalTestSubStruct `  toml:"struct_slice_ptr"  `
3455}
3456
3457type arrayTooSmallStruct struct {
3458	Slice       [1]string                    `  toml:"str_slice"  `
3459	StructSlice [1]basicMarshalTestSubStruct `  toml:"struct_slice"  `
3460}
3461
3462func TestUnmarshalSlice(t *testing.T) {
3463	tree, _ := LoadBytes(sliceTomlDemo)
3464	tree, _ = TreeFromMap(tree.ToMap())
3465
3466	var actual sliceStruct
3467	err := tree.Unmarshal(&actual)
3468	if err != nil {
3469		t.Error("shound not err", err)
3470	}
3471	expected := sliceStruct{
3472		Slice:          []string{"Howdy", "Hey There"},
3473		SlicePtr:       &[]string{"Howdy", "Hey There"},
3474		IntSlice:       []int{1, 2},
3475		IntSlicePtr:    &[]int{1, 2},
3476		StructSlice:    []basicMarshalTestSubStruct{{"1"}, {"2"}},
3477		StructSlicePtr: &[]basicMarshalTestSubStruct{{"1"}, {"2"}},
3478	}
3479	if !reflect.DeepEqual(actual, expected) {
3480		t.Errorf("Bad unmarshal: expected %v, got %v", expected, actual)
3481	}
3482
3483}
3484
3485func TestUnmarshalSliceFail(t *testing.T) {
3486	tree, _ := TreeFromMap(map[string]interface{}{
3487		"str_slice": []int{1, 2},
3488	})
3489
3490	var actual sliceStruct
3491	err := tree.Unmarshal(&actual)
3492	if err.Error() != "(0, 0): Can't convert 1(int64) to string" {
3493		t.Error("expect err:(0, 0): Can't convert 1(int64) to string but got ", err)
3494	}
3495}
3496
3497func TestUnmarshalSliceFail2(t *testing.T) {
3498	tree, _ := Load(`str_slice=[1,2]`)
3499
3500	var actual sliceStruct
3501	err := tree.Unmarshal(&actual)
3502	if err.Error() != "(1, 1): Can't convert 1(int64) to string" {
3503		t.Error("expect err:(1, 1): Can't convert 1(int64) to string but got ", err)
3504	}
3505
3506}
3507
3508func TestMarshalMixedTypeArray(t *testing.T) {
3509	type InnerStruct struct {
3510		IntField int
3511		StrField string
3512	}
3513
3514	type TestStruct struct {
3515		ArrayField []interface{}
3516	}
3517
3518	expected := []byte(`ArrayField = [3.14, 100, true, "hello world", { IntField = 100, StrField = "inner1" }, [{ IntField = 200, StrField = "inner2" }, { IntField = 300, StrField = "inner3" }]]
3519`)
3520
3521	if result, err := Marshal(TestStruct{
3522		ArrayField: []interface{}{
3523			3.14,
3524			100,
3525			true,
3526			"hello world",
3527			InnerStruct{
3528				IntField: 100,
3529				StrField: "inner1",
3530			},
3531			[]InnerStruct{
3532				{IntField: 200, StrField: "inner2"},
3533				{IntField: 300, StrField: "inner3"},
3534			},
3535		},
3536	}); err == nil {
3537		if !bytes.Equal(result, expected) {
3538			t.Errorf("Bad marshal: expected\n----\n%s\n----\ngot\n----\n%s\n----\n", expected, result)
3539		}
3540	} else {
3541		t.Fatal(err)
3542	}
3543}
3544
3545func TestUnmarshalMixedTypeArray(t *testing.T) {
3546	type TestStruct struct {
3547		ArrayField []interface{}
3548	}
3549
3550	toml := []byte(`ArrayField = [3.14,100,true,"hello world",{Field = "inner1"},[{Field = "inner2"},{Field = "inner3"}]]
3551`)
3552
3553	actual := TestStruct{}
3554	expected := TestStruct{
3555		ArrayField: []interface{}{
3556			3.14,
3557			int64(100),
3558			true,
3559			"hello world",
3560			map[string]interface{}{
3561				"Field": "inner1",
3562			},
3563			[]map[string]interface{}{
3564				{"Field": "inner2"},
3565				{"Field": "inner3"},
3566			},
3567		},
3568	}
3569
3570	if err := Unmarshal(toml, &actual); err == nil {
3571		if !reflect.DeepEqual(actual, expected) {
3572			t.Errorf("Bad unmarshal: expected %#v, got %#v", expected, actual)
3573		}
3574	} else {
3575		t.Fatal(err)
3576	}
3577}
3578
3579func TestUnmarshalArray(t *testing.T) {
3580	var tree *Tree
3581	var err error
3582
3583	tree, _ = LoadBytes(sliceTomlDemo)
3584	var actual1 arrayStruct
3585	err = tree.Unmarshal(&actual1)
3586	if err != nil {
3587		t.Error("shound not err", err)
3588	}
3589
3590	tree, _ = TreeFromMap(tree.ToMap())
3591	var actual2 arrayStruct
3592	err = tree.Unmarshal(&actual2)
3593	if err != nil {
3594		t.Error("shound not err", err)
3595	}
3596
3597	expected := arrayStruct{
3598		Slice:          [4]string{"Howdy", "Hey There"},
3599		SlicePtr:       &[4]string{"Howdy", "Hey There"},
3600		IntSlice:       [4]int{1, 2},
3601		IntSlicePtr:    &[4]int{1, 2},
3602		StructSlice:    [4]basicMarshalTestSubStruct{{"1"}, {"2"}},
3603		StructSlicePtr: &[4]basicMarshalTestSubStruct{{"1"}, {"2"}},
3604	}
3605	if !reflect.DeepEqual(actual1, expected) {
3606		t.Errorf("Bad unmarshal: expected %v, got %v", expected, actual1)
3607	}
3608	if !reflect.DeepEqual(actual2, expected) {
3609		t.Errorf("Bad unmarshal: expected %v, got %v", expected, actual2)
3610	}
3611}
3612
3613func TestUnmarshalArrayFail(t *testing.T) {
3614	tree, _ := TreeFromMap(map[string]interface{}{
3615		"str_slice": []string{"Howdy", "Hey There"},
3616	})
3617
3618	var actual arrayTooSmallStruct
3619	err := tree.Unmarshal(&actual)
3620	if err.Error() != "(0, 0): unmarshal: TOML array length (2) exceeds destination array length (1)" {
3621		t.Error("expect err:(0, 0): unmarshal: TOML array length (2) exceeds destination array length (1) but got ", err)
3622	}
3623}
3624
3625func TestUnmarshalArrayFail2(t *testing.T) {
3626	tree, _ := Load(`str_slice=["Howdy","Hey There"]`)
3627
3628	var actual arrayTooSmallStruct
3629	err := tree.Unmarshal(&actual)
3630	if err.Error() != "(1, 1): unmarshal: TOML array length (2) exceeds destination array length (1)" {
3631		t.Error("expect err:(1, 1): unmarshal: TOML array length (2) exceeds destination array length (1) but got ", err)
3632	}
3633}
3634
3635func TestUnmarshalArrayFail3(t *testing.T) {
3636	tree, _ := Load(`[[struct_slice]]
3637String2="1"
3638[[struct_slice]]
3639String2="2"`)
3640
3641	var actual arrayTooSmallStruct
3642	err := tree.Unmarshal(&actual)
3643	if err.Error() != "(3, 1): unmarshal: TOML array length (2) exceeds destination array length (1)" {
3644		t.Error("expect err:(3, 1): unmarshal: TOML array length (2) exceeds destination array length (1) but got ", err)
3645	}
3646}
3647
3648func TestDecoderStrict(t *testing.T) {
3649	input := `
3650[decoded]
3651  key = ""
3652
3653[undecoded]
3654  key = ""
3655
3656  [undecoded.inner]
3657	key = ""
3658
3659  [[undecoded.array]]
3660	key = ""
3661
3662  [[undecoded.array]]
3663	key = ""
3664
3665`
3666	var doc struct {
3667		Decoded struct {
3668			Key string
3669		}
3670	}
3671
3672	expected := `undecoded keys: ["undecoded.array.0.key" "undecoded.array.1.key" "undecoded.inner.key" "undecoded.key"]`
3673
3674	err := NewDecoder(bytes.NewReader([]byte(input))).Strict(true).Decode(&doc)
3675	if err == nil {
3676		t.Error("expected error, got none")
3677	} else if err.Error() != expected {
3678		t.Errorf("expect err: %s, got: %s", expected, err.Error())
3679	}
3680
3681	if err := NewDecoder(bytes.NewReader([]byte(input))).Decode(&doc); err != nil {
3682		t.Errorf("unexpected err: %s", err)
3683	}
3684
3685	var m map[string]interface{}
3686	if err := NewDecoder(bytes.NewReader([]byte(input))).Decode(&m); err != nil {
3687		t.Errorf("unexpected err: %s", err)
3688	}
3689}
3690
3691func TestDecoderStrictValid(t *testing.T) {
3692	input := `
3693[decoded]
3694  key = ""
3695`
3696	var doc struct {
3697		Decoded struct {
3698			Key string
3699		}
3700	}
3701
3702	err := NewDecoder(bytes.NewReader([]byte(input))).Strict(true).Decode(&doc)
3703	if err != nil {
3704		t.Fatal("unexpected error:", err)
3705	}
3706}
3707
3708type docUnmarshalTOML struct {
3709	Decoded struct {
3710		Key string
3711	}
3712}
3713
3714func (d *docUnmarshalTOML) UnmarshalTOML(i interface{}) error {
3715	if iMap, ok := i.(map[string]interface{}); !ok {
3716		return fmt.Errorf("type assertion error: wants %T, have %T", map[string]interface{}{}, i)
3717	} else if key, ok := iMap["key"]; !ok {
3718		return fmt.Errorf("key '%s' not in map", "key")
3719	} else if keyString, ok := key.(string); !ok {
3720		return fmt.Errorf("type assertion error: wants %T, have %T", "", key)
3721	} else {
3722		d.Decoded.Key = keyString
3723	}
3724	return nil
3725}
3726
3727func TestDecoderStrictCustomUnmarshal(t *testing.T) {
3728	input := `key = "ok"`
3729	var doc docUnmarshalTOML
3730	err := NewDecoder(bytes.NewReader([]byte(input))).Strict(true).Decode(&doc)
3731	if err != nil {
3732		t.Fatal("unexpected error:", err)
3733	}
3734	if doc.Decoded.Key != "ok" {
3735		t.Errorf("Bad unmarshal: expected ok, got %v", doc.Decoded.Key)
3736	}
3737}
3738
3739type parent struct {
3740	Doc        docUnmarshalTOML
3741	DocPointer *docUnmarshalTOML
3742}
3743
3744func TestCustomUnmarshal(t *testing.T) {
3745	input := `
3746[Doc]
3747    key = "ok1"
3748[DocPointer]
3749    key = "ok2"
3750`
3751
3752	var d parent
3753	if err := Unmarshal([]byte(input), &d); err != nil {
3754		t.Fatalf("unexpected err: %s", err.Error())
3755	}
3756	if d.Doc.Decoded.Key != "ok1" {
3757		t.Errorf("Bad unmarshal: expected ok, got %v", d.Doc.Decoded.Key)
3758	}
3759	if d.DocPointer.Decoded.Key != "ok2" {
3760		t.Errorf("Bad unmarshal: expected ok, got %v", d.DocPointer.Decoded.Key)
3761	}
3762}
3763
3764func TestCustomUnmarshalError(t *testing.T) {
3765	input := `
3766[Doc]
3767    key = 1
3768[DocPointer]
3769    key = "ok2"
3770`
3771
3772	expected := "(2, 1): unmarshal toml: type assertion error: wants string, have int64"
3773
3774	var d parent
3775	err := Unmarshal([]byte(input), &d)
3776	if err == nil {
3777		t.Error("expected error, got none")
3778	} else if err.Error() != expected {
3779		t.Errorf("expect err: %s, got: %s", expected, err.Error())
3780	}
3781}
3782
3783type intWrapper struct {
3784	Value int
3785}
3786
3787func (w *intWrapper) UnmarshalText(text []byte) error {
3788	var err error
3789	if w.Value, err = strconv.Atoi(string(text)); err == nil {
3790		return nil
3791	}
3792	if b, err := strconv.ParseBool(string(text)); err == nil {
3793		if b {
3794			w.Value = 1
3795		}
3796		return nil
3797	}
3798	if f, err := strconv.ParseFloat(string(text), 32); err == nil {
3799		w.Value = int(f)
3800		return nil
3801	}
3802	return fmt.Errorf("unsupported: %s", text)
3803}
3804
3805func TestTextUnmarshal(t *testing.T) {
3806	var doc struct {
3807		UnixTime intWrapper
3808		Version  *intWrapper
3809
3810		Bool  intWrapper
3811		Int   intWrapper
3812		Float intWrapper
3813	}
3814
3815	input := `
3816UnixTime = "12"
3817Version = "42"
3818Bool = true
3819Int = 21
3820Float = 2.0
3821`
3822
3823	if err := Unmarshal([]byte(input), &doc); err != nil {
3824		t.Fatalf("unexpected err: %s", err.Error())
3825	}
3826	if doc.UnixTime.Value != 12 {
3827		t.Fatalf("expected UnixTime: 12 got: %d", doc.UnixTime.Value)
3828	}
3829	if doc.Version.Value != 42 {
3830		t.Fatalf("expected Version: 42 got: %d", doc.Version.Value)
3831	}
3832	if doc.Bool.Value != 1 {
3833		t.Fatalf("expected Bool: 1 got: %d", doc.Bool.Value)
3834	}
3835	if doc.Int.Value != 21 {
3836		t.Fatalf("expected Int: 21 got: %d", doc.Int.Value)
3837	}
3838	if doc.Float.Value != 2 {
3839		t.Fatalf("expected Float: 2 got: %d", doc.Float.Value)
3840	}
3841}
3842
3843func TestTextUnmarshalError(t *testing.T) {
3844	var doc struct {
3845		Failer intWrapper
3846	}
3847
3848	input := `Failer = "hello"`
3849	if err := Unmarshal([]byte(input), &doc); err == nil {
3850		t.Fatalf("expected err, got none")
3851	}
3852}
3853
3854// issue406
3855func TestPreserveNotEmptyField(t *testing.T) {
3856	toml := []byte(`Field1 = "ccc"`)
3857	type Inner struct {
3858		InnerField1 string
3859		InnerField2 int
3860	}
3861	type TestStruct struct {
3862		Field1 string
3863		Field2 int
3864		Field3 Inner
3865	}
3866
3867	actual := TestStruct{
3868		"aaa",
3869		100,
3870		Inner{
3871			"bbb",
3872			200,
3873		},
3874	}
3875
3876	expected := TestStruct{
3877		"ccc",
3878		100,
3879		Inner{
3880			"bbb",
3881			200,
3882		},
3883	}
3884
3885	err := Unmarshal(toml, &actual)
3886	if err != nil {
3887		t.Fatal(err)
3888	}
3889
3890	if !reflect.DeepEqual(actual, expected) {
3891		t.Errorf("Bad unmarshal: expected %+v, got %+v", expected, actual)
3892	}
3893}
3894