yaml_test.go 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271
  1. package yaml
  2. import (
  3. "fmt"
  4. "math"
  5. "reflect"
  6. "strconv"
  7. "testing"
  8. )
  9. type MarshalTest struct {
  10. A string
  11. B int64
  12. // Would like to test float64, but it's not supported in go-yaml.
  13. // (See https://github.com/go-yaml/yaml/issues/83.)
  14. C float32
  15. }
  16. func TestMarshal(t *testing.T) {
  17. f32String := strconv.FormatFloat(math.MaxFloat32, 'g', -1, 32)
  18. s := MarshalTest{"a", math.MaxInt64, math.MaxFloat32}
  19. e := []byte(fmt.Sprintf("A: a\nB: %d\nC: %s\n", math.MaxInt64, f32String))
  20. y, err := Marshal(s)
  21. if err != nil {
  22. t.Errorf("error marshaling YAML: %v", err)
  23. }
  24. if !reflect.DeepEqual(y, e) {
  25. t.Errorf("marshal YAML was unsuccessful, expected: %#v, got: %#v",
  26. string(e), string(y))
  27. }
  28. }
  29. type UnmarshalString struct {
  30. A string
  31. True string
  32. }
  33. type UnmarshalStringMap struct {
  34. A map[string]string
  35. }
  36. type UnmarshalNestedString struct {
  37. A NestedString
  38. }
  39. type NestedString struct {
  40. A string
  41. }
  42. type UnmarshalSlice struct {
  43. A []NestedSlice
  44. }
  45. type NestedSlice struct {
  46. B string
  47. C *string
  48. }
  49. func TestUnmarshal(t *testing.T) {
  50. y := []byte("a: 1")
  51. s1 := UnmarshalString{}
  52. e1 := UnmarshalString{A: "1"}
  53. unmarshal(t, y, &s1, &e1)
  54. y = []byte("a: true")
  55. s1 = UnmarshalString{}
  56. e1 = UnmarshalString{A: "true"}
  57. unmarshal(t, y, &s1, &e1)
  58. y = []byte("true: 1")
  59. s1 = UnmarshalString{}
  60. e1 = UnmarshalString{True: "1"}
  61. unmarshal(t, y, &s1, &e1)
  62. y = []byte("a:\n a: 1")
  63. s2 := UnmarshalNestedString{}
  64. e2 := UnmarshalNestedString{NestedString{"1"}}
  65. unmarshal(t, y, &s2, &e2)
  66. y = []byte("a:\n - b: abc\n c: def\n - b: 123\n c: 456\n")
  67. s3 := UnmarshalSlice{}
  68. e3 := UnmarshalSlice{[]NestedSlice{NestedSlice{"abc", strPtr("def")}, NestedSlice{"123", strPtr("456")}}}
  69. unmarshal(t, y, &s3, &e3)
  70. y = []byte("a:\n b: 1")
  71. s4 := UnmarshalStringMap{}
  72. e4 := UnmarshalStringMap{map[string]string{"b": "1"}}
  73. unmarshal(t, y, &s4, &e4)
  74. }
  75. func unmarshal(t *testing.T, y []byte, s, e interface{}) {
  76. err := Unmarshal(y, s)
  77. if err != nil {
  78. t.Errorf("error unmarshaling YAML: %v", err)
  79. }
  80. if !reflect.DeepEqual(s, e) {
  81. t.Errorf("unmarshal YAML was unsuccessful, expected: %+#v, got: %+#v",
  82. e, s)
  83. }
  84. }
  85. type Case struct {
  86. input string
  87. output string
  88. // By default we test that reversing the output == input. But if there is a
  89. // difference in the reversed output, you can optionally specify it here.
  90. reverse *string
  91. }
  92. type RunType int
  93. const (
  94. RunTypeJSONToYAML RunType = iota
  95. RunTypeYAMLToJSON
  96. )
  97. func TestJSONToYAML(t *testing.T) {
  98. cases := []Case{
  99. {
  100. `{"t":"a"}`,
  101. "t: a\n",
  102. nil,
  103. }, {
  104. `{"t":null}`,
  105. "t: null\n",
  106. nil,
  107. },
  108. }
  109. runCases(t, RunTypeJSONToYAML, cases)
  110. }
  111. func TestYAMLToJSON(t *testing.T) {
  112. cases := []Case{
  113. {
  114. "t: a\n",
  115. `{"t":"a"}`,
  116. nil,
  117. }, {
  118. "t: \n",
  119. `{"t":null}`,
  120. strPtr("t: null\n"),
  121. }, {
  122. "t: null\n",
  123. `{"t":null}`,
  124. nil,
  125. }, {
  126. "1: a\n",
  127. `{"1":"a"}`,
  128. strPtr("\"1\": a\n"),
  129. }, {
  130. "1000000000000000000000000000000000000: a\n",
  131. `{"1e+36":"a"}`,
  132. strPtr("\"1e+36\": a\n"),
  133. }, {
  134. "1e+36: a\n",
  135. `{"1e+36":"a"}`,
  136. strPtr("\"1e+36\": a\n"),
  137. }, {
  138. "\"1e+36\": a\n",
  139. `{"1e+36":"a"}`,
  140. nil,
  141. }, {
  142. "\"1.2\": a\n",
  143. `{"1.2":"a"}`,
  144. nil,
  145. }, {
  146. "- t: a\n",
  147. `[{"t":"a"}]`,
  148. nil,
  149. }, {
  150. "- t: a\n" +
  151. "- t:\n" +
  152. " b: 1\n" +
  153. " c: 2\n",
  154. `[{"t":"a"},{"t":{"b":1,"c":2}}]`,
  155. nil,
  156. }, {
  157. `[{t: a}, {t: {b: 1, c: 2}}]`,
  158. `[{"t":"a"},{"t":{"b":1,"c":2}}]`,
  159. strPtr("- t: a\n" +
  160. "- t:\n" +
  161. " b: 1\n" +
  162. " c: 2\n"),
  163. }, {
  164. "- t: \n",
  165. `[{"t":null}]`,
  166. strPtr("- t: null\n"),
  167. }, {
  168. "- t: null\n",
  169. `[{"t":null}]`,
  170. nil,
  171. },
  172. }
  173. // Cases that should produce errors.
  174. _ = []Case{
  175. {
  176. "~: a",
  177. `{"null":"a"}`,
  178. nil,
  179. }, {
  180. "a: !!binary gIGC\n",
  181. "{\"a\":\"\x80\x81\x82\"}",
  182. nil,
  183. },
  184. }
  185. runCases(t, RunTypeYAMLToJSON, cases)
  186. }
  187. func runCases(t *testing.T, runType RunType, cases []Case) {
  188. var f func([]byte) ([]byte, error)
  189. var invF func([]byte) ([]byte, error)
  190. var msg string
  191. var invMsg string
  192. if runType == RunTypeJSONToYAML {
  193. f = JSONToYAML
  194. invF = YAMLToJSON
  195. msg = "JSON to YAML"
  196. invMsg = "YAML back to JSON"
  197. } else {
  198. f = YAMLToJSON
  199. invF = JSONToYAML
  200. msg = "YAML to JSON"
  201. invMsg = "JSON back to YAML"
  202. }
  203. for _, c := range cases {
  204. // Convert the string.
  205. t.Logf("converting %s\n", c.input)
  206. output, err := f([]byte(c.input))
  207. if err != nil {
  208. t.Errorf("Failed to convert %s, input: `%s`, err: %v", msg, c.input, err)
  209. }
  210. // Check it against the expected output.
  211. if string(output) != c.output {
  212. t.Errorf("Failed to convert %s, input: `%s`, expected `%s`, got `%s`",
  213. msg, c.input, c.output, string(output))
  214. }
  215. // Set the string that we will compare the reversed output to.
  216. reverse := c.input
  217. // If a special reverse string was specified, use that instead.
  218. if c.reverse != nil {
  219. reverse = *c.reverse
  220. }
  221. // Reverse the output.
  222. input, err := invF(output)
  223. if err != nil {
  224. t.Errorf("Failed to convert %s, input: `%s`, err: %v", invMsg, string(output), err)
  225. }
  226. // Check the reverse is equal to the input (or to *c.reverse).
  227. if string(input) != reverse {
  228. t.Errorf("Failed to convert %s, input: `%s`, expected `%s`, got `%s`",
  229. invMsg, string(output), reverse, string(input))
  230. }
  231. }
  232. }
  233. // To be able to easily fill in the *Case.reverse string above.
  234. func strPtr(s string) *string {
  235. return &s
  236. }