encode_test.go 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282
  1. package toml
  2. import (
  3. "bytes"
  4. "testing"
  5. )
  6. // XXX(burntsushi)
  7. // I think these tests probably should be removed. They are good, but they
  8. // ought to be obsolete by toml-test.
  9. func TestEncode(t *testing.T) {
  10. tests := map[string]struct {
  11. input interface{}
  12. wantOutput string
  13. wantError error
  14. }{
  15. "bool field": {
  16. input: struct {
  17. BoolTrue bool
  18. BoolFalse bool
  19. }{true, false},
  20. wantOutput: "BoolTrue = true\nBoolFalse = false",
  21. },
  22. "int fields": {
  23. input: struct {
  24. Int int
  25. Int8 int8
  26. Int16 int16
  27. Int32 int32
  28. Int64 int64
  29. }{1, 2, 3, 4, 5},
  30. wantOutput: "Int = 1\nInt8 = 2\nInt16 = 3\nInt32 = 4\nInt64 = 5",
  31. },
  32. "uint fields": {
  33. input: struct {
  34. Uint uint
  35. Uint8 uint8
  36. Uint16 uint16
  37. Uint32 uint32
  38. Uint64 uint64
  39. }{1, 2, 3, 4, 5},
  40. wantOutput: "Uint = 1\nUint8 = 2\nUint16 = 3\nUint32 = 4" +
  41. "\nUint64 = 5",
  42. },
  43. "float fields": {
  44. input: struct {
  45. Float32 float32
  46. Float64 float64
  47. }{1.5, 2.5},
  48. wantOutput: "Float32 = 1.5\nFloat64 = 2.5",
  49. },
  50. "string field": {
  51. input: struct{ String string }{"foo"},
  52. wantOutput: `String = "foo"`,
  53. },
  54. "array fields": {
  55. input: struct {
  56. IntArray0 [0]int
  57. IntArray3 [3]int
  58. }{[0]int{}, [3]int{1, 2, 3}},
  59. wantOutput: "IntArray0 = []\nIntArray3 = [1, 2, 3]",
  60. },
  61. "slice fields": {
  62. input: struct{ IntSliceNil, IntSlice0, IntSlice3 []int }{
  63. nil, []int{}, []int{1, 2, 3},
  64. },
  65. wantOutput: "IntSlice0 = []\nIntSlice3 = [1, 2, 3]",
  66. },
  67. "nested arrays and slices": {
  68. input: struct {
  69. SliceOfArrays [][2]int
  70. ArrayOfSlices [2][]int
  71. SliceOfArraysOfSlices [][2][]int
  72. ArrayOfSlicesOfArrays [2][][2]int
  73. SliceOfMixedArrays [][2]interface{}
  74. ArrayOfMixedSlices [2][]interface{}
  75. }{
  76. [][2]int{[2]int{1, 2}, [2]int{3, 4}},
  77. [2][]int{[]int{1, 2}, []int{3, 4}},
  78. [][2][]int{
  79. [2][]int{
  80. []int{1, 2}, []int{3, 4},
  81. },
  82. [2][]int{
  83. []int{5, 6}, []int{7, 8},
  84. },
  85. },
  86. [2][][2]int{
  87. [][2]int{
  88. [2]int{1, 2}, [2]int{3, 4},
  89. },
  90. [][2]int{
  91. [2]int{5, 6}, [2]int{7, 8},
  92. },
  93. },
  94. [][2]interface{}{
  95. [2]interface{}{1, 2}, [2]interface{}{"a", "b"},
  96. },
  97. [2][]interface{}{
  98. []interface{}{1, 2}, []interface{}{"a", "b"},
  99. },
  100. },
  101. wantOutput: `SliceOfArrays = [[1, 2], [3, 4]]
  102. ArrayOfSlices = [[1, 2], [3, 4]]
  103. SliceOfArraysOfSlices = [[[1, 2], [3, 4]], [[5, 6], [7, 8]]]
  104. ArrayOfSlicesOfArrays = [[[1, 2], [3, 4]], [[5, 6], [7, 8]]]
  105. SliceOfMixedArrays = [[1, 2], ["a", "b"]]
  106. ArrayOfMixedSlices = [[1, 2], ["a", "b"]]`,
  107. },
  108. "(error) slice with element type mismatch (string and integer)": {
  109. input: struct{ Mixed []interface{} }{[]interface{}{1, "a"}},
  110. wantError: ErrArrayMixedElementTypes,
  111. },
  112. "(error) slice with element type mismatch (integer and float)": {
  113. input: struct{ Mixed []interface{} }{[]interface{}{1, 2.5}},
  114. wantError: ErrArrayMixedElementTypes,
  115. },
  116. "slice with elems of differing Go types, same TOML types": {
  117. input: struct {
  118. MixedInts []interface{}
  119. MixedFloats []interface{}
  120. }{
  121. []interface{}{
  122. int(1), int8(2), int16(3), int32(4), int64(5),
  123. uint(1), uint8(2), uint16(3), uint32(4), uint64(5),
  124. },
  125. []interface{}{float32(1.5), float64(2.5)},
  126. },
  127. wantOutput: "MixedInts = [1, 2, 3, 4, 5, 1, 2, 3, 4, 5]\n" +
  128. "MixedFloats = [1.5, 2.5]",
  129. },
  130. "(error) slice w/ element type mismatch (one is nested array)": {
  131. input: struct{ Mixed []interface{} }{
  132. []interface{}{1, []interface{}{2}},
  133. },
  134. wantError: ErrArrayMixedElementTypes,
  135. },
  136. "(error) slice with 1 nil element": {
  137. input: struct{ NilElement1 []interface{} }{[]interface{}{nil}},
  138. wantError: ErrArrayNilElement,
  139. },
  140. "(error) slice with 1 nil element (and other non-nil elements)": {
  141. input: struct{ NilElement []interface{} }{
  142. []interface{}{1, nil},
  143. },
  144. wantError: ErrArrayNilElement,
  145. },
  146. "simple map": {
  147. input: map[string]int{"a": 1, "b": 2},
  148. wantOutput: "a = 1\nb = 2",
  149. },
  150. "map with interface{} value type": {
  151. input: map[string]interface{}{"a": 1, "b": "c"},
  152. wantOutput: "a = 1\nb = \"c\"",
  153. },
  154. "map with interface{} value type, some of which are structs": {
  155. input: map[string]interface{}{
  156. "a": struct{ Int int }{2},
  157. "b": 1,
  158. },
  159. wantOutput: "b = 1\n[a]\n Int = 2",
  160. },
  161. "nested map": {
  162. input: map[string]map[string]int{
  163. "a": map[string]int{"b": 1},
  164. "c": map[string]int{"d": 2},
  165. },
  166. wantOutput: "[a]\n b = 1\n\n[c]\n d = 2",
  167. },
  168. "nested struct": {
  169. input: struct{ Struct struct{ Int int } }{
  170. struct{ Int int }{1},
  171. },
  172. wantOutput: "[Struct]\n Int = 1",
  173. },
  174. "nested struct and non-struct field": {
  175. input: struct {
  176. Struct struct{ Int int }
  177. Bool bool
  178. }{struct{ Int int }{1}, true},
  179. wantOutput: "Bool = true\n\n[Struct]\n Int = 1",
  180. },
  181. "2 nested structs": {
  182. input: struct{ Struct1, Struct2 struct{ Int int } }{
  183. struct{ Int int }{1}, struct{ Int int }{2},
  184. },
  185. wantOutput: "[Struct1]\n Int = 1\n\n[Struct2]\n Int = 2",
  186. },
  187. "deeply nested structs": {
  188. input: struct {
  189. Struct1, Struct2 struct{ Struct3 *struct{ Int int } }
  190. }{
  191. struct{ Struct3 *struct{ Int int } }{&struct{ Int int }{1}},
  192. struct{ Struct3 *struct{ Int int } }{nil},
  193. },
  194. wantOutput: "[Struct1]\n [Struct1.Struct3]\n Int = 1" +
  195. "\n\n[Struct2]\n",
  196. },
  197. "nested struct with nil struct elem": {
  198. input: struct {
  199. Struct struct{ Inner *struct{ Int int } }
  200. }{
  201. struct{ Inner *struct{ Int int } }{nil},
  202. },
  203. wantOutput: "[Struct]\n",
  204. },
  205. "nested struct with no fields": {
  206. input: struct {
  207. Struct struct{ Inner struct{} }
  208. }{
  209. struct{ Inner struct{} }{struct{}{}},
  210. },
  211. wantOutput: "[Struct]\n [Struct.Inner]\n",
  212. },
  213. "struct with tags": {
  214. input: struct {
  215. Struct struct {
  216. Int int `toml:"_int"`
  217. } `toml:"_struct"`
  218. Bool bool `toml:"_bool"`
  219. }{
  220. struct {
  221. Int int `toml:"_int"`
  222. }{1}, true,
  223. },
  224. wantOutput: "_bool = true\n\n[_struct]\n _int = 1",
  225. },
  226. "embedded struct": {
  227. input: struct{ Embedded }{Embedded{1}},
  228. wantOutput: "_int = 1",
  229. },
  230. "embedded *struct": {
  231. input: struct{ *Embedded }{&Embedded{1}},
  232. wantOutput: "_int = 1",
  233. },
  234. "nested embedded struct": {
  235. input: struct {
  236. Struct struct{ Embedded } `toml:"_struct"`
  237. }{struct{ Embedded }{Embedded{1}}},
  238. wantOutput: "[_struct]\n _int = 1",
  239. },
  240. "nested embedded *struct": {
  241. input: struct {
  242. Struct struct{ *Embedded } `toml:"_struct"`
  243. }{struct{ *Embedded }{&Embedded{1}}},
  244. wantOutput: "[_struct]\n _int = 1",
  245. },
  246. "array of tables": {
  247. input: struct {
  248. Structs []*struct{ Int int } `toml:"struct"`
  249. }{
  250. []*struct{ Int int }{
  251. {1}, nil, {3},
  252. },
  253. },
  254. wantOutput: "[[struct]]\n Int = 1\n\n[[struct]]\n Int = 3",
  255. },
  256. }
  257. for label, test := range tests {
  258. var buf bytes.Buffer
  259. e := NewEncoder(&buf)
  260. err := e.Encode(test.input)
  261. if err != test.wantError {
  262. if test.wantError != nil {
  263. t.Errorf("%s: want Encode error %v, got %v",
  264. label, test.wantError, err)
  265. } else {
  266. t.Errorf("%s: Encode failed: %s", label, err)
  267. }
  268. }
  269. if err != nil {
  270. continue
  271. }
  272. if got := buf.String(); test.wantOutput != got {
  273. t.Errorf("%s: want %q, got %q", label, test.wantOutput, got)
  274. }
  275. }
  276. }
  277. type Embedded struct {
  278. Int int `toml:"_int"`
  279. }