encode_test.go 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664
  1. //
  2. // Copyright (c) 2011-2019 Canonical Ltd
  3. //
  4. // Licensed under the Apache License, Version 2.0 (the "License");
  5. // you may not use this file except in compliance with the License.
  6. // You may obtain a copy of the License at
  7. //
  8. // http://www.apache.org/licenses/LICENSE-2.0
  9. //
  10. // Unless required by applicable law or agreed to in writing, software
  11. // distributed under the License is distributed on an "AS IS" BASIS,
  12. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. // See the License for the specific language governing permissions and
  14. // limitations under the License.
  15. package yaml_test
  16. import (
  17. "bytes"
  18. "fmt"
  19. "math"
  20. "strconv"
  21. "strings"
  22. "time"
  23. "net"
  24. "os"
  25. . "gopkg.in/check.v1"
  26. "gopkg.in/yaml.v3"
  27. )
  28. var marshalIntTest = 123
  29. var marshalTests = []struct {
  30. value interface{}
  31. data string
  32. }{
  33. {
  34. nil,
  35. "null\n",
  36. }, {
  37. (*marshalerType)(nil),
  38. "null\n",
  39. }, {
  40. &struct{}{},
  41. "{}\n",
  42. }, {
  43. map[string]string{"v": "hi"},
  44. "v: hi\n",
  45. }, {
  46. map[string]interface{}{"v": "hi"},
  47. "v: hi\n",
  48. }, {
  49. map[string]string{"v": "true"},
  50. "v: \"true\"\n",
  51. }, {
  52. map[string]string{"v": "false"},
  53. "v: \"false\"\n",
  54. }, {
  55. map[string]interface{}{"v": true},
  56. "v: true\n",
  57. }, {
  58. map[string]interface{}{"v": false},
  59. "v: false\n",
  60. }, {
  61. map[string]interface{}{"v": 10},
  62. "v: 10\n",
  63. }, {
  64. map[string]interface{}{"v": -10},
  65. "v: -10\n",
  66. }, {
  67. map[string]uint{"v": 42},
  68. "v: 42\n",
  69. }, {
  70. map[string]interface{}{"v": int64(4294967296)},
  71. "v: 4294967296\n",
  72. }, {
  73. map[string]int64{"v": int64(4294967296)},
  74. "v: 4294967296\n",
  75. }, {
  76. map[string]uint64{"v": 4294967296},
  77. "v: 4294967296\n",
  78. }, {
  79. map[string]interface{}{"v": "10"},
  80. "v: \"10\"\n",
  81. }, {
  82. map[string]interface{}{"v": 0.1},
  83. "v: 0.1\n",
  84. }, {
  85. map[string]interface{}{"v": float64(0.1)},
  86. "v: 0.1\n",
  87. }, {
  88. map[string]interface{}{"v": float32(0.99)},
  89. "v: 0.99\n",
  90. }, {
  91. map[string]interface{}{"v": -0.1},
  92. "v: -0.1\n",
  93. }, {
  94. map[string]interface{}{"v": math.Inf(+1)},
  95. "v: .inf\n",
  96. }, {
  97. map[string]interface{}{"v": math.Inf(-1)},
  98. "v: -.inf\n",
  99. }, {
  100. map[string]interface{}{"v": math.NaN()},
  101. "v: .nan\n",
  102. }, {
  103. map[string]interface{}{"v": nil},
  104. "v: null\n",
  105. }, {
  106. map[string]interface{}{"v": ""},
  107. "v: \"\"\n",
  108. }, {
  109. map[string][]string{"v": []string{"A", "B"}},
  110. "v:\n - A\n - B\n",
  111. }, {
  112. map[string][]string{"v": []string{"A", "B\nC"}},
  113. "v:\n - A\n - |-\n B\n C\n",
  114. }, {
  115. map[string][]interface{}{"v": []interface{}{"A", 1, map[string][]int{"B": []int{2, 3}}}},
  116. "v:\n - A\n - 1\n - B:\n - 2\n - 3\n",
  117. }, {
  118. map[string]interface{}{"a": map[interface{}]interface{}{"b": "c"}},
  119. "a:\n b: c\n",
  120. }, {
  121. map[string]interface{}{"a": "-"},
  122. "a: '-'\n",
  123. },
  124. // Simple values.
  125. {
  126. &marshalIntTest,
  127. "123\n",
  128. },
  129. // Structures
  130. {
  131. &struct{ Hello string }{"world"},
  132. "hello: world\n",
  133. }, {
  134. &struct {
  135. A struct {
  136. B string
  137. }
  138. }{struct{ B string }{"c"}},
  139. "a:\n b: c\n",
  140. }, {
  141. &struct {
  142. A *struct {
  143. B string
  144. }
  145. }{&struct{ B string }{"c"}},
  146. "a:\n b: c\n",
  147. }, {
  148. &struct {
  149. A *struct {
  150. B string
  151. }
  152. }{},
  153. "a: null\n",
  154. }, {
  155. &struct{ A int }{1},
  156. "a: 1\n",
  157. }, {
  158. &struct{ A []int }{[]int{1, 2}},
  159. "a:\n - 1\n - 2\n",
  160. }, {
  161. &struct{ A [2]int }{[2]int{1, 2}},
  162. "a:\n - 1\n - 2\n",
  163. }, {
  164. &struct {
  165. B int "a"
  166. }{1},
  167. "a: 1\n",
  168. }, {
  169. &struct{ A bool }{true},
  170. "a: true\n",
  171. },
  172. // Conditional flag
  173. {
  174. &struct {
  175. A int "a,omitempty"
  176. B int "b,omitempty"
  177. }{1, 0},
  178. "a: 1\n",
  179. }, {
  180. &struct {
  181. A int "a,omitempty"
  182. B int "b,omitempty"
  183. }{0, 0},
  184. "{}\n",
  185. }, {
  186. &struct {
  187. A *struct{ X, y int } "a,omitempty,flow"
  188. }{&struct{ X, y int }{1, 2}},
  189. "a: {x: 1}\n",
  190. }, {
  191. &struct {
  192. A *struct{ X, y int } "a,omitempty,flow"
  193. }{nil},
  194. "{}\n",
  195. }, {
  196. &struct {
  197. A *struct{ X, y int } "a,omitempty,flow"
  198. }{&struct{ X, y int }{}},
  199. "a: {x: 0}\n",
  200. }, {
  201. &struct {
  202. A struct{ X, y int } "a,omitempty,flow"
  203. }{struct{ X, y int }{1, 2}},
  204. "a: {x: 1}\n",
  205. }, {
  206. &struct {
  207. A struct{ X, y int } "a,omitempty,flow"
  208. }{struct{ X, y int }{0, 1}},
  209. "{}\n",
  210. }, {
  211. &struct {
  212. A float64 "a,omitempty"
  213. B float64 "b,omitempty"
  214. }{1, 0},
  215. "a: 1\n",
  216. },
  217. {
  218. &struct {
  219. T1 time.Time "t1,omitempty"
  220. T2 time.Time "t2,omitempty"
  221. T3 *time.Time "t3,omitempty"
  222. T4 *time.Time "t4,omitempty"
  223. }{
  224. T2: time.Date(2018, 1, 9, 10, 40, 47, 0, time.UTC),
  225. T4: newTime(time.Date(2098, 1, 9, 10, 40, 47, 0, time.UTC)),
  226. },
  227. "t2: 2018-01-09T10:40:47Z\nt4: 2098-01-09T10:40:47Z\n",
  228. },
  229. // Nil interface that implements Marshaler.
  230. {
  231. map[string]yaml.Marshaler{
  232. "a": nil,
  233. },
  234. "a: null\n",
  235. },
  236. // Flow flag
  237. {
  238. &struct {
  239. A []int "a,flow"
  240. }{[]int{1, 2}},
  241. "a: [1, 2]\n",
  242. }, {
  243. &struct {
  244. A map[string]string "a,flow"
  245. }{map[string]string{"b": "c", "d": "e"}},
  246. "a: {b: c, d: e}\n",
  247. }, {
  248. &struct {
  249. A struct {
  250. B, D string
  251. } "a,flow"
  252. }{struct{ B, D string }{"c", "e"}},
  253. "a: {b: c, d: e}\n",
  254. }, {
  255. &struct {
  256. A string "a,flow"
  257. }{"b\nc"},
  258. "a: \"b\\nc\"\n",
  259. },
  260. // Unexported field
  261. {
  262. &struct {
  263. u int
  264. A int
  265. }{0, 1},
  266. "a: 1\n",
  267. },
  268. // Ignored field
  269. {
  270. &struct {
  271. A int
  272. B int "-"
  273. }{1, 2},
  274. "a: 1\n",
  275. },
  276. // Struct inlining
  277. {
  278. &struct {
  279. A int
  280. C inlineB `yaml:",inline"`
  281. }{1, inlineB{2, inlineC{3}}},
  282. "a: 1\nb: 2\nc: 3\n",
  283. },
  284. // Struct inlining as a pointer
  285. {
  286. &struct {
  287. A int
  288. C *inlineB `yaml:",inline"`
  289. }{1, &inlineB{2, inlineC{3}}},
  290. "a: 1\nb: 2\nc: 3\n",
  291. }, {
  292. &struct {
  293. A int
  294. C *inlineB `yaml:",inline"`
  295. }{1, nil},
  296. "a: 1\n",
  297. }, {
  298. &struct {
  299. A int
  300. D *inlineD `yaml:",inline"`
  301. }{1, &inlineD{&inlineC{3}, 4}},
  302. "a: 1\nc: 3\nd: 4\n",
  303. },
  304. // Map inlining
  305. {
  306. &struct {
  307. A int
  308. C map[string]int `yaml:",inline"`
  309. }{1, map[string]int{"b": 2, "c": 3}},
  310. "a: 1\nb: 2\nc: 3\n",
  311. },
  312. // Duration
  313. {
  314. map[string]time.Duration{"a": 3 * time.Second},
  315. "a: 3s\n",
  316. },
  317. // Issue #24: bug in map merging logic.
  318. {
  319. map[string]string{"a": "<foo>"},
  320. "a: <foo>\n",
  321. },
  322. // Issue #34: marshal unsupported base 60 floats quoted for compatibility
  323. // with old YAML 1.1 parsers.
  324. {
  325. map[string]string{"a": "1:1"},
  326. "a: \"1:1\"\n",
  327. },
  328. // Binary data.
  329. {
  330. map[string]string{"a": "\x00"},
  331. "a: \"\\0\"\n",
  332. }, {
  333. map[string]string{"a": "\x80\x81\x82"},
  334. "a: !!binary gIGC\n",
  335. }, {
  336. map[string]string{"a": strings.Repeat("\x90", 54)},
  337. "a: !!binary |\n " + strings.Repeat("kJCQ", 17) + "kJ\n CQ\n",
  338. },
  339. // Encode unicode as utf-8 rather than in escaped form.
  340. {
  341. map[string]string{"a": "你好"},
  342. "a: 你好\n",
  343. },
  344. // Support encoding.TextMarshaler.
  345. {
  346. map[string]net.IP{"a": net.IPv4(1, 2, 3, 4)},
  347. "a: 1.2.3.4\n",
  348. },
  349. // time.Time gets a timestamp tag.
  350. {
  351. map[string]time.Time{"a": time.Date(2015, 2, 24, 18, 19, 39, 0, time.UTC)},
  352. "a: 2015-02-24T18:19:39Z\n",
  353. },
  354. {
  355. map[string]*time.Time{"a": newTime(time.Date(2015, 2, 24, 18, 19, 39, 0, time.UTC))},
  356. "a: 2015-02-24T18:19:39Z\n",
  357. },
  358. {
  359. // This is confirmed to be properly decoded in Python (libyaml) without a timestamp tag.
  360. map[string]time.Time{"a": time.Date(2015, 2, 24, 18, 19, 39, 123456789, time.FixedZone("FOO", -3*60*60))},
  361. "a: 2015-02-24T18:19:39.123456789-03:00\n",
  362. },
  363. // Ensure timestamp-like strings are quoted.
  364. {
  365. map[string]string{"a": "2015-02-24T18:19:39Z"},
  366. "a: \"2015-02-24T18:19:39Z\"\n",
  367. },
  368. // Ensure strings containing ": " are quoted (reported as PR #43, but not reproducible).
  369. {
  370. map[string]string{"a": "b: c"},
  371. "a: 'b: c'\n",
  372. },
  373. // Containing hash mark ('#') in string should be quoted
  374. {
  375. map[string]string{"a": "Hello #comment"},
  376. "a: 'Hello #comment'\n",
  377. },
  378. {
  379. map[string]string{"a": "你好 #comment"},
  380. "a: '你好 #comment'\n",
  381. },
  382. // Ensure MarshalYAML also gets called on the result of MarshalYAML itself.
  383. {
  384. &marshalerType{marshalerType{true}},
  385. "true\n",
  386. }, {
  387. &marshalerType{&marshalerType{true}},
  388. "true\n",
  389. },
  390. // Check indentation of maps inside sequences inside maps.
  391. {
  392. map[string]interface{}{"a": map[string]interface{}{"b": []map[string]int{{"c": 1, "d": 2}}}},
  393. "a:\n b:\n - c: 1\n d: 2\n",
  394. },
  395. // Strings with tabs were disallowed as literals (issue #471).
  396. {
  397. map[string]string{"a": "\tB\n\tC\n"},
  398. "a: |\n \tB\n \tC\n",
  399. },
  400. }
  401. func (s *S) TestMarshal(c *C) {
  402. defer os.Setenv("TZ", os.Getenv("TZ"))
  403. os.Setenv("TZ", "UTC")
  404. for i, item := range marshalTests {
  405. c.Logf("test %d: %q", i, item.data)
  406. data, err := yaml.Marshal(item.value)
  407. c.Assert(err, IsNil)
  408. c.Assert(string(data), Equals, item.data)
  409. }
  410. }
  411. func (s *S) TestEncoderSingleDocument(c *C) {
  412. for i, item := range marshalTests {
  413. c.Logf("test %d. %q", i, item.data)
  414. var buf bytes.Buffer
  415. enc := yaml.NewEncoder(&buf)
  416. err := enc.Encode(item.value)
  417. c.Assert(err, Equals, nil)
  418. err = enc.Close()
  419. c.Assert(err, Equals, nil)
  420. c.Assert(buf.String(), Equals, item.data)
  421. }
  422. }
  423. func (s *S) TestEncoderMultipleDocuments(c *C) {
  424. var buf bytes.Buffer
  425. enc := yaml.NewEncoder(&buf)
  426. err := enc.Encode(map[string]string{"a": "b"})
  427. c.Assert(err, Equals, nil)
  428. err = enc.Encode(map[string]string{"c": "d"})
  429. c.Assert(err, Equals, nil)
  430. err = enc.Close()
  431. c.Assert(err, Equals, nil)
  432. c.Assert(buf.String(), Equals, "a: b\n---\nc: d\n")
  433. }
  434. func (s *S) TestEncoderWriteError(c *C) {
  435. enc := yaml.NewEncoder(errorWriter{})
  436. err := enc.Encode(map[string]string{"a": "b"})
  437. c.Assert(err, ErrorMatches, `yaml: write error: some write error`) // Data not flushed yet
  438. }
  439. type errorWriter struct{}
  440. func (errorWriter) Write([]byte) (int, error) {
  441. return 0, fmt.Errorf("some write error")
  442. }
  443. var marshalErrorTests = []struct {
  444. value interface{}
  445. error string
  446. panic string
  447. }{{
  448. value: &struct {
  449. B int
  450. inlineB ",inline"
  451. }{1, inlineB{2, inlineC{3}}},
  452. panic: `duplicated key 'b' in struct struct \{ B int; .*`,
  453. }, {
  454. value: &struct {
  455. A int
  456. B map[string]int ",inline"
  457. }{1, map[string]int{"a": 2}},
  458. panic: `cannot have key "a" in inlined map: conflicts with struct field`,
  459. }}
  460. func (s *S) TestMarshalErrors(c *C) {
  461. for _, item := range marshalErrorTests {
  462. if item.panic != "" {
  463. c.Assert(func() { yaml.Marshal(item.value) }, PanicMatches, item.panic)
  464. } else {
  465. _, err := yaml.Marshal(item.value)
  466. c.Assert(err, ErrorMatches, item.error)
  467. }
  468. }
  469. }
  470. func (s *S) TestMarshalTypeCache(c *C) {
  471. var data []byte
  472. var err error
  473. func() {
  474. type T struct{ A int }
  475. data, err = yaml.Marshal(&T{})
  476. c.Assert(err, IsNil)
  477. }()
  478. func() {
  479. type T struct{ B int }
  480. data, err = yaml.Marshal(&T{})
  481. c.Assert(err, IsNil)
  482. }()
  483. c.Assert(string(data), Equals, "b: 0\n")
  484. }
  485. var marshalerTests = []struct {
  486. data string
  487. value interface{}
  488. }{
  489. {"_:\n hi: there\n", map[interface{}]interface{}{"hi": "there"}},
  490. {"_:\n - 1\n - A\n", []interface{}{1, "A"}},
  491. {"_: 10\n", 10},
  492. {"_: null\n", nil},
  493. {"_: BAR!\n", "BAR!"},
  494. }
  495. type marshalerType struct {
  496. value interface{}
  497. }
  498. func (o marshalerType) MarshalText() ([]byte, error) {
  499. panic("MarshalText called on type with MarshalYAML")
  500. }
  501. func (o marshalerType) MarshalYAML() (interface{}, error) {
  502. return o.value, nil
  503. }
  504. type marshalerValue struct {
  505. Field marshalerType "_"
  506. }
  507. func (s *S) TestMarshaler(c *C) {
  508. for _, item := range marshalerTests {
  509. obj := &marshalerValue{}
  510. obj.Field.value = item.value
  511. data, err := yaml.Marshal(obj)
  512. c.Assert(err, IsNil)
  513. c.Assert(string(data), Equals, string(item.data))
  514. }
  515. }
  516. func (s *S) TestMarshalerWholeDocument(c *C) {
  517. obj := &marshalerType{}
  518. obj.value = map[string]string{"hello": "world!"}
  519. data, err := yaml.Marshal(obj)
  520. c.Assert(err, IsNil)
  521. c.Assert(string(data), Equals, "hello: world!\n")
  522. }
  523. type failingMarshaler struct{}
  524. func (ft *failingMarshaler) MarshalYAML() (interface{}, error) {
  525. return nil, failingErr
  526. }
  527. func (s *S) TestMarshalerError(c *C) {
  528. _, err := yaml.Marshal(&failingMarshaler{})
  529. c.Assert(err, Equals, failingErr)
  530. }
  531. func (s *S) TestSetIndent(c *C) {
  532. var buf bytes.Buffer
  533. enc := yaml.NewEncoder(&buf)
  534. enc.SetIndent(8)
  535. err := enc.Encode(map[string]interface{}{"a": map[string]interface{}{"b": map[string]string{"c": "d"}}})
  536. c.Assert(err, Equals, nil)
  537. err = enc.Close()
  538. c.Assert(err, Equals, nil)
  539. c.Assert(buf.String(), Equals, "a:\n b:\n c: d\n")
  540. }
  541. func (s *S) TestSortedOutput(c *C) {
  542. order := []interface{}{
  543. false,
  544. true,
  545. 1,
  546. uint(1),
  547. 1.0,
  548. 1.1,
  549. 1.2,
  550. 2,
  551. uint(2),
  552. 2.0,
  553. 2.1,
  554. "",
  555. ".1",
  556. ".2",
  557. ".a",
  558. "1",
  559. "2",
  560. "a!10",
  561. "a/0001",
  562. "a/002",
  563. "a/3",
  564. "a/10",
  565. "a/11",
  566. "a/0012",
  567. "a/100",
  568. "a~10",
  569. "ab/1",
  570. "b/1",
  571. "b/01",
  572. "b/2",
  573. "b/02",
  574. "b/3",
  575. "b/03",
  576. "b1",
  577. "b01",
  578. "b3",
  579. "c2.10",
  580. "c10.2",
  581. "d1",
  582. "d7",
  583. "d7abc",
  584. "d12",
  585. "d12a",
  586. "e2b",
  587. "e4b",
  588. "e21a",
  589. }
  590. m := make(map[interface{}]int)
  591. for _, k := range order {
  592. m[k] = 1
  593. }
  594. data, err := yaml.Marshal(m)
  595. c.Assert(err, IsNil)
  596. out := "\n" + string(data)
  597. last := 0
  598. for i, k := range order {
  599. repr := fmt.Sprint(k)
  600. if s, ok := k.(string); ok {
  601. if _, err = strconv.ParseFloat(repr, 32); s == "" || err == nil {
  602. repr = `"` + repr + `"`
  603. }
  604. }
  605. index := strings.Index(out, "\n"+repr+":")
  606. if index == -1 {
  607. c.Fatalf("%#v is not in the output: %#v", k, out)
  608. }
  609. if index < last {
  610. c.Fatalf("%#v was generated before %#v: %q", k, order[i-1], out)
  611. }
  612. last = index
  613. }
  614. }
  615. func newTime(t time.Time) *time.Time {
  616. return &t
  617. }