encode_test.go 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270
  1. package goyaml_test
  2. import (
  3. "fmt"
  4. . "launchpad.net/gocheck"
  5. "launchpad.net/goyaml"
  6. "math"
  7. "strconv"
  8. "strings"
  9. )
  10. var marshalIntTest = 123
  11. var marshalTests = []struct {
  12. data string
  13. value interface{}
  14. }{
  15. {"{}\n", &struct{}{}},
  16. {"v: hi\n", map[string]string{"v": "hi"}},
  17. {"v: hi\n", map[string]interface{}{"v": "hi"}},
  18. {"v: \"true\"\n", map[string]string{"v": "true"}},
  19. {"v: \"false\"\n", map[string]string{"v": "false"}},
  20. {"v: true\n", map[string]interface{}{"v": true}},
  21. {"v: false\n", map[string]interface{}{"v": false}},
  22. {"v: 10\n", map[string]interface{}{"v": 10}},
  23. {"v: -10\n", map[string]interface{}{"v": -10}},
  24. {"v: 42\n", map[string]uint{"v": 42}},
  25. {"v: 4294967296\n", map[string]interface{}{"v": int64(4294967296)}},
  26. {"v: 4294967296\n", map[string]int64{"v": int64(4294967296)}},
  27. {"v: 4294967296\n", map[string]uint64{"v": 4294967296}},
  28. {"v: \"10\"\n", map[string]interface{}{"v": "10"}},
  29. {"v: 0.1\n", map[string]interface{}{"v": 0.1}},
  30. {"v: 0.1\n", map[string]interface{}{"v": float64(0.1)}},
  31. {"v: -0.1\n", map[string]interface{}{"v": -0.1}},
  32. {"v: .inf\n", map[string]interface{}{"v": math.Inf(+1)}},
  33. {"v: -.inf\n", map[string]interface{}{"v": math.Inf(-1)}},
  34. {"v: .nan\n", map[string]interface{}{"v": math.NaN()}},
  35. {"v: null\n", map[string]interface{}{"v": nil}},
  36. {"v: \"\"\n", map[string]interface{}{"v": ""}},
  37. {"v:\n- A\n- B\n", map[string][]string{"v": []string{"A", "B"}}},
  38. {"v:\n- A\n- 1\n", map[string][]interface{}{"v": []interface{}{"A", 1}}},
  39. {"a:\n b: c\n",
  40. map[string]interface{}{"a": map[interface{}]interface{}{"b": "c"}}},
  41. // Simple values.
  42. {"123\n", &marshalIntTest},
  43. // Structures
  44. {"hello: world\n", &struct{ Hello string }{"world"}},
  45. {"a:\n b: c\n", &struct {
  46. A struct {
  47. B string
  48. }
  49. }{struct{ B string }{"c"}}},
  50. {"a:\n b: c\n", &struct {
  51. A *struct {
  52. B string
  53. }
  54. }{&struct{ B string }{"c"}}},
  55. {"a: null\n", &struct {
  56. A *struct {
  57. B string
  58. }
  59. }{}},
  60. {"a: 1\n", &struct{ A int }{1}},
  61. {"a:\n- 1\n- 2\n", &struct{ A []int }{[]int{1, 2}}},
  62. {"a: 1\n", &struct {
  63. B int "a"
  64. }{1}},
  65. {"a: true\n", &struct{ A bool }{true}},
  66. // Conditional flag
  67. {"a: 1\n", &struct {
  68. A int "a,omitempty"
  69. B int "b,omitempty"
  70. }{1, 0}},
  71. {"{}\n", &struct {
  72. A int "a,omitempty"
  73. B int "b,omitempty"
  74. }{0, 0}},
  75. {"{}\n", &struct {
  76. A *struct{ X int } "a,omitempty"
  77. B int "b,omitempty"
  78. }{nil, 0}},
  79. // Flow flag
  80. {"a: [1, 2]\n", &struct {
  81. A []int "a,flow"
  82. }{[]int{1, 2}}},
  83. {"a: {b: c}\n",
  84. &struct {
  85. A map[string]string "a,flow"
  86. }{map[string]string{"b": "c"}}},
  87. {"a: {b: c}\n",
  88. &struct {
  89. A struct {
  90. B string
  91. } "a,flow"
  92. }{struct{ B string }{"c"}}},
  93. // Unexported field
  94. {"a: 1\n",
  95. &struct {
  96. u int
  97. A int
  98. }{0, 1}},
  99. // Ignored field
  100. {"a: 1\n",
  101. &struct {
  102. A int
  103. B int "-"
  104. }{1, 2}},
  105. }
  106. func (s *S) TestMarshal(c *C) {
  107. for _, item := range marshalTests {
  108. data, err := goyaml.Marshal(item.value)
  109. c.Assert(err, IsNil)
  110. c.Assert(string(data), Equals, item.data)
  111. }
  112. }
  113. //var unmarshalErrorTests = []struct{data, error string}{
  114. // {"v: !!float 'error'", "Can't decode !!str 'error' as a !!float"},
  115. //}
  116. //
  117. //func (s *S) TestUnmarshalErrors(c *C) {
  118. // for _, item := range unmarshalErrorTests {
  119. // var value interface{}
  120. // err := goyaml.Unmarshal([]byte(item.data), &value)
  121. // c.Assert(err, Matches, item.error)
  122. // }
  123. //}
  124. var marshalTaggedIfaceTest interface{} = &struct{ A string }{"B"}
  125. var getterTests = []struct {
  126. data, tag string
  127. value interface{}
  128. }{
  129. {"_:\n hi: there\n", "", map[interface{}]interface{}{"hi": "there"}},
  130. {"_:\n- 1\n- A\n", "", []interface{}{1, "A"}},
  131. {"_: 10\n", "", 10},
  132. {"_: null\n", "", nil},
  133. {"_: !foo BAR!\n", "!foo", "BAR!"},
  134. {"_: !foo 1\n", "!foo", "1"},
  135. {"_: !foo '\"1\"'\n", "!foo", "\"1\""},
  136. {"_: !foo 1.1\n", "!foo", 1.1},
  137. {"_: !foo 1\n", "!foo", 1},
  138. {"_: !foo 1\n", "!foo", uint(1)},
  139. {"_: !foo true\n", "!foo", true},
  140. {"_: !foo\n- A\n- B\n", "!foo", []string{"A", "B"}},
  141. {"_: !foo\n A: B\n", "!foo", map[string]string{"A": "B"}},
  142. {"_: !foo\n a: B\n", "!foo", &marshalTaggedIfaceTest},
  143. }
  144. func (s *S) TestMarshalTypeCache(c *C) {
  145. var data []byte
  146. var err error
  147. func() {
  148. type T struct{ A int }
  149. data, err = goyaml.Marshal(&T{})
  150. c.Assert(err, IsNil)
  151. }()
  152. func() {
  153. type T struct{ B int }
  154. data, err = goyaml.Marshal(&T{})
  155. c.Assert(err, IsNil)
  156. }()
  157. c.Assert(string(data), Equals, "b: 0\n")
  158. }
  159. type typeWithGetter struct {
  160. tag string
  161. value interface{}
  162. }
  163. func (o typeWithGetter) GetYAML() (tag string, value interface{}) {
  164. return o.tag, o.value
  165. }
  166. type typeWithGetterField struct {
  167. Field typeWithGetter "_"
  168. }
  169. func (s *S) TestMashalWithGetter(c *C) {
  170. for _, item := range getterTests {
  171. obj := &typeWithGetterField{}
  172. obj.Field.tag = item.tag
  173. obj.Field.value = item.value
  174. data, err := goyaml.Marshal(obj)
  175. c.Assert(err, IsNil)
  176. c.Assert(string(data), Equals, string(item.data))
  177. }
  178. }
  179. func (s *S) TestUnmarshalWholeDocumentWithGetter(c *C) {
  180. obj := &typeWithGetter{}
  181. obj.tag = ""
  182. obj.value = map[string]string{"hello": "world!"}
  183. data, err := goyaml.Marshal(obj)
  184. c.Assert(err, IsNil)
  185. c.Assert(string(data), Equals, "hello: world!\n")
  186. }
  187. func (s *S) TestSortedOutput(c *C) {
  188. order := []interface{}{
  189. false,
  190. true,
  191. 1,
  192. uint(1),
  193. 1.0,
  194. 1.1,
  195. 1.2,
  196. 2,
  197. uint(2),
  198. 2.0,
  199. 2.1,
  200. "",
  201. ".1",
  202. ".2",
  203. ".a",
  204. "1",
  205. "2",
  206. "a!10",
  207. "a/2",
  208. "a/10",
  209. "a~10",
  210. "ab/1",
  211. "b/1",
  212. "b/01",
  213. "b/2",
  214. "b/02",
  215. "b/3",
  216. "b/03",
  217. "b1",
  218. "b01",
  219. "b3",
  220. "c2.10",
  221. "c10.2",
  222. "d1",
  223. "d12",
  224. "d12a",
  225. }
  226. m := make(map[interface{}]int)
  227. for _, k := range order {
  228. m[k] = 1
  229. }
  230. data, err := goyaml.Marshal(m)
  231. c.Assert(err, IsNil)
  232. out := "\n" + string(data)
  233. last := 0
  234. for i, k := range order {
  235. repr := fmt.Sprint(k)
  236. if s, ok := k.(string); ok {
  237. if _, err = strconv.ParseFloat(repr, 32); s == "" || err == nil {
  238. repr = `"` + repr + `"`
  239. }
  240. }
  241. index := strings.Index(out, "\n"+repr+":")
  242. if index == -1 {
  243. c.Fatalf("%#v is not in the output: %#v", k, out)
  244. }
  245. if index < last {
  246. c.Fatalf("%#v was generated before %#v: %q", k, order[i-1], out)
  247. }
  248. last = index
  249. }
  250. }