decode_test.go 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. package goyaml_test
  2. import (
  3. . "gocheck"
  4. "goyaml"
  5. "reflect"
  6. "math"
  7. )
  8. var unmarshalTests = []struct{data string; value interface{}}{
  9. // It will encode either value as a string if asked for.
  10. {"hello: world", map[string]string{"hello": "world"}},
  11. {"hello: true", map[string]string{"hello": "true"}},
  12. // And when given the option, will preserve the YAML type.
  13. {"hello: world", map[string]interface{}{"hello": "world"}},
  14. {"hello: true", map[string]interface{}{"hello": true}},
  15. {"hello: 10", map[string]interface{}{"hello": 10}},
  16. {"hello: 0b10", map[string]interface{}{"hello": 2}},
  17. {"hello: 0xA", map[string]interface{}{"hello": 10}},
  18. {"hello: 4294967296", map[string]interface{}{"hello": int64(4294967296)}},
  19. {"hello: 4294967296", map[string]int64{"hello": int64(4294967296)}},
  20. {"hello: 0.1", map[string]interface{}{"hello": 0.1}},
  21. {"hello: .1", map[string]interface{}{"hello": 0.1}},
  22. {"hello: .Inf", map[string]interface{}{"hello": math.Inf(+1)}},
  23. {"hello: -.Inf", map[string]interface{}{"hello": math.Inf(-1)}},
  24. {"hello: -10", map[string]interface{}{"hello": -10}},
  25. {"hello: -.1", map[string]interface{}{"hello": -0.1}},
  26. // Floats from spec
  27. {"canonical: 6.8523e+5", map[string]interface{}{"canonical": 6.8523e+5}},
  28. {"expo: 685.230_15e+03", map[string]interface{}{"expo": 685.23015e+03}},
  29. {"fixed: 685_230.15", map[string]interface{}{"fixed": 685230.15}},
  30. //{"sexa: 190:20:30.15", map[string]interface{}{"sexa": 0}}, // Unsupported
  31. {"neginf: -.inf", map[string]interface{}{"neginf": math.Inf(-1)}},
  32. {"notanum: .NaN", map[string]interface{}{"notanum": math.NaN}},
  33. {"fixed: 685_230.15", map[string]float{"fixed": 685230.15}},
  34. // Bools from spec
  35. {"canonical: y", map[string]interface{}{"canonical": true}},
  36. {"answer: NO", map[string]interface{}{"answer": false}},
  37. {"logical: True", map[string]interface{}{"logical": true}},
  38. {"option: on", map[string]interface{}{"option": true}},
  39. {"option: on", map[string]bool{"option": true}},
  40. // Ints from spec
  41. {"canonical: 685230", map[string]interface{}{"canonical": 685230}},
  42. {"decimal: +685_230", map[string]interface{}{"decimal": 685230}},
  43. {"octal: 02472256", map[string]interface{}{"octal": 685230}},
  44. {"hexa: 0x_0A_74_AE", map[string]interface{}{"hexa": 685230}},
  45. {"bin: 0b1010_0111_0100_1010_1110", map[string]interface{}{"bin": 685230}},
  46. {"bin: -0b101010", map[string]interface{}{"bin": -42}},
  47. //{"sexa: 190:20:30", map[string]interface{}{"sexa": 0}}, // Unsupported
  48. {"decimal: +685_230", map[string]int{"decimal": 685230}},
  49. // Nulls from spec
  50. {"empty:", map[string]interface{}{"empty": nil}},
  51. {"canonical: ~", map[string]interface{}{"canonical": nil}},
  52. {"english: null", map[string]interface{}{"english": nil}},
  53. {"~: null key", map[interface{}]string{nil: "null key"}},
  54. {"empty:", map[string]*bool{"empty": nil}},
  55. // Sequence
  56. {"seq: [A,B]", map[string]interface{}{"seq": []interface{}{"A", "B"}}},
  57. {"seq: [A,B,C]", map[string][]string{"seq": []string{"A", "B", "C"}}},
  58. {"seq: [A,1,C]", map[string][]string{"seq": []string{"A", "1", "C"}}},
  59. {"seq: [A,1,C]", map[string][]int{"seq": []int{1}}},
  60. {"seq: [A,1,C]", map[string]interface{}{"seq": []interface{}{"A", 1, "C"}}},
  61. // Map inside interface with no type hints.
  62. {"a: {b: c}",
  63. map[string]interface{}{"a": map[interface{}]interface{}{"b": "c"}}},
  64. // Structs and type conversions.
  65. {"hello: world", &struct{Hello string}{"world"}},
  66. {"a: {b: c}", &struct{A struct{B string}}{struct{B string}{"c"}}},
  67. {"a: {b: c}", &struct{A *struct{B string}}{&struct{B string}{"c"}}},
  68. {"a: 1", &struct{A int}{1}},
  69. {"a: [1, 2]", &struct{A []int}{[]int{1, 2}}},
  70. {"a: 1", &struct{B int}{0}},
  71. {"a: 1", &struct{B int "a"}{1}},
  72. {"a: y", &struct{A bool}{true}},
  73. // Some cross type conversions
  74. {"v: 42", map[string]uint{"v": 42}},
  75. {"v: -42", map[string]uint{}},
  76. {"v: 4294967296", map[string]uint64{"v": 4294967296}},
  77. {"v: -4294967296", map[string]uint64{}},
  78. // Overflow cases.
  79. {"v: 4294967297", map[string]int32{}},
  80. {"v: 128", map[string]int8{}},
  81. // Quoted values.
  82. {"'1': '2'", map[interface{}]interface{}{"1": "2"}},
  83. // Explicit tags.
  84. {"v: !!float '1.1'", map[string]interface{}{"v": 1.1}},
  85. {"v: !!null ''", map[string]interface{}{"v": nil}},
  86. {"%TAG !y! tag:yaml.org,2002:\n---\nv: !y!int '1'",
  87. map[string]interface{}{"v": 1}},
  88. }
  89. func (s *S) TestUnmarshal(c *C) {
  90. for _, item := range unmarshalTests {
  91. t := reflect.NewValue(item.value).Type()
  92. var value interface{}
  93. if t, ok := t.(*reflect.MapType); ok {
  94. value = reflect.MakeMap(t).Interface()
  95. } else {
  96. pt := reflect.NewValue(item.value).Type().(*reflect.PtrType)
  97. pv := reflect.MakeZero(pt).(*reflect.PtrValue)
  98. pv.PointTo(reflect.MakeZero(pt.Elem()))
  99. value = pv.Interface()
  100. }
  101. err := goyaml.Unmarshal([]byte(item.data), value)
  102. c.Assert(err, IsNil)
  103. c.Assert(value, Equals, item.value)
  104. }
  105. }
  106. var unmarshalErrorTests = []struct{data, error string}{
  107. {"v: !!float 'error'", "Can't decode !!str 'error' as a !!float"},
  108. }
  109. func (s *S) TestUnmarshalErrors(c *C) {
  110. for _, item := range unmarshalErrorTests {
  111. var value interface{}
  112. err := goyaml.Unmarshal([]byte(item.data), &value)
  113. c.Assert(err, Matches, item.error)
  114. }
  115. }
  116. var setterTests = []struct{data, tag string; value interface{}}{
  117. {"_: {hi: there}", "!!map", map[interface{}]interface{}{"hi": "there"}},
  118. {"_: [1,A]", "!!seq", []interface{}{1, "A"}},
  119. {"_: 10", "!!int", 10},
  120. {"_: null", "!!null", nil},
  121. {"_: !!foo 'BAR!'", "!!foo", "BAR!"},
  122. }
  123. var setterResult = map[int]bool{}
  124. type typeWithSetter struct {
  125. tag string
  126. value interface{}
  127. }
  128. func (o *typeWithSetter) SetYAML(tag string, value interface{}) (ok bool) {
  129. o.tag = tag
  130. o.value = value
  131. if i, ok := value.(int); ok {
  132. if result, ok := setterResult[i]; ok {
  133. return result
  134. }
  135. }
  136. return true
  137. }
  138. type typeWithSetterField struct {
  139. Field *typeWithSetter "_"
  140. }
  141. func (s *S) TestUnmarshalWithSetter(c *C) {
  142. for _, item := range setterTests {
  143. obj := &typeWithSetterField{}
  144. err := goyaml.Unmarshal([]byte(item.data), obj)
  145. c.Assert(err, IsNil)
  146. c.Assert(obj.Field, NotNil,
  147. Bug("Pointer not initialized (%#v)", item.value))
  148. c.Assert(obj.Field.tag, Equals, item.tag)
  149. c.Assert(obj.Field.value, Equals, item.value)
  150. }
  151. }
  152. func (s *S) TestUnmarshalWholeDocumentWithSetter(c *C) {
  153. obj := &typeWithSetter{}
  154. err := goyaml.Unmarshal([]byte(setterTests[0].data), obj)
  155. c.Assert(err, IsNil)
  156. c.Assert(obj.tag, Equals, setterTests[0].tag)
  157. value, ok := obj.value.(map[interface{}]interface{})
  158. c.Assert(ok, Equals, true)
  159. c.Assert(value["_"], Equals, setterTests[0].value)
  160. }
  161. func (s *S) TestUnmarshalWithFalseSetterIgnoresValue(c *C) {
  162. setterResult[2] = false
  163. setterResult[4] = false
  164. defer func() {
  165. setterResult[2] = false, false
  166. setterResult[4] = false, false
  167. }()
  168. m := map[string]*typeWithSetter{}
  169. data := "{abc: 1, def: 2, ghi: 3, jkl: 4}"
  170. err := goyaml.Unmarshal([]byte(data), m)
  171. c.Assert(err, IsNil)
  172. c.Assert(m["abc"], NotNil)
  173. c.Assert(m["def"], IsNil)
  174. c.Assert(m["ghi"], NotNil)
  175. c.Assert(m["jkl"], IsNil)
  176. c.Assert(m["abc"].value, Equals, 1)
  177. c.Assert(m["ghi"].value, Equals, 3)
  178. }