1// Copyright (c) 2012-2018 Ugorji Nwoke. All rights reserved. 2// Use of this source code is governed by a MIT license found in the LICENSE file. 3 4package codec 5 6// This file sets up the variables used, including testInitFns. 7// Each file should add initialization that should be performed 8// after flags are parsed. 9// 10// init is a multi-step process: 11// - setup vars (handled by init functions in each file) 12// - parse flags 13// - setup derived vars (handled by pre-init registered functions - registered in init function) 14// - post init (handled by post-init registered functions - registered in init function) 15// This way, no one has to manage carefully control the initialization 16// using file names, etc. 17// 18// Tests which require external dependencies need the -tag=x parameter. 19// They should be run as: 20// go test -tags=x -run=. <other parameters ...> 21// Benchmarks should also take this parameter, to include the sereal, xdr, etc. 22// To run against codecgen, etc, make sure you pass extra parameters. 23// Example usage: 24// go test "-tags=x codecgen" -bench=. <other parameters ...> 25// 26// To fully test everything: 27// go test -tags=x -benchtime=100ms -tv -bg -bi -brw -bu -v -run=. -bench=. 28 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 43import ( 44 "bytes" 45 "flag" 46 "fmt" 47 "io" 48 "io/ioutil" 49 "log" 50 "sync" 51 "testing" 52) 53 54// __DO_NOT_REMOVE__NEEDED_FOR_REPLACING__IMPORT_PATH__FOR_CODEC_BENCH__ 55 56type testHED struct { 57 H Handle 58 E *Encoder 59 D *Decoder 60} 61 62type ioReaderWrapper struct { 63 r io.Reader 64} 65 66func (x ioReaderWrapper) Read(p []byte) (n int, err error) { 67 return x.r.Read(p) 68} 69 70type ioWriterWrapper struct { 71 w io.Writer 72} 73 74func (x ioWriterWrapper) Write(p []byte) (n int, err error) { 75 return x.w.Write(p) 76} 77 78var ( 79 // testNoopH = NoopHandle(8) 80 testMsgpackH = &MsgpackHandle{} 81 testBincH = &BincHandle{} 82 testSimpleH = &SimpleHandle{} 83 testCborH = &CborHandle{} 84 testJsonH = &JsonHandle{} 85 86 testHandles []Handle 87 testPreInitFns []func() 88 testPostInitFns []func() 89 90 testOnce sync.Once 91 92 testHEDs []testHED 93) 94 95// flag variables used by tests (and bench) 96var ( 97 testDepth int 98 99 testVerbose bool 100 testInitDebug bool 101 testStructToArray bool 102 testCanonical bool 103 testUseReset bool 104 testSkipIntf bool 105 testInternStr bool 106 testUseMust bool 107 testCheckCircRef bool 108 109 testUseIoEncDec int 110 testUseIoWrapper bool 111 112 testMaxInitLen int 113 114 testNumRepeatString int 115 116 testRpcBufsize int 117) 118 119// variables that are not flags, but which can configure the handles 120var ( 121 testEncodeOptions EncodeOptions 122 testDecodeOptions DecodeOptions 123) 124 125// flag variables used by bench 126var ( 127 benchDoInitBench bool 128 benchVerify bool 129 benchUnscientificRes bool = false 130 benchMapStringKeyOnly bool 131 //depth of 0 maps to ~400bytes json-encoded string, 1 maps to ~1400 bytes, etc 132 //For depth>1, we likely trigger stack growth for encoders, making benchmarking unreliable. 133 benchDepth int 134 benchInitDebug bool 135) 136 137func init() { 138 log.SetOutput(ioutil.Discard) // don't allow things log to standard out/err 139 testHEDs = make([]testHED, 0, 32) 140 testHandles = append(testHandles, 141 // testNoopH, 142 testMsgpackH, testBincH, testSimpleH, testCborH, testJsonH) 143 // set ExplicitRelease on each handle 144 testMsgpackH.ExplicitRelease = true 145 testBincH.ExplicitRelease = true 146 testSimpleH.ExplicitRelease = true 147 testCborH.ExplicitRelease = true 148 testJsonH.ExplicitRelease = true 149 150 testInitFlags() 151 benchInitFlags() 152} 153 154func testInitFlags() { 155 // delete(testDecOpts.ExtFuncs, timeTyp) 156 flag.IntVar(&testDepth, "tsd", 0, "Test Struc Depth") 157 flag.BoolVar(&testVerbose, "tv", false, "Test Verbose (no longer used - here for compatibility)") 158 flag.BoolVar(&testInitDebug, "tg", false, "Test Init Debug") 159 flag.IntVar(&testUseIoEncDec, "ti", -1, "Use IO Reader/Writer for Marshal/Unmarshal ie >= 0") 160 flag.BoolVar(&testUseIoWrapper, "tiw", false, "Wrap the IO Reader/Writer with a base pass-through reader/writer") 161 flag.BoolVar(&testStructToArray, "ts", false, "Set StructToArray option") 162 flag.BoolVar(&testCanonical, "tc", false, "Set Canonical option") 163 flag.BoolVar(&testInternStr, "te", false, "Set InternStr option") 164 flag.BoolVar(&testSkipIntf, "tf", false, "Skip Interfaces") 165 flag.BoolVar(&testUseReset, "tr", false, "Use Reset") 166 flag.IntVar(&testNumRepeatString, "trs", 8, "Create string variables by repeating a string N times") 167 flag.IntVar(&testMaxInitLen, "tx", 0, "Max Init Len") 168 flag.BoolVar(&testUseMust, "tm", true, "Use Must(En|De)code") 169 flag.BoolVar(&testCheckCircRef, "tl", false, "Use Check Circular Ref") 170} 171 172func benchInitFlags() { 173 flag.BoolVar(&benchMapStringKeyOnly, "bs", false, "Bench use maps with string keys only") 174 flag.BoolVar(&benchInitDebug, "bg", false, "Bench Debug") 175 flag.IntVar(&benchDepth, "bd", 1, "Bench Depth") 176 flag.BoolVar(&benchDoInitBench, "bi", false, "Run Bench Init") 177 flag.BoolVar(&benchVerify, "bv", false, "Verify Decoded Value during Benchmark") 178 flag.BoolVar(&benchUnscientificRes, "bu", false, "Show Unscientific Results during Benchmark") 179} 180 181func testHEDGet(h Handle) *testHED { 182 for i := range testHEDs { 183 v := &testHEDs[i] 184 if v.H == h { 185 return v 186 } 187 } 188 testHEDs = append(testHEDs, testHED{h, NewEncoder(nil, h), NewDecoder(nil, h)}) 189 return &testHEDs[len(testHEDs)-1] 190} 191 192func testReinit() { 193 testOnce = sync.Once{} 194 testHEDs = nil 195} 196 197func testInitAll() { 198 // only parse it once. 199 if !flag.Parsed() { 200 flag.Parse() 201 } 202 for _, f := range testPreInitFns { 203 f() 204 } 205 for _, f := range testPostInitFns { 206 f() 207 } 208} 209 210func sTestCodecEncode(ts interface{}, bsIn []byte, fn func([]byte) *bytes.Buffer, 211 h Handle, bh *BasicHandle) (bs []byte, err error) { 212 // bs = make([]byte, 0, approxSize) 213 var e *Encoder 214 var buf *bytes.Buffer 215 if testUseReset { 216 e = testHEDGet(h).E 217 } else { 218 e = NewEncoder(nil, h) 219 } 220 var oldWriteBufferSize int 221 if testUseIoEncDec >= 0 { 222 buf = fn(bsIn) 223 // set the encode options for using a buffer 224 oldWriteBufferSize = bh.WriterBufferSize 225 bh.WriterBufferSize = testUseIoEncDec 226 if testUseIoWrapper { 227 e.Reset(ioWriterWrapper{buf}) 228 } else { 229 e.Reset(buf) 230 } 231 } else { 232 bs = bsIn 233 e.ResetBytes(&bs) 234 } 235 if testUseMust { 236 e.MustEncode(ts) 237 } else { 238 err = e.Encode(ts) 239 } 240 if testUseIoEncDec >= 0 { 241 bs = buf.Bytes() 242 bh.WriterBufferSize = oldWriteBufferSize 243 } 244 if !testUseReset { 245 e.Release() 246 } 247 return 248} 249 250func sTestCodecDecode(bs []byte, ts interface{}, h Handle, bh *BasicHandle) (err error) { 251 var d *Decoder 252 // var buf *bytes.Reader 253 if testUseReset { 254 d = testHEDGet(h).D 255 } else { 256 d = NewDecoder(nil, h) 257 } 258 var oldReadBufferSize int 259 if testUseIoEncDec >= 0 { 260 buf := bytes.NewReader(bs) 261 oldReadBufferSize = bh.ReaderBufferSize 262 bh.ReaderBufferSize = testUseIoEncDec 263 if testUseIoWrapper { 264 d.Reset(ioReaderWrapper{buf}) 265 } else { 266 d.Reset(buf) 267 } 268 } else { 269 d.ResetBytes(bs) 270 } 271 if testUseMust { 272 d.MustDecode(ts) 273 } else { 274 err = d.Decode(ts) 275 } 276 if testUseIoEncDec >= 0 { 277 bh.ReaderBufferSize = oldReadBufferSize 278 } 279 if !testUseReset { 280 d.Release() 281 } 282 return 283} 284 285// --- functions below are used by both benchmarks and tests 286 287func logT(x interface{}, format string, args ...interface{}) { 288 if t, ok := x.(*testing.T); ok && t != nil { 289 t.Logf(format, args...) 290 } else if b, ok := x.(*testing.B); ok && b != nil { 291 b.Logf(format, args...) 292 } else { // if testing.Verbose() { // if testVerbose { 293 if len(format) == 0 || format[len(format)-1] != '\n' { 294 format = format + "\n" 295 } 296 fmt.Printf(format, args...) 297 } 298} 299 300// --- functions below are used only by benchmarks alone 301 302func fnBenchmarkByteBuf(bsIn []byte) (buf *bytes.Buffer) { 303 // var buf bytes.Buffer 304 // buf.Grow(approxSize) 305 buf = bytes.NewBuffer(bsIn) 306 buf.Truncate(0) 307 return 308} 309 310// func benchFnCodecEncode(ts interface{}, bsIn []byte, h Handle) (bs []byte, err error) { 311// return testCodecEncode(ts, bsIn, fnBenchmarkByteBuf, h) 312// } 313 314// func benchFnCodecDecode(bs []byte, ts interface{}, h Handle) (err error) { 315// return testCodecDecode(bs, ts, h) 316// } 317