helper_test.go 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  1. // Copyright (c) 2012-2015 Ugorji Nwoke. All rights reserved.
  2. // Use of this source code is governed by a MIT license found in the LICENSE file.
  3. package codec
  4. // All non-std package dependencies related to testing live in this file,
  5. // so porting to different environment is easy (just update functions).
  6. //
  7. // This file sets up the variables used, including testInitFns.
  8. // Each file should add initialization that should be performed
  9. // after flags are parsed.
  10. //
  11. // init is a multi-step process:
  12. // - setup vars (handled by init functions in each file)
  13. // - parse flags
  14. // - setup derived vars (handled by pre-init registered functions - registered in init function)
  15. // - post init (handled by post-init registered functions - registered in init function)
  16. // This way, no one has to manage carefully control the initialization
  17. // using file names, etc.
  18. //
  19. // Tests which require external dependencies need the -tag=x parameter.
  20. // They should be run as:
  21. // go test -tags=x -run=. <other parameters ...>
  22. // Benchmarks should also take this parameter, to include the sereal, xdr, etc.
  23. // To run against codecgen, etc, make sure you pass extra parameters.
  24. // Example usage:
  25. // go test "-tags=x codecgen unsafe" -bench=. <other parameters ...>
  26. //
  27. // To fully test everything:
  28. // go test -tags=x -benchtime=100ms -tv -bg -bi -brw -bu -v -run=. -bench=.
  29. // Handling flags
  30. // codec_test.go will define a set of global flags for testing, including:
  31. // - Use Reset
  32. // - Use IO reader/writer (vs direct bytes)
  33. // - Set Canonical
  34. // - Set InternStrings
  35. // - Use Symbols
  36. //
  37. // This way, we can test them all by running same set of tests with a different
  38. // set of flags.
  39. //
  40. // Following this, all the benchmarks will utilize flags set by codec_test.go
  41. // and will not redefine these "global" flags.
  42. import (
  43. "bytes"
  44. "errors"
  45. "flag"
  46. "fmt"
  47. "reflect"
  48. "sync"
  49. "testing"
  50. )
  51. type testHED struct {
  52. H Handle
  53. E *Encoder
  54. D *Decoder
  55. }
  56. var (
  57. testNoopH = NoopHandle(8)
  58. testMsgpackH = &MsgpackHandle{}
  59. testBincH = &BincHandle{}
  60. testSimpleH = &SimpleHandle{}
  61. testCborH = &CborHandle{}
  62. testJsonH = &JsonHandle{}
  63. testHandles []Handle
  64. testPreInitFns []func()
  65. testPostInitFns []func()
  66. testOnce sync.Once
  67. testHEDs []testHED
  68. )
  69. // variables used by tests
  70. var (
  71. testVerbose bool
  72. testInitDebug bool
  73. testUseIoEncDec bool
  74. testStructToArray bool
  75. testCanonical bool
  76. testUseReset bool
  77. testWriteNoSymbols bool
  78. testSkipIntf bool
  79. testInternStr bool
  80. testUseMust bool
  81. testCheckCircRef bool
  82. testJsonIndent int
  83. )
  84. func init() {
  85. testHEDs = make([]testHED, 0, 32)
  86. testHandles = append(testHandles,
  87. testNoopH, testMsgpackH, testBincH, testSimpleH,
  88. testCborH, testJsonH)
  89. }
  90. func testHEDGet(h Handle) *testHED {
  91. for i := range testHEDs {
  92. v := &testHEDs[i]
  93. if v.H == h {
  94. return v
  95. }
  96. }
  97. testHEDs = append(testHEDs, testHED{h, NewEncoder(nil, h), NewDecoder(nil, h)})
  98. return &testHEDs[len(testHEDs)-1]
  99. }
  100. func testInitAll() {
  101. flag.Parse()
  102. for _, f := range testPreInitFns {
  103. f()
  104. }
  105. for _, f := range testPostInitFns {
  106. f()
  107. }
  108. }
  109. func testCodecEncode(ts interface{}, bsIn []byte,
  110. fn func([]byte) *bytes.Buffer, h Handle) (bs []byte, err error) {
  111. // bs = make([]byte, 0, approxSize)
  112. var e *Encoder
  113. var buf *bytes.Buffer
  114. if testUseReset {
  115. e = testHEDGet(h).E
  116. } else {
  117. e = NewEncoder(nil, h)
  118. }
  119. if testUseIoEncDec {
  120. buf = fn(bsIn)
  121. e.Reset(buf)
  122. } else {
  123. bs = bsIn
  124. e.ResetBytes(&bs)
  125. }
  126. if testUseMust {
  127. e.MustEncode(ts)
  128. } else {
  129. err = e.Encode(ts)
  130. }
  131. if testUseIoEncDec {
  132. bs = buf.Bytes()
  133. }
  134. return
  135. }
  136. func testCodecDecode(bs []byte, ts interface{}, h Handle) (err error) {
  137. var d *Decoder
  138. var buf *bytes.Reader
  139. if testUseReset {
  140. d = testHEDGet(h).D
  141. } else {
  142. d = NewDecoder(nil, h)
  143. }
  144. if testUseIoEncDec {
  145. buf = bytes.NewReader(bs)
  146. d.Reset(buf)
  147. } else {
  148. d.ResetBytes(bs)
  149. }
  150. if testUseMust {
  151. d.MustDecode(ts)
  152. } else {
  153. err = d.Decode(ts)
  154. }
  155. return
  156. }
  157. // ----- functions below are used only by tests (not benchmarks)
  158. const (
  159. testLogToT = true
  160. failNowOnFail = true
  161. )
  162. func checkErrT(t *testing.T, err error) {
  163. if err != nil {
  164. logT(t, err.Error())
  165. failT(t)
  166. }
  167. }
  168. func checkEqualT(t *testing.T, v1 interface{}, v2 interface{}, desc string) (err error) {
  169. if err = deepEqual(v1, v2); err != nil {
  170. logT(t, "Not Equal: %s: %v. v1: %v, v2: %v", desc, err, v1, v2)
  171. failT(t)
  172. }
  173. return
  174. }
  175. func failT(t *testing.T) {
  176. if failNowOnFail {
  177. t.FailNow()
  178. } else {
  179. t.Fail()
  180. }
  181. }
  182. // --- these functions are used by both benchmarks and tests
  183. func deepEqual(v1, v2 interface{}) (err error) {
  184. if !reflect.DeepEqual(v1, v2) {
  185. err = errors.New("Not Match")
  186. }
  187. return
  188. }
  189. func logT(x interface{}, format string, args ...interface{}) {
  190. if t, ok := x.(*testing.T); ok && t != nil && testLogToT {
  191. if testVerbose {
  192. t.Logf(format, args...)
  193. }
  194. } else if b, ok := x.(*testing.B); ok && b != nil && testLogToT {
  195. b.Logf(format, args...)
  196. } else {
  197. if len(format) == 0 || format[len(format)-1] != '\n' {
  198. format = format + "\n"
  199. }
  200. fmt.Printf(format, args...)
  201. }
  202. }
  203. func approxDataSize(rv reflect.Value) (sum int) {
  204. switch rk := rv.Kind(); rk {
  205. case reflect.Invalid:
  206. case reflect.Ptr, reflect.Interface:
  207. sum += int(rv.Type().Size())
  208. sum += approxDataSize(rv.Elem())
  209. case reflect.Slice:
  210. sum += int(rv.Type().Size())
  211. for j := 0; j < rv.Len(); j++ {
  212. sum += approxDataSize(rv.Index(j))
  213. }
  214. case reflect.String:
  215. sum += int(rv.Type().Size())
  216. sum += rv.Len()
  217. case reflect.Map:
  218. sum += int(rv.Type().Size())
  219. for _, mk := range rv.MapKeys() {
  220. sum += approxDataSize(mk)
  221. sum += approxDataSize(rv.MapIndex(mk))
  222. }
  223. case reflect.Struct:
  224. //struct size already includes the full data size.
  225. //sum += int(rv.Type().Size())
  226. for j := 0; j < rv.NumField(); j++ {
  227. sum += approxDataSize(rv.Field(j))
  228. }
  229. default:
  230. //pure value types
  231. sum += int(rv.Type().Size())
  232. }
  233. return
  234. }