cbor_test.go 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  1. // Copyright (c) 2012, 2013 Ugorji Nwoke. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license found in the LICENSE file.
  3. package codec
  4. import (
  5. "bytes"
  6. "encoding/hex"
  7. "encoding/json"
  8. "math"
  9. "os"
  10. "reflect"
  11. "regexp"
  12. "strconv"
  13. "strings"
  14. "testing"
  15. )
  16. func TestCborIndefiniteLength(t *testing.T) {
  17. oldMapType := testCborH.MapType
  18. defer func() {
  19. testCborH.MapType = oldMapType
  20. }()
  21. testCborH.MapType = testMapStrIntfTyp
  22. // var (
  23. // M1 map[string][]byte
  24. // M2 map[uint64]bool
  25. // L1 []interface{}
  26. // S1 []string
  27. // B1 []byte
  28. // )
  29. var v, vv interface{}
  30. // define it (v), encode it using indefinite lengths, decode it (vv), compare v to vv
  31. v = map[string]interface{}{
  32. "one-byte-key": []byte{1, 2, 3, 4, 5, 6},
  33. "two-string-key": "two-value",
  34. "three-list-key": []interface{}{true, false, uint64(1), int64(-1)},
  35. }
  36. var buf bytes.Buffer
  37. // buf.Reset()
  38. e := NewEncoder(&buf, testCborH)
  39. buf.WriteByte(cborBdIndefiniteMap)
  40. //----
  41. buf.WriteByte(cborBdIndefiniteString)
  42. e.MustEncode("one-")
  43. e.MustEncode("byte-")
  44. e.MustEncode("key")
  45. buf.WriteByte(cborBdBreak)
  46. buf.WriteByte(cborBdIndefiniteBytes)
  47. e.MustEncode([]byte{1, 2, 3})
  48. e.MustEncode([]byte{4, 5, 6})
  49. buf.WriteByte(cborBdBreak)
  50. //----
  51. buf.WriteByte(cborBdIndefiniteString)
  52. e.MustEncode("two-")
  53. e.MustEncode("string-")
  54. e.MustEncode("key")
  55. buf.WriteByte(cborBdBreak)
  56. buf.WriteByte(cborBdIndefiniteString)
  57. e.MustEncode([]byte("two-")) // encode as bytes, to check robustness of code
  58. e.MustEncode([]byte("value"))
  59. buf.WriteByte(cborBdBreak)
  60. //----
  61. buf.WriteByte(cborBdIndefiniteString)
  62. e.MustEncode("three-")
  63. e.MustEncode("list-")
  64. e.MustEncode("key")
  65. buf.WriteByte(cborBdBreak)
  66. buf.WriteByte(cborBdIndefiniteArray)
  67. e.MustEncode(true)
  68. e.MustEncode(false)
  69. e.MustEncode(uint64(1))
  70. e.MustEncode(int64(-1))
  71. buf.WriteByte(cborBdBreak)
  72. buf.WriteByte(cborBdBreak) // close map
  73. NewDecoderBytes(buf.Bytes(), testCborH).MustDecode(&vv)
  74. if err := deepEqual(v, vv); err != nil {
  75. logT(t, "-------- Before and After marshal do not match: Error: %v", err)
  76. logT(t, " ....... GOLDEN: (%T) %#v", v, v)
  77. logT(t, " ....... DECODED: (%T) %#v", vv, vv)
  78. failT(t)
  79. }
  80. }
  81. type testCborGolden struct {
  82. Base64 string `json:"cbor"`
  83. Hex string `json:"hex"`
  84. Roundtrip bool `json:"roundtrip"`
  85. Decoded interface{} `json:"decoded"`
  86. Diagnostic string `json:"diagnostic"`
  87. Skip bool `json:"skip"`
  88. }
  89. // Some tests are skipped because they include numbers outside the range of int64/uint64
  90. func doTestCborGoldens(t *testing.T) {
  91. oldMapType := testCborH.MapType
  92. defer func() {
  93. testCborH.MapType = oldMapType
  94. }()
  95. testCborH.MapType = testMapStrIntfTyp
  96. // decode test-cbor-goldens.json into a list of []*testCborGolden
  97. // for each one,
  98. // - decode hex into []byte bs
  99. // - decode bs into interface{} v
  100. // - compare both using deepequal
  101. // - for any miss, record it
  102. var gs []*testCborGolden
  103. f, err := os.Open("test-cbor-goldens.json")
  104. if err != nil {
  105. logT(t, "error opening test-cbor-goldens.json: %v", err)
  106. failT(t)
  107. }
  108. d := json.NewDecoder(f)
  109. d.UseNumber()
  110. err = d.Decode(&gs)
  111. if err != nil {
  112. logT(t, "error json decoding test-cbor-goldens.json: %v", err)
  113. failT(t)
  114. }
  115. tagregex := regexp.MustCompile(`[\d]+\(.+?\)`)
  116. hexregex := regexp.MustCompile(`h'([0-9a-fA-F]*)'`)
  117. for i, g := range gs {
  118. // fmt.Printf("%v, skip: %v, isTag: %v, %s\n", i, g.Skip, tagregex.MatchString(g.Diagnostic), g.Diagnostic)
  119. // skip tags or simple or those with prefix, as we can't verify them.
  120. if g.Skip || strings.HasPrefix(g.Diagnostic, "simple(") || tagregex.MatchString(g.Diagnostic) {
  121. // fmt.Printf("%v: skipped\n", i)
  122. logT(t, "[%v] skipping because skip=true OR unsupported simple value or Tag Value", i)
  123. continue
  124. }
  125. // println("++++++++++++", i, "g.Diagnostic", g.Diagnostic)
  126. if hexregex.MatchString(g.Diagnostic) {
  127. // println(i, "g.Diagnostic matched hex")
  128. if s2 := g.Diagnostic[2 : len(g.Diagnostic)-1]; s2 == "" {
  129. g.Decoded = []byte{}
  130. } else if bs2, err2 := hex.DecodeString(s2); err2 == nil {
  131. g.Decoded = bs2
  132. }
  133. // fmt.Printf("%v: hex: %v\n", i, g.Decoded)
  134. }
  135. bs, err := hex.DecodeString(g.Hex)
  136. if err != nil {
  137. logT(t, "[%v] error hex decoding %s [%v]: %v", i, g.Hex, err)
  138. failT(t)
  139. }
  140. var v interface{}
  141. NewDecoderBytes(bs, testCborH).MustDecode(&v)
  142. if _, ok := v.(RawExt); ok {
  143. continue
  144. }
  145. // check the diagnostics to compare
  146. switch g.Diagnostic {
  147. case "Infinity":
  148. b := math.IsInf(v.(float64), 1)
  149. testCborError(t, i, math.Inf(1), v, nil, &b)
  150. case "-Infinity":
  151. b := math.IsInf(v.(float64), -1)
  152. testCborError(t, i, math.Inf(-1), v, nil, &b)
  153. case "NaN":
  154. // println(i, "checking NaN")
  155. b := math.IsNaN(v.(float64))
  156. testCborError(t, i, math.NaN(), v, nil, &b)
  157. case "undefined":
  158. b := v == nil
  159. testCborError(t, i, nil, v, nil, &b)
  160. default:
  161. v0 := g.Decoded
  162. testCborCoerceJsonNumber(reflect.ValueOf(&v0))
  163. testCborError(t, i, v0, v, deepEqual(v0, v), nil)
  164. }
  165. }
  166. }
  167. func testCborError(t *testing.T, i int, v0, v1 interface{}, err error, equal *bool) {
  168. if err == nil && equal == nil {
  169. // fmt.Printf("%v testCborError passed (err and equal nil)\n", i)
  170. return
  171. }
  172. if err != nil {
  173. logT(t, "[%v] deepEqual error: %v", i, err)
  174. logT(t, " ....... GOLDEN: (%T) %#v", v0, v0)
  175. logT(t, " ....... DECODED: (%T) %#v", v1, v1)
  176. failT(t)
  177. }
  178. if equal != nil && !*equal {
  179. logT(t, "[%v] values not equal", i)
  180. logT(t, " ....... GOLDEN: (%T) %#v", v0, v0)
  181. logT(t, " ....... DECODED: (%T) %#v", v1, v1)
  182. failT(t)
  183. }
  184. // fmt.Printf("%v testCborError passed (checks passed)\n", i)
  185. }
  186. var testJsonNumTyp = reflect.TypeOf(json.Number(""))
  187. // coerce a value from json decoding to convert json.Number into a uint64, int64 or float64.
  188. // This will allow it to be checked for equality using deepEqual.
  189. func testCborCoerceJsonNumber(rv reflect.Value) (out reflect.Value, changed bool) {
  190. if !rv.IsValid() {
  191. return
  192. }
  193. // fmt.Printf(">>>>>>>>>> testCborCoerceJsonNumber: typ: %T, %v, %v, val: %v\n",
  194. // rv.Interface(), rv.Kind(), rv.Type(), rv.Interface())
  195. if rv.Type() == testJsonNumTyp {
  196. // if there is an e OR . in it, decode as float
  197. // if there is a - in front, decode as int64
  198. // else decode as uint64
  199. s := rv.String()
  200. if strings.Index(s, "e") >= 0 || strings.Index(s, ".") >= 0 {
  201. xx, _ := strconv.ParseFloat(s, 64)
  202. out = reflect.ValueOf(xx)
  203. } else if s[0] == '-' {
  204. xx, _ := strconv.ParseInt(s, 10, 64)
  205. out = reflect.ValueOf(xx)
  206. } else {
  207. xx, _ := strconv.ParseUint(s, 10, 64)
  208. out = reflect.ValueOf(xx)
  209. }
  210. changed = true
  211. return
  212. }
  213. switch rk := rv.Kind(); rk {
  214. case reflect.Ptr:
  215. testCborCoerceJsonNumber(rv.Elem())
  216. case reflect.Interface:
  217. if out2, changed2 := testCborCoerceJsonNumber(rv.Elem()); changed2 {
  218. if rv.CanSet() {
  219. rv.Set(out2)
  220. } else {
  221. return out2, true
  222. }
  223. }
  224. case reflect.Map:
  225. for _, mk := range rv.MapKeys() {
  226. if out2, changed2 := testCborCoerceJsonNumber(rv.MapIndex(mk)); changed2 {
  227. rv.SetMapIndex(mk, out2)
  228. }
  229. }
  230. case reflect.Slice:
  231. for j := 0; j < rv.Len(); j++ {
  232. if out2, changed2 := testCborCoerceJsonNumber(rv.Index(j)); changed2 {
  233. rv.Index(j).Set(out2)
  234. }
  235. }
  236. }
  237. return
  238. }
  239. func TestCborGoldens(t *testing.T) {
  240. doTestCborGoldens(t)
  241. }