12 func TestEncodeRoundTrip(t *testing.T) {
24 []string{"one", "two", "three"},
28 net.ParseIP("192.168.59.254"),
31 var firstBuffer bytes.Buffer
32 e := NewEncoder(&firstBuffer)
33 err := e.Encode(inputs)
38 if _, err := Decode(firstBuffer.String(), &outputs); err != nil {
39 t.Logf("Could not decode:\n-----\n%s\n-----\n",
44 // could test each value individually, but I'm lazy
45 var secondBuffer bytes.Buffer
46 e2 := NewEncoder(&secondBuffer)
47 err = e2.Encode(outputs)
51 if firstBuffer.String() != secondBuffer.String() {
54 "\n\n is not identical to\n\n",
55 secondBuffer.String())
60 // I think these tests probably should be removed. They are good, but they
61 // ought to be obsolete by toml-test.
62 func TestEncode(t *testing.T) {
63 type Embedded struct {
68 date := time.Date(2014, 5, 11, 20, 30, 40, 0, time.FixedZone("IST", 3600))
69 dateStr := "2014-05-11T19:30:40Z"
71 tests := map[string]struct {
81 wantOutput: "BoolTrue = true\nBoolFalse = false\n",
91 wantOutput: "Int = 1\nInt8 = 2\nInt16 = 3\nInt32 = 4\nInt64 = 5\n",
101 wantOutput: "Uint = 1\nUint8 = 2\nUint16 = 3\nUint32 = 4" +
109 wantOutput: "Float32 = 1.5\nFloat64 = 2.5\n",
112 input: struct{ String string }{"foo"},
113 wantOutput: "String = \"foo\"\n",
115 "string field and unexported field": {
120 wantOutput: "String = \"foo\"\n",
122 "datetime field in UTC": {
123 input: struct{ Date time.Time }{date},
124 wantOutput: fmt.Sprintf("Date = %s\n", dateStr),
126 "datetime field as primitive": {
127 // Using a map here to fail if isStructOrMap() returns true for
129 input: map[string]interface{}{
133 wantOutput: fmt.Sprintf("Date = %s\nInt = 1\n", dateStr),
139 }{[0]int{}, [3]int{1, 2, 3}},
140 wantOutput: "IntArray0 = []\nIntArray3 = [1, 2, 3]\n",
143 input: struct{ IntSliceNil, IntSlice0, IntSlice3 []int }{
144 nil, []int{}, []int{1, 2, 3},
146 wantOutput: "IntSlice0 = []\nIntSlice3 = [1, 2, 3]\n",
149 input: struct{ DatetimeSlice []time.Time }{
150 []time.Time{date, date},
152 wantOutput: fmt.Sprintf("DatetimeSlice = [%s, %s]\n",
155 "nested arrays and slices": {
157 SliceOfArrays [][2]int
158 ArrayOfSlices [2][]int
159 SliceOfArraysOfSlices [][2][]int
160 ArrayOfSlicesOfArrays [2][][2]int
161 SliceOfMixedArrays [][2]interface{}
162 ArrayOfMixedSlices [2][]interface{}
164 [][2]int{{1, 2}, {3, 4}},
165 [2][]int{{1, 2}, {3, 4}},
189 wantOutput: `SliceOfArrays = [[1, 2], [3, 4]]
190 ArrayOfSlices = [[1, 2], [3, 4]]
191 SliceOfArraysOfSlices = [[[1, 2], [3, 4]], [[5, 6], [7, 8]]]
192 ArrayOfSlicesOfArrays = [[[1, 2], [3, 4]], [[5, 6], [7, 8]]]
193 SliceOfMixedArrays = [[1, 2], ["a", "b"]]
194 ArrayOfMixedSlices = [[1, 2], ["a", "b"]]
198 input: struct{ Empty []interface{} }{[]interface{}{}},
199 wantOutput: "Empty = []\n",
201 "(error) slice with element type mismatch (string and integer)": {
202 input: struct{ Mixed []interface{} }{[]interface{}{1, "a"}},
203 wantError: errArrayMixedElementTypes,
205 "(error) slice with element type mismatch (integer and float)": {
206 input: struct{ Mixed []interface{} }{[]interface{}{1, 2.5}},
207 wantError: errArrayMixedElementTypes,
209 "slice with elems of differing Go types, same TOML types": {
211 MixedInts []interface{}
212 MixedFloats []interface{}
215 int(1), int8(2), int16(3), int32(4), int64(5),
216 uint(1), uint8(2), uint16(3), uint32(4), uint64(5),
218 []interface{}{float32(1.5), float64(2.5)},
220 wantOutput: "MixedInts = [1, 2, 3, 4, 5, 1, 2, 3, 4, 5]\n" +
221 "MixedFloats = [1.5, 2.5]\n",
223 "(error) slice w/ element type mismatch (one is nested array)": {
224 input: struct{ Mixed []interface{} }{
225 []interface{}{1, []interface{}{2}},
227 wantError: errArrayMixedElementTypes,
229 "(error) slice with 1 nil element": {
230 input: struct{ NilElement1 []interface{} }{[]interface{}{nil}},
231 wantError: errArrayNilElement,
233 "(error) slice with 1 nil element (and other non-nil elements)": {
234 input: struct{ NilElement []interface{} }{
235 []interface{}{1, nil},
237 wantError: errArrayNilElement,
240 input: map[string]int{"a": 1, "b": 2},
241 wantOutput: "a = 1\nb = 2\n",
243 "map with interface{} value type": {
244 input: map[string]interface{}{"a": 1, "b": "c"},
245 wantOutput: "a = 1\nb = \"c\"\n",
247 "map with interface{} value type, some of which are structs": {
248 input: map[string]interface{}{
249 "a": struct{ Int int }{2},
252 wantOutput: "b = 1\n\n[a]\n Int = 2\n",
255 input: map[string]map[string]int{
259 wantOutput: "[a]\n b = 1\n\n[c]\n d = 2\n",
262 input: struct{ Struct struct{ Int int } }{
263 struct{ Int int }{1},
265 wantOutput: "[Struct]\n Int = 1\n",
267 "nested struct and non-struct field": {
269 Struct struct{ Int int }
271 }{struct{ Int int }{1}, true},
272 wantOutput: "Bool = true\n\n[Struct]\n Int = 1\n",
274 "2 nested structs": {
275 input: struct{ Struct1, Struct2 struct{ Int int } }{
276 struct{ Int int }{1}, struct{ Int int }{2},
278 wantOutput: "[Struct1]\n Int = 1\n\n[Struct2]\n Int = 2\n",
280 "deeply nested structs": {
282 Struct1, Struct2 struct{ Struct3 *struct{ Int int } }
284 struct{ Struct3 *struct{ Int int } }{&struct{ Int int }{1}},
285 struct{ Struct3 *struct{ Int int } }{nil},
287 wantOutput: "[Struct1]\n [Struct1.Struct3]\n Int = 1" +
290 "nested struct with nil struct elem": {
292 Struct struct{ Inner *struct{ Int int } }
294 struct{ Inner *struct{ Int int } }{nil},
296 wantOutput: "[Struct]\n",
298 "nested struct with no fields": {
300 Struct struct{ Inner struct{} }
302 struct{ Inner struct{} }{struct{}{}},
304 wantOutput: "[Struct]\n [Struct.Inner]\n",
306 "struct with tags": {
309 Int int `toml:"_int"`
311 Bool bool `toml:"_bool"`
314 Int int `toml:"_int"`
317 wantOutput: "_bool = true\n\n[_struct]\n _int = 1\n",
320 input: struct{ Embedded }{Embedded{1}},
321 wantOutput: "_int = 1\n",
323 "embedded *struct": {
324 input: struct{ *Embedded }{&Embedded{1}},
325 wantOutput: "_int = 1\n",
327 "nested embedded struct": {
329 Struct struct{ Embedded } `toml:"_struct"`
330 }{struct{ Embedded }{Embedded{1}}},
331 wantOutput: "[_struct]\n _int = 1\n",
333 "nested embedded *struct": {
335 Struct struct{ *Embedded } `toml:"_struct"`
336 }{struct{ *Embedded }{&Embedded{1}}},
337 wantOutput: "[_struct]\n _int = 1\n",
339 "embedded non-struct": {
340 input: struct{ NonStruct }{5},
341 wantOutput: "NonStruct = 5\n",
345 Structs []*struct{ Int int } `toml:"struct"`
347 []*struct{ Int int }{{1}, {3}},
349 wantOutput: "[[struct]]\n Int = 1\n\n[[struct]]\n Int = 3\n",
351 "array of tables order": {
352 input: map[string]interface{}{
353 "map": map[string]interface{}{
355 "arr": []map[string]int{
362 wantOutput: "[map]\n zero = 5\n\n [[map.arr]]\n friend = 5\n",
364 "(error) top-level slice": {
365 input: []struct{ Int int }{{1}, {2}, {3}},
368 "(error) slice of slice": {
370 Slices [][]struct{ Int int }
372 [][]struct{ Int int }{{{1}}, {{2}}, {{3}}},
374 wantError: errArrayNoTable,
376 "(error) map no string key": {
377 input: map[int]string{1: ""},
378 wantError: errNonString,
380 "(error) empty key name": {
381 input: map[string]int{"": 1},
382 wantError: errAnything,
384 "(error) empty map name": {
385 input: map[string]interface{}{
386 "": map[string]int{"v": 1},
388 wantError: errAnything,
391 for label, test := range tests {
392 encodeExpected(t, label, test.input, test.wantOutput, test.wantError)
396 func TestEncodeNestedTableArrays(t *testing.T) {
398 Name string `toml:"name"`
401 Name string `toml:"name"`
402 Songs []song `toml:"songs"`
404 type springsteen struct {
405 Albums []album `toml:"albums"`
407 value := springsteen{
410 []song{{"Jungleland"}, {"Meeting Across the River"}}},
412 []song{{"Glory Days"}, {"Dancing in the Dark"}}},
415 expected := `[[albums]]
422 name = "Meeting Across the River"
425 name = "Born in the USA"
431 name = "Dancing in the Dark"
433 encodeExpected(t, "nested table arrays", value, expected, nil)
436 func TestEncodeArrayHashWithNormalHashOrder(t *testing.T) {
454 expected := "V = 1\n\n[A]\n V = 2\n\n[[B]]\n V = 3\n"
455 encodeExpected(t, "array hash with normal hash order", val, expected, nil)
458 func TestEncodeWithOmitEmpty(t *testing.T) {
460 Bool bool `toml:"bool,omitempty"`
461 String string `toml:"string,omitempty"`
462 Array [0]byte `toml:"array,omitempty"`
463 Slice []int `toml:"slice,omitempty"`
464 Map map[string]string `toml:"map,omitempty"`
468 encodeExpected(t, "fields with omitempty are omitted when empty", v, "", nil)
472 Slice: []int{2, 3, 4},
473 Map: map[string]string{"foo": "bar"},
475 expected := `bool = true
482 encodeExpected(t, "fields with omitempty are not omitted when non-empty",
486 func TestEncodeWithOmitZero(t *testing.T) {
488 Number int `toml:"number,omitzero"`
489 Real float64 `toml:"real,omitzero"`
490 Unsigned uint `toml:"unsigned,omitzero"`
493 value := simple{0, 0.0, uint(0)}
496 encodeExpected(t, "simple with omitzero, all zero", value, expected, nil)
501 expected = `number = 10
505 encodeExpected(t, "simple with omitzero, non-zero", value, expected, nil)
508 func TestEncodeOmitemptyWithEmptyName(t *testing.T) {
510 S []int `toml:",omitempty"`
512 v := simple{[]int{1, 2, 3}}
513 expected := "S = [1, 2, 3]\n"
514 encodeExpected(t, "simple with omitempty, no name, non-empty field",
518 func TestEncodeAnonymousStruct(t *testing.T) {
519 type Inner struct{ N int }
520 type Outer0 struct{ Inner }
525 v0 := Outer0{Inner{3}}
526 expected := "N = 3\n"
527 encodeExpected(t, "embedded anonymous untagged struct", v0, expected, nil)
529 v1 := Outer1{Inner{3}}
530 expected = "[inner]\n N = 3\n"
531 encodeExpected(t, "embedded anonymous tagged struct", v1, expected, nil)
534 func TestEncodeAnonymousStructPointerField(t *testing.T) {
535 type Inner struct{ N int }
536 type Outer0 struct{ *Inner }
538 *Inner `toml:"inner"`
543 encodeExpected(t, "nil anonymous untagged struct pointer field", v0, expected, nil)
545 v0 = Outer0{&Inner{3}}
547 encodeExpected(t, "non-nil anonymous untagged struct pointer field", v0, expected, nil)
551 encodeExpected(t, "nil anonymous tagged struct pointer field", v1, expected, nil)
553 v1 = Outer1{&Inner{3}}
554 expected = "[inner]\n N = 3\n"
555 encodeExpected(t, "non-nil anonymous tagged struct pointer field", v1, expected, nil)
558 func TestEncodeIgnoredFields(t *testing.T) {
560 Number int `toml:"-"`
564 encodeExpected(t, "ignored field", value, expected, nil)
568 t *testing.T, label string, val interface{}, wantStr string, wantErr error,
571 enc := NewEncoder(&buf)
572 err := enc.Encode(val)
575 if wantErr == errAnything && err != nil {
578 t.Errorf("%s: want Encode error %v, got %v", label, wantErr, err)
580 t.Errorf("%s: Encode failed: %s", label, err)
586 if got := buf.String(); wantStr != got {
587 t.Errorf("%s: want\n-----\n%q\n-----\nbut got\n-----\n%q\n-----\n",
592 func ExampleEncoder_Encode() {
593 date, _ := time.Parse(time.RFC822, "14 Mar 10 18:00 UTC")
594 var config = map[string]interface{}{
596 "counts": []int{1, 1, 2, 3, 5, 8},
597 "hash": map[string]string{
602 buf := new(bytes.Buffer)
603 if err := NewEncoder(buf).Encode(config); err != nil {
606 fmt.Println(buf.String())
609 // counts = [1, 1, 2, 3, 5, 8]
610 // date = 2010-03-14T18:00:00Z