encode_test.go 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615
  1. package toml
  2. import (
  3. "bytes"
  4. "fmt"
  5. "log"
  6. "net"
  7. "testing"
  8. "time"
  9. )
  10. func TestEncodeRoundTrip(t *testing.T) {
  11. type Config struct {
  12. Age int
  13. Cats []string
  14. Pi float64
  15. Perfection []int
  16. DOB time.Time
  17. Ipaddress net.IP
  18. }
  19. var inputs = Config{
  20. 13,
  21. []string{"one", "two", "three"},
  22. 3.145,
  23. []int{11, 2, 3, 4},
  24. time.Now(),
  25. net.ParseIP("192.168.59.254"),
  26. }
  27. var firstBuffer bytes.Buffer
  28. e := NewEncoder(&firstBuffer)
  29. err := e.Encode(inputs)
  30. if err != nil {
  31. t.Fatal(err)
  32. }
  33. var outputs Config
  34. if _, err := Decode(firstBuffer.String(), &outputs); err != nil {
  35. t.Logf("Could not decode:\n-----\n%s\n-----\n",
  36. firstBuffer.String())
  37. t.Fatal(err)
  38. }
  39. // could test each value individually, but I'm lazy
  40. var secondBuffer bytes.Buffer
  41. e2 := NewEncoder(&secondBuffer)
  42. err = e2.Encode(outputs)
  43. if err != nil {
  44. t.Fatal(err)
  45. }
  46. if firstBuffer.String() != secondBuffer.String() {
  47. t.Error(
  48. firstBuffer.String(),
  49. "\n\n is not identical to\n\n",
  50. secondBuffer.String())
  51. }
  52. }
  53. // XXX(burntsushi)
  54. // I think these tests probably should be removed. They are good, but they
  55. // ought to be obsolete by toml-test.
  56. func TestEncode(t *testing.T) {
  57. type Embedded struct {
  58. Int int `toml:"_int"`
  59. }
  60. type NonStruct int
  61. date := time.Date(2014, 5, 11, 20, 30, 40, 0, time.FixedZone("IST", 3600))
  62. dateStr := "2014-05-11T19:30:40Z"
  63. tests := map[string]struct {
  64. input interface{}
  65. wantOutput string
  66. wantError error
  67. }{
  68. "bool field": {
  69. input: struct {
  70. BoolTrue bool
  71. BoolFalse bool
  72. }{true, false},
  73. wantOutput: "BoolTrue = true\nBoolFalse = false\n",
  74. },
  75. "int fields": {
  76. input: struct {
  77. Int int
  78. Int8 int8
  79. Int16 int16
  80. Int32 int32
  81. Int64 int64
  82. }{1, 2, 3, 4, 5},
  83. wantOutput: "Int = 1\nInt8 = 2\nInt16 = 3\nInt32 = 4\nInt64 = 5\n",
  84. },
  85. "uint fields": {
  86. input: struct {
  87. Uint uint
  88. Uint8 uint8
  89. Uint16 uint16
  90. Uint32 uint32
  91. Uint64 uint64
  92. }{1, 2, 3, 4, 5},
  93. wantOutput: "Uint = 1\nUint8 = 2\nUint16 = 3\nUint32 = 4" +
  94. "\nUint64 = 5\n",
  95. },
  96. "float fields": {
  97. input: struct {
  98. Float32 float32
  99. Float64 float64
  100. }{1.5, 2.5},
  101. wantOutput: "Float32 = 1.5\nFloat64 = 2.5\n",
  102. },
  103. "string field": {
  104. input: struct{ String string }{"foo"},
  105. wantOutput: "String = \"foo\"\n",
  106. },
  107. "string field and unexported field": {
  108. input: struct {
  109. String string
  110. unexported int
  111. }{"foo", 0},
  112. wantOutput: "String = \"foo\"\n",
  113. },
  114. "datetime field in UTC": {
  115. input: struct{ Date time.Time }{date},
  116. wantOutput: fmt.Sprintf("Date = %s\n", dateStr),
  117. },
  118. "datetime field as primitive": {
  119. // Using a map here to fail if isStructOrMap() returns true for
  120. // time.Time.
  121. input: map[string]interface{}{
  122. "Date": date,
  123. "Int": 1,
  124. },
  125. wantOutput: fmt.Sprintf("Date = %s\nInt = 1\n", dateStr),
  126. },
  127. "array fields": {
  128. input: struct {
  129. IntArray0 [0]int
  130. IntArray3 [3]int
  131. }{[0]int{}, [3]int{1, 2, 3}},
  132. wantOutput: "IntArray0 = []\nIntArray3 = [1, 2, 3]\n",
  133. },
  134. "slice fields": {
  135. input: struct{ IntSliceNil, IntSlice0, IntSlice3 []int }{
  136. nil, []int{}, []int{1, 2, 3},
  137. },
  138. wantOutput: "IntSlice0 = []\nIntSlice3 = [1, 2, 3]\n",
  139. },
  140. "datetime slices": {
  141. input: struct{ DatetimeSlice []time.Time }{
  142. []time.Time{date, date},
  143. },
  144. wantOutput: fmt.Sprintf("DatetimeSlice = [%s, %s]\n",
  145. dateStr, dateStr),
  146. },
  147. "nested arrays and slices": {
  148. input: struct {
  149. SliceOfArrays [][2]int
  150. ArrayOfSlices [2][]int
  151. SliceOfArraysOfSlices [][2][]int
  152. ArrayOfSlicesOfArrays [2][][2]int
  153. SliceOfMixedArrays [][2]interface{}
  154. ArrayOfMixedSlices [2][]interface{}
  155. }{
  156. [][2]int{{1, 2}, {3, 4}},
  157. [2][]int{{1, 2}, {3, 4}},
  158. [][2][]int{
  159. {
  160. {1, 2}, {3, 4},
  161. },
  162. {
  163. {5, 6}, {7, 8},
  164. },
  165. },
  166. [2][][2]int{
  167. {
  168. {1, 2}, {3, 4},
  169. },
  170. {
  171. {5, 6}, {7, 8},
  172. },
  173. },
  174. [][2]interface{}{
  175. {1, 2}, {"a", "b"},
  176. },
  177. [2][]interface{}{
  178. {1, 2}, {"a", "b"},
  179. },
  180. },
  181. wantOutput: `SliceOfArrays = [[1, 2], [3, 4]]
  182. ArrayOfSlices = [[1, 2], [3, 4]]
  183. SliceOfArraysOfSlices = [[[1, 2], [3, 4]], [[5, 6], [7, 8]]]
  184. ArrayOfSlicesOfArrays = [[[1, 2], [3, 4]], [[5, 6], [7, 8]]]
  185. SliceOfMixedArrays = [[1, 2], ["a", "b"]]
  186. ArrayOfMixedSlices = [[1, 2], ["a", "b"]]
  187. `,
  188. },
  189. "empty slice": {
  190. input: struct{ Empty []interface{} }{[]interface{}{}},
  191. wantOutput: "Empty = []\n",
  192. },
  193. "(error) slice with element type mismatch (string and integer)": {
  194. input: struct{ Mixed []interface{} }{[]interface{}{1, "a"}},
  195. wantError: errArrayMixedElementTypes,
  196. },
  197. "(error) slice with element type mismatch (integer and float)": {
  198. input: struct{ Mixed []interface{} }{[]interface{}{1, 2.5}},
  199. wantError: errArrayMixedElementTypes,
  200. },
  201. "slice with elems of differing Go types, same TOML types": {
  202. input: struct {
  203. MixedInts []interface{}
  204. MixedFloats []interface{}
  205. }{
  206. []interface{}{
  207. int(1), int8(2), int16(3), int32(4), int64(5),
  208. uint(1), uint8(2), uint16(3), uint32(4), uint64(5),
  209. },
  210. []interface{}{float32(1.5), float64(2.5)},
  211. },
  212. wantOutput: "MixedInts = [1, 2, 3, 4, 5, 1, 2, 3, 4, 5]\n" +
  213. "MixedFloats = [1.5, 2.5]\n",
  214. },
  215. "(error) slice w/ element type mismatch (one is nested array)": {
  216. input: struct{ Mixed []interface{} }{
  217. []interface{}{1, []interface{}{2}},
  218. },
  219. wantError: errArrayMixedElementTypes,
  220. },
  221. "(error) slice with 1 nil element": {
  222. input: struct{ NilElement1 []interface{} }{[]interface{}{nil}},
  223. wantError: errArrayNilElement,
  224. },
  225. "(error) slice with 1 nil element (and other non-nil elements)": {
  226. input: struct{ NilElement []interface{} }{
  227. []interface{}{1, nil},
  228. },
  229. wantError: errArrayNilElement,
  230. },
  231. "simple map": {
  232. input: map[string]int{"a": 1, "b": 2},
  233. wantOutput: "a = 1\nb = 2\n",
  234. },
  235. "map with interface{} value type": {
  236. input: map[string]interface{}{"a": 1, "b": "c"},
  237. wantOutput: "a = 1\nb = \"c\"\n",
  238. },
  239. "map with interface{} value type, some of which are structs": {
  240. input: map[string]interface{}{
  241. "a": struct{ Int int }{2},
  242. "b": 1,
  243. },
  244. wantOutput: "b = 1\n\n[a]\n Int = 2\n",
  245. },
  246. "nested map": {
  247. input: map[string]map[string]int{
  248. "a": {"b": 1},
  249. "c": {"d": 2},
  250. },
  251. wantOutput: "[a]\n b = 1\n\n[c]\n d = 2\n",
  252. },
  253. "nested struct": {
  254. input: struct{ Struct struct{ Int int } }{
  255. struct{ Int int }{1},
  256. },
  257. wantOutput: "[Struct]\n Int = 1\n",
  258. },
  259. "nested struct and non-struct field": {
  260. input: struct {
  261. Struct struct{ Int int }
  262. Bool bool
  263. }{struct{ Int int }{1}, true},
  264. wantOutput: "Bool = true\n\n[Struct]\n Int = 1\n",
  265. },
  266. "2 nested structs": {
  267. input: struct{ Struct1, Struct2 struct{ Int int } }{
  268. struct{ Int int }{1}, struct{ Int int }{2},
  269. },
  270. wantOutput: "[Struct1]\n Int = 1\n\n[Struct2]\n Int = 2\n",
  271. },
  272. "deeply nested structs": {
  273. input: struct {
  274. Struct1, Struct2 struct{ Struct3 *struct{ Int int } }
  275. }{
  276. struct{ Struct3 *struct{ Int int } }{&struct{ Int int }{1}},
  277. struct{ Struct3 *struct{ Int int } }{nil},
  278. },
  279. wantOutput: "[Struct1]\n [Struct1.Struct3]\n Int = 1" +
  280. "\n\n[Struct2]\n",
  281. },
  282. "nested struct with nil struct elem": {
  283. input: struct {
  284. Struct struct{ Inner *struct{ Int int } }
  285. }{
  286. struct{ Inner *struct{ Int int } }{nil},
  287. },
  288. wantOutput: "[Struct]\n",
  289. },
  290. "nested struct with no fields": {
  291. input: struct {
  292. Struct struct{ Inner struct{} }
  293. }{
  294. struct{ Inner struct{} }{struct{}{}},
  295. },
  296. wantOutput: "[Struct]\n [Struct.Inner]\n",
  297. },
  298. "struct with tags": {
  299. input: struct {
  300. Struct struct {
  301. Int int `toml:"_int"`
  302. } `toml:"_struct"`
  303. Bool bool `toml:"_bool"`
  304. }{
  305. struct {
  306. Int int `toml:"_int"`
  307. }{1}, true,
  308. },
  309. wantOutput: "_bool = true\n\n[_struct]\n _int = 1\n",
  310. },
  311. "embedded struct": {
  312. input: struct{ Embedded }{Embedded{1}},
  313. wantOutput: "_int = 1\n",
  314. },
  315. "embedded *struct": {
  316. input: struct{ *Embedded }{&Embedded{1}},
  317. wantOutput: "_int = 1\n",
  318. },
  319. "nested embedded struct": {
  320. input: struct {
  321. Struct struct{ Embedded } `toml:"_struct"`
  322. }{struct{ Embedded }{Embedded{1}}},
  323. wantOutput: "[_struct]\n _int = 1\n",
  324. },
  325. "nested embedded *struct": {
  326. input: struct {
  327. Struct struct{ *Embedded } `toml:"_struct"`
  328. }{struct{ *Embedded }{&Embedded{1}}},
  329. wantOutput: "[_struct]\n _int = 1\n",
  330. },
  331. "embedded non-struct": {
  332. input: struct{ NonStruct }{5},
  333. wantOutput: "NonStruct = 5\n",
  334. },
  335. "array of tables": {
  336. input: struct {
  337. Structs []*struct{ Int int } `toml:"struct"`
  338. }{
  339. []*struct{ Int int }{{1}, {3}},
  340. },
  341. wantOutput: "[[struct]]\n Int = 1\n\n[[struct]]\n Int = 3\n",
  342. },
  343. "array of tables order": {
  344. input: map[string]interface{}{
  345. "map": map[string]interface{}{
  346. "zero": 5,
  347. "arr": []map[string]int{
  348. {
  349. "friend": 5,
  350. },
  351. },
  352. },
  353. },
  354. wantOutput: "[map]\n zero = 5\n\n [[map.arr]]\n friend = 5\n",
  355. },
  356. "(error) top-level slice": {
  357. input: []struct{ Int int }{{1}, {2}, {3}},
  358. wantError: errNoKey,
  359. },
  360. "(error) slice of slice": {
  361. input: struct {
  362. Slices [][]struct{ Int int }
  363. }{
  364. [][]struct{ Int int }{{{1}}, {{2}}, {{3}}},
  365. },
  366. wantError: errArrayNoTable,
  367. },
  368. "(error) map no string key": {
  369. input: map[int]string{1: ""},
  370. wantError: errNonString,
  371. },
  372. "(error) empty key name": {
  373. input: map[string]int{"": 1},
  374. wantError: errAnything,
  375. },
  376. "(error) empty map name": {
  377. input: map[string]interface{}{
  378. "": map[string]int{"v": 1},
  379. },
  380. wantError: errAnything,
  381. },
  382. }
  383. for label, test := range tests {
  384. encodeExpected(t, label, test.input, test.wantOutput, test.wantError)
  385. }
  386. }
  387. func TestEncodeNestedTableArrays(t *testing.T) {
  388. type song struct {
  389. Name string `toml:"name"`
  390. }
  391. type album struct {
  392. Name string `toml:"name"`
  393. Songs []song `toml:"songs"`
  394. }
  395. type springsteen struct {
  396. Albums []album `toml:"albums"`
  397. }
  398. value := springsteen{
  399. []album{
  400. {"Born to Run",
  401. []song{{"Jungleland"}, {"Meeting Across the River"}}},
  402. {"Born in the USA",
  403. []song{{"Glory Days"}, {"Dancing in the Dark"}}},
  404. },
  405. }
  406. expected := `[[albums]]
  407. name = "Born to Run"
  408. [[albums.songs]]
  409. name = "Jungleland"
  410. [[albums.songs]]
  411. name = "Meeting Across the River"
  412. [[albums]]
  413. name = "Born in the USA"
  414. [[albums.songs]]
  415. name = "Glory Days"
  416. [[albums.songs]]
  417. name = "Dancing in the Dark"
  418. `
  419. encodeExpected(t, "nested table arrays", value, expected, nil)
  420. }
  421. func TestEncodeArrayHashWithNormalHashOrder(t *testing.T) {
  422. type Alpha struct {
  423. V int
  424. }
  425. type Beta struct {
  426. V int
  427. }
  428. type Conf struct {
  429. V int
  430. A Alpha
  431. B []Beta
  432. }
  433. val := Conf{
  434. V: 1,
  435. A: Alpha{2},
  436. B: []Beta{{3}},
  437. }
  438. expected := "V = 1\n\n[A]\n V = 2\n\n[[B]]\n V = 3\n"
  439. encodeExpected(t, "array hash with normal hash order", val, expected, nil)
  440. }
  441. func TestEncodeWithOmitEmpty(t *testing.T) {
  442. type simple struct {
  443. Bool bool `toml:"bool,omitempty"`
  444. String string `toml:"string,omitempty"`
  445. Array [0]byte `toml:"array,omitempty"`
  446. Slice []int `toml:"slice,omitempty"`
  447. Map map[string]string `toml:"map,omitempty"`
  448. }
  449. var v simple
  450. encodeExpected(t, "fields with omitempty are omitted when empty", v, "", nil)
  451. v = simple{
  452. Bool: true,
  453. String: " ",
  454. Slice: []int{2, 3, 4},
  455. Map: map[string]string{"foo": "bar"},
  456. }
  457. expected := `bool = true
  458. string = " "
  459. slice = [2, 3, 4]
  460. [map]
  461. foo = "bar"
  462. `
  463. encodeExpected(t, "fields with omitempty are not omitted when non-empty",
  464. v, expected, nil)
  465. }
  466. func TestEncodeWithOmitZero(t *testing.T) {
  467. type simple struct {
  468. Number int `toml:"number,omitzero"`
  469. Real float64 `toml:"real,omitzero"`
  470. Unsigned uint `toml:"unsigned,omitzero"`
  471. }
  472. value := simple{0, 0.0, uint(0)}
  473. expected := ""
  474. encodeExpected(t, "simple with omitzero, all zero", value, expected, nil)
  475. value.Number = 10
  476. value.Real = 20
  477. value.Unsigned = 5
  478. expected = `number = 10
  479. real = 20.0
  480. unsigned = 5
  481. `
  482. encodeExpected(t, "simple with omitzero, non-zero", value, expected, nil)
  483. }
  484. func TestEncodeOmitemptyWithEmptyName(t *testing.T) {
  485. type simple struct {
  486. S []int `toml:",omitempty"`
  487. }
  488. v := simple{[]int{1, 2, 3}}
  489. expected := "S = [1, 2, 3]\n"
  490. encodeExpected(t, "simple with omitempty, no name, non-empty field",
  491. v, expected, nil)
  492. }
  493. func TestEncodeAnonymousStruct(t *testing.T) {
  494. type Inner struct{ N int }
  495. type Outer0 struct{ Inner }
  496. type Outer1 struct {
  497. Inner `toml:"inner"`
  498. }
  499. v0 := Outer0{Inner{3}}
  500. expected := "N = 3\n"
  501. encodeExpected(t, "embedded anonymous untagged struct", v0, expected, nil)
  502. v1 := Outer1{Inner{3}}
  503. expected = "[inner]\n N = 3\n"
  504. encodeExpected(t, "embedded anonymous tagged struct", v1, expected, nil)
  505. }
  506. func TestEncodeAnonymousStructPointerField(t *testing.T) {
  507. type Inner struct{ N int }
  508. type Outer0 struct{ *Inner }
  509. type Outer1 struct {
  510. *Inner `toml:"inner"`
  511. }
  512. v0 := Outer0{}
  513. expected := ""
  514. encodeExpected(t, "nil anonymous untagged struct pointer field", v0, expected, nil)
  515. v0 = Outer0{&Inner{3}}
  516. expected = "N = 3\n"
  517. encodeExpected(t, "non-nil anonymous untagged struct pointer field", v0, expected, nil)
  518. v1 := Outer1{}
  519. expected = ""
  520. encodeExpected(t, "nil anonymous tagged struct pointer field", v1, expected, nil)
  521. v1 = Outer1{&Inner{3}}
  522. expected = "[inner]\n N = 3\n"
  523. encodeExpected(t, "non-nil anonymous tagged struct pointer field", v1, expected, nil)
  524. }
  525. func TestEncodeIgnoredFields(t *testing.T) {
  526. type simple struct {
  527. Number int `toml:"-"`
  528. }
  529. value := simple{}
  530. expected := ""
  531. encodeExpected(t, "ignored field", value, expected, nil)
  532. }
  533. func encodeExpected(
  534. t *testing.T, label string, val interface{}, wantStr string, wantErr error,
  535. ) {
  536. var buf bytes.Buffer
  537. enc := NewEncoder(&buf)
  538. err := enc.Encode(val)
  539. if err != wantErr {
  540. if wantErr != nil {
  541. if wantErr == errAnything && err != nil {
  542. return
  543. }
  544. t.Errorf("%s: want Encode error %v, got %v", label, wantErr, err)
  545. } else {
  546. t.Errorf("%s: Encode failed: %s", label, err)
  547. }
  548. }
  549. if err != nil {
  550. return
  551. }
  552. if got := buf.String(); wantStr != got {
  553. t.Errorf("%s: want\n-----\n%q\n-----\nbut got\n-----\n%q\n-----\n",
  554. label, wantStr, got)
  555. }
  556. }
  557. func ExampleEncoder_Encode() {
  558. date, _ := time.Parse(time.RFC822, "14 Mar 10 18:00 UTC")
  559. var config = map[string]interface{}{
  560. "date": date,
  561. "counts": []int{1, 1, 2, 3, 5, 8},
  562. "hash": map[string]string{
  563. "key1": "val1",
  564. "key2": "val2",
  565. },
  566. }
  567. buf := new(bytes.Buffer)
  568. if err := NewEncoder(buf).Encode(config); err != nil {
  569. log.Fatal(err)
  570. }
  571. fmt.Println(buf.String())
  572. // Output:
  573. // counts = [1, 1, 2, 3, 5, 8]
  574. // date = 2010-03-14T18:00:00Z
  575. //
  576. // [hash]
  577. // key1 = "val1"
  578. // key2 = "val2"
  579. }