decode_test.go 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299
  1. package goyaml_test
  2. import (
  3. "io/ioutil"
  4. . "launchpad.net/gocheck"
  5. "launchpad.net/goyaml"
  6. "math"
  7. "reflect"
  8. )
  9. var unmarshalIntTest = 123
  10. var unmarshalTests = []struct {
  11. data string
  12. value interface{}
  13. }{
  14. {"", &struct{}{}},
  15. {"{}", &struct{}{}},
  16. {"v: hi", map[string]string{"v": "hi"}},
  17. {"v: hi", map[string]interface{}{"v": "hi"}},
  18. {"v: true", map[string]string{"v": "true"}},
  19. {"v: true", map[string]interface{}{"v": true}},
  20. {"v: 10", map[string]interface{}{"v": 10}},
  21. {"v: 0b10", map[string]interface{}{"v": 2}},
  22. {"v: 0xA", map[string]interface{}{"v": 10}},
  23. {"v: 4294967296", map[string]int64{"v": 4294967296}},
  24. {"v: 0.1", map[string]interface{}{"v": 0.1}},
  25. {"v: .1", map[string]interface{}{"v": 0.1}},
  26. {"v: .Inf", map[string]interface{}{"v": math.Inf(+1)}},
  27. {"v: -.Inf", map[string]interface{}{"v": math.Inf(-1)}},
  28. {"v: -10", map[string]interface{}{"v": -10}},
  29. {"v: -.1", map[string]interface{}{"v": -0.1}},
  30. // Simple values.
  31. {"123", &unmarshalIntTest},
  32. // Floats from spec
  33. {"canonical: 6.8523e+5", map[string]interface{}{"canonical": 6.8523e+5}},
  34. {"expo: 685.230_15e+03", map[string]interface{}{"expo": 685.23015e+03}},
  35. {"fixed: 685_230.15", map[string]interface{}{"fixed": 685230.15}},
  36. //{"sexa: 190:20:30.15", map[string]interface{}{"sexa": 0}}, // Unsupported
  37. {"neginf: -.inf", map[string]interface{}{"neginf": math.Inf(-1)}},
  38. //{"notanum: .NaN", map[string]interface{}{"notanum": math.NaN()}}, // Equality of NaN fails.
  39. {"fixed: 685_230.15", map[string]float64{"fixed": 685230.15}},
  40. // Bools from spec
  41. {"canonical: y", map[string]interface{}{"canonical": true}},
  42. {"answer: NO", map[string]interface{}{"answer": false}},
  43. {"logical: True", map[string]interface{}{"logical": true}},
  44. {"option: on", map[string]interface{}{"option": true}},
  45. {"option: on", map[string]bool{"option": true}},
  46. // Ints from spec
  47. {"canonical: 685230", map[string]interface{}{"canonical": 685230}},
  48. {"decimal: +685_230", map[string]interface{}{"decimal": 685230}},
  49. {"octal: 02472256", map[string]interface{}{"octal": 685230}},
  50. {"hexa: 0x_0A_74_AE", map[string]interface{}{"hexa": 685230}},
  51. {"bin: 0b1010_0111_0100_1010_1110", map[string]interface{}{"bin": 685230}},
  52. {"bin: -0b101010", map[string]interface{}{"bin": -42}},
  53. //{"sexa: 190:20:30", map[string]interface{}{"sexa": 0}}, // Unsupported
  54. {"decimal: +685_230", map[string]int{"decimal": 685230}},
  55. // Nulls from spec
  56. {"empty:", map[string]interface{}{"empty": nil}},
  57. {"canonical: ~", map[string]interface{}{"canonical": nil}},
  58. {"english: null", map[string]interface{}{"english": nil}},
  59. {"~: null key", map[interface{}]string{nil: "null key"}},
  60. {"empty:", map[string]*bool{"empty": nil}},
  61. // Flow sequence
  62. {"seq: [A,B]", map[string]interface{}{"seq": []interface{}{"A", "B"}}},
  63. {"seq: [A,B,C,]", map[string][]string{"seq": []string{"A", "B", "C"}}},
  64. {"seq: [A,1,C]", map[string][]string{"seq": []string{"A", "1", "C"}}},
  65. {"seq: [A,1,C]", map[string][]int{"seq": []int{1}}},
  66. {"seq: [A,1,C]", map[string]interface{}{"seq": []interface{}{"A", 1, "C"}}},
  67. // Block sequence
  68. {"seq:\n - A\n - B", map[string]interface{}{"seq": []interface{}{"A", "B"}}},
  69. {"seq:\n - A\n - B\n - C", map[string][]string{"seq": []string{"A", "B", "C"}}},
  70. {"seq:\n - A\n - 1\n - C", map[string][]string{"seq": []string{"A", "1", "C"}}},
  71. {"seq:\n - A\n - 1\n - C", map[string][]int{"seq": []int{1}}},
  72. {"seq:\n - A\n - 1\n - C", map[string]interface{}{"seq": []interface{}{"A", 1, "C"}}},
  73. // Literal block scalar
  74. {"scalar: | # Comment\n\n literal\n\n \ttext\n\n",
  75. map[string]string{"scalar": "\nliteral\n\n\ttext\n"}},
  76. // Folded block scalar
  77. {"scalar: > # Comment\n\n folded\n line\n \n next\n line\n * one\n * two\n\n last\n line\n\n",
  78. map[string]string{"scalar": "\nfolded line\nnext line\n * one\n * two\n\nlast line\n"}},
  79. // Map inside interface with no type hints.
  80. {"a: {b: c}",
  81. map[string]interface{}{"a": map[interface{}]interface{}{"b": "c"}}},
  82. // Structs and type conversions.
  83. {"hello: world", &struct{ Hello string }{"world"}},
  84. {"a: {b: c}", &struct{ A struct{ B string } }{struct{ B string }{"c"}}},
  85. {"a: {b: c}", &struct{ A *struct{ B string } }{&struct{ B string }{"c"}}},
  86. {"a: {b: c}", &struct{ A map[string]string }{map[string]string{"b": "c"}}},
  87. {"a: {b: c}", &struct{ A *map[string]string }{&map[string]string{"b": "c"}}},
  88. {"a:", &struct{ A map[string]string }{}},
  89. {"a: 1", &struct{ A int }{1}},
  90. {"a: [1, 2]", &struct{ A []int }{[]int{1, 2}}},
  91. {"a: 1", &struct{ B int }{0}},
  92. {"a: 1", &struct {
  93. B int "a"
  94. }{1}},
  95. {"a: y", &struct{ A bool }{true}},
  96. // Some cross type conversions
  97. {"v: 42", map[string]uint{"v": 42}},
  98. {"v: -42", map[string]uint{}},
  99. {"v: 4294967296", map[string]uint64{"v": 4294967296}},
  100. {"v: -4294967296", map[string]uint64{}},
  101. // Overflow cases.
  102. {"v: 4294967297", map[string]int32{}},
  103. {"v: 128", map[string]int8{}},
  104. // Quoted values.
  105. {"'1': '\"2\"'", map[interface{}]interface{}{"1": "\"2\""}},
  106. // Explicit tags.
  107. {"v: !!float '1.1'", map[string]interface{}{"v": 1.1}},
  108. {"v: !!null ''", map[string]interface{}{"v": nil}},
  109. {"%TAG !y! tag:yaml.org,2002:\n---\nv: !y!int '1'",
  110. map[string]interface{}{"v": 1}},
  111. // Anchors and aliases.
  112. {"a: &x 1\nb: &y 2\nc: *x\nd: *y\n", &struct{ A, B, C, D int }{1, 2, 1, 2}},
  113. {"a: &a {c: 1}\nb: *a",
  114. &struct {
  115. A, B struct {
  116. C int
  117. }
  118. }{struct{ C int }{1}, struct{ C int }{1}}},
  119. {"a: &a [1, 2]\nb: *a", &struct{ B []int }{[]int{1, 2}}},
  120. // BUG #1133337
  121. {"foo: ''", map[string]*string{"foo": new(string)}},
  122. {"foo: null", map[string]string{}},
  123. // Ignored field
  124. {"a: 1\nb: 2\n",
  125. &struct {
  126. A int
  127. B int "-"
  128. }{1, 0}},
  129. }
  130. func (s *S) TestUnmarshal(c *C) {
  131. for i, item := range unmarshalTests {
  132. t := reflect.ValueOf(item.value).Type()
  133. var value interface{}
  134. if t.Kind() == reflect.Map {
  135. value = reflect.MakeMap(t).Interface()
  136. } else {
  137. pt := reflect.ValueOf(item.value).Type()
  138. pv := reflect.New(pt.Elem())
  139. value = pv.Interface()
  140. }
  141. err := goyaml.Unmarshal([]byte(item.data), value)
  142. c.Assert(err, IsNil, Commentf("Item #%d", i))
  143. c.Assert(value, DeepEquals, item.value)
  144. }
  145. }
  146. func (s *S) TestUnmarshalNaN(c *C) {
  147. value := map[string]interface{}{}
  148. err := goyaml.Unmarshal([]byte("notanum: .NaN"), &value)
  149. c.Assert(err, IsNil)
  150. c.Assert(math.IsNaN(value["notanum"].(float64)), Equals, true)
  151. }
  152. var unmarshalErrorTests = []struct {
  153. data, error string
  154. }{
  155. {"v: !!float 'error'", "YAML error: Can't decode !!str 'error' as a !!float"},
  156. {"v: [A,", "YAML error: line 1: did not find expected node content"},
  157. {"v:\n- [A,", "YAML error: line 2: did not find expected node content"},
  158. {"a: *b\n", "YAML error: Unknown anchor 'b' referenced"},
  159. {"a: &a\n b: *a\n", "YAML error: Anchor 'a' value contains itself"},
  160. }
  161. func (s *S) TestUnmarshalErrors(c *C) {
  162. for _, item := range unmarshalErrorTests {
  163. var value interface{}
  164. err := goyaml.Unmarshal([]byte(item.data), &value)
  165. c.Assert(err, ErrorMatches, item.error, Commentf("Partial unmarshal: %#v", value))
  166. }
  167. }
  168. var setterTests = []struct {
  169. data, tag string
  170. value interface{}
  171. }{
  172. {"_: {hi: there}", "!!map", map[interface{}]interface{}{"hi": "there"}},
  173. {"_: [1,A]", "!!seq", []interface{}{1, "A"}},
  174. {"_: 10", "!!int", 10},
  175. {"_: null", "!!null", nil},
  176. {"_: !!foo 'BAR!'", "!!foo", "BAR!"},
  177. }
  178. var setterResult = map[int]bool{}
  179. type typeWithSetter struct {
  180. tag string
  181. value interface{}
  182. }
  183. func (o *typeWithSetter) SetYAML(tag string, value interface{}) (ok bool) {
  184. o.tag = tag
  185. o.value = value
  186. if i, ok := value.(int); ok {
  187. if result, ok := setterResult[i]; ok {
  188. return result
  189. }
  190. }
  191. return true
  192. }
  193. type typeWithSetterField struct {
  194. Field *typeWithSetter "_"
  195. }
  196. func (s *S) TestUnmarshalWithSetter(c *C) {
  197. for _, item := range setterTests {
  198. obj := &typeWithSetterField{}
  199. err := goyaml.Unmarshal([]byte(item.data), obj)
  200. c.Assert(err, IsNil)
  201. c.Assert(obj.Field, NotNil,
  202. Commentf("Pointer not initialized (%#v)", item.value))
  203. c.Assert(obj.Field.tag, Equals, item.tag)
  204. c.Assert(obj.Field.value, DeepEquals, item.value)
  205. }
  206. }
  207. func (s *S) TestUnmarshalWholeDocumentWithSetter(c *C) {
  208. obj := &typeWithSetter{}
  209. err := goyaml.Unmarshal([]byte(setterTests[0].data), obj)
  210. c.Assert(err, IsNil)
  211. c.Assert(obj.tag, Equals, setterTests[0].tag)
  212. value, ok := obj.value.(map[interface{}]interface{})
  213. c.Assert(ok, Equals, true)
  214. c.Assert(value["_"], DeepEquals, setterTests[0].value)
  215. }
  216. func (s *S) TestUnmarshalWithFalseSetterIgnoresValue(c *C) {
  217. setterResult[2] = false
  218. setterResult[4] = false
  219. defer func() {
  220. delete(setterResult, 2)
  221. delete(setterResult, 4)
  222. }()
  223. m := map[string]*typeWithSetter{}
  224. data := "{abc: 1, def: 2, ghi: 3, jkl: 4}"
  225. err := goyaml.Unmarshal([]byte(data), m)
  226. c.Assert(err, IsNil)
  227. c.Assert(m["abc"], NotNil)
  228. c.Assert(m["def"], IsNil)
  229. c.Assert(m["ghi"], NotNil)
  230. c.Assert(m["jkl"], IsNil)
  231. c.Assert(m["abc"].value, Equals, 1)
  232. c.Assert(m["ghi"].value, Equals, 3)
  233. }
  234. //var data []byte
  235. //func init() {
  236. // var err error
  237. // data, err = ioutil.ReadFile("/tmp/file.yaml")
  238. // if err != nil {
  239. // panic(err)
  240. // }
  241. //}
  242. //
  243. //func (s *S) BenchmarkUnmarshal(c *C) {
  244. // var err error
  245. // for i := 0; i < c.N; i++ {
  246. // var v map[string]interface{}
  247. // err = goyaml.Unmarshal(data, &v)
  248. // }
  249. // if err != nil {
  250. // panic(err)
  251. // }
  252. //}
  253. //
  254. //func (s *S) BenchmarkMarshal(c *C) {
  255. // var v map[string]interface{}
  256. // goyaml.Unmarshal(data, &v)
  257. // c.ResetTimer()
  258. // for i := 0; i < c.N; i++ {
  259. // goyaml.Marshal(&v)
  260. // }
  261. //}