encode_test.go 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482
  1. package yaml_test
  2. import (
  3. "fmt"
  4. "math"
  5. "strconv"
  6. "strings"
  7. "time"
  8. . "gopkg.in/check.v1"
  9. "gopkg.in/yaml.v2"
  10. "net"
  11. )
  12. var marshalIntTest = 123
  13. var marshalTests = []struct {
  14. value interface{}
  15. data string
  16. }{
  17. {
  18. nil,
  19. "null\n",
  20. }, {
  21. &struct{}{},
  22. "{}\n",
  23. }, {
  24. map[string]string{"v": "hi"},
  25. "v: hi\n",
  26. }, {
  27. map[string]interface{}{"v": "hi"},
  28. "v: hi\n",
  29. }, {
  30. map[string]string{"v": "true"},
  31. "v: \"true\"\n",
  32. }, {
  33. map[string]string{"v": "false"},
  34. "v: \"false\"\n",
  35. }, {
  36. map[string]interface{}{"v": true},
  37. "v: true\n",
  38. }, {
  39. map[string]interface{}{"v": false},
  40. "v: false\n",
  41. }, {
  42. map[string]interface{}{"v": 10},
  43. "v: 10\n",
  44. }, {
  45. map[string]interface{}{"v": -10},
  46. "v: -10\n",
  47. }, {
  48. map[string]uint{"v": 42},
  49. "v: 42\n",
  50. }, {
  51. map[string]interface{}{"v": int64(4294967296)},
  52. "v: 4294967296\n",
  53. }, {
  54. map[string]int64{"v": int64(4294967296)},
  55. "v: 4294967296\n",
  56. }, {
  57. map[string]uint64{"v": 4294967296},
  58. "v: 4294967296\n",
  59. }, {
  60. map[string]interface{}{"v": "10"},
  61. "v: \"10\"\n",
  62. }, {
  63. map[string]interface{}{"v": 0.1},
  64. "v: 0.1\n",
  65. }, {
  66. map[string]interface{}{"v": float64(0.1)},
  67. "v: 0.1\n",
  68. }, {
  69. map[string]interface{}{"v": -0.1},
  70. "v: -0.1\n",
  71. }, {
  72. map[string]interface{}{"v": math.Inf(+1)},
  73. "v: .inf\n",
  74. }, {
  75. map[string]interface{}{"v": math.Inf(-1)},
  76. "v: -.inf\n",
  77. }, {
  78. map[string]interface{}{"v": math.NaN()},
  79. "v: .nan\n",
  80. }, {
  81. map[string]interface{}{"v": nil},
  82. "v: null\n",
  83. }, {
  84. map[string]interface{}{"v": ""},
  85. "v: \"\"\n",
  86. }, {
  87. map[string][]string{"v": []string{"A", "B"}},
  88. "v:\n- A\n- B\n",
  89. }, {
  90. map[string][]string{"v": []string{"A", "B\nC"}},
  91. "v:\n- A\n- |-\n B\n C\n",
  92. }, {
  93. map[string][]interface{}{"v": []interface{}{"A", 1, map[string][]int{"B": []int{2, 3}}}},
  94. "v:\n- A\n- 1\n- B:\n - 2\n - 3\n",
  95. }, {
  96. map[string]interface{}{"a": map[interface{}]interface{}{"b": "c"}},
  97. "a:\n b: c\n",
  98. }, {
  99. map[string]interface{}{"a": "-"},
  100. "a: '-'\n",
  101. },
  102. // Simple values.
  103. {
  104. &marshalIntTest,
  105. "123\n",
  106. },
  107. // Structures
  108. {
  109. &struct{ Hello string }{"world"},
  110. "hello: world\n",
  111. }, {
  112. &struct {
  113. A struct {
  114. B string
  115. }
  116. }{struct{ B string }{"c"}},
  117. "a:\n b: c\n",
  118. }, {
  119. &struct {
  120. A *struct {
  121. B string
  122. }
  123. }{&struct{ B string }{"c"}},
  124. "a:\n b: c\n",
  125. }, {
  126. &struct {
  127. A *struct {
  128. B string
  129. }
  130. }{},
  131. "a: null\n",
  132. }, {
  133. &struct{ A int }{1},
  134. "a: 1\n",
  135. }, {
  136. &struct{ A []int }{[]int{1, 2}},
  137. "a:\n- 1\n- 2\n",
  138. }, {
  139. &struct {
  140. B int "a"
  141. }{1},
  142. "a: 1\n",
  143. }, {
  144. &struct{ A bool }{true},
  145. "a: true\n",
  146. },
  147. // Conditional flag
  148. {
  149. &struct {
  150. A int "a,omitempty"
  151. B int "b,omitempty"
  152. }{1, 0},
  153. "a: 1\n",
  154. }, {
  155. &struct {
  156. A int "a,omitempty"
  157. B int "b,omitempty"
  158. }{0, 0},
  159. "{}\n",
  160. }, {
  161. &struct {
  162. A *struct{ X, y int } "a,omitempty,flow"
  163. }{&struct{ X, y int }{1, 2}},
  164. "a: {x: 1}\n",
  165. }, {
  166. &struct {
  167. A *struct{ X, y int } "a,omitempty,flow"
  168. }{nil},
  169. "{}\n",
  170. }, {
  171. &struct {
  172. A *struct{ X, y int } "a,omitempty,flow"
  173. }{&struct{ X, y int }{}},
  174. "a: {x: 0}\n",
  175. }, {
  176. &struct {
  177. A struct{ X, y int } "a,omitempty,flow"
  178. }{struct{ X, y int }{1, 2}},
  179. "a: {x: 1}\n",
  180. }, {
  181. &struct {
  182. A struct{ X, y int } "a,omitempty,flow"
  183. }{struct{ X, y int }{0, 1}},
  184. "{}\n",
  185. },
  186. // Flow flag
  187. {
  188. &struct {
  189. A []int "a,flow"
  190. }{[]int{1, 2}},
  191. "a: [1, 2]\n",
  192. }, {
  193. &struct {
  194. A map[string]string "a,flow"
  195. }{map[string]string{"b": "c", "d": "e"}},
  196. "a: {b: c, d: e}\n",
  197. }, {
  198. &struct {
  199. A struct {
  200. B, D string
  201. } "a,flow"
  202. }{struct{ B, D string }{"c", "e"}},
  203. "a: {b: c, d: e}\n",
  204. },
  205. // Unexported field
  206. {
  207. &struct {
  208. u int
  209. A int
  210. }{0, 1},
  211. "a: 1\n",
  212. },
  213. // Ignored field
  214. {
  215. &struct {
  216. A int
  217. B int "-"
  218. }{1, 2},
  219. "a: 1\n",
  220. },
  221. // Struct inlining
  222. {
  223. &struct {
  224. A int
  225. C inlineB `yaml:",inline"`
  226. }{1, inlineB{2, inlineC{3}}},
  227. "a: 1\nb: 2\nc: 3\n",
  228. },
  229. // Map inlining
  230. {
  231. &struct {
  232. A int
  233. C map[string]int `yaml:",inline"`
  234. }{1, map[string]int{"b": 2, "c": 3}},
  235. "a: 1\nb: 2\nc: 3\n",
  236. },
  237. // Duration
  238. {
  239. map[string]time.Duration{"a": 3 * time.Second},
  240. "a: 3s\n",
  241. },
  242. // Issue #24: bug in map merging logic.
  243. {
  244. map[string]string{"a": "<foo>"},
  245. "a: <foo>\n",
  246. },
  247. // Issue #34: marshal unsupported base 60 floats quoted for compatibility
  248. // with old YAML 1.1 parsers.
  249. {
  250. map[string]string{"a": "1:1"},
  251. "a: \"1:1\"\n",
  252. },
  253. // Binary data.
  254. {
  255. map[string]string{"a": "\x00"},
  256. "a: \"\\0\"\n",
  257. }, {
  258. map[string]string{"a": "\x80\x81\x82"},
  259. "a: !!binary gIGC\n",
  260. }, {
  261. map[string]string{"a": strings.Repeat("\x90", 54)},
  262. "a: !!binary |\n " + strings.Repeat("kJCQ", 17) + "kJ\n CQ\n",
  263. },
  264. // Ordered maps.
  265. {
  266. &yaml.MapSlice{{"b", 2}, {"a", 1}, {"d", 4}, {"c", 3}, {"sub", yaml.MapSlice{{"e", 5}}}},
  267. "b: 2\na: 1\nd: 4\nc: 3\nsub:\n e: 5\n",
  268. },
  269. // Encode unicode as utf-8 rather than in escaped form.
  270. {
  271. map[string]string{"a": "你好"},
  272. "a: 你好\n",
  273. },
  274. // Support encoding.TextMarshaler.
  275. {
  276. map[string]net.IP{"a": net.IPv4(1, 2, 3, 4)},
  277. "a: 1.2.3.4\n",
  278. },
  279. {
  280. map[string]time.Time{"a": time.Unix(1424801979, 0)},
  281. "a: 2015-02-24T15:19:39-03:00\n",
  282. },
  283. // Ensure strings containing ": " are quoted (reported as PR #43, but not reproducible).
  284. {
  285. map[string]string{"a": "b: c"},
  286. "a: 'b: c'\n",
  287. },
  288. }
  289. func (s *S) TestMarshal(c *C) {
  290. for _, item := range marshalTests {
  291. data, err := yaml.Marshal(item.value)
  292. c.Assert(err, IsNil)
  293. c.Assert(string(data), Equals, item.data)
  294. }
  295. }
  296. var marshalErrorTests = []struct {
  297. value interface{}
  298. error string
  299. panic string
  300. }{{
  301. value: &struct {
  302. B int
  303. inlineB ",inline"
  304. }{1, inlineB{2, inlineC{3}}},
  305. panic: `Duplicated key 'b' in struct struct \{ B int; .*`,
  306. }, {
  307. value: &struct {
  308. A int
  309. B map[string]int ",inline"
  310. }{1, map[string]int{"a": 2}},
  311. panic: `Can't have key "a" in inlined map; conflicts with struct field`,
  312. }}
  313. func (s *S) TestMarshalErrors(c *C) {
  314. for _, item := range marshalErrorTests {
  315. if item.panic != "" {
  316. c.Assert(func() { yaml.Marshal(item.value) }, PanicMatches, item.panic)
  317. } else {
  318. _, err := yaml.Marshal(item.value)
  319. c.Assert(err, ErrorMatches, item.error)
  320. }
  321. }
  322. }
  323. func (s *S) TestMarshalTypeCache(c *C) {
  324. var data []byte
  325. var err error
  326. func() {
  327. type T struct{ A int }
  328. data, err = yaml.Marshal(&T{})
  329. c.Assert(err, IsNil)
  330. }()
  331. func() {
  332. type T struct{ B int }
  333. data, err = yaml.Marshal(&T{})
  334. c.Assert(err, IsNil)
  335. }()
  336. c.Assert(string(data), Equals, "b: 0\n")
  337. }
  338. var marshalerTests = []struct {
  339. data string
  340. value interface{}
  341. }{
  342. {"_:\n hi: there\n", map[interface{}]interface{}{"hi": "there"}},
  343. {"_:\n- 1\n- A\n", []interface{}{1, "A"}},
  344. {"_: 10\n", 10},
  345. {"_: null\n", nil},
  346. {"_: BAR!\n", "BAR!"},
  347. }
  348. type marshalerType struct {
  349. value interface{}
  350. }
  351. func (o marshalerType) MarshalText() ([]byte, error) {
  352. panic("MarshalText called on type with MarshalYAML")
  353. }
  354. func (o marshalerType) MarshalYAML() (interface{}, error) {
  355. return o.value, nil
  356. }
  357. type marshalerValue struct {
  358. Field marshalerType "_"
  359. }
  360. func (s *S) TestMarshaler(c *C) {
  361. for _, item := range marshalerTests {
  362. obj := &marshalerValue{}
  363. obj.Field.value = item.value
  364. data, err := yaml.Marshal(obj)
  365. c.Assert(err, IsNil)
  366. c.Assert(string(data), Equals, string(item.data))
  367. }
  368. }
  369. func (s *S) TestMarshalerWholeDocument(c *C) {
  370. obj := &marshalerType{}
  371. obj.value = map[string]string{"hello": "world!"}
  372. data, err := yaml.Marshal(obj)
  373. c.Assert(err, IsNil)
  374. c.Assert(string(data), Equals, "hello: world!\n")
  375. }
  376. type failingMarshaler struct{}
  377. func (ft *failingMarshaler) MarshalYAML() (interface{}, error) {
  378. return nil, failingErr
  379. }
  380. func (s *S) TestMarshalerError(c *C) {
  381. _, err := yaml.Marshal(&failingMarshaler{})
  382. c.Assert(err, Equals, failingErr)
  383. }
  384. func (s *S) TestSortedOutput(c *C) {
  385. order := []interface{}{
  386. false,
  387. true,
  388. 1,
  389. uint(1),
  390. 1.0,
  391. 1.1,
  392. 1.2,
  393. 2,
  394. uint(2),
  395. 2.0,
  396. 2.1,
  397. "",
  398. ".1",
  399. ".2",
  400. ".a",
  401. "1",
  402. "2",
  403. "a!10",
  404. "a/2",
  405. "a/10",
  406. "a~10",
  407. "ab/1",
  408. "b/1",
  409. "b/01",
  410. "b/2",
  411. "b/02",
  412. "b/3",
  413. "b/03",
  414. "b1",
  415. "b01",
  416. "b3",
  417. "c2.10",
  418. "c10.2",
  419. "d1",
  420. "d12",
  421. "d12a",
  422. }
  423. m := make(map[interface{}]int)
  424. for _, k := range order {
  425. m[k] = 1
  426. }
  427. data, err := yaml.Marshal(m)
  428. c.Assert(err, IsNil)
  429. out := "\n" + string(data)
  430. last := 0
  431. for i, k := range order {
  432. repr := fmt.Sprint(k)
  433. if s, ok := k.(string); ok {
  434. if _, err = strconv.ParseFloat(repr, 32); s == "" || err == nil {
  435. repr = `"` + repr + `"`
  436. }
  437. }
  438. index := strings.Index(out, "\n"+repr+":")
  439. if index == -1 {
  440. c.Fatalf("%#v is not in the output: %#v", k, out)
  441. }
  442. if index < last {
  443. c.Fatalf("%#v was generated before %#v: %q", k, order[i-1], out)
  444. }
  445. last = index
  446. }
  447. }