Giant blob of minor changes
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / github.com / !burnt!sushi / toml@v0.3.1 / decode_test.go
1 package toml
2
3 import (
4         "fmt"
5         "log"
6         "math"
7         "reflect"
8         "strings"
9         "testing"
10         "time"
11 )
12
13 func TestDecodeSimple(t *testing.T) {
14         var testSimple = `
15 age = 250
16 andrew = "gallant"
17 kait = "brady"
18 now = 1987-07-05T05:45:00Z
19 nowEast = 2017-06-22T16:15:21+08:00
20 nowWest = 2017-06-22T02:14:36-06:00
21 yesOrNo = true
22 pi = 3.14
23 colors = [
24         ["red", "green", "blue"],
25         ["cyan", "magenta", "yellow", "black"],
26 ]
27
28 [My.Cats]
29 plato = "cat 1"
30 cauchy = "cat 2"
31 `
32
33         type cats struct {
34                 Plato  string
35                 Cauchy string
36         }
37         type simple struct {
38                 Age     int
39                 Colors  [][]string
40                 Pi      float64
41                 YesOrNo bool
42                 Now     time.Time
43                 NowEast time.Time
44                 NowWest time.Time
45                 Andrew  string
46                 Kait    string
47                 My      map[string]cats
48         }
49
50         var val simple
51         _, err := Decode(testSimple, &val)
52         if err != nil {
53                 t.Fatal(err)
54         }
55
56         now, err := time.Parse("2006-01-02T15:04:05", "1987-07-05T05:45:00")
57         if err != nil {
58                 panic(err)
59         }
60         nowEast, err := time.Parse("2006-01-02T15:04:05-07:00", "2017-06-22T16:15:21+08:00")
61         if err != nil {
62                 panic(err)
63         }
64         nowWest, err := time.Parse("2006-01-02T15:04:05-07:00", "2017-06-22T02:14:36-06:00")
65         if err != nil {
66                 panic(err)
67         }
68         var answer = simple{
69                 Age:     250,
70                 Andrew:  "gallant",
71                 Kait:    "brady",
72                 Now:     now,
73                 NowEast: nowEast,
74                 NowWest: nowWest,
75                 YesOrNo: true,
76                 Pi:      3.14,
77                 Colors: [][]string{
78                         {"red", "green", "blue"},
79                         {"cyan", "magenta", "yellow", "black"},
80                 },
81                 My: map[string]cats{
82                         "Cats": {Plato: "cat 1", Cauchy: "cat 2"},
83                 },
84         }
85         if !reflect.DeepEqual(val, answer) {
86                 t.Fatalf("Expected\n-----\n%#v\n-----\nbut got\n-----\n%#v\n",
87                         answer, val)
88         }
89 }
90
91 func TestDecodeEmbedded(t *testing.T) {
92         type Dog struct{ Name string }
93         type Age int
94         type cat struct{ Name string }
95
96         for _, test := range []struct {
97                 label       string
98                 input       string
99                 decodeInto  interface{}
100                 wantDecoded interface{}
101         }{
102                 {
103                         label:       "embedded struct",
104                         input:       `Name = "milton"`,
105                         decodeInto:  &struct{ Dog }{},
106                         wantDecoded: &struct{ Dog }{Dog{"milton"}},
107                 },
108                 {
109                         label:       "embedded non-nil pointer to struct",
110                         input:       `Name = "milton"`,
111                         decodeInto:  &struct{ *Dog }{},
112                         wantDecoded: &struct{ *Dog }{&Dog{"milton"}},
113                 },
114                 {
115                         label:       "embedded nil pointer to struct",
116                         input:       ``,
117                         decodeInto:  &struct{ *Dog }{},
118                         wantDecoded: &struct{ *Dog }{nil},
119                 },
120                 {
121                         label:       "unexported embedded struct",
122                         input:       `Name = "socks"`,
123                         decodeInto:  &struct{ cat }{},
124                         wantDecoded: &struct{ cat }{cat{"socks"}},
125                 },
126                 {
127                         label:       "embedded int",
128                         input:       `Age = -5`,
129                         decodeInto:  &struct{ Age }{},
130                         wantDecoded: &struct{ Age }{-5},
131                 },
132         } {
133                 _, err := Decode(test.input, test.decodeInto)
134                 if err != nil {
135                         t.Fatal(err)
136                 }
137                 if !reflect.DeepEqual(test.wantDecoded, test.decodeInto) {
138                         t.Errorf("%s: want decoded == %+v, got %+v",
139                                 test.label, test.wantDecoded, test.decodeInto)
140                 }
141         }
142 }
143
144 func TestDecodeIgnoredFields(t *testing.T) {
145         type simple struct {
146                 Number int `toml:"-"`
147         }
148         const input = `
149 Number = 123
150 - = 234
151 `
152         var s simple
153         if _, err := Decode(input, &s); err != nil {
154                 t.Fatal(err)
155         }
156         if s.Number != 0 {
157                 t.Errorf("got: %d; want 0", s.Number)
158         }
159 }
160
161 func TestTableArrays(t *testing.T) {
162         var tomlTableArrays = `
163 [[albums]]
164 name = "Born to Run"
165
166   [[albums.songs]]
167   name = "Jungleland"
168
169   [[albums.songs]]
170   name = "Meeting Across the River"
171
172 [[albums]]
173 name = "Born in the USA"
174
175   [[albums.songs]]
176   name = "Glory Days"
177
178   [[albums.songs]]
179   name = "Dancing in the Dark"
180 `
181
182         type Song struct {
183                 Name string
184         }
185
186         type Album struct {
187                 Name  string
188                 Songs []Song
189         }
190
191         type Music struct {
192                 Albums []Album
193         }
194
195         expected := Music{[]Album{
196                 {"Born to Run", []Song{{"Jungleland"}, {"Meeting Across the River"}}},
197                 {"Born in the USA", []Song{{"Glory Days"}, {"Dancing in the Dark"}}},
198         }}
199         var got Music
200         if _, err := Decode(tomlTableArrays, &got); err != nil {
201                 t.Fatal(err)
202         }
203         if !reflect.DeepEqual(expected, got) {
204                 t.Fatalf("\n%#v\n!=\n%#v\n", expected, got)
205         }
206 }
207
208 func TestTableNesting(t *testing.T) {
209         for _, tt := range []struct {
210                 t    string
211                 want []string
212         }{
213                 {"[a.b.c]", []string{"a", "b", "c"}},
214                 {`[a."b.c"]`, []string{"a", "b.c"}},
215                 {`[a.'b.c']`, []string{"a", "b.c"}},
216                 {`[a.' b ']`, []string{"a", " b "}},
217                 {"[ d.e.f ]", []string{"d", "e", "f"}},
218                 {"[ g . h . i ]", []string{"g", "h", "i"}},
219                 {`[ j . "Êž" . 'l' ]`, []string{"j", "Êž", "l"}},
220         } {
221                 var m map[string]interface{}
222                 if _, err := Decode(tt.t, &m); err != nil {
223                         t.Errorf("Decode(%q): got error: %s", tt.t, err)
224                         continue
225                 }
226                 if keys := extractNestedKeys(m); !reflect.DeepEqual(keys, tt.want) {
227                         t.Errorf("Decode(%q): got nested keys %#v; want %#v",
228                                 tt.t, keys, tt.want)
229                 }
230         }
231 }
232
233 func extractNestedKeys(v map[string]interface{}) []string {
234         var result []string
235         for {
236                 if len(v) != 1 {
237                         return result
238                 }
239                 for k, m := range v {
240                         result = append(result, k)
241                         var ok bool
242                         v, ok = m.(map[string]interface{})
243                         if !ok {
244                                 return result
245                         }
246                 }
247
248         }
249 }
250
251 // Case insensitive matching tests.
252 // A bit more comprehensive than needed given the current implementation,
253 // but implementations change.
254 // Probably still missing demonstrations of some ugly corner cases regarding
255 // case insensitive matching and multiple fields.
256 func TestCase(t *testing.T) {
257         var caseToml = `
258 tOpString = "string"
259 tOpInt = 1
260 tOpFloat = 1.1
261 tOpBool = true
262 tOpdate = 2006-01-02T15:04:05Z
263 tOparray = [ "array" ]
264 Match = "i should be in Match only"
265 MatcH = "i should be in MatcH only"
266 once = "just once"
267 [nEst.eD]
268 nEstedString = "another string"
269 `
270
271         type InsensitiveEd struct {
272                 NestedString string
273         }
274
275         type InsensitiveNest struct {
276                 Ed InsensitiveEd
277         }
278
279         type Insensitive struct {
280                 TopString string
281                 TopInt    int
282                 TopFloat  float64
283                 TopBool   bool
284                 TopDate   time.Time
285                 TopArray  []string
286                 Match     string
287                 MatcH     string
288                 Once      string
289                 OncE      string
290                 Nest      InsensitiveNest
291         }
292
293         tme, err := time.Parse(time.RFC3339, time.RFC3339[:len(time.RFC3339)-5])
294         if err != nil {
295                 panic(err)
296         }
297         expected := Insensitive{
298                 TopString: "string",
299                 TopInt:    1,
300                 TopFloat:  1.1,
301                 TopBool:   true,
302                 TopDate:   tme,
303                 TopArray:  []string{"array"},
304                 MatcH:     "i should be in MatcH only",
305                 Match:     "i should be in Match only",
306                 Once:      "just once",
307                 OncE:      "",
308                 Nest: InsensitiveNest{
309                         Ed: InsensitiveEd{NestedString: "another string"},
310                 },
311         }
312         var got Insensitive
313         if _, err := Decode(caseToml, &got); err != nil {
314                 t.Fatal(err)
315         }
316         if !reflect.DeepEqual(expected, got) {
317                 t.Fatalf("\n%#v\n!=\n%#v\n", expected, got)
318         }
319 }
320
321 func TestPointers(t *testing.T) {
322         type Object struct {
323                 Type        string
324                 Description string
325         }
326
327         type Dict struct {
328                 NamedObject map[string]*Object
329                 BaseObject  *Object
330                 Strptr      *string
331                 Strptrs     []*string
332         }
333         s1, s2, s3 := "blah", "abc", "def"
334         expected := &Dict{
335                 Strptr:  &s1,
336                 Strptrs: []*string{&s2, &s3},
337                 NamedObject: map[string]*Object{
338                         "foo": {"FOO", "fooooo!!!"},
339                         "bar": {"BAR", "ba-ba-ba-ba-barrrr!!!"},
340                 },
341                 BaseObject: &Object{"BASE", "da base"},
342         }
343
344         ex1 := `
345 Strptr = "blah"
346 Strptrs = ["abc", "def"]
347
348 [NamedObject.foo]
349 Type = "FOO"
350 Description = "fooooo!!!"
351
352 [NamedObject.bar]
353 Type = "BAR"
354 Description = "ba-ba-ba-ba-barrrr!!!"
355
356 [BaseObject]
357 Type = "BASE"
358 Description = "da base"
359 `
360         dict := new(Dict)
361         _, err := Decode(ex1, dict)
362         if err != nil {
363                 t.Errorf("Decode error: %v", err)
364         }
365         if !reflect.DeepEqual(expected, dict) {
366                 t.Fatalf("\n%#v\n!=\n%#v\n", expected, dict)
367         }
368 }
369
370 func TestDecodeDatetime(t *testing.T) {
371         const noTimestamp = "2006-01-02T15:04:05"
372         for _, tt := range []struct {
373                 s      string
374                 t      string
375                 format string
376         }{
377                 {"1979-05-27T07:32:00Z", "1979-05-27T07:32:00Z", time.RFC3339},
378                 {"1979-05-27T00:32:00-07:00", "1979-05-27T00:32:00-07:00", time.RFC3339},
379                 {
380                         "1979-05-27T00:32:00.999999-07:00",
381                         "1979-05-27T00:32:00.999999-07:00",
382                         time.RFC3339,
383                 },
384                 {"1979-05-27T07:32:00", "1979-05-27T07:32:00", noTimestamp},
385                 {
386                         "1979-05-27T00:32:00.999999",
387                         "1979-05-27T00:32:00.999999",
388                         noTimestamp,
389                 },
390                 {"1979-05-27", "1979-05-27T00:00:00", noTimestamp},
391         } {
392                 var x struct{ D time.Time }
393                 input := "d = " + tt.s
394                 if _, err := Decode(input, &x); err != nil {
395                         t.Errorf("Decode(%q): got error: %s", input, err)
396                         continue
397                 }
398                 want, err := time.ParseInLocation(tt.format, tt.t, time.Local)
399                 if err != nil {
400                         panic(err)
401                 }
402                 if !x.D.Equal(want) {
403                         t.Errorf("Decode(%q): got %s; want %s", input, x.D, want)
404                 }
405         }
406 }
407
408 func TestDecodeBadDatetime(t *testing.T) {
409         var x struct{ T time.Time }
410         for _, s := range []string{
411                 "123",
412                 "2006-01-50T00:00:00Z",
413                 "2006-01-30T00:00",
414                 "2006-01-30T",
415         } {
416                 input := "T = " + s
417                 if _, err := Decode(input, &x); err == nil {
418                         t.Errorf("Expected invalid DateTime error for %q", s)
419                 }
420         }
421 }
422
423 func TestDecodeMultilineStrings(t *testing.T) {
424         var x struct {
425                 S string
426         }
427         const s0 = `s = """
428 a b \n c
429 d e f
430 """`
431         if _, err := Decode(s0, &x); err != nil {
432                 t.Fatal(err)
433         }
434         if want := "a b \n c\nd e f\n"; x.S != want {
435                 t.Errorf("got: %q; want: %q", x.S, want)
436         }
437         const s1 = `s = """a b c\
438 """`
439         if _, err := Decode(s1, &x); err != nil {
440                 t.Fatal(err)
441         }
442         if want := "a b c"; x.S != want {
443                 t.Errorf("got: %q; want: %q", x.S, want)
444         }
445 }
446
447 type sphere struct {
448         Center [3]float64
449         Radius float64
450 }
451
452 func TestDecodeSimpleArray(t *testing.T) {
453         var s1 sphere
454         if _, err := Decode(`center = [0.0, 1.5, 0.0]`, &s1); err != nil {
455                 t.Fatal(err)
456         }
457 }
458
459 func TestDecodeArrayWrongSize(t *testing.T) {
460         var s1 sphere
461         if _, err := Decode(`center = [0.1, 2.3]`, &s1); err == nil {
462                 t.Fatal("Expected array type mismatch error")
463         }
464 }
465
466 func TestDecodeLargeIntoSmallInt(t *testing.T) {
467         type table struct {
468                 Value int8
469         }
470         var tab table
471         if _, err := Decode(`value = 500`, &tab); err == nil {
472                 t.Fatal("Expected integer out-of-bounds error.")
473         }
474 }
475
476 func TestDecodeSizedInts(t *testing.T) {
477         type table struct {
478                 U8  uint8
479                 U16 uint16
480                 U32 uint32
481                 U64 uint64
482                 U   uint
483                 I8  int8
484                 I16 int16
485                 I32 int32
486                 I64 int64
487                 I   int
488         }
489         answer := table{1, 1, 1, 1, 1, -1, -1, -1, -1, -1}
490         toml := `
491         u8 = 1
492         u16 = 1
493         u32 = 1
494         u64 = 1
495         u = 1
496         i8 = -1
497         i16 = -1
498         i32 = -1
499         i64 = -1
500         i = -1
501         `
502         var tab table
503         if _, err := Decode(toml, &tab); err != nil {
504                 t.Fatal(err.Error())
505         }
506         if answer != tab {
507                 t.Fatalf("Expected %#v but got %#v", answer, tab)
508         }
509 }
510
511 func TestDecodeInts(t *testing.T) {
512         for _, tt := range []struct {
513                 s    string
514                 want int64
515         }{
516                 {"0", 0},
517                 {"+99", 99},
518                 {"-10", -10},
519                 {"1_234_567", 1234567},
520                 {"1_2_3_4", 1234},
521                 {"-9_223_372_036_854_775_808", math.MinInt64},
522                 {"9_223_372_036_854_775_807", math.MaxInt64},
523         } {
524                 var x struct{ N int64 }
525                 input := "n = " + tt.s
526                 if _, err := Decode(input, &x); err != nil {
527                         t.Errorf("Decode(%q): got error: %s", input, err)
528                         continue
529                 }
530                 if x.N != tt.want {
531                         t.Errorf("Decode(%q): got %d; want %d", input, x.N, tt.want)
532                 }
533         }
534 }
535
536 func TestDecodeFloats(t *testing.T) {
537         for _, tt := range []struct {
538                 s    string
539                 want float64
540         }{
541                 {"+1.0", 1},
542                 {"3.1415", 3.1415},
543                 {"-0.01", -0.01},
544                 {"5e+22", 5e22},
545                 {"1e6", 1e6},
546                 {"-2E-2", -2e-2},
547                 {"6.626e-34", 6.626e-34},
548                 {"9_224_617.445_991_228_313", 9224617.445991228313},
549                 {"9_876.54_32e1_0", 9876.5432e10},
550         } {
551                 var x struct{ N float64 }
552                 input := "n = " + tt.s
553                 if _, err := Decode(input, &x); err != nil {
554                         t.Errorf("Decode(%q): got error: %s", input, err)
555                         continue
556                 }
557                 if x.N != tt.want {
558                         t.Errorf("Decode(%q): got %f; want %f", input, x.N, tt.want)
559                 }
560         }
561 }
562
563 func TestDecodeMalformedNumbers(t *testing.T) {
564         for _, tt := range []struct {
565                 s    string
566                 want string
567         }{
568                 {"++99", "expected a digit"},
569                 {"0..1", "must be followed by one or more digits"},
570                 {"0.1.2", "Invalid float value"},
571                 {"1e2.3", "Invalid float value"},
572                 {"1e2e3", "Invalid float value"},
573                 {"_123", "expected value"},
574                 {"123_", "surrounded by digits"},
575                 {"1._23", "surrounded by digits"},
576                 {"1e__23", "surrounded by digits"},
577                 {"123.", "must be followed by one or more digits"},
578                 {"1.e2", "must be followed by one or more digits"},
579         } {
580                 var x struct{ N interface{} }
581                 input := "n = " + tt.s
582                 _, err := Decode(input, &x)
583                 if err == nil {
584                         t.Errorf("Decode(%q): got nil, want error containing %q",
585                                 input, tt.want)
586                         continue
587                 }
588                 if !strings.Contains(err.Error(), tt.want) {
589                         t.Errorf("Decode(%q): got %q, want error containing %q",
590                                 input, err, tt.want)
591                 }
592         }
593 }
594
595 func TestDecodeBadValues(t *testing.T) {
596         for _, tt := range []struct {
597                 v    interface{}
598                 want string
599         }{
600                 {3, "non-pointer int"},
601                 {(*int)(nil), "nil"},
602         } {
603                 _, err := Decode(`x = 3`, tt.v)
604                 if err == nil {
605                         t.Errorf("Decode(%v): got nil; want error containing %q",
606                                 tt.v, tt.want)
607                         continue
608                 }
609                 if !strings.Contains(err.Error(), tt.want) {
610                         t.Errorf("Decode(%v): got %q; want error containing %q",
611                                 tt.v, err, tt.want)
612                 }
613         }
614 }
615
616 func TestUnmarshaler(t *testing.T) {
617
618         var tomlBlob = `
619 [dishes.hamboogie]
620 name = "Hamboogie with fries"
621 price = 10.99
622
623 [[dishes.hamboogie.ingredients]]
624 name = "Bread Bun"
625
626 [[dishes.hamboogie.ingredients]]
627 name = "Lettuce"
628
629 [[dishes.hamboogie.ingredients]]
630 name = "Real Beef Patty"
631
632 [[dishes.hamboogie.ingredients]]
633 name = "Tomato"
634
635 [dishes.eggsalad]
636 name = "Egg Salad with rice"
637 price = 3.99
638
639 [[dishes.eggsalad.ingredients]]
640 name = "Egg"
641
642 [[dishes.eggsalad.ingredients]]
643 name = "Mayo"
644
645 [[dishes.eggsalad.ingredients]]
646 name = "Rice"
647 `
648         m := &menu{}
649         if _, err := Decode(tomlBlob, m); err != nil {
650                 t.Fatal(err)
651         }
652
653         if len(m.Dishes) != 2 {
654                 t.Log("two dishes should be loaded with UnmarshalTOML()")
655                 t.Errorf("expected %d but got %d", 2, len(m.Dishes))
656         }
657
658         eggSalad := m.Dishes["eggsalad"]
659         if _, ok := interface{}(eggSalad).(dish); !ok {
660                 t.Errorf("expected a dish")
661         }
662
663         if eggSalad.Name != "Egg Salad with rice" {
664                 t.Errorf("expected the dish to be named 'Egg Salad with rice'")
665         }
666
667         if len(eggSalad.Ingredients) != 3 {
668                 t.Log("dish should be loaded with UnmarshalTOML()")
669                 t.Errorf("expected %d but got %d", 3, len(eggSalad.Ingredients))
670         }
671
672         found := false
673         for _, i := range eggSalad.Ingredients {
674                 if i.Name == "Rice" {
675                         found = true
676                         break
677                 }
678         }
679         if !found {
680                 t.Error("Rice was not loaded in UnmarshalTOML()")
681         }
682
683         // test on a value - must be passed as *
684         o := menu{}
685         if _, err := Decode(tomlBlob, &o); err != nil {
686                 t.Fatal(err)
687         }
688
689 }
690
691 func TestDecodeInlineTable(t *testing.T) {
692         input := `
693 [CookieJar]
694 Types = {Chocolate = "yummy", Oatmeal = "best ever"}
695
696 [Seasons]
697 Locations = {NY = {Temp = "not cold", Rating = 4}, MI = {Temp = "freezing", Rating = 9}}
698 `
699         type cookieJar struct {
700                 Types map[string]string
701         }
702         type properties struct {
703                 Temp   string
704                 Rating int
705         }
706         type seasons struct {
707                 Locations map[string]properties
708         }
709         type wrapper struct {
710                 CookieJar cookieJar
711                 Seasons   seasons
712         }
713         var got wrapper
714
715         meta, err := Decode(input, &got)
716         if err != nil {
717                 t.Fatal(err)
718         }
719         want := wrapper{
720                 CookieJar: cookieJar{
721                         Types: map[string]string{
722                                 "Chocolate": "yummy",
723                                 "Oatmeal":   "best ever",
724                         },
725                 },
726                 Seasons: seasons{
727                         Locations: map[string]properties{
728                                 "NY": {
729                                         Temp:   "not cold",
730                                         Rating: 4,
731                                 },
732                                 "MI": {
733                                         Temp:   "freezing",
734                                         Rating: 9,
735                                 },
736                         },
737                 },
738         }
739         if !reflect.DeepEqual(got, want) {
740                 t.Fatalf("after decode, got:\n\n%#v\n\nwant:\n\n%#v", got, want)
741         }
742         if len(meta.keys) != 12 {
743                 t.Errorf("after decode, got %d meta keys; want 12", len(meta.keys))
744         }
745         if len(meta.types) != 12 {
746                 t.Errorf("after decode, got %d meta types; want 12", len(meta.types))
747         }
748 }
749
750 func TestDecodeInlineTableArray(t *testing.T) {
751         type point struct {
752                 X, Y, Z int
753         }
754         var got struct {
755                 Points []point
756         }
757         // Example inline table array from the spec.
758         const in = `
759 points = [ { x = 1, y = 2, z = 3 },
760            { x = 7, y = 8, z = 9 },
761            { x = 2, y = 4, z = 8 } ]
762
763 `
764         if _, err := Decode(in, &got); err != nil {
765                 t.Fatal(err)
766         }
767         want := []point{
768                 {X: 1, Y: 2, Z: 3},
769                 {X: 7, Y: 8, Z: 9},
770                 {X: 2, Y: 4, Z: 8},
771         }
772         if !reflect.DeepEqual(got.Points, want) {
773                 t.Errorf("got %#v; want %#v", got.Points, want)
774         }
775 }
776
777 func TestDecodeMalformedInlineTable(t *testing.T) {
778         for _, tt := range []struct {
779                 s    string
780                 want string
781         }{
782                 {"{,}", "unexpected comma"},
783                 {"{x = 3 y = 4}", "expected a comma or an inline table terminator"},
784                 {"{x=3,,y=4}", "unexpected comma"},
785                 {"{x=3,\ny=4}", "newlines not allowed"},
786                 {"{x=3\n,y=4}", "newlines not allowed"},
787         } {
788                 var x struct{ A map[string]int }
789                 input := "a = " + tt.s
790                 _, err := Decode(input, &x)
791                 if err == nil {
792                         t.Errorf("Decode(%q): got nil, want error containing %q",
793                                 input, tt.want)
794                         continue
795                 }
796                 if !strings.Contains(err.Error(), tt.want) {
797                         t.Errorf("Decode(%q): got %q, want error containing %q",
798                                 input, err, tt.want)
799                 }
800         }
801 }
802
803 type menu struct {
804         Dishes map[string]dish
805 }
806
807 func (m *menu) UnmarshalTOML(p interface{}) error {
808         m.Dishes = make(map[string]dish)
809         data, _ := p.(map[string]interface{})
810         dishes := data["dishes"].(map[string]interface{})
811         for n, v := range dishes {
812                 if d, ok := v.(map[string]interface{}); ok {
813                         nd := dish{}
814                         nd.UnmarshalTOML(d)
815                         m.Dishes[n] = nd
816                 } else {
817                         return fmt.Errorf("not a dish")
818                 }
819         }
820         return nil
821 }
822
823 type dish struct {
824         Name        string
825         Price       float32
826         Ingredients []ingredient
827 }
828
829 func (d *dish) UnmarshalTOML(p interface{}) error {
830         data, _ := p.(map[string]interface{})
831         d.Name, _ = data["name"].(string)
832         d.Price, _ = data["price"].(float32)
833         ingredients, _ := data["ingredients"].([]map[string]interface{})
834         for _, e := range ingredients {
835                 n, _ := interface{}(e).(map[string]interface{})
836                 name, _ := n["name"].(string)
837                 i := ingredient{name}
838                 d.Ingredients = append(d.Ingredients, i)
839         }
840         return nil
841 }
842
843 type ingredient struct {
844         Name string
845 }
846
847 func TestDecodeSlices(t *testing.T) {
848         type T struct {
849                 S []string
850         }
851         for i, tt := range []struct {
852                 v     T
853                 input string
854                 want  T
855         }{
856                 {T{}, "", T{}},
857                 {T{[]string{}}, "", T{[]string{}}},
858                 {T{[]string{"a", "b"}}, "", T{[]string{"a", "b"}}},
859                 {T{}, "S = []", T{[]string{}}},
860                 {T{[]string{}}, "S = []", T{[]string{}}},
861                 {T{[]string{"a", "b"}}, "S = []", T{[]string{}}},
862                 {T{}, `S = ["x"]`, T{[]string{"x"}}},
863                 {T{[]string{}}, `S = ["x"]`, T{[]string{"x"}}},
864                 {T{[]string{"a", "b"}}, `S = ["x"]`, T{[]string{"x"}}},
865         } {
866                 if _, err := Decode(tt.input, &tt.v); err != nil {
867                         t.Errorf("[%d] %s", i, err)
868                         continue
869                 }
870                 if !reflect.DeepEqual(tt.v, tt.want) {
871                         t.Errorf("[%d] got %#v; want %#v", i, tt.v, tt.want)
872                 }
873         }
874 }
875
876 func TestDecodePrimitive(t *testing.T) {
877         type S struct {
878                 P Primitive
879         }
880         type T struct {
881                 S []int
882         }
883         slicep := func(s []int) *[]int { return &s }
884         arrayp := func(a [2]int) *[2]int { return &a }
885         mapp := func(m map[string]int) *map[string]int { return &m }
886         for i, tt := range []struct {
887                 v     interface{}
888                 input string
889                 want  interface{}
890         }{
891                 // slices
892                 {slicep(nil), "", slicep(nil)},
893                 {slicep([]int{}), "", slicep([]int{})},
894                 {slicep([]int{1, 2, 3}), "", slicep([]int{1, 2, 3})},
895                 {slicep(nil), "P = [1,2]", slicep([]int{1, 2})},
896                 {slicep([]int{}), "P = [1,2]", slicep([]int{1, 2})},
897                 {slicep([]int{1, 2, 3}), "P = [1,2]", slicep([]int{1, 2})},
898
899                 // arrays
900                 {arrayp([2]int{2, 3}), "", arrayp([2]int{2, 3})},
901                 {arrayp([2]int{2, 3}), "P = [3,4]", arrayp([2]int{3, 4})},
902
903                 // maps
904                 {mapp(nil), "", mapp(nil)},
905                 {mapp(map[string]int{}), "", mapp(map[string]int{})},
906                 {mapp(map[string]int{"a": 1}), "", mapp(map[string]int{"a": 1})},
907                 {mapp(nil), "[P]\na = 2", mapp(map[string]int{"a": 2})},
908                 {mapp(map[string]int{}), "[P]\na = 2", mapp(map[string]int{"a": 2})},
909                 {mapp(map[string]int{"a": 1, "b": 3}), "[P]\na = 2", mapp(map[string]int{"a": 2, "b": 3})},
910
911                 // structs
912                 {&T{nil}, "[P]", &T{nil}},
913                 {&T{[]int{}}, "[P]", &T{[]int{}}},
914                 {&T{[]int{1, 2, 3}}, "[P]", &T{[]int{1, 2, 3}}},
915                 {&T{nil}, "[P]\nS = [1,2]", &T{[]int{1, 2}}},
916                 {&T{[]int{}}, "[P]\nS = [1,2]", &T{[]int{1, 2}}},
917                 {&T{[]int{1, 2, 3}}, "[P]\nS = [1,2]", &T{[]int{1, 2}}},
918         } {
919                 var s S
920                 md, err := Decode(tt.input, &s)
921                 if err != nil {
922                         t.Errorf("[%d] Decode error: %s", i, err)
923                         continue
924                 }
925                 if err := md.PrimitiveDecode(s.P, tt.v); err != nil {
926                         t.Errorf("[%d] PrimitiveDecode error: %s", i, err)
927                         continue
928                 }
929                 if !reflect.DeepEqual(tt.v, tt.want) {
930                         t.Errorf("[%d] got %#v; want %#v", i, tt.v, tt.want)
931                 }
932         }
933 }
934
935 func TestDecodeErrors(t *testing.T) {
936         for _, s := range []string{
937                 `x="`,
938                 `x='`,
939                 `x='''`,
940
941                 // Cases found by fuzzing in
942                 // https://github.com/BurntSushi/toml/issues/155.
943                 `""�`,   // used to panic with index out of range
944                 `e="""`, // used to hang
945         } {
946                 var x struct{}
947                 _, err := Decode(s, &x)
948                 if err == nil {
949                         t.Errorf("Decode(%q): got nil error", s)
950                 }
951         }
952 }
953
954 // Test for https://github.com/BurntSushi/toml/pull/166.
955 func TestDecodeBoolArray(t *testing.T) {
956         for _, tt := range []struct {
957                 s    string
958                 got  interface{}
959                 want interface{}
960         }{
961                 {
962                         "a = [true, false]",
963                         &struct{ A []bool }{},
964                         &struct{ A []bool }{[]bool{true, false}},
965                 },
966                 {
967                         "a = {a = true, b = false}",
968                         &struct{ A map[string]bool }{},
969                         &struct{ A map[string]bool }{map[string]bool{"a": true, "b": false}},
970                 },
971         } {
972                 if _, err := Decode(tt.s, tt.got); err != nil {
973                         t.Errorf("Decode(%q): %s", tt.s, err)
974                         continue
975                 }
976                 if !reflect.DeepEqual(tt.got, tt.want) {
977                         t.Errorf("Decode(%q): got %#v; want %#v", tt.s, tt.got, tt.want)
978                 }
979         }
980 }
981
982 func ExampleMetaData_PrimitiveDecode() {
983         var md MetaData
984         var err error
985
986         var tomlBlob = `
987 ranking = ["Springsteen", "J Geils"]
988
989 [bands.Springsteen]
990 started = 1973
991 albums = ["Greetings", "WIESS", "Born to Run", "Darkness"]
992
993 [bands."J Geils"]
994 started = 1970
995 albums = ["The J. Geils Band", "Full House", "Blow Your Face Out"]
996 `
997
998         type band struct {
999                 Started int
1000                 Albums  []string
1001         }
1002         type classics struct {
1003                 Ranking []string
1004                 Bands   map[string]Primitive
1005         }
1006
1007         // Do the initial decode. Reflection is delayed on Primitive values.
1008         var music classics
1009         if md, err = Decode(tomlBlob, &music); err != nil {
1010                 log.Fatal(err)
1011         }
1012
1013         // MetaData still includes information on Primitive values.
1014         fmt.Printf("Is `bands.Springsteen` defined? %v\n",
1015                 md.IsDefined("bands", "Springsteen"))
1016
1017         // Decode primitive data into Go values.
1018         for _, artist := range music.Ranking {
1019                 // A band is a primitive value, so we need to decode it to get a
1020                 // real `band` value.
1021                 primValue := music.Bands[artist]
1022
1023                 var aBand band
1024                 if err = md.PrimitiveDecode(primValue, &aBand); err != nil {
1025                         log.Fatal(err)
1026                 }
1027                 fmt.Printf("%s started in %d.\n", artist, aBand.Started)
1028         }
1029         // Check to see if there were any fields left undecoded.
1030         // Note that this won't be empty before decoding the Primitive value!
1031         fmt.Printf("Undecoded: %q\n", md.Undecoded())
1032
1033         // Output:
1034         // Is `bands.Springsteen` defined? true
1035         // Springsteen started in 1973.
1036         // J Geils started in 1970.
1037         // Undecoded: []
1038 }
1039
1040 func ExampleDecode() {
1041         var tomlBlob = `
1042 # Some comments.
1043 [alpha]
1044 ip = "10.0.0.1"
1045
1046         [alpha.config]
1047         Ports = [ 8001, 8002 ]
1048         Location = "Toronto"
1049         Created = 1987-07-05T05:45:00Z
1050
1051 [beta]
1052 ip = "10.0.0.2"
1053
1054         [beta.config]
1055         Ports = [ 9001, 9002 ]
1056         Location = "New Jersey"
1057         Created = 1887-01-05T05:55:00Z
1058 `
1059
1060         type serverConfig struct {
1061                 Ports    []int
1062                 Location string
1063                 Created  time.Time
1064         }
1065
1066         type server struct {
1067                 IP     string       `toml:"ip,omitempty"`
1068                 Config serverConfig `toml:"config"`
1069         }
1070
1071         type servers map[string]server
1072
1073         var config servers
1074         if _, err := Decode(tomlBlob, &config); err != nil {
1075                 log.Fatal(err)
1076         }
1077
1078         for _, name := range []string{"alpha", "beta"} {
1079                 s := config[name]
1080                 fmt.Printf("Server: %s (ip: %s) in %s created on %s\n",
1081                         name, s.IP, s.Config.Location,
1082                         s.Config.Created.Format("2006-01-02"))
1083                 fmt.Printf("Ports: %v\n", s.Config.Ports)
1084         }
1085
1086         // Output:
1087         // Server: alpha (ip: 10.0.0.1) in Toronto created on 1987-07-05
1088         // Ports: [8001 8002]
1089         // Server: beta (ip: 10.0.0.2) in New Jersey created on 1887-01-05
1090         // Ports: [9001 9002]
1091 }
1092
1093 type duration struct {
1094         time.Duration
1095 }
1096
1097 func (d *duration) UnmarshalText(text []byte) error {
1098         var err error
1099         d.Duration, err = time.ParseDuration(string(text))
1100         return err
1101 }
1102
1103 // Example Unmarshaler shows how to decode TOML strings into your own
1104 // custom data type.
1105 func Example_unmarshaler() {
1106         blob := `
1107 [[song]]
1108 name = "Thunder Road"
1109 duration = "4m49s"
1110
1111 [[song]]
1112 name = "Stairway to Heaven"
1113 duration = "8m03s"
1114 `
1115         type song struct {
1116                 Name     string
1117                 Duration duration
1118         }
1119         type songs struct {
1120                 Song []song
1121         }
1122         var favorites songs
1123         if _, err := Decode(blob, &favorites); err != nil {
1124                 log.Fatal(err)
1125         }
1126
1127         // Code to implement the TextUnmarshaler interface for `duration`:
1128         //
1129         // type duration struct {
1130         //      time.Duration
1131         // }
1132         //
1133         // func (d *duration) UnmarshalText(text []byte) error {
1134         //      var err error
1135         //      d.Duration, err = time.ParseDuration(string(text))
1136         //      return err
1137         // }
1138
1139         for _, s := range favorites.Song {
1140                 fmt.Printf("%s (%s)\n", s.Name, s.Duration)
1141         }
1142         // Output:
1143         // Thunder Road (4m49s)
1144         // Stairway to Heaven (8m3s)
1145 }
1146
1147 // Example StrictDecoding shows how to detect whether there are keys in the
1148 // TOML document that weren't decoded into the value given. This is useful
1149 // for returning an error to the user if they've included extraneous fields
1150 // in their configuration.
1151 func Example_strictDecoding() {
1152         var blob = `
1153 key1 = "value1"
1154 key2 = "value2"
1155 key3 = "value3"
1156 `
1157         type config struct {
1158                 Key1 string
1159                 Key3 string
1160         }
1161
1162         var conf config
1163         md, err := Decode(blob, &conf)
1164         if err != nil {
1165                 log.Fatal(err)
1166         }
1167         fmt.Printf("Undecoded keys: %q\n", md.Undecoded())
1168         // Output:
1169         // Undecoded keys: ["key2"]
1170 }
1171
1172 // Example UnmarshalTOML shows how to implement a struct type that knows how to
1173 // unmarshal itself. The struct must take full responsibility for mapping the
1174 // values passed into the struct. The method may be used with interfaces in a
1175 // struct in cases where the actual type is not known until the data is
1176 // examined.
1177 func Example_unmarshalTOML() {
1178
1179         var blob = `
1180 [[parts]]
1181 type = "valve"
1182 id = "valve-1"
1183 size = 1.2
1184 rating = 4
1185
1186 [[parts]]
1187 type = "valve"
1188 id = "valve-2"
1189 size = 2.1
1190 rating = 5
1191
1192 [[parts]]
1193 type = "pipe"
1194 id = "pipe-1"
1195 length = 2.1
1196 diameter = 12
1197
1198 [[parts]]
1199 type = "cable"
1200 id = "cable-1"
1201 length = 12
1202 rating = 3.1
1203 `
1204         o := &order{}
1205         err := Unmarshal([]byte(blob), o)
1206         if err != nil {
1207                 log.Fatal(err)
1208         }
1209
1210         fmt.Println(len(o.parts))
1211
1212         for _, part := range o.parts {
1213                 fmt.Println(part.Name())
1214         }
1215
1216         // Code to implement UmarshalJSON.
1217
1218         // type order struct {
1219         //      // NOTE `order.parts` is a private slice of type `part` which is an
1220         //      // interface and may only be loaded from toml using the
1221         //      // UnmarshalTOML() method of the Umarshaler interface.
1222         //      parts parts
1223         // }
1224
1225         // func (o *order) UnmarshalTOML(data interface{}) error {
1226
1227         //      // NOTE the example below contains detailed type casting to show how
1228         //      // the 'data' is retrieved. In operational use, a type cast wrapper
1229         //      // may be preferred e.g.
1230         //      //
1231         //      // func AsMap(v interface{}) (map[string]interface{}, error) {
1232         //      //              return v.(map[string]interface{})
1233         //      // }
1234         //      //
1235         //      // resulting in:
1236         //      // d, _ := AsMap(data)
1237         //      //
1238
1239         //      d, _ := data.(map[string]interface{})
1240         //      parts, _ := d["parts"].([]map[string]interface{})
1241
1242         //      for _, p := range parts {
1243
1244         //              typ, _ := p["type"].(string)
1245         //              id, _ := p["id"].(string)
1246
1247         //              // detect the type of part and handle each case
1248         //              switch p["type"] {
1249         //              case "valve":
1250
1251         //                      size := float32(p["size"].(float64))
1252         //                      rating := int(p["rating"].(int64))
1253
1254         //                      valve := &valve{
1255         //                              Type:   typ,
1256         //                              ID:     id,
1257         //                              Size:   size,
1258         //                              Rating: rating,
1259         //                      }
1260
1261         //                      o.parts = append(o.parts, valve)
1262
1263         //              case "pipe":
1264
1265         //                      length := float32(p["length"].(float64))
1266         //                      diameter := int(p["diameter"].(int64))
1267
1268         //                      pipe := &pipe{
1269         //                              Type:     typ,
1270         //                              ID:       id,
1271         //                              Length:   length,
1272         //                              Diameter: diameter,
1273         //                      }
1274
1275         //                      o.parts = append(o.parts, pipe)
1276
1277         //              case "cable":
1278
1279         //                      length := int(p["length"].(int64))
1280         //                      rating := float32(p["rating"].(float64))
1281
1282         //                      cable := &cable{
1283         //                              Type:   typ,
1284         //                              ID:     id,
1285         //                              Length: length,
1286         //                              Rating: rating,
1287         //                      }
1288
1289         //                      o.parts = append(o.parts, cable)
1290
1291         //              }
1292         //      }
1293
1294         //      return nil
1295         // }
1296
1297         // type parts []part
1298
1299         // type part interface {
1300         //      Name() string
1301         // }
1302
1303         // type valve struct {
1304         //      Type   string
1305         //      ID     string
1306         //      Size   float32
1307         //      Rating int
1308         // }
1309
1310         // func (v *valve) Name() string {
1311         //      return fmt.Sprintf("VALVE: %s", v.ID)
1312         // }
1313
1314         // type pipe struct {
1315         //      Type     string
1316         //      ID       string
1317         //      Length   float32
1318         //      Diameter int
1319         // }
1320
1321         // func (p *pipe) Name() string {
1322         //      return fmt.Sprintf("PIPE: %s", p.ID)
1323         // }
1324
1325         // type cable struct {
1326         //      Type   string
1327         //      ID     string
1328         //      Length int
1329         //      Rating float32
1330         // }
1331
1332         // func (c *cable) Name() string {
1333         //      return fmt.Sprintf("CABLE: %s", c.ID)
1334         // }
1335
1336         // Output:
1337         // 4
1338         // VALVE: valve-1
1339         // VALVE: valve-2
1340         // PIPE: pipe-1
1341         // CABLE: cable-1
1342
1343 }
1344
1345 type order struct {
1346         // NOTE `order.parts` is a private slice of type `part` which is an
1347         // interface and may only be loaded from toml using the UnmarshalTOML()
1348         // method of the Umarshaler interface.
1349         parts parts
1350 }
1351
1352 func (o *order) UnmarshalTOML(data interface{}) error {
1353
1354         // NOTE the example below contains detailed type casting to show how
1355         // the 'data' is retrieved. In operational use, a type cast wrapper
1356         // may be preferred e.g.
1357         //
1358         // func AsMap(v interface{}) (map[string]interface{}, error) {
1359         //              return v.(map[string]interface{})
1360         // }
1361         //
1362         // resulting in:
1363         // d, _ := AsMap(data)
1364         //
1365
1366         d, _ := data.(map[string]interface{})
1367         parts, _ := d["parts"].([]map[string]interface{})
1368
1369         for _, p := range parts {
1370
1371                 typ, _ := p["type"].(string)
1372                 id, _ := p["id"].(string)
1373
1374                 // detect the type of part and handle each case
1375                 switch p["type"] {
1376                 case "valve":
1377
1378                         size := float32(p["size"].(float64))
1379                         rating := int(p["rating"].(int64))
1380
1381                         valve := &valve{
1382                                 Type:   typ,
1383                                 ID:     id,
1384                                 Size:   size,
1385                                 Rating: rating,
1386                         }
1387
1388                         o.parts = append(o.parts, valve)
1389
1390                 case "pipe":
1391
1392                         length := float32(p["length"].(float64))
1393                         diameter := int(p["diameter"].(int64))
1394
1395                         pipe := &pipe{
1396                                 Type:     typ,
1397                                 ID:       id,
1398                                 Length:   length,
1399                                 Diameter: diameter,
1400                         }
1401
1402                         o.parts = append(o.parts, pipe)
1403
1404                 case "cable":
1405
1406                         length := int(p["length"].(int64))
1407                         rating := float32(p["rating"].(float64))
1408
1409                         cable := &cable{
1410                                 Type:   typ,
1411                                 ID:     id,
1412                                 Length: length,
1413                                 Rating: rating,
1414                         }
1415
1416                         o.parts = append(o.parts, cable)
1417
1418                 }
1419         }
1420
1421         return nil
1422 }
1423
1424 type parts []part
1425
1426 type part interface {
1427         Name() string
1428 }
1429
1430 type valve struct {
1431         Type   string
1432         ID     string
1433         Size   float32
1434         Rating int
1435 }
1436
1437 func (v *valve) Name() string {
1438         return fmt.Sprintf("VALVE: %s", v.ID)
1439 }
1440
1441 type pipe struct {
1442         Type     string
1443         ID       string
1444         Length   float32
1445         Diameter int
1446 }
1447
1448 func (p *pipe) Name() string {
1449         return fmt.Sprintf("PIPE: %s", p.ID)
1450 }
1451
1452 type cable struct {
1453         Type   string
1454         ID     string
1455         Length int
1456         Rating float32
1457 }
1458
1459 func (c *cable) Name() string {
1460         return fmt.Sprintf("CABLE: %s", c.ID)
1461 }