encode_test.go 7.0 KB

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