encode_test.go 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379
  1. package yaml_test
  2. import (
  3. "fmt"
  4. . "launchpad.net/gocheck"
  5. "gonuts.org/v1/yaml"
  6. "math"
  7. "strconv"
  8. "strings"
  9. )
  10. var marshalIntTest = 123
  11. var marshalTests = []struct {
  12. value interface{}
  13. data string
  14. }{
  15. {
  16. &struct{}{},
  17. "{}\n",
  18. }, {
  19. map[string]string{"v": "hi"},
  20. "v: hi\n",
  21. }, {
  22. map[string]interface{}{"v": "hi"},
  23. "v: hi\n",
  24. }, {
  25. map[string]string{"v": "true"},
  26. "v: \"true\"\n",
  27. }, {
  28. map[string]string{"v": "false"},
  29. "v: \"false\"\n",
  30. }, {
  31. map[string]interface{}{"v": true},
  32. "v: true\n",
  33. }, {
  34. map[string]interface{}{"v": false},
  35. "v: false\n",
  36. }, {
  37. map[string]interface{}{"v": 10},
  38. "v: 10\n",
  39. }, {
  40. map[string]interface{}{"v": -10},
  41. "v: -10\n",
  42. }, {
  43. map[string]uint{"v": 42},
  44. "v: 42\n",
  45. }, {
  46. map[string]interface{}{"v": int64(4294967296)},
  47. "v: 4294967296\n",
  48. }, {
  49. map[string]int64{"v": int64(4294967296)},
  50. "v: 4294967296\n",
  51. }, {
  52. map[string]uint64{"v": 4294967296},
  53. "v: 4294967296\n",
  54. }, {
  55. map[string]interface{}{"v": "10"},
  56. "v: \"10\"\n",
  57. }, {
  58. map[string]interface{}{"v": 0.1},
  59. "v: 0.1\n",
  60. }, {
  61. map[string]interface{}{"v": float64(0.1)},
  62. "v: 0.1\n",
  63. }, {
  64. map[string]interface{}{"v": -0.1},
  65. "v: -0.1\n",
  66. }, {
  67. map[string]interface{}{"v": math.Inf(+1)},
  68. "v: .inf\n",
  69. }, {
  70. map[string]interface{}{"v": math.Inf(-1)},
  71. "v: -.inf\n",
  72. }, {
  73. map[string]interface{}{"v": math.NaN()},
  74. "v: .nan\n",
  75. }, {
  76. map[string]interface{}{"v": nil},
  77. "v: null\n",
  78. }, {
  79. map[string]interface{}{"v": ""},
  80. "v: \"\"\n",
  81. }, {
  82. map[string][]string{"v": []string{"A", "B"}},
  83. "v:\n- A\n- B\n",
  84. }, {
  85. map[string][]string{"v": []string{"A", "B\nC"}},
  86. "v:\n- A\n- 'B\n\n C'\n",
  87. }, {
  88. map[string][]interface{}{"v": []interface{}{"A", 1, map[string][]int{"B": []int{2, 3}}}},
  89. "v:\n- A\n- 1\n- B:\n - 2\n - 3\n",
  90. }, {
  91. map[string]interface{}{"a": map[interface{}]interface{}{"b": "c"}},
  92. "a:\n b: c\n",
  93. }, {
  94. map[string]interface{}{"a": "-"},
  95. "a: '-'\n",
  96. },
  97. // Simple values.
  98. {
  99. &marshalIntTest,
  100. "123\n",
  101. },
  102. // Structures
  103. {
  104. &struct{ Hello string }{"world"},
  105. "hello: world\n",
  106. }, {
  107. &struct {
  108. A struct {
  109. B string
  110. }
  111. }{struct{ B string }{"c"}},
  112. "a:\n b: c\n",
  113. }, {
  114. &struct {
  115. A *struct {
  116. B string
  117. }
  118. }{&struct{ B string }{"c"}},
  119. "a:\n b: c\n",
  120. }, {
  121. &struct {
  122. A *struct {
  123. B string
  124. }
  125. }{},
  126. "a: null\n",
  127. }, {
  128. &struct{ A int }{1},
  129. "a: 1\n",
  130. }, {
  131. &struct{ A []int }{[]int{1, 2}},
  132. "a:\n- 1\n- 2\n",
  133. }, {
  134. &struct {
  135. B int "a"
  136. }{1},
  137. "a: 1\n",
  138. }, {
  139. &struct{ A bool }{true},
  140. "a: true\n",
  141. },
  142. // Conditional flag
  143. {
  144. &struct {
  145. A int "a,omitempty"
  146. B int "b,omitempty"
  147. }{1, 0},
  148. "a: 1\n",
  149. }, {
  150. &struct {
  151. A int "a,omitempty"
  152. B int "b,omitempty"
  153. }{0, 0},
  154. "{}\n",
  155. }, {
  156. &struct {
  157. A *struct{ X int } "a,omitempty"
  158. B int "b,omitempty"
  159. }{nil, 0},
  160. "{}\n",
  161. },
  162. // Flow flag
  163. {
  164. &struct {
  165. A []int "a,flow"
  166. }{[]int{1, 2}},
  167. "a: [1, 2]\n",
  168. }, {
  169. &struct {
  170. A map[string]string "a,flow"
  171. }{map[string]string{"b": "c", "d": "e"}},
  172. "a: {b: c, d: e}\n",
  173. }, {
  174. &struct {
  175. A struct {
  176. B, D string
  177. } "a,flow"
  178. }{struct{ B, D string }{"c", "e"}},
  179. "a: {b: c, d: e}\n",
  180. },
  181. // Unexported field
  182. {
  183. &struct {
  184. u int
  185. A int
  186. }{0, 1},
  187. "a: 1\n",
  188. },
  189. // Ignored field
  190. {
  191. &struct {
  192. A int
  193. B int "-"
  194. }{1, 2},
  195. "a: 1\n",
  196. },
  197. // Struct inlining
  198. {
  199. &struct {
  200. A int
  201. C inlineB `yaml:",inline"`
  202. }{1, inlineB{2, inlineC{3}}},
  203. "a: 1\nb: 2\nc: 3\n",
  204. },
  205. }
  206. func (s *S) TestMarshal(c *C) {
  207. for _, item := range marshalTests {
  208. data, err := yaml.Marshal(item.value)
  209. c.Assert(err, IsNil)
  210. c.Assert(string(data), Equals, item.data)
  211. }
  212. }
  213. var marshalErrorTests = []struct {
  214. value interface{}
  215. error string
  216. }{
  217. {
  218. &struct {
  219. B int
  220. inlineB ",inline"
  221. }{1, inlineB{2, inlineC{3}}},
  222. `Duplicated key 'b' in struct struct \{ B int; .*`,
  223. },
  224. }
  225. func (s *S) TestMarshalErrors(c *C) {
  226. for _, item := range marshalErrorTests {
  227. _, err := yaml.Marshal(item.value)
  228. c.Assert(err, ErrorMatches, item.error)
  229. }
  230. }
  231. var marshalTaggedIfaceTest interface{} = &struct{ A string }{"B"}
  232. var getterTests = []struct {
  233. data, tag string
  234. value interface{}
  235. }{
  236. {"_:\n hi: there\n", "", map[interface{}]interface{}{"hi": "there"}},
  237. {"_:\n- 1\n- A\n", "", []interface{}{1, "A"}},
  238. {"_: 10\n", "", 10},
  239. {"_: null\n", "", nil},
  240. {"_: !foo BAR!\n", "!foo", "BAR!"},
  241. {"_: !foo 1\n", "!foo", "1"},
  242. {"_: !foo '\"1\"'\n", "!foo", "\"1\""},
  243. {"_: !foo 1.1\n", "!foo", 1.1},
  244. {"_: !foo 1\n", "!foo", 1},
  245. {"_: !foo 1\n", "!foo", uint(1)},
  246. {"_: !foo true\n", "!foo", true},
  247. {"_: !foo\n- A\n- B\n", "!foo", []string{"A", "B"}},
  248. {"_: !foo\n A: B\n", "!foo", map[string]string{"A": "B"}},
  249. {"_: !foo\n a: B\n", "!foo", &marshalTaggedIfaceTest},
  250. }
  251. func (s *S) TestMarshalTypeCache(c *C) {
  252. var data []byte
  253. var err error
  254. func() {
  255. type T struct{ A int }
  256. data, err = yaml.Marshal(&T{})
  257. c.Assert(err, IsNil)
  258. }()
  259. func() {
  260. type T struct{ B int }
  261. data, err = yaml.Marshal(&T{})
  262. c.Assert(err, IsNil)
  263. }()
  264. c.Assert(string(data), Equals, "b: 0\n")
  265. }
  266. type typeWithGetter struct {
  267. tag string
  268. value interface{}
  269. }
  270. func (o typeWithGetter) GetYAML() (tag string, value interface{}) {
  271. return o.tag, o.value
  272. }
  273. type typeWithGetterField struct {
  274. Field typeWithGetter "_"
  275. }
  276. func (s *S) TestMashalWithGetter(c *C) {
  277. for _, item := range getterTests {
  278. obj := &typeWithGetterField{}
  279. obj.Field.tag = item.tag
  280. obj.Field.value = item.value
  281. data, err := yaml.Marshal(obj)
  282. c.Assert(err, IsNil)
  283. c.Assert(string(data), Equals, string(item.data))
  284. }
  285. }
  286. func (s *S) TestUnmarshalWholeDocumentWithGetter(c *C) {
  287. obj := &typeWithGetter{}
  288. obj.tag = ""
  289. obj.value = map[string]string{"hello": "world!"}
  290. data, err := yaml.Marshal(obj)
  291. c.Assert(err, IsNil)
  292. c.Assert(string(data), Equals, "hello: world!\n")
  293. }
  294. func (s *S) TestSortedOutput(c *C) {
  295. order := []interface{}{
  296. false,
  297. true,
  298. 1,
  299. uint(1),
  300. 1.0,
  301. 1.1,
  302. 1.2,
  303. 2,
  304. uint(2),
  305. 2.0,
  306. 2.1,
  307. "",
  308. ".1",
  309. ".2",
  310. ".a",
  311. "1",
  312. "2",
  313. "a!10",
  314. "a/2",
  315. "a/10",
  316. "a~10",
  317. "ab/1",
  318. "b/1",
  319. "b/01",
  320. "b/2",
  321. "b/02",
  322. "b/3",
  323. "b/03",
  324. "b1",
  325. "b01",
  326. "b3",
  327. "c2.10",
  328. "c10.2",
  329. "d1",
  330. "d12",
  331. "d12a",
  332. }
  333. m := make(map[interface{}]int)
  334. for _, k := range order {
  335. m[k] = 1
  336. }
  337. data, err := yaml.Marshal(m)
  338. c.Assert(err, IsNil)
  339. out := "\n" + string(data)
  340. last := 0
  341. for i, k := range order {
  342. repr := fmt.Sprint(k)
  343. if s, ok := k.(string); ok {
  344. if _, err = strconv.ParseFloat(repr, 32); s == "" || err == nil {
  345. repr = `"` + repr + `"`
  346. }
  347. }
  348. index := strings.Index(out, "\n"+repr+":")
  349. if index == -1 {
  350. c.Fatalf("%#v is not in the output: %#v", k, out)
  351. }
  352. if index < last {
  353. c.Fatalf("%#v was generated before %#v: %q", k, order[i-1], out)
  354. }
  355. last = index
  356. }
  357. }