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