decode_test.go 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468
  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. {
  15. "",
  16. &struct{}{},
  17. }, {
  18. "{}", &struct{}{},
  19. }, {
  20. "v: hi",
  21. map[string]string{"v": "hi"},
  22. }, {
  23. "v: hi", map[string]interface{}{"v": "hi"},
  24. }, {
  25. "v: true",
  26. map[string]string{"v": "true"},
  27. }, {
  28. "v: true",
  29. map[string]interface{}{"v": true},
  30. }, {
  31. "v: 10",
  32. map[string]interface{}{"v": 10},
  33. }, {
  34. "v: 0b10",
  35. map[string]interface{}{"v": 2},
  36. }, {
  37. "v: 0xA",
  38. map[string]interface{}{"v": 10},
  39. }, {
  40. "v: 4294967296",
  41. map[string]int64{"v": 4294967296},
  42. }, {
  43. "v: 0.1",
  44. map[string]interface{}{"v": 0.1},
  45. }, {
  46. "v: .1",
  47. map[string]interface{}{"v": 0.1},
  48. }, {
  49. "v: .Inf",
  50. map[string]interface{}{"v": math.Inf(+1)},
  51. }, {
  52. "v: -.Inf",
  53. map[string]interface{}{"v": math.Inf(-1)},
  54. }, {
  55. "v: -10",
  56. map[string]interface{}{"v": -10},
  57. }, {
  58. "v: -.1",
  59. map[string]interface{}{"v": -0.1},
  60. },
  61. // Simple values.
  62. {
  63. "123",
  64. &unmarshalIntTest,
  65. },
  66. // Floats from spec
  67. {
  68. "canonical: 6.8523e+5",
  69. map[string]interface{}{"canonical": 6.8523e+5},
  70. }, {
  71. "expo: 685.230_15e+03",
  72. map[string]interface{}{"expo": 685.23015e+03},
  73. }, {
  74. "fixed: 685_230.15",
  75. map[string]interface{}{"fixed": 685230.15},
  76. }, {
  77. "neginf: -.inf",
  78. map[string]interface{}{"neginf": math.Inf(-1)},
  79. }, {
  80. "fixed: 685_230.15",
  81. map[string]float64{"fixed": 685230.15},
  82. },
  83. //{"sexa: 190:20:30.15", map[string]interface{}{"sexa": 0}}, // Unsupported
  84. //{"notanum: .NaN", map[string]interface{}{"notanum": math.NaN()}}, // Equality of NaN fails.
  85. // Bools from spec
  86. {
  87. "canonical: y",
  88. map[string]interface{}{"canonical": true},
  89. }, {
  90. "answer: NO",
  91. map[string]interface{}{"answer": false},
  92. }, {
  93. "logical: True",
  94. map[string]interface{}{"logical": true},
  95. }, {
  96. "option: on",
  97. map[string]interface{}{"option": true},
  98. }, {
  99. "option: on",
  100. map[string]bool{"option": true},
  101. },
  102. // Ints from spec
  103. {
  104. "canonical: 685230",
  105. map[string]interface{}{"canonical": 685230},
  106. }, {
  107. "decimal: +685_230",
  108. map[string]interface{}{"decimal": 685230},
  109. }, {
  110. "octal: 02472256",
  111. map[string]interface{}{"octal": 685230},
  112. }, {
  113. "hexa: 0x_0A_74_AE",
  114. map[string]interface{}{"hexa": 685230},
  115. }, {
  116. "bin: 0b1010_0111_0100_1010_1110",
  117. map[string]interface{}{"bin": 685230},
  118. }, {
  119. "bin: -0b101010",
  120. map[string]interface{}{"bin": -42},
  121. }, {
  122. "decimal: +685_230",
  123. map[string]int{"decimal": 685230},
  124. },
  125. //{"sexa: 190:20:30", map[string]interface{}{"sexa": 0}}, // Unsupported
  126. // Nulls from spec
  127. {
  128. "empty:",
  129. map[string]interface{}{"empty": nil},
  130. }, {
  131. "canonical: ~",
  132. map[string]interface{}{"canonical": nil},
  133. }, {
  134. "english: null",
  135. map[string]interface{}{"english": nil},
  136. }, {
  137. "~: null key",
  138. map[interface{}]string{nil: "null key"},
  139. }, {
  140. "empty:",
  141. map[string]*bool{"empty": nil},
  142. },
  143. // Flow sequence
  144. {
  145. "seq: [A,B]",
  146. map[string]interface{}{"seq": []interface{}{"A", "B"}},
  147. }, {
  148. "seq: [A,B,C,]",
  149. map[string][]string{"seq": []string{"A", "B", "C"}},
  150. }, {
  151. "seq: [A,1,C]",
  152. map[string][]string{"seq": []string{"A", "1", "C"}},
  153. }, {
  154. "seq: [A,1,C]",
  155. map[string][]int{"seq": []int{1}},
  156. }, {
  157. "seq: [A,1,C]",
  158. map[string]interface{}{"seq": []interface{}{"A", 1, "C"}},
  159. },
  160. // Block sequence
  161. {
  162. "seq:\n - A\n - B",
  163. map[string]interface{}{"seq": []interface{}{"A", "B"}},
  164. }, {
  165. "seq:\n - A\n - B\n - C",
  166. map[string][]string{"seq": []string{"A", "B", "C"}},
  167. }, {
  168. "seq:\n - A\n - 1\n - C",
  169. map[string][]string{"seq": []string{"A", "1", "C"}},
  170. }, {
  171. "seq:\n - A\n - 1\n - C",
  172. map[string][]int{"seq": []int{1}},
  173. }, {
  174. "seq:\n - A\n - 1\n - C",
  175. map[string]interface{}{"seq": []interface{}{"A", 1, "C"}},
  176. },
  177. // Literal block scalar
  178. {
  179. "scalar: | # Comment\n\n literal\n\n \ttext\n\n",
  180. map[string]string{"scalar": "\nliteral\n\n\ttext\n"},
  181. },
  182. // Folded block scalar
  183. {
  184. "scalar: > # Comment\n\n folded\n line\n \n next\n line\n * one\n * two\n\n last\n line\n\n",
  185. map[string]string{"scalar": "\nfolded line\nnext line\n * one\n * two\n\nlast line\n"},
  186. },
  187. // Map inside interface with no type hints.
  188. {
  189. "a: {b: c}",
  190. map[string]interface{}{"a": map[interface{}]interface{}{"b": "c"}},
  191. },
  192. // Structs and type conversions.
  193. {
  194. "hello: world",
  195. &struct{ Hello string }{"world"},
  196. }, {
  197. "a: {b: c}",
  198. &struct{ A struct{ B string } }{struct{ B string }{"c"}},
  199. }, {
  200. "a: {b: c}",
  201. &struct{ A *struct{ B string } }{&struct{ B string }{"c"}},
  202. }, {
  203. "a: {b: c}",
  204. &struct{ A map[string]string }{map[string]string{"b": "c"}},
  205. }, {
  206. "a: {b: c}",
  207. &struct{ A *map[string]string }{&map[string]string{"b": "c"}},
  208. }, {
  209. "a:",
  210. &struct{ A map[string]string }{},
  211. }, {
  212. "a: 1",
  213. &struct{ A int }{1},
  214. }, {
  215. "a: [1, 2]",
  216. &struct{ A []int }{[]int{1, 2}},
  217. }, {
  218. "a: 1",
  219. &struct{ B int }{0},
  220. }, {
  221. "a: 1",
  222. &struct {
  223. B int "a"
  224. }{1},
  225. }, {
  226. "a: y",
  227. &struct{ A bool }{true},
  228. },
  229. // Some cross type conversions
  230. {
  231. "v: 42",
  232. map[string]uint{"v": 42},
  233. }, {
  234. "v: -42",
  235. map[string]uint{},
  236. }, {
  237. "v: 4294967296",
  238. map[string]uint64{"v": 4294967296},
  239. }, {
  240. "v: -4294967296",
  241. map[string]uint64{},
  242. },
  243. // Overflow cases.
  244. {
  245. "v: 4294967297",
  246. map[string]int32{},
  247. }, {
  248. "v: 128",
  249. map[string]int8{},
  250. },
  251. // Quoted values.
  252. {
  253. "'1': '\"2\"'",
  254. map[interface{}]interface{}{"1": "\"2\""},
  255. }, {
  256. "v:\n- A\n- 'B\n\n C'\n",
  257. map[string][]string{"v": []string{"A", "B\nC"}},
  258. },
  259. // Explicit tags.
  260. {
  261. "v: !!float '1.1'",
  262. map[string]interface{}{"v": 1.1},
  263. }, {
  264. "v: !!null ''",
  265. map[string]interface{}{"v": nil},
  266. }, {
  267. "%TAG !y! tag:yaml.org,2002:\n---\nv: !y!int '1'",
  268. map[string]interface{}{"v": 1},
  269. },
  270. // Anchors and aliases.
  271. {
  272. "a: &x 1\nb: &y 2\nc: *x\nd: *y\n",
  273. &struct{ A, B, C, D int }{1, 2, 1, 2},
  274. }, {
  275. "a: &a {c: 1}\nb: *a",
  276. &struct {
  277. A, B struct {
  278. C int
  279. }
  280. }{struct{ C int }{1}, struct{ C int }{1}},
  281. }, {
  282. "a: &a [1, 2]\nb: *a",
  283. &struct{ B []int }{[]int{1, 2}},
  284. },
  285. // BUG #1133337
  286. {
  287. "foo: ''",
  288. map[string]*string{"foo": new(string)},
  289. }, {
  290. "foo: null",
  291. map[string]string{},
  292. },
  293. // Ignored field
  294. {
  295. "a: 1\nb: 2\n",
  296. &struct {
  297. A int
  298. B int "-"
  299. }{1, 0},
  300. },
  301. }
  302. func (s *S) TestUnmarshal(c *C) {
  303. for i, item := range unmarshalTests {
  304. t := reflect.ValueOf(item.value).Type()
  305. var value interface{}
  306. if t.Kind() == reflect.Map {
  307. value = reflect.MakeMap(t).Interface()
  308. } else {
  309. pt := reflect.ValueOf(item.value).Type()
  310. pv := reflect.New(pt.Elem())
  311. value = pv.Interface()
  312. }
  313. err := goyaml.Unmarshal([]byte(item.data), value)
  314. c.Assert(err, IsNil, Commentf("Item #%d", i))
  315. c.Assert(value, DeepEquals, item.value)
  316. }
  317. }
  318. func (s *S) TestUnmarshalNaN(c *C) {
  319. value := map[string]interface{}{}
  320. err := goyaml.Unmarshal([]byte("notanum: .NaN"), &value)
  321. c.Assert(err, IsNil)
  322. c.Assert(math.IsNaN(value["notanum"].(float64)), Equals, true)
  323. }
  324. var unmarshalErrorTests = []struct {
  325. data, error string
  326. }{
  327. {"v: !!float 'error'", "YAML error: Can't decode !!str 'error' as a !!float"},
  328. {"v: [A,", "YAML error: line 1: did not find expected node content"},
  329. {"v:\n- [A,", "YAML error: line 2: did not find expected node content"},
  330. {"a: *b\n", "YAML error: Unknown anchor 'b' referenced"},
  331. {"a: &a\n b: *a\n", "YAML error: Anchor 'a' value contains itself"},
  332. }
  333. func (s *S) TestUnmarshalErrors(c *C) {
  334. for _, item := range unmarshalErrorTests {
  335. var value interface{}
  336. err := goyaml.Unmarshal([]byte(item.data), &value)
  337. c.Assert(err, ErrorMatches, item.error, Commentf("Partial unmarshal: %#v", value))
  338. }
  339. }
  340. var setterTests = []struct {
  341. data, tag string
  342. value interface{}
  343. }{
  344. {"_: {hi: there}", "!!map", map[interface{}]interface{}{"hi": "there"}},
  345. {"_: [1,A]", "!!seq", []interface{}{1, "A"}},
  346. {"_: 10", "!!int", 10},
  347. {"_: null", "!!null", nil},
  348. {"_: !!foo 'BAR!'", "!!foo", "BAR!"},
  349. }
  350. var setterResult = map[int]bool{}
  351. type typeWithSetter struct {
  352. tag string
  353. value interface{}
  354. }
  355. func (o *typeWithSetter) SetYAML(tag string, value interface{}) (ok bool) {
  356. o.tag = tag
  357. o.value = value
  358. if i, ok := value.(int); ok {
  359. if result, ok := setterResult[i]; ok {
  360. return result
  361. }
  362. }
  363. return true
  364. }
  365. type typeWithSetterField struct {
  366. Field *typeWithSetter "_"
  367. }
  368. func (s *S) TestUnmarshalWithSetter(c *C) {
  369. for _, item := range setterTests {
  370. obj := &typeWithSetterField{}
  371. err := goyaml.Unmarshal([]byte(item.data), obj)
  372. c.Assert(err, IsNil)
  373. c.Assert(obj.Field, NotNil,
  374. Commentf("Pointer not initialized (%#v)", item.value))
  375. c.Assert(obj.Field.tag, Equals, item.tag)
  376. c.Assert(obj.Field.value, DeepEquals, item.value)
  377. }
  378. }
  379. func (s *S) TestUnmarshalWholeDocumentWithSetter(c *C) {
  380. obj := &typeWithSetter{}
  381. err := goyaml.Unmarshal([]byte(setterTests[0].data), obj)
  382. c.Assert(err, IsNil)
  383. c.Assert(obj.tag, Equals, setterTests[0].tag)
  384. value, ok := obj.value.(map[interface{}]interface{})
  385. c.Assert(ok, Equals, true)
  386. c.Assert(value["_"], DeepEquals, setterTests[0].value)
  387. }
  388. func (s *S) TestUnmarshalWithFalseSetterIgnoresValue(c *C) {
  389. setterResult[2] = false
  390. setterResult[4] = false
  391. defer func() {
  392. delete(setterResult, 2)
  393. delete(setterResult, 4)
  394. }()
  395. m := map[string]*typeWithSetter{}
  396. data := "{abc: 1, def: 2, ghi: 3, jkl: 4}"
  397. err := goyaml.Unmarshal([]byte(data), m)
  398. c.Assert(err, IsNil)
  399. c.Assert(m["abc"], NotNil)
  400. c.Assert(m["def"], IsNil)
  401. c.Assert(m["ghi"], NotNil)
  402. c.Assert(m["jkl"], IsNil)
  403. c.Assert(m["abc"].value, Equals, 1)
  404. c.Assert(m["ghi"].value, Equals, 3)
  405. }
  406. var data []byte
  407. func init() {
  408. var err error
  409. data, err = ioutil.ReadFile("/tmp/file.yaml")
  410. if err != nil {
  411. panic(err)
  412. }
  413. }
  414. func (s *S) BenchmarkUnmarshal(c *C) {
  415. var err error
  416. for i := 0; i < c.N; i++ {
  417. var v map[string]interface{}
  418. err = goyaml.Unmarshal(data, &v)
  419. }
  420. if err != nil {
  421. panic(err)
  422. }
  423. }
  424. func (s *S) BenchmarkMarshal(c *C) {
  425. var v map[string]interface{}
  426. goyaml.Unmarshal(data, &v)
  427. c.ResetTimer()
  428. for i := 0; i < c.N; i++ {
  429. goyaml.Marshal(&v)
  430. }
  431. }