1package imported_tests
2
3// Those tests were imported directly from go-toml v1
4// https://raw.githubusercontent.com/pelletier/go-toml/a2e52561804c6cd9392ebf0048ca64fe4af67a43/marshal_test.go
5// They have been cleaned up to only include Unmarshal tests, and only depend
6// on the public API. Tests related to strict mode have been commented out and
7// marked as skipped until we figure out if that's something we want in v2.
8
9import (
10	"bytes"
11	"errors"
12	"fmt"
13	"reflect"
14	"strconv"
15	"testing"
16	"time"
17
18	"github.com/pelletier/go-toml/v2"
19	"github.com/stretchr/testify/assert"
20	"github.com/stretchr/testify/require"
21)
22
23type basicMarshalTestStruct struct {
24	String     string   `toml:"Zstring"`
25	StringList []string `toml:"Ystrlist"`
26	BasicMarshalTestSubAnonymousStruct
27	Sub     basicMarshalTestSubStruct   `toml:"Xsubdoc"`
28	SubList []basicMarshalTestSubStruct `toml:"Wsublist"`
29}
30
31type basicMarshalTestSubStruct struct {
32	String2 string
33}
34
35type BasicMarshalTestSubAnonymousStruct struct {
36	String3 string
37}
38
39var basicTestData = basicMarshalTestStruct{
40	String:                             "Hello",
41	StringList:                         []string{"Howdy", "Hey There"},
42	BasicMarshalTestSubAnonymousStruct: BasicMarshalTestSubAnonymousStruct{"One"},
43	Sub:                                basicMarshalTestSubStruct{"Two"},
44	SubList:                            []basicMarshalTestSubStruct{{"Three"}, {"Four"}},
45}
46
47var basicTestToml = []byte(`String3 = "One"
48Ystrlist = ["Howdy", "Hey There"]
49Zstring = "Hello"
50
51[[Wsublist]]
52  String2 = "Three"
53
54[[Wsublist]]
55  String2 = "Four"
56
57[Xsubdoc]
58  String2 = "Two"
59`)
60
61var marshalTestToml = []byte(`title = "TOML Marshal Testing"
62
63[basic]
64  bool = true
65  date = 1979-05-27T07:32:00Z
66  float = 123.4
67  float64 = 123.456782132399
68  int = 5000
69  string = "Bite me"
70  uint = 5001
71
72[basic_lists]
73  bools = [true, false, true]
74  dates = [1979-05-27T07:32:00Z, 1980-05-27T07:32:00Z]
75  floats = [12.3, 45.6, 78.9]
76  ints = [8001, 8001, 8002]
77  strings = ["One", "Two", "Three"]
78  uints = [5002, 5003]
79
80[basic_map]
81  one = "one"
82  two = "two"
83
84[subdoc]
85
86  [subdoc.first]
87    name = "First"
88
89  [subdoc.second]
90    name = "Second"
91
92[[subdoclist]]
93  name = "List.First"
94
95[[subdoclist]]
96  name = "List.Second"
97
98[[subdocptrs]]
99  name = "Second"
100`)
101
102type Conf struct {
103	Name  string
104	Age   int
105	Inter interface{}
106}
107
108type NestedStruct struct {
109	FirstName string
110	LastName  string
111	Age       int
112}
113
114var doc = []byte(`Name = "rui"
115Age = 18
116
117[Inter]
118  FirstName = "wang"
119  LastName = "jl"
120  Age = 100`)
121
122func TestInterface(t *testing.T) {
123	var config Conf
124	config.Inter = &NestedStruct{}
125	err := toml.Unmarshal(doc, &config)
126	require.NoError(t, err)
127	expected := Conf{
128		Name: "rui",
129		Age:  18,
130		Inter: map[string]interface{}{
131			"FirstName": "wang",
132			"LastName":  "jl",
133			"Age":       int64(100),
134		},
135	}
136	assert.Equal(t, expected, config)
137}
138
139func TestBasicUnmarshal(t *testing.T) {
140	result := basicMarshalTestStruct{}
141	err := toml.Unmarshal(basicTestToml, &result)
142	require.NoError(t, err)
143	require.Equal(t, basicTestData, result)
144}
145
146type quotedKeyMarshalTestStruct struct {
147	String  string                      `toml:"Z.string-àéù"`
148	Float   float64                     `toml:"Yfloat-��"`
149	Sub     basicMarshalTestSubStruct   `toml:"Xsubdoc-àéù"`
150	SubList []basicMarshalTestSubStruct `toml:"W.sublist-��"`
151}
152
153// TODO: Remove nolint once var is used by a test
154//nolint:deadcode,unused,varcheck
155var quotedKeyMarshalTestData = quotedKeyMarshalTestStruct{
156	String:  "Hello",
157	Float:   3.5,
158	Sub:     basicMarshalTestSubStruct{"One"},
159	SubList: []basicMarshalTestSubStruct{{"Two"}, {"Three"}},
160}
161
162// TODO: Remove nolint once var is used by a test
163//nolint:deadcode,unused,varcheck
164var quotedKeyMarshalTestToml = []byte(`"Yfloat-��" = 3.5
165"Z.string-àéù" = "Hello"
166
167[["W.sublist-��"]]
168  String2 = "Two"
169
170[["W.sublist-��"]]
171  String2 = "Three"
172
173["Xsubdoc-àéù"]
174  String2 = "One"
175`)
176
177type testDoc struct {
178	Title       string            `toml:"title"`
179	BasicLists  testDocBasicLists `toml:"basic_lists"`
180	SubDocPtrs  []*testSubDoc     `toml:"subdocptrs"`
181	BasicMap    map[string]string `toml:"basic_map"`
182	Subdocs     testDocSubs       `toml:"subdoc"`
183	Basics      testDocBasics     `toml:"basic"`
184	SubDocList  []testSubDoc      `toml:"subdoclist"`
185	err         int               `toml:"shouldntBeHere"` // nolint:structcheck,unused
186	unexported  int               `toml:"shouldntBeHere"`
187	Unexported2 int               `toml:"-"`
188}
189
190type testMapDoc struct {
191	Title    string            `toml:"title"`
192	BasicMap map[string]string `toml:"basic_map"`
193	LongMap  map[string]string `toml:"long_map"`
194}
195
196type testDocBasics struct {
197	Uint       uint      `toml:"uint"`
198	Bool       bool      `toml:"bool"`
199	Float32    float32   `toml:"float"`
200	Float64    float64   `toml:"float64"`
201	Int        int       `toml:"int"`
202	String     *string   `toml:"string"`
203	Date       time.Time `toml:"date"`
204	unexported int       `toml:"shouldntBeHere"`
205}
206
207type testDocBasicLists struct {
208	Floats  []*float32  `toml:"floats"`
209	Bools   []bool      `toml:"bools"`
210	Dates   []time.Time `toml:"dates"`
211	Ints    []int       `toml:"ints"`
212	UInts   []uint      `toml:"uints"`
213	Strings []string    `toml:"strings"`
214}
215
216type testDocSubs struct {
217	Second *testSubDoc `toml:"second"`
218	First  testSubDoc  `toml:"first"`
219}
220
221type testSubDoc struct {
222	Name       string `toml:"name"`
223	unexported int    `toml:"shouldntBeHere"`
224}
225
226var (
227	biteMe         = "Bite me"
228	float1 float32 = 12.3
229	float2 float32 = 45.6
230	float3 float32 = 78.9
231	subdoc         = testSubDoc{"Second", 0}
232)
233
234var docData = testDoc{
235	Title:       "TOML Marshal Testing",
236	unexported:  0,
237	Unexported2: 0,
238	Basics: testDocBasics{
239		Bool:       true,
240		Date:       time.Date(1979, 5, 27, 7, 32, 0, 0, time.UTC),
241		Float32:    123.4,
242		Float64:    123.456782132399,
243		Int:        5000,
244		Uint:       5001,
245		String:     &biteMe,
246		unexported: 0,
247	},
248	BasicLists: testDocBasicLists{
249		Bools: []bool{true, false, true},
250		Dates: []time.Time{
251			time.Date(1979, 5, 27, 7, 32, 0, 0, time.UTC),
252			time.Date(1980, 5, 27, 7, 32, 0, 0, time.UTC),
253		},
254		Floats:  []*float32{&float1, &float2, &float3},
255		Ints:    []int{8001, 8001, 8002},
256		Strings: []string{"One", "Two", "Three"},
257		UInts:   []uint{5002, 5003},
258	},
259	BasicMap: map[string]string{
260		"one": "one",
261		"two": "two",
262	},
263	Subdocs: testDocSubs{
264		First:  testSubDoc{"First", 0},
265		Second: &subdoc,
266	},
267	SubDocList: []testSubDoc{
268		{"List.First", 0},
269		{"List.Second", 0},
270	},
271	SubDocPtrs: []*testSubDoc{&subdoc},
272}
273
274// TODO: Remove nolint once var is used by a test
275//nolint:deadcode,unused,varcheck
276var mapTestDoc = testMapDoc{
277	Title: "TOML Marshal Testing",
278	BasicMap: map[string]string{
279		"one": "one",
280		"two": "two",
281	},
282	LongMap: map[string]string{
283		"h1":  "8",
284		"i2":  "9",
285		"b3":  "2",
286		"d4":  "4",
287		"f5":  "6",
288		"e6":  "5",
289		"a7":  "1",
290		"c8":  "3",
291		"j9":  "10",
292		"g10": "7",
293	},
294}
295
296func TestDocUnmarshal(t *testing.T) {
297	result := testDoc{}
298	err := toml.Unmarshal(marshalTestToml, &result)
299	expected := docData
300	require.NoError(t, err)
301	assert.Equal(t, expected, result)
302}
303
304type unexportedMarshalTestStruct struct {
305	String      string                      `toml:"string"`
306	StringList  []string                    `toml:"strlist"`
307	Sub         basicMarshalTestSubStruct   `toml:"subdoc"`
308	SubList     []basicMarshalTestSubStruct `toml:"sublist"`
309	unexported  int                         `toml:"shouldntBeHere"`
310	Unexported2 int                         `toml:"-"`
311}
312
313var unexportedTestData = unexportedMarshalTestStruct{
314	String:      "Hello",
315	StringList:  []string{"Howdy", "Hey There"},
316	Sub:         basicMarshalTestSubStruct{"One"},
317	SubList:     []basicMarshalTestSubStruct{{"Two"}, {"Three"}},
318	unexported:  0,
319	Unexported2: 0,
320}
321
322var unexportedTestToml = []byte(`string = "Hello"
323strlist = ["Howdy","Hey There"]
324unexported = 1
325shouldntBeHere = 2
326
327[subdoc]
328  String2 = "One"
329
330[[sublist]]
331  String2 = "Two"
332
333[[sublist]]
334  String2 = "Three"
335`)
336
337func TestUnexportedUnmarshal(t *testing.T) {
338	result := unexportedMarshalTestStruct{}
339	err := toml.Unmarshal(unexportedTestToml, &result)
340	require.NoError(t, err)
341	assert.Equal(t, unexportedTestData, result)
342}
343
344type errStruct struct {
345	Bool   bool      `toml:"bool"`
346	Date   time.Time `toml:"date"`
347	Float  float64   `toml:"float"`
348	Int    int16     `toml:"int"`
349	String *string   `toml:"string"`
350}
351
352type mapErr struct {
353	Vals map[string]float64
354}
355
356type intErr struct {
357	Int1  int
358	Int2  int8
359	Int3  int16
360	Int4  int32
361	Int5  int64
362	UInt1 uint
363	UInt2 uint8
364	UInt3 uint16
365	UInt4 uint32
366	UInt5 uint64
367	Flt1  float32
368	Flt2  float64
369}
370
371var intErrTomls = []string{
372	"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",
373	"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",
374	"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",
375	"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",
376	"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",
377	"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",
378	"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",
379	"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",
380	"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",
381	"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",
382	"Int1 = 1\nInt2 = 2\nInt3 = 3\nInt4 = 4\nInt5 = 5\nUInt1 = 1\nUInt2 = 2\nUInt3 = 3\nUInt4 = 4\nUInt5 = 5\nFlt1 = []\nFlt2 = 2.0",
383	"Int1 = 1\nInt2 = 2\nInt3 = 3\nInt4 = 4\nInt5 = 5\nUInt1 = 1\nUInt2 = 2\nUInt3 = 3\nUInt4 = 4\nUInt5 = 5\nFlt1 = 1.0\nFlt2 = []",
384}
385
386func TestErrUnmarshal(t *testing.T) {
387	errTomls := []string{
388		"bool = truly\ndate = 1979-05-27T07:32:00Z\nfloat = 123.4\nint = 5000\nstring = \"Bite me\"",
389		"bool = true\ndate = 1979-05-27T07:3200Z\nfloat = 123.4\nint = 5000\nstring = \"Bite me\"",
390		"bool = true\ndate = 1979-05-27T07:32:00Z\nfloat = 123a4\nint = 5000\nstring = \"Bite me\"",
391		"bool = true\ndate = 1979-05-27T07:32:00Z\nfloat = 123.4\nint = j000\nstring = \"Bite me\"",
392		"bool = true\ndate = 1979-05-27T07:32:00Z\nfloat = 123.4\nint = 5000\nstring = Bite me",
393		"bool = true\ndate = 1979-05-27T07:32:00Z\nfloat = 123.4\nint = 5000\nstring = Bite me",
394		"bool = 1\ndate = 1979-05-27T07:32:00Z\nfloat = 123.4\nint = 5000\nstring = \"Bite me\"",
395		"bool = true\ndate = 1\nfloat = 123.4\nint = 5000\nstring = \"Bite me\"",
396		"bool = true\ndate = 1979-05-27T07:32:00Z\n\"sorry\"\nint = 5000\nstring = \"Bite me\"",
397		"bool = true\ndate = 1979-05-27T07:32:00Z\nfloat = 123.4\nint = \"sorry\"\nstring = \"Bite me\"",
398		"bool = true\ndate = 1979-05-27T07:32:00Z\nfloat = 123.4\nint = 5000\nstring = 1",
399	}
400
401	for ind, x := range errTomls {
402		t.Run(fmt.Sprintf("Base Case %d", ind), func(t *testing.T) {
403			result := errStruct{}
404			err := toml.Unmarshal([]byte(x), &result)
405			if err == nil {
406				t.Errorf("Expected err from case %d\n", ind)
407			}
408		})
409	}
410	result2 := mapErr{}
411	err := toml.Unmarshal([]byte("[Vals]\nfred=\"1.2\""), &result2)
412	if err == nil {
413		t.Errorf("Expected err from map")
414	}
415	for ind, x := range intErrTomls {
416		result3 := intErr{}
417		err := toml.Unmarshal([]byte(x), &result3)
418		if err == nil {
419			t.Errorf("Expected int err from case %d\n", ind)
420		}
421	}
422}
423
424var emptyTestToml = []byte(`bool = false
425int = 0
426string = ""
427stringlist = []
428title = "Placeholder"
429
430[map]
431`)
432
433func TestEmptytomlUnmarshal(t *testing.T) {
434	type emptyMarshalTestStruct struct {
435		Title      string                  `toml:"title"`
436		Bool       bool                    `toml:"bool"`
437		Int        int                     `toml:"int"`
438		String     string                  `toml:"string"`
439		StringList []string                `toml:"stringlist"`
440		Ptr        *basicMarshalTestStruct `toml:"ptr"`
441		Map        map[string]string       `toml:"map"`
442	}
443
444	emptyTestData := emptyMarshalTestStruct{
445		Title:      "Placeholder",
446		Bool:       false,
447		Int:        0,
448		String:     "",
449		StringList: []string{},
450		Ptr:        nil,
451		Map:        nil,
452	}
453
454	result := emptyMarshalTestStruct{}
455	err := toml.Unmarshal(emptyTestToml, &result)
456	require.NoError(t, err)
457	assert.Equal(t, emptyTestData, result)
458}
459
460func TestEmptyUnmarshalOmit(t *testing.T) {
461	t.Skipf("Have not figured yet if omitempty is a good idea")
462
463	type emptyMarshalTestStruct2 struct {
464		Title      string                  `toml:"title"`
465		Bool       bool                    `toml:"bool,omitempty"`
466		Int        int                     `toml:"int, omitempty"`
467		String     string                  `toml:"string,omitempty "`
468		StringList []string                `toml:"stringlist,omitempty"`
469		Ptr        *basicMarshalTestStruct `toml:"ptr,omitempty"`
470		Map        map[string]string       `toml:"map,omitempty"`
471	}
472
473	emptyTestData2 := emptyMarshalTestStruct2{
474		Title:      "Placeholder",
475		Bool:       false,
476		Int:        0,
477		String:     "",
478		StringList: []string{},
479		Ptr:        nil,
480		Map:        map[string]string{},
481	}
482
483	result := emptyMarshalTestStruct2{}
484	err := toml.Unmarshal(emptyTestToml, &result)
485	require.NoError(t, err)
486	assert.Equal(t, emptyTestData2, result)
487}
488
489type pointerMarshalTestStruct struct {
490	Str       *string
491	List      *[]string
492	ListPtr   *[]*string
493	Map       *map[string]string
494	MapPtr    *map[string]*string
495	EmptyStr  *string
496	EmptyList *[]string
497	EmptyMap  *map[string]string
498	DblPtr    *[]*[]*string
499}
500
501var (
502	pointerStr      = "Hello"
503	pointerList     = []string{"Hello back"}
504	pointerListPtr  = []*string{&pointerStr}
505	pointerMap      = map[string]string{"response": "Goodbye"}
506	pointerMapPtr   = map[string]*string{"alternate": &pointerStr}
507	pointerTestData = pointerMarshalTestStruct{
508		Str:       &pointerStr,
509		List:      &pointerList,
510		ListPtr:   &pointerListPtr,
511		Map:       &pointerMap,
512		MapPtr:    &pointerMapPtr,
513		EmptyStr:  nil,
514		EmptyList: nil,
515		EmptyMap:  nil,
516	}
517)
518
519var pointerTestToml = []byte(`List = ["Hello back"]
520ListPtr = ["Hello"]
521Str = "Hello"
522
523[Map]
524  response = "Goodbye"
525
526[MapPtr]
527  alternate = "Hello"
528`)
529
530func TestPointerUnmarshal(t *testing.T) {
531	result := pointerMarshalTestStruct{}
532	err := toml.Unmarshal(pointerTestToml, &result)
533	require.NoError(t, err)
534	assert.Equal(t, pointerTestData, result)
535}
536
537func TestUnmarshalTypeMismatch(t *testing.T) {
538	result := pointerMarshalTestStruct{}
539	err := toml.Unmarshal([]byte("List = 123"), &result)
540	assert.Error(t, err)
541}
542
543type nestedMarshalTestStruct struct {
544	String [][]string
545	// Struct [][]basicMarshalTestSubStruct
546	StringPtr *[]*[]*string
547	// StructPtr *[]*[]*basicMarshalTestSubStruct
548}
549
550var (
551	str1    = "Three"
552	str2    = "Four"
553	strPtr  = []*string{&str1, &str2}
554	strPtr2 = []*[]*string{&strPtr}
555)
556
557var nestedTestData = nestedMarshalTestStruct{
558	String:    [][]string{{"Five", "Six"}, {"One", "Two"}},
559	StringPtr: &strPtr2,
560}
561
562var nestedTestToml = []byte(`String = [["Five", "Six"], ["One", "Two"]]
563StringPtr = [["Three", "Four"]]
564`)
565
566func TestNestedUnmarshal(t *testing.T) {
567	result := nestedMarshalTestStruct{}
568	err := toml.Unmarshal(nestedTestToml, &result)
569	require.NoError(t, err)
570	assert.Equal(t, nestedTestData, result)
571}
572
573type customMarshalerParent struct {
574	Self    customMarshaler   `toml:"me"`
575	Friends []customMarshaler `toml:"friends"`
576}
577
578type customMarshaler struct {
579	FirstName string
580	LastName  string
581}
582
583func (c customMarshaler) MarshalTOML() ([]byte, error) {
584	fullName := fmt.Sprintf("%s %s", c.FirstName, c.LastName)
585	return []byte(fullName), nil
586}
587
588var customMarshalerData = customMarshaler{FirstName: "Sally", LastName: "Fields"}
589
590// TODO: Remove nolint once var is used by a test
591//nolint:deadcode,unused,varcheck
592var customMarshalerToml = []byte(`Sally Fields`)
593
594// TODO: Remove nolint once var is used by a test
595//nolint:deadcode,unused,varcheck
596var nestedCustomMarshalerData = customMarshalerParent{
597	Self:    customMarshaler{FirstName: "Maiku", LastName: "Suteda"},
598	Friends: []customMarshaler{customMarshalerData},
599}
600
601// TODO: Remove nolint once var is used by a test
602//nolint:deadcode,unused,varcheck
603var nestedCustomMarshalerToml = []byte(`friends = ["Sally Fields"]
604me = "Maiku Suteda"
605`)
606
607var nestedCustomMarshalerTomlForUnmarshal = []byte(`[friends]
608FirstName = "Sally"
609LastName = "Fields"`)
610
611type IntOrString string
612
613func (x *IntOrString) MarshalTOML() ([]byte, error) {
614	s := *(*string)(x)
615	_, err := strconv.Atoi(s)
616	if err != nil {
617		return []byte(fmt.Sprintf(`"%s"`, s)), nil
618	}
619	return []byte(s), nil
620}
621
622func TestUnmarshalTextMarshaler(t *testing.T) {
623	nested := struct {
624		Friends textMarshaler `toml:"friends"`
625	}{}
626
627	expected := struct {
628		Friends textMarshaler `toml:"friends"`
629	}{
630		Friends: textMarshaler{FirstName: "Sally", LastName: "Fields"},
631	}
632
633	err := toml.Unmarshal(nestedCustomMarshalerTomlForUnmarshal, &nested)
634	if err != nil {
635		t.Fatal(err)
636	}
637	if !reflect.DeepEqual(nested, expected) {
638		t.Errorf("Bad unmarshal: expected %v, got %v", expected, nested)
639	}
640}
641
642// TODO: Remove nolint once type and methods are used by a test
643//nolint:unused
644type precedentMarshaler struct {
645	FirstName string
646	LastName  string
647}
648
649//nolint:unused
650func (m precedentMarshaler) MarshalText() ([]byte, error) {
651	return []byte("shadowed"), nil
652}
653
654//nolint:unused
655func (m precedentMarshaler) MarshalTOML() ([]byte, error) {
656	fullName := fmt.Sprintf("%s %s", m.FirstName, m.LastName)
657	return []byte(fullName), nil
658}
659
660// TODO: Remove nolint once type and method are used by a test
661//nolint:unused
662type customPointerMarshaler struct {
663	FirstName string
664	LastName  string
665}
666
667//nolint:unused
668func (m *customPointerMarshaler) MarshalTOML() ([]byte, error) {
669	return []byte(`"hidden"`), nil
670}
671
672// TODO: Remove nolint once type and method are used by a test
673//nolint:unused
674type textPointerMarshaler struct {
675	FirstName string
676	LastName  string
677}
678
679//nolint:unused
680func (m *textPointerMarshaler) MarshalText() ([]byte, error) {
681	return []byte("hidden"), nil
682}
683
684// TODO: Remove nolint once var is used by a test
685//nolint:deadcode,unused,varcheck
686var commentTestToml = []byte(`
687# it's a comment on type
688[postgres]
689  # isCommented = "dvalue"
690  noComment = "cvalue"
691
692  # A comment on AttrB with a
693  # break line
694  password = "bvalue"
695
696  # A comment on AttrA
697  user = "avalue"
698
699  [[postgres.My]]
700
701    # a comment on my on typeC
702    My = "Foo"
703
704  [[postgres.My]]
705
706    # a comment on my on typeC
707    My = "Baar"
708`)
709
710type mapsTestStruct struct {
711	Simple map[string]string
712	Paths  map[string]string
713	Other  map[string]float64
714	X      struct {
715		Y struct {
716			Z map[string]bool
717		}
718	}
719}
720
721// TODO: Remove nolint once var is used by a test
722//nolint:deadcode,unused,varcheck
723var mapsTestData = mapsTestStruct{
724	Simple: map[string]string{
725		"one plus one": "two",
726		"next":         "three",
727	},
728	Paths: map[string]string{
729		"/this/is/a/path": "/this/is/also/a/path",
730		"/heloo.txt":      "/tmp/lololo.txt",
731	},
732	Other: map[string]float64{
733		"testing": 3.9999,
734	},
735	X: struct{ Y struct{ Z map[string]bool } }{
736		Y: struct{ Z map[string]bool }{
737			Z: map[string]bool{
738				"is.Nested": true,
739			},
740		},
741	},
742}
743
744// TODO: Remove nolint once var is used by a test
745//nolint:deadcode,unused,varcheck
746var mapsTestToml = []byte(`
747[Other]
748  "testing" = 3.9999
749
750[Paths]
751  "/heloo.txt" = "/tmp/lololo.txt"
752  "/this/is/a/path" = "/this/is/also/a/path"
753
754[Simple]
755  "next" = "three"
756  "one plus one" = "two"
757
758[X]
759
760  [X.Y]
761
762    [X.Y.Z]
763      "is.Nested" = true
764`)
765
766// TODO: Remove nolint once type is used by a test
767//nolint:deadcode,unused
768type structArrayNoTag struct {
769	A struct {
770		B []int64
771		C []int64
772	}
773}
774
775// TODO: Remove nolint once var is used by a test
776//nolint:deadcode,unused,varcheck
777var customTagTestToml = []byte(`
778[postgres]
779  password = "bvalue"
780  user = "avalue"
781
782  [[postgres.My]]
783    My = "Foo"
784
785  [[postgres.My]]
786    My = "Baar"
787`)
788
789// TODO: Remove nolint once var is used by a test
790//nolint:deadcode,unused,varcheck
791var customCommentTagTestToml = []byte(`
792# db connection
793[postgres]
794
795  # db pass
796  password = "bvalue"
797
798  # db user
799  user = "avalue"
800`)
801
802// TODO: Remove nolint once var is used by a test
803//nolint:deadcode,unused,varcheck
804var customCommentedTagTestToml = []byte(`
805[postgres]
806  # password = "bvalue"
807  # user = "avalue"
808`)
809
810func TestUnmarshalTabInStringAndQuotedKey(t *testing.T) {
811	type Test struct {
812		Field1 string `toml:"Fie	ld1"`
813		Field2 string
814	}
815
816	type TestCase struct {
817		desc     string
818		input    []byte
819		expected Test
820	}
821
822	testCases := []TestCase{
823		{
824			desc:  "multiline string with tab",
825			input: []byte("Field2 = \"\"\"\nhello\tworld\"\"\""),
826			expected: Test{
827				Field2: "hello\tworld",
828			},
829		},
830		{
831			desc:  "quoted key with tab",
832			input: []byte("\"Fie\tld1\" = \"key with tab\""),
833			expected: Test{
834				Field1: "key with tab",
835			},
836		},
837		{
838			desc:  "basic string tab",
839			input: []byte("Field2 = \"hello\tworld\""),
840			expected: Test{
841				Field2: "hello\tworld",
842			},
843		},
844	}
845
846	for _, test := range testCases {
847		t.Run(test.desc, func(t *testing.T) {
848			result := Test{}
849			err := toml.Unmarshal(test.input, &result)
850			require.NoError(t, err)
851			assert.Equal(t, test.expected, result)
852		})
853	}
854}
855
856// TODO: Remove nolint once var is used by a test
857//nolint:deadcode,unused,varcheck
858var customMultilineTagTestToml = []byte(`int_slice = [
859  1,
860  2,
861  3,
862]
863`)
864
865// TODO: Remove nolint once var is used by a test
866//nolint:deadcode,unused,varcheck
867var testDocBasicToml = []byte(`
868[document]
869  bool_val = true
870  date_val = 1979-05-27T07:32:00Z
871  float_val = 123.4
872  int_val = 5000
873  string_val = "Bite me"
874  uint_val = 5001
875`)
876
877// TODO: Remove nolint once type is used by a test
878//nolint:deadcode
879type testDocCustomTag struct {
880	Doc testDocBasicsCustomTag `file:"document"`
881}
882
883// TODO: Remove nolint once type is used by a test
884//nolint:deadcode
885type testDocBasicsCustomTag struct {
886	Bool       bool      `file:"bool_val"`
887	Date       time.Time `file:"date_val"`
888	Float      float32   `file:"float_val"`
889	Int        int       `file:"int_val"`
890	Uint       uint      `file:"uint_val"`
891	String     *string   `file:"string_val"`
892	unexported int       `file:"shouldntBeHere"`
893}
894
895// TODO: Remove nolint once var is used by a test
896//nolint:deadcode,varcheck
897var testDocCustomTagData = testDocCustomTag{
898	Doc: testDocBasicsCustomTag{
899		Bool:       true,
900		Date:       time.Date(1979, 5, 27, 7, 32, 0, 0, time.UTC),
901		Float:      123.4,
902		Int:        5000,
903		Uint:       5001,
904		String:     &biteMe,
905		unexported: 0,
906	},
907}
908
909func TestUnmarshalMap(t *testing.T) {
910	testToml := []byte(`
911		a = 1
912		b = 2
913		c = 3
914		`)
915	var result map[string]int
916	err := toml.Unmarshal(testToml, &result)
917	if err != nil {
918		t.Errorf("Received unexpected error: %s", err)
919		return
920	}
921
922	expected := map[string]int{
923		"a": 1,
924		"b": 2,
925		"c": 3,
926	}
927
928	if !reflect.DeepEqual(result, expected) {
929		t.Errorf("Bad unmarshal: expected %v, got %v", expected, result)
930	}
931}
932
933func TestUnmarshalMapWithTypedKey(t *testing.T) {
934	testToml := []byte(`
935		a = 1
936		b = 2
937		c = 3
938		`)
939
940	type letter string
941	var result map[letter]int
942	err := toml.Unmarshal(testToml, &result)
943	if err != nil {
944		t.Errorf("Received unexpected error: %s", err)
945		return
946	}
947
948	expected := map[letter]int{
949		"a": 1,
950		"b": 2,
951		"c": 3,
952	}
953
954	if !reflect.DeepEqual(result, expected) {
955		t.Errorf("Bad unmarshal: expected %v, got %v", expected, result)
956	}
957}
958
959func TestUnmarshalNonPointer(t *testing.T) {
960	a := 1
961	err := toml.Unmarshal([]byte{}, a)
962	if err == nil {
963		t.Fatal("unmarshal should err when given a non pointer")
964	}
965}
966
967func TestUnmarshalInvalidPointerKind(t *testing.T) {
968	t.Skipf("should this really be an error?")
969	a := 1
970	err := toml.Unmarshal([]byte{}, &a)
971	assert.Error(t, err)
972}
973
974// TODO: Remove nolint once var is used by a test
975//nolint:deadcode,unused
976type testDuration struct {
977	Nanosec   time.Duration  `toml:"nanosec"`
978	Microsec1 time.Duration  `toml:"microsec1"`
979	Microsec2 *time.Duration `toml:"microsec2"`
980	Millisec  time.Duration  `toml:"millisec"`
981	Sec       time.Duration  `toml:"sec"`
982	Min       time.Duration  `toml:"min"`
983	Hour      time.Duration  `toml:"hour"`
984	Mixed     time.Duration  `toml:"mixed"`
985	AString   string         `toml:"a_string"`
986}
987
988// TODO: Remove nolint once var is used by a test
989//nolint:deadcode,unused,varcheck
990var testDurationToml = []byte(`
991nanosec = "1ns"
992microsec1 = "1us"
993microsec2 = "1µs"
994millisec = "1ms"
995sec = "1s"
996min = "1m"
997hour = "1h"
998mixed = "1h1m1s1ms1µs1ns"
999a_string = "15s"
1000`)
1001
1002// TODO: Remove nolint once var is used by a test
1003//nolint:deadcode,unused,varcheck
1004var testDurationToml2 = []byte(`a_string = "15s"
1005hour = "1h0m0s"
1006microsec1 = "1µs"
1007microsec2 = "1µs"
1008millisec = "1ms"
1009min = "1m0s"
1010mixed = "1h1m1.001001001s"
1011nanosec = "1ns"
1012sec = "1s"
1013`)
1014
1015// TODO: Remove nolint once type is used by a test
1016//nolint:deadcode,unused
1017type testBadDuration struct {
1018	Val time.Duration `toml:"val"`
1019}
1020
1021// TODO: add back camelCase test
1022var testCamelCaseKeyToml = []byte(`fooBar = 10`) //nolint:unused
1023
1024//nolint:unused
1025func TestUnmarshalCamelCaseKey(t *testing.T) {
1026	t.Skipf("don't know if it is a good idea to automatically convert like that yet")
1027	var x struct {
1028		FooBar int
1029		B      int
1030	}
1031
1032	if err := toml.Unmarshal(testCamelCaseKeyToml, &x); err != nil {
1033		t.Fatal(err)
1034	}
1035
1036	if x.FooBar != 10 {
1037		t.Fatal("Did not set camelCase'd key")
1038	}
1039}
1040
1041func TestUnmarshalNegativeUint(t *testing.T) {
1042	t.Skipf("not sure if we this should always error")
1043	type check struct{ U uint } // nolint:unused
1044	err := toml.Unmarshal([]byte("U = -1"), &check{})
1045	assert.Error(t, err)
1046}
1047
1048func TestUnmarshalCheckConversionFloatInt(t *testing.T) {
1049	type conversionCheck struct {
1050		U uint
1051		I int
1052		F float64
1053	}
1054
1055	type TestCase struct {
1056		desc  string
1057		input string
1058	}
1059
1060	testCases := []TestCase{
1061		{
1062			desc:  "unsigned int",
1063			input: `U = 1e300`,
1064		},
1065		{
1066			desc:  "int",
1067			input: `I = 1e300`,
1068		},
1069		{
1070			desc:  "float",
1071			input: `F = 9223372036854775806`,
1072		},
1073	}
1074
1075	for _, test := range testCases {
1076		t.Run(test.desc, func(t *testing.T) {
1077			err := toml.Unmarshal([]byte(test.input), &conversionCheck{})
1078			require.Error(t, err)
1079		})
1080	}
1081}
1082
1083func TestUnmarshalOverflow(t *testing.T) {
1084	type overflow struct {
1085		U8  uint8
1086		I8  int8
1087		F32 float32
1088	}
1089
1090	type TestCase struct {
1091		desc  string
1092		input string
1093	}
1094
1095	testCases := []TestCase{
1096		{
1097			desc:  "byte",
1098			input: `U8 = 300`,
1099		},
1100		{
1101			desc:  "int8",
1102			input: `I8 = 300`,
1103		},
1104		{
1105			desc:  "float32",
1106			input: `F32 = 1e300`,
1107		},
1108	}
1109
1110	for _, test := range testCases {
1111		t.Run(test.desc, func(t *testing.T) {
1112			err := toml.Unmarshal([]byte(test.input), &overflow{})
1113			require.Error(t, err)
1114		})
1115	}
1116}
1117
1118func TestUnmarshalDefault(t *testing.T) {
1119	t.Skipf("don't know if it is a good idea to have `default`")
1120	t.Run("main", func(t *testing.T) {
1121		type EmbeddedStruct struct {
1122			StringField string `default:"c"`
1123		}
1124
1125		type aliasUint uint
1126
1127		var doc struct {
1128			StringField       string        `default:"a"`
1129			BoolField         bool          `default:"true"`
1130			UintField         uint          `default:"1"`
1131			Uint8Field        uint8         `default:"8"`
1132			Uint16Field       uint16        `default:"16"`
1133			Uint32Field       uint32        `default:"32"`
1134			Uint64Field       uint64        `default:"64"`
1135			IntField          int           `default:"-1"`
1136			Int8Field         int8          `default:"-8"`
1137			Int16Field        int16         `default:"-16"`
1138			Int32Field        int32         `default:"-32"`
1139			Int64Field        int64         `default:"-64"`
1140			Float32Field      float32       `default:"32.1"`
1141			Float64Field      float64       `default:"64.1"`
1142			DurationField     time.Duration `default:"120ms"`
1143			DurationField2    time.Duration `default:"120000000"`
1144			NonEmbeddedStruct struct {
1145				StringField string `default:"b"`
1146			}
1147			EmbeddedStruct
1148			AliasUintField aliasUint `default:"1000"`
1149		}
1150
1151		err := toml.Unmarshal([]byte(``), &doc)
1152		if err != nil {
1153			t.Fatal(err)
1154		}
1155		if doc.BoolField != true {
1156			t.Errorf("BoolField should be true, not %t", doc.BoolField)
1157		}
1158		if doc.StringField != "a" {
1159			t.Errorf("StringField should be \"a\", not %s", doc.StringField)
1160		}
1161		if doc.UintField != 1 {
1162			t.Errorf("UintField should be 1, not %d", doc.UintField)
1163		}
1164		if doc.Uint8Field != 8 {
1165			t.Errorf("Uint8Field should be 8, not %d", doc.Uint8Field)
1166		}
1167		if doc.Uint16Field != 16 {
1168			t.Errorf("Uint16Field should be 16, not %d", doc.Uint16Field)
1169		}
1170		if doc.Uint32Field != 32 {
1171			t.Errorf("Uint32Field should be 32, not %d", doc.Uint32Field)
1172		}
1173		if doc.Uint64Field != 64 {
1174			t.Errorf("Uint64Field should be 64, not %d", doc.Uint64Field)
1175		}
1176		if doc.IntField != -1 {
1177			t.Errorf("IntField should be -1, not %d", doc.IntField)
1178		}
1179		if doc.Int8Field != -8 {
1180			t.Errorf("Int8Field should be -8, not %d", doc.Int8Field)
1181		}
1182		if doc.Int16Field != -16 {
1183			t.Errorf("Int16Field should be -16, not %d", doc.Int16Field)
1184		}
1185		if doc.Int32Field != -32 {
1186			t.Errorf("Int32Field should be -32, not %d", doc.Int32Field)
1187		}
1188		if doc.Int64Field != -64 {
1189			t.Errorf("Int64Field should be -64, not %d", doc.Int64Field)
1190		}
1191		if doc.Float32Field != 32.1 {
1192			t.Errorf("Float32Field should be 32.1, not %f", doc.Float32Field)
1193		}
1194		if doc.Float64Field != 64.1 {
1195			t.Errorf("Float64Field should be 64.1, not %f", doc.Float64Field)
1196		}
1197		if doc.DurationField != 120*time.Millisecond {
1198			t.Errorf("DurationField should be 120ms, not %s", doc.DurationField.String())
1199		}
1200		if doc.DurationField2 != 120*time.Millisecond {
1201			t.Errorf("DurationField2 should be 120000000, not %d", doc.DurationField2)
1202		}
1203		if doc.NonEmbeddedStruct.StringField != "b" {
1204			t.Errorf("StringField should be \"b\", not %s", doc.NonEmbeddedStruct.StringField)
1205		}
1206		if doc.EmbeddedStruct.StringField != "c" {
1207			t.Errorf("StringField should be \"c\", not %s", doc.EmbeddedStruct.StringField)
1208		}
1209		if doc.AliasUintField != 1000 {
1210			t.Errorf("AliasUintField should be 1000, not %d", doc.AliasUintField)
1211		}
1212	})
1213
1214	t.Run("failure bool", func(t *testing.T) {
1215		var doc struct {
1216			Field bool `default:"blah"`
1217		}
1218
1219		err := toml.Unmarshal([]byte(``), &doc)
1220		if err == nil {
1221			t.Fatal("should error")
1222		}
1223	})
1224
1225	t.Run("failure int", func(t *testing.T) {
1226		var doc struct {
1227			Field int `default:"blah"`
1228		}
1229
1230		err := toml.Unmarshal([]byte(``), &doc)
1231		if err == nil {
1232			t.Fatal("should error")
1233		}
1234	})
1235
1236	t.Run("failure int64", func(t *testing.T) {
1237		var doc struct {
1238			Field int64 `default:"blah"`
1239		}
1240
1241		err := toml.Unmarshal([]byte(``), &doc)
1242		if err == nil {
1243			t.Fatal("should error")
1244		}
1245	})
1246
1247	t.Run("failure float64", func(t *testing.T) {
1248		var doc struct {
1249			Field float64 `default:"blah"`
1250		}
1251
1252		err := toml.Unmarshal([]byte(``), &doc)
1253		if err == nil {
1254			t.Fatal("should error")
1255		}
1256	})
1257
1258	t.Run("failure duration", func(t *testing.T) {
1259		var doc struct {
1260			Field time.Duration `default:"blah"`
1261		}
1262
1263		err := toml.Unmarshal([]byte(``), &doc)
1264		if err == nil {
1265			t.Fatal("should error")
1266		}
1267	})
1268
1269	t.Run("failure unsupported", func(t *testing.T) {
1270		var doc struct {
1271			Field struct{} `default:"blah"`
1272		}
1273
1274		err := toml.Unmarshal([]byte(``), &doc)
1275		if err == nil {
1276			t.Fatal("should error")
1277		}
1278	})
1279}
1280
1281func TestUnmarshalNestedAnonymousStructs(t *testing.T) {
1282	type Nested struct {
1283		Value string `toml:"nested_field"`
1284	}
1285	type Deep struct {
1286		Nested
1287	}
1288	type Document struct {
1289		Deep
1290		Value string `toml:"own_field"`
1291	}
1292
1293	var doc Document
1294
1295	err := toml.Unmarshal([]byte(`nested_field = "nested value"`+"\n"+`own_field = "own value"`), &doc)
1296	if err != nil {
1297		t.Fatal("should not error")
1298	}
1299	if doc.Value != "own value" || doc.Nested.Value != "nested value" {
1300		t.Fatal("unexpected values")
1301	}
1302}
1303
1304func TestUnmarshalNestedAnonymousStructs_Controversial(t *testing.T) {
1305	t.Skipf("TODO: what does encoding/json do?")
1306	type Nested struct {
1307		Value string `toml:"nested"`
1308	}
1309	type Deep struct {
1310		Nested
1311	}
1312	type Document struct {
1313		Deep
1314		Value string `toml:"own"`
1315	}
1316
1317	var doc Document
1318
1319	err := toml.Unmarshal([]byte(`nested = "nested value"`+"\n"+`own = "own value"`), &doc)
1320	if err == nil {
1321		t.Fatal("should error")
1322	}
1323}
1324
1325type unexportedFieldPreservationTest struct {
1326	Exported   string `toml:"exported"`
1327	unexported string
1328	Nested1    unexportedFieldPreservationTestNested    `toml:"nested1"`
1329	Nested2    *unexportedFieldPreservationTestNested   `toml:"nested2"`
1330	Nested3    *unexportedFieldPreservationTestNested   `toml:"nested3"`
1331	Slice1     []unexportedFieldPreservationTestNested  `toml:"slice1"`
1332	Slice2     []*unexportedFieldPreservationTestNested `toml:"slice2"`
1333}
1334
1335type unexportedFieldPreservationTestNested struct {
1336	Exported1   string `toml:"exported1"`
1337	unexported1 string
1338}
1339
1340func TestUnmarshalPreservesUnexportedFields(t *testing.T) {
1341	doc := `
1342	exported = "visible"
1343	unexported = "ignored"
1344
1345	[nested1]
1346	exported1 = "visible1"
1347	unexported1 = "ignored1"
1348
1349	[nested2]
1350	exported1 = "visible2"
1351	unexported1 = "ignored2"
1352
1353	[nested3]
1354	exported1 = "visible3"
1355	unexported1 = "ignored3"
1356
1357	[[slice1]]
1358	exported1 = "visible3"
1359
1360	[[slice1]]
1361	exported1 = "visible4"
1362
1363	[[slice2]]
1364	exported1 = "visible5"
1365	`
1366
1367	t.Run("unexported field should not be set from toml", func(t *testing.T) {
1368		var actual unexportedFieldPreservationTest
1369		err := toml.Unmarshal([]byte(doc), &actual)
1370		if err != nil {
1371			t.Fatal("did not expect an error")
1372		}
1373
1374		expect := unexportedFieldPreservationTest{
1375			Exported:   "visible",
1376			unexported: "",
1377			Nested1:    unexportedFieldPreservationTestNested{"visible1", ""},
1378			Nested2:    &unexportedFieldPreservationTestNested{"visible2", ""},
1379			Nested3:    &unexportedFieldPreservationTestNested{"visible3", ""},
1380			Slice1: []unexportedFieldPreservationTestNested{
1381				{Exported1: "visible3"},
1382				{Exported1: "visible4"},
1383			},
1384			Slice2: []*unexportedFieldPreservationTestNested{
1385				{Exported1: "visible5"},
1386			},
1387		}
1388
1389		if !reflect.DeepEqual(actual, expect) {
1390			t.Fatalf("%+v did not equal %+v", actual, expect)
1391		}
1392	})
1393
1394	t.Run("unexported field should be preserved", func(t *testing.T) {
1395		actual := unexportedFieldPreservationTest{
1396			Exported:   "foo",
1397			unexported: "bar",
1398			Nested1:    unexportedFieldPreservationTestNested{"baz", "bax"},
1399			Nested2:    nil,
1400			Nested3:    &unexportedFieldPreservationTestNested{"baz", "bax"},
1401		}
1402		err := toml.Unmarshal([]byte(doc), &actual)
1403		if err != nil {
1404			t.Fatal("did not expect an error")
1405		}
1406
1407		expect := unexportedFieldPreservationTest{
1408			Exported:   "visible",
1409			unexported: "bar",
1410			Nested1:    unexportedFieldPreservationTestNested{"visible1", "bax"},
1411			Nested2:    &unexportedFieldPreservationTestNested{"visible2", ""},
1412			Nested3:    &unexportedFieldPreservationTestNested{"visible3", "bax"},
1413			Slice1: []unexportedFieldPreservationTestNested{
1414				{Exported1: "visible3"},
1415				{Exported1: "visible4"},
1416			},
1417			Slice2: []*unexportedFieldPreservationTestNested{
1418				{Exported1: "visible5"},
1419			},
1420		}
1421
1422		if !reflect.DeepEqual(actual, expect) {
1423			t.Fatalf("%+v did not equal %+v", actual, expect)
1424		}
1425	})
1426}
1427
1428func TestUnmarshalLocalDate(t *testing.T) {
1429	t.Run("ToLocalDate", func(t *testing.T) {
1430		type dateStruct struct {
1431			Date toml.LocalDate
1432		}
1433
1434		doc := `date = 1979-05-27`
1435
1436		var obj dateStruct
1437
1438		err := toml.Unmarshal([]byte(doc), &obj)
1439		if err != nil {
1440			t.Fatal(err)
1441		}
1442
1443		if obj.Date.Year != 1979 {
1444			t.Errorf("expected year 1979, got %d", obj.Date.Year)
1445		}
1446		if obj.Date.Month != 5 {
1447			t.Errorf("expected month 5, got %d", obj.Date.Month)
1448		}
1449		if obj.Date.Day != 27 {
1450			t.Errorf("expected day 27, got %d", obj.Date.Day)
1451		}
1452	})
1453
1454	t.Run("ToLocalDate", func(t *testing.T) {
1455		type dateStruct struct {
1456			Date time.Time
1457		}
1458
1459		doc := `date = 1979-05-27`
1460
1461		var obj dateStruct
1462
1463		err := toml.Unmarshal([]byte(doc), &obj)
1464		if err != nil {
1465			t.Fatal(err)
1466		}
1467
1468		if obj.Date.Year() != 1979 {
1469			t.Errorf("expected year 1979, got %d", obj.Date.Year())
1470		}
1471		if obj.Date.Month() != 5 {
1472			t.Errorf("expected month 5, got %d", obj.Date.Month())
1473		}
1474		if obj.Date.Day() != 27 {
1475			t.Errorf("expected day 27, got %d", obj.Date.Day())
1476		}
1477	})
1478}
1479
1480func TestUnmarshalLocalDateTime(t *testing.T) {
1481	examples := []struct {
1482		name string
1483		in   string
1484		out  toml.LocalDateTime
1485	}{
1486		{
1487			name: "normal",
1488			in:   "1979-05-27T07:32:00",
1489			out: toml.LocalDateTime{
1490				LocalDate: toml.LocalDate{
1491					Year:  1979,
1492					Month: 5,
1493					Day:   27,
1494				},
1495				LocalTime: toml.LocalTime{
1496					Hour:       7,
1497					Minute:     32,
1498					Second:     0,
1499					Nanosecond: 0,
1500				},
1501			},
1502		},
1503		{
1504			name: "with nanoseconds",
1505			in:   "1979-05-27T00:32:00.999999",
1506			out: toml.LocalDateTime{
1507				LocalDate: toml.LocalDate{
1508					Year:  1979,
1509					Month: 5,
1510					Day:   27,
1511				},
1512				LocalTime: toml.LocalTime{
1513					Hour:       0,
1514					Minute:     32,
1515					Second:     0,
1516					Nanosecond: 999999000,
1517				},
1518			},
1519		},
1520	}
1521
1522	for i, example := range examples {
1523		doc := fmt.Sprintf(`date = %s`, example.in)
1524
1525		t.Run(fmt.Sprintf("ToLocalDateTime_%d_%s", i, example.name), func(t *testing.T) {
1526			type dateStruct struct {
1527				Date toml.LocalDateTime
1528			}
1529
1530			var obj dateStruct
1531
1532			err := toml.Unmarshal([]byte(doc), &obj)
1533			if err != nil {
1534				t.Fatal(err)
1535			}
1536
1537			if obj.Date != example.out {
1538				t.Errorf("expected '%s', got '%s'", example.out, obj.Date)
1539			}
1540		})
1541
1542		t.Run(fmt.Sprintf("ToTime_%d_%s", i, example.name), func(t *testing.T) {
1543			type dateStruct struct {
1544				Date time.Time
1545			}
1546
1547			var obj dateStruct
1548
1549			err := toml.Unmarshal([]byte(doc), &obj)
1550			if err != nil {
1551				t.Fatal(err)
1552			}
1553
1554			if obj.Date.Year() != example.out.Year {
1555				t.Errorf("expected year %d, got %d", example.out.Year, obj.Date.Year())
1556			}
1557			if obj.Date.Month() != time.Month(example.out.Month) {
1558				t.Errorf("expected month %d, got %d", example.out.Month, obj.Date.Month())
1559			}
1560			if obj.Date.Day() != example.out.Day {
1561				t.Errorf("expected day %d, got %d", example.out.Day, obj.Date.Day())
1562			}
1563			if obj.Date.Hour() != example.out.Hour {
1564				t.Errorf("expected hour %d, got %d", example.out.Hour, obj.Date.Hour())
1565			}
1566			if obj.Date.Minute() != example.out.Minute {
1567				t.Errorf("expected minute %d, got %d", example.out.Minute, obj.Date.Minute())
1568			}
1569			if obj.Date.Second() != example.out.Second {
1570				t.Errorf("expected second %d, got %d", example.out.Second, obj.Date.Second())
1571			}
1572			if obj.Date.Nanosecond() != example.out.Nanosecond {
1573				t.Errorf("expected nanoseconds %d, got %d", example.out.Nanosecond, obj.Date.Nanosecond())
1574			}
1575		})
1576	}
1577}
1578
1579func TestUnmarshalLocalTime(t *testing.T) {
1580	examples := []struct {
1581		name string
1582		in   string
1583		out  toml.LocalTime
1584	}{
1585		{
1586			name: "normal",
1587			in:   "07:32:00",
1588			out: toml.LocalTime{
1589				Hour:       7,
1590				Minute:     32,
1591				Second:     0,
1592				Nanosecond: 0,
1593			},
1594		},
1595		{
1596			name: "with nanoseconds",
1597			in:   "00:32:00.999999",
1598			out: toml.LocalTime{
1599				Hour:       0,
1600				Minute:     32,
1601				Second:     0,
1602				Nanosecond: 999999000,
1603			},
1604		},
1605	}
1606
1607	for i, example := range examples {
1608		doc := fmt.Sprintf(`Time = %s`, example.in)
1609
1610		t.Run(fmt.Sprintf("ToLocalTime_%d_%s", i, example.name), func(t *testing.T) {
1611			type dateStruct struct {
1612				Time toml.LocalTime
1613			}
1614
1615			var obj dateStruct
1616
1617			err := toml.Unmarshal([]byte(doc), &obj)
1618			if err != nil {
1619				t.Fatal(err)
1620			}
1621
1622			if obj.Time != example.out {
1623				t.Errorf("expected '%s', got '%s'", example.out, obj.Time)
1624			}
1625		})
1626	}
1627}
1628
1629// test case for issue #339
1630func TestUnmarshalSameInnerField(t *testing.T) {
1631	type InterStruct2 struct {
1632		Test string
1633		Name string
1634		Age  int
1635	}
1636	type Inter2 struct {
1637		Name         string
1638		Age          int
1639		InterStruct2 InterStruct2
1640	}
1641	type Server struct {
1642		Name   string `toml:"name"`
1643		Inter2 Inter2 `toml:"inter2"`
1644	}
1645
1646	var server Server
1647
1648	if err := toml.Unmarshal([]byte(`name = "123"
1649[inter2]
1650name = "inter2"
1651age = 222`), &server); err == nil {
1652		expected := Server{
1653			Name: "123",
1654			Inter2: Inter2{
1655				Name: "inter2",
1656				Age:  222,
1657			},
1658		}
1659		if !reflect.DeepEqual(server, expected) {
1660			t.Errorf("Bad unmarshal: expected %v, got %v", expected, server)
1661		}
1662	} else {
1663		t.Fatalf("unexpected error: %v", err)
1664	}
1665}
1666
1667func TestUnmarshalToNilInterface(t *testing.T) {
1668	doc := []byte(`
1669PrimitiveField = "Hello"
1670ArrayField = [1,2,3]
1671InterfacePointerField = "World"
1672
1673[StructField]
1674Field1 = 123
1675Field2 = "Field2"
1676
1677[MapField]
1678MapField1 = [4,5,6]
1679MapField2 = {A = "A"}
1680MapField3 = false
1681
1682[[StructArrayField]]
1683Name = "Allen"
1684Age = 20
1685
1686[[StructArrayField]]
1687Name = "Jack"
1688Age = 23
1689`)
1690
1691	type OuterStruct struct {
1692		PrimitiveField        interface{}
1693		ArrayField            interface{}
1694		StructArrayField      interface{}
1695		MapField              map[string]interface{}
1696		StructField           interface{}
1697		NilField              interface{}
1698		InterfacePointerField *interface{}
1699	}
1700
1701	var s interface{} = "World"
1702	expected := OuterStruct{
1703		PrimitiveField: "Hello",
1704		ArrayField:     []interface{}{int64(1), int64(2), int64(3)},
1705		StructField: map[string]interface{}{
1706			"Field1": int64(123),
1707			"Field2": "Field2",
1708		},
1709		MapField: map[string]interface{}{
1710			"MapField1": []interface{}{int64(4), int64(5), int64(6)},
1711			"MapField2": map[string]interface{}{
1712				"A": "A",
1713			},
1714			"MapField3": false,
1715		},
1716		NilField:              nil,
1717		InterfacePointerField: &s,
1718		StructArrayField: []interface{}{
1719			map[string]interface{}{
1720				"Name": "Allen",
1721				"Age":  int64(20),
1722			},
1723			map[string]interface{}{
1724				"Name": "Jack",
1725				"Age":  int64(23),
1726			},
1727		},
1728	}
1729	actual := OuterStruct{}
1730	err := toml.Unmarshal(doc, &actual)
1731	require.NoError(t, err)
1732	assert.Equal(t, expected, actual)
1733}
1734
1735func TestUnmarshalToNonNilInterface(t *testing.T) {
1736	doc := []byte(`
1737PrimitiveField = "Allen"
1738ArrayField = [1,2,3]
1739
1740[StructField]
1741InnerField = "After1"
1742
1743[PointerField]
1744InnerField = "After2"
1745
1746[InterfacePointerField]
1747InnerField = "After"
1748
1749[MapField]
1750MapField1 = [4,5,6]
1751MapField2 = {A = "A"}
1752MapField3 = false
1753
1754[[StructArrayField]]
1755InnerField = "After3"
1756
1757[[StructArrayField]]
1758InnerField = "After4"
1759`)
1760	type InnerStruct struct {
1761		InnerField interface{}
1762	}
1763
1764	type OuterStruct struct {
1765		PrimitiveField        interface{}
1766		ArrayField            interface{}
1767		StructArrayField      interface{}
1768		MapField              map[string]interface{}
1769		StructField           interface{}
1770		PointerField          interface{}
1771		NilField              interface{}
1772		InterfacePointerField *interface{}
1773	}
1774
1775	var s interface{} = InnerStruct{"After"}
1776	expected := OuterStruct{
1777		PrimitiveField: "Allen",
1778		ArrayField:     []interface{}{int64(1), int64(2), int64(3)},
1779		StructField:    map[string]interface{}{"InnerField": "After1"},
1780		MapField: map[string]interface{}{
1781			"MapField1": []interface{}{int64(4), int64(5), int64(6)},
1782			"MapField2": map[string]interface{}{
1783				"A": "A",
1784			},
1785			"MapField3": false,
1786		},
1787		PointerField:          map[string]interface{}{"InnerField": "After2"},
1788		NilField:              nil,
1789		InterfacePointerField: &s,
1790		StructArrayField: []interface{}{
1791			map[string]interface{}{"InnerField": "After3"},
1792			map[string]interface{}{"InnerField": "After4"},
1793		},
1794	}
1795	actual := OuterStruct{
1796		PrimitiveField: "aaa",
1797		ArrayField:     []int{100, 200, 300, 400},
1798		StructField:    InnerStruct{InnerField: "Before1"},
1799		MapField: map[string]interface{}{
1800			"MapField1": []int{4, 5, 6},
1801			"MapField2": map[string]string{
1802				"B": "BBB",
1803			},
1804			"MapField3": true,
1805		},
1806		PointerField:          &InnerStruct{InnerField: "Before2"},
1807		NilField:              nil,
1808		InterfacePointerField: &s,
1809		StructArrayField: []InnerStruct{
1810			{InnerField: "Before3"},
1811			{InnerField: "Before4"},
1812		},
1813	}
1814
1815	err := toml.Unmarshal(doc, &actual)
1816	require.NoError(t, err)
1817	assert.Equal(t, expected, actual)
1818}
1819
1820func TestUnmarshalNil(t *testing.T) {
1821	assert.Error(t, toml.Unmarshal([]byte(`whatever = "whatever"`), nil))
1822	assert.Error(t, toml.Unmarshal([]byte(`whatever = "whatever"`), (*struct{})(nil)))
1823}
1824
1825var sliceTomlDemo = []byte(`str_slice = ["Howdy","Hey There"]
1826str_slice_ptr= ["Howdy","Hey There"]
1827int_slice=[1,2]
1828int_slice_ptr=[1,2]
1829[[struct_slice]]
1830String2="1"
1831[[struct_slice]]
1832String2="2"
1833[[struct_slice_ptr]]
1834String2="1"
1835[[struct_slice_ptr]]
1836String2="2"
1837`)
1838
1839type sliceStruct struct {
1840	Slice          []string                     `  toml:"str_slice"  `
1841	SlicePtr       *[]string                    `  toml:"str_slice_ptr"  `
1842	IntSlice       []int                        `  toml:"int_slice"  `
1843	IntSlicePtr    *[]int                       `  toml:"int_slice_ptr"  `
1844	StructSlice    []basicMarshalTestSubStruct  `  toml:"struct_slice"  `
1845	StructSlicePtr *[]basicMarshalTestSubStruct `  toml:"struct_slice_ptr"  `
1846}
1847
1848type arrayStruct struct {
1849	Slice          [4]string                     `  toml:"str_slice"  `
1850	SlicePtr       *[4]string                    `  toml:"str_slice_ptr"  `
1851	IntSlice       [4]int                        `  toml:"int_slice"  `
1852	IntSlicePtr    *[4]int                       `  toml:"int_slice_ptr"  `
1853	StructSlice    [4]basicMarshalTestSubStruct  `  toml:"struct_slice"  `
1854	StructSlicePtr *[4]basicMarshalTestSubStruct `  toml:"struct_slice_ptr"  `
1855}
1856
1857type arrayTooSmallStruct struct {
1858	Slice       [1]string                    `  toml:"str_slice"  `
1859	StructSlice [1]basicMarshalTestSubStruct `  toml:"struct_slice"  `
1860}
1861
1862func TestUnmarshalSlice(t *testing.T) {
1863	var actual sliceStruct
1864	err := toml.Unmarshal(sliceTomlDemo, &actual)
1865	require.NoError(t, err)
1866	expected := sliceStruct{
1867		Slice:          []string{"Howdy", "Hey There"},
1868		SlicePtr:       &[]string{"Howdy", "Hey There"},
1869		IntSlice:       []int{1, 2},
1870		IntSlicePtr:    &[]int{1, 2},
1871		StructSlice:    []basicMarshalTestSubStruct{{"1"}, {"2"}},
1872		StructSlicePtr: &[]basicMarshalTestSubStruct{{"1"}, {"2"}},
1873	}
1874	assert.Equal(t, expected, actual)
1875}
1876
1877func TestUnmarshalSliceFail(t *testing.T) {
1878	var actual sliceStruct
1879	assert.Error(t, toml.Unmarshal([]byte(`str_slice = [1, 2]`), &actual))
1880}
1881
1882func TestUnmarshalSliceFail2(t *testing.T) {
1883	doc := `str_slice=[1,2]`
1884	var actual sliceStruct
1885	assert.Error(t, toml.Unmarshal([]byte(doc), &actual))
1886}
1887
1888func TestUnmarshalMixedTypeSlice(t *testing.T) {
1889	type TestStruct struct {
1890		ArrayField []interface{}
1891	}
1892
1893	//doc := []byte(`ArrayField = [3.14,100,true,"hello world",{Field = "inner1"},[{Field = "inner2"},{Field = "inner3"}]]
1894	//`)
1895
1896	doc := []byte(`ArrayField = [{Field = "inner1"},[{Field = "inner2"},{Field = "inner3"}]]
1897`)
1898
1899	actual := TestStruct{}
1900	expected := TestStruct{
1901		ArrayField: []interface{}{
1902			//3.14,
1903			//int64(100),
1904			//true,
1905			//"hello world",
1906			map[string]interface{}{
1907				"Field": "inner1",
1908			},
1909			[]interface{}{
1910				map[string]interface{}{"Field": "inner2"},
1911				map[string]interface{}{"Field": "inner3"},
1912			},
1913		},
1914	}
1915	err := toml.Unmarshal(doc, &actual)
1916	require.NoError(t, err)
1917	assert.Equal(t, expected, actual)
1918}
1919
1920func TestUnmarshalArray(t *testing.T) {
1921	var err error
1922
1923	var actual arrayStruct
1924	err = toml.Unmarshal(sliceTomlDemo, &actual)
1925	require.NoError(t, err)
1926
1927	expected := arrayStruct{
1928		Slice:          [4]string{"Howdy", "Hey There"},
1929		SlicePtr:       &[4]string{"Howdy", "Hey There"},
1930		IntSlice:       [4]int{1, 2},
1931		IntSlicePtr:    &[4]int{1, 2},
1932		StructSlice:    [4]basicMarshalTestSubStruct{{"1"}, {"2"}},
1933		StructSlicePtr: &[4]basicMarshalTestSubStruct{{"1"}, {"2"}},
1934	}
1935	assert.Equal(t, expected, actual)
1936}
1937
1938func TestUnmarshalArrayFail3(t *testing.T) {
1939	doc := `[[struct_slice]]
1940String2="1"
1941[[struct_slice]]
1942String2="2"`
1943
1944	var actual arrayTooSmallStruct
1945	err := toml.Unmarshal([]byte(doc), &actual)
1946	assert.Error(t, err)
1947}
1948
1949func decoder(doc string) *toml.Decoder {
1950	return toml.NewDecoder(bytes.NewReader([]byte(doc)))
1951}
1952
1953func strictDecoder(doc string) *toml.Decoder {
1954	d := decoder(doc)
1955	d.SetStrict(true)
1956	return d
1957}
1958
1959func TestDecoderStrict(t *testing.T) {
1960	input := `
1961	[decoded]
1962	 key = ""
1963
1964	[undecoded]
1965	 key = ""
1966
1967	 [undecoded.inner]
1968		key = ""
1969
1970	 [[undecoded.array]]
1971		key = ""
1972
1973	 [[undecoded.array]]
1974		key = ""
1975
1976	`
1977	var doc struct {
1978		Decoded struct {
1979			Key string
1980		}
1981	}
1982
1983	err := strictDecoder(input).Decode(&doc)
1984	require.Error(t, err)
1985	require.IsType(t, &toml.StrictMissingError{}, err)
1986	se := err.(*toml.StrictMissingError)
1987
1988	keys := []toml.Key{}
1989
1990	for _, e := range se.Errors {
1991		keys = append(keys, e.Key())
1992	}
1993
1994	expectedKeys := []toml.Key{
1995		{"undecoded"},
1996		{"undecoded", "inner"},
1997		{"undecoded", "array"},
1998		{"undecoded", "array"},
1999	}
2000
2001	require.Equal(t, expectedKeys, keys)
2002
2003	err = decoder(input).Decode(&doc)
2004	require.NoError(t, err)
2005
2006	var m map[string]interface{}
2007	err = decoder(input).Decode(&m)
2008}
2009
2010func TestDecoderStrictValid(t *testing.T) {
2011	input := `
2012	[decoded]
2013	 key = ""
2014	`
2015	var doc struct {
2016		Decoded struct {
2017			Key string
2018		}
2019	}
2020
2021	err := strictDecoder(input).Decode(&doc)
2022	require.NoError(t, err)
2023}
2024
2025type docUnmarshalTOML struct {
2026	Decoded struct {
2027		Key string
2028	}
2029}
2030
2031func (d *docUnmarshalTOML) UnmarshalTOML(i interface{}) error {
2032	if iMap, ok := i.(map[string]interface{}); !ok {
2033		return fmt.Errorf("type assertion error: wants %T, have %T", map[string]interface{}{}, i)
2034	} else if key, ok := iMap["key"]; !ok {
2035		return fmt.Errorf("key '%s' not in map", "key")
2036	} else if keyString, ok := key.(string); !ok {
2037		return fmt.Errorf("type assertion error: wants %T, have %T", "", key)
2038	} else {
2039		d.Decoded.Key = keyString
2040	}
2041	return nil
2042}
2043
2044func TestDecoderStrictCustomUnmarshal(t *testing.T) {
2045	t.Skip()
2046	//input := `key = "ok"`
2047	//var doc docUnmarshalTOML
2048	//err := NewDecoder(bytes.NewReader([]byte(input))).Strict(true).Decode(&doc)
2049	//if err != nil {
2050	//	t.Fatal("unexpected error:", err)
2051	//}
2052	//if doc.Decoded.Key != "ok" {
2053	//	t.Errorf("Bad unmarshal: expected ok, got %v", doc.Decoded.Key)
2054	//}
2055}
2056
2057type parent struct {
2058	Doc        docUnmarshalTOML
2059	DocPointer *docUnmarshalTOML
2060}
2061
2062func TestCustomUnmarshal(t *testing.T) {
2063	t.Skip("not sure if UnmarshalTOML is a good idea")
2064	input := `
2065[Doc]
2066    key = "ok1"
2067[DocPointer]
2068    key = "ok2"
2069`
2070
2071	var d parent
2072	err := toml.Unmarshal([]byte(input), &d)
2073	require.NoError(t, err)
2074	assert.Equal(t, "ok1", d.Doc.Decoded.Key)
2075	assert.Equal(t, "ok2", d.DocPointer.Decoded.Key)
2076}
2077
2078func TestCustomUnmarshalError(t *testing.T) {
2079	t.Skip("not sure if UnmarshalTOML is a good idea")
2080
2081	input := `
2082[Doc]
2083    key = 1
2084[DocPointer]
2085    key = "ok2"
2086`
2087
2088	expected := "(2, 1): unmarshal toml: type assertion error: wants string, have int64"
2089
2090	var d parent
2091	err := toml.Unmarshal([]byte(input), &d)
2092	if err == nil {
2093		t.Error("expected error, got none")
2094	} else if err.Error() != expected {
2095		t.Errorf("expect err: %s, got: %s", expected, err.Error())
2096	}
2097}
2098
2099type intWrapper struct {
2100	Value int
2101}
2102
2103func (w *intWrapper) UnmarshalText(text []byte) error {
2104	var err error
2105	if w.Value, err = strconv.Atoi(string(text)); err == nil {
2106		return nil
2107	}
2108	if b, err := strconv.ParseBool(string(text)); err == nil {
2109		if b {
2110			w.Value = 1
2111		}
2112		return nil
2113	}
2114	if f, err := strconv.ParseFloat(string(text), 32); err == nil {
2115		w.Value = int(f)
2116		return nil
2117	}
2118	return fmt.Errorf("unsupported: %s", text)
2119}
2120
2121func TestTextUnmarshal(t *testing.T) {
2122	var doc struct {
2123		UnixTime intWrapper
2124		Version  *intWrapper
2125
2126		Bool  intWrapper
2127		Int   intWrapper
2128		Float intWrapper
2129	}
2130
2131	input := `
2132UnixTime = "12"
2133Version = "42"
2134Bool = true
2135Int = 21
2136Float = 2.0
2137`
2138	err := toml.Unmarshal([]byte(input), &doc)
2139	require.NoError(t, err)
2140	assert.Equal(t, 12, doc.UnixTime.Value)
2141	assert.Equal(t, 42, doc.Version.Value)
2142	assert.Equal(t, 1, doc.Bool.Value)
2143	assert.Equal(t, 21, doc.Int.Value)
2144	assert.Equal(t, 2, doc.Float.Value)
2145}
2146
2147func TestTextUnmarshalError(t *testing.T) {
2148	var doc struct {
2149		Failer intWrapper
2150	}
2151
2152	input := `Failer = "hello"`
2153	if err := toml.Unmarshal([]byte(input), &doc); err == nil {
2154		t.Fatalf("expected err, got none")
2155	}
2156}
2157
2158// issue406
2159func TestPreserveNotEmptyField(t *testing.T) {
2160	doc := []byte(`Field1 = "ccc"`)
2161	type Inner struct {
2162		InnerField1 string
2163		InnerField2 int
2164	}
2165	type TestStruct struct {
2166		Field1 string
2167		Field2 int
2168		Field3 Inner
2169	}
2170
2171	actual := TestStruct{
2172		"aaa",
2173		100,
2174		Inner{
2175			"bbb",
2176			200,
2177		},
2178	}
2179
2180	expected := TestStruct{
2181		"ccc",
2182		100,
2183		Inner{
2184			"bbb",
2185			200,
2186		},
2187	}
2188
2189	err := toml.Unmarshal(doc, &actual)
2190	if err != nil {
2191		t.Fatal(err)
2192	}
2193
2194	if !reflect.DeepEqual(actual, expected) {
2195		t.Errorf("Bad unmarshal: expected %+v, got %+v", expected, actual)
2196	}
2197}
2198
2199// github issue 432
2200func TestUnmarshalEmptyInterface(t *testing.T) {
2201	doc := []byte(`User = "pelletier"`)
2202
2203	var v interface{}
2204
2205	err := toml.Unmarshal(doc, &v)
2206	if err != nil {
2207		t.Fatal(err)
2208	}
2209	require.IsType(t, map[string]interface{}{}, v)
2210
2211	x := v.(map[string]interface{})
2212	assert.Equal(t, "pelletier", x["User"])
2213}
2214
2215func TestUnmarshalEmptyInterfaceDeep(t *testing.T) {
2216	t.Skipf("TODO")
2217	doc := []byte(`
2218User = "pelletier"
2219Age = 99
2220
2221[foo]
2222bar = 42
2223`)
2224
2225	var v interface{}
2226
2227	err := toml.Unmarshal(doc, &v)
2228	if err != nil {
2229		t.Fatal(err)
2230	}
2231
2232	x, ok := v.(map[string]interface{})
2233	if !ok {
2234		t.Fatal(err)
2235	}
2236
2237	expected := map[string]interface{}{
2238		"User": "pelletier",
2239		"Age":  99,
2240		"foo": map[string]interface{}{
2241			"bar": 42,
2242		},
2243	}
2244
2245	reflect.DeepEqual(x, expected)
2246}
2247
2248type Config struct {
2249	Key string `toml:"key"`
2250	Obj Custom `toml:"obj"`
2251}
2252
2253type Custom struct {
2254	v string
2255}
2256
2257func (c *Custom) UnmarshalTOML(v interface{}) error {
2258	c.v = "called"
2259	return nil
2260}
2261
2262func TestGithubIssue431(t *testing.T) {
2263	doc := `key = "value"`
2264	var c Config
2265	if err := toml.Unmarshal([]byte(doc), &c); err != nil {
2266		t.Fatalf("unexpected error: %s", err)
2267	}
2268
2269	if c.Key != "value" {
2270		t.Errorf("expected c.Key='value', not '%s'", c.Key)
2271	}
2272
2273	if c.Obj.v == "called" {
2274		t.Errorf("UnmarshalTOML should not have been called")
2275	}
2276}
2277
2278type durationString struct {
2279	time.Duration
2280}
2281
2282func (d *durationString) UnmarshalTOML(v interface{}) error {
2283	d.Duration = 10 * time.Second
2284	return nil
2285}
2286
2287type config437Error struct{}
2288
2289func (e *config437Error) UnmarshalTOML(v interface{}) error {
2290	return errors.New("expected")
2291}
2292
2293type config437 struct {
2294	HTTP struct {
2295		PingTimeout durationString `toml:"PingTimeout"`
2296		ErrorField  config437Error
2297	} `toml:"HTTP"`
2298}
2299
2300func TestGithubIssue437(t *testing.T) {
2301	t.Skipf("unmarshalTOML not implemented")
2302	src := `
2303[HTTP]
2304PingTimeout = "32m"
2305`
2306	cfg := &config437{}
2307	cfg.HTTP.PingTimeout = durationString{time.Second}
2308
2309	err := toml.Unmarshal([]byte(src), cfg)
2310	if err != nil {
2311		t.Fatalf("unexpected errors %s", err)
2312	}
2313	expected := durationString{10 * time.Second}
2314	if cfg.HTTP.PingTimeout != expected {
2315		t.Fatalf("expected '%s', got '%s'", expected, cfg.HTTP.PingTimeout)
2316	}
2317}
2318
2319func TestLeafUnmarshalerError(t *testing.T) {
2320	src := `
2321[HTTP]
2322ErrorField = "foo"
2323`
2324	cfg := &config437{}
2325
2326	err := toml.Unmarshal([]byte(src), cfg)
2327	if err == nil {
2328		t.Fatalf("error was expected")
2329	}
2330}
2331