github.com/ugorji/go/codec@v1.2.13-0.20240307214044-07c54c229a5a/shared_test.go (about) 1 // Copyright (c) 2012-2020 Ugorji Nwoke. All rights reserved. 2 // Use of this source code is governed by a MIT license found in the LICENSE file. 3 4 package 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 43 import ( 44 "bytes" 45 "flag" 46 "io" 47 "io/ioutil" 48 "log" 49 "sync" 50 ) 51 52 // __DO_NOT_REMOVE__NEEDED_FOR_REPLACING__IMPORT_PATH__FOR_CODEC_BENCH__ 53 54 type testHED struct { 55 H Handle 56 E *Encoder 57 D *Decoder 58 } 59 60 type ioReaderWrapper struct { 61 r io.Reader 62 } 63 64 func (x ioReaderWrapper) Read(p []byte) (n int, err error) { 65 return x.r.Read(p) 66 } 67 68 type ioWriterWrapper struct { 69 w io.Writer 70 } 71 72 func (x ioWriterWrapper) Write(p []byte) (n int, err error) { 73 return x.w.Write(p) 74 } 75 76 var ( 77 // testNoopH = NoopHandle(8) 78 testMsgpackH = &MsgpackHandle{} 79 testBincH = &BincHandle{} 80 testSimpleH = &SimpleHandle{} 81 testCborH = &CborHandle{} 82 testJsonH = &JsonHandle{} 83 84 testHandles []Handle 85 testPreInitFns []func() 86 testPostInitFns []func() 87 88 testOnce sync.Once 89 90 testHEDs []testHED 91 ) 92 93 // flag variables used by tests (and bench) 94 var ( 95 testVerbose bool 96 97 //depth of 0 maps to ~400bytes json-encoded string, 1 maps to ~1400 bytes, etc 98 //For depth>1, we likely trigger stack growth for encoders, making benchmarking unreliable. 99 testDepth int 100 101 testMaxInitLen int 102 103 testUseReset bool 104 testUseParallel bool 105 106 testSkipIntf bool 107 108 testUseIoEncDec int 109 testUseIoWrapper bool 110 111 testNumRepeatString int 112 113 testRpcBufsize int 114 testMapStringKeyOnly bool 115 116 testBenchmarkNoConfig bool 117 ) 118 119 // variables that are not flags, but which can configure the handles 120 var ( 121 testEncodeOptions EncodeOptions 122 testDecodeOptions DecodeOptions 123 testRPCOptions RPCOptions 124 ) 125 126 func init() { 127 log.SetOutput(ioutil.Discard) // don't allow things log to standard out/err 128 testHEDs = make([]testHED, 0, 32) 129 testHandles = append(testHandles, 130 // testNoopH, 131 testMsgpackH, testBincH, testSimpleH, testCborH, testJsonH) 132 // JSON should do HTMLCharsAsIs by default 133 testJsonH.HTMLCharsAsIs = true 134 // testJsonH.InternString = true 135 testInitFlags() 136 benchInitFlags() 137 } 138 139 func testInitFlags() { 140 var bIgnore bool 141 // delete(testDecOpts.ExtFuncs, timeTyp) 142 flag.BoolVar(&testVerbose, "tv", false, "Text Extra Verbose Logging if -v if set") 143 flag.IntVar(&testUseIoEncDec, "ti", -1, "Use IO Reader/Writer for Marshal/Unmarshal ie >= 0") 144 flag.BoolVar(&testUseIoWrapper, "tiw", false, "Wrap the IO Reader/Writer with a base pass-through reader/writer") 145 146 flag.BoolVar(&testSkipIntf, "tf", false, "Skip Interfaces") 147 flag.BoolVar(&testUseReset, "tr", false, "Use Reset") 148 flag.BoolVar(&testUseParallel, "tp", false, "Run tests in parallel") 149 flag.IntVar(&testNumRepeatString, "trs", 8, "Create string variables by repeating a string N times") 150 flag.BoolVar(&bIgnore, "tm", true, "(Deprecated) Use Must(En|De)code") 151 152 flag.IntVar(&testMaxInitLen, "tx", 0, "Max Init Len") 153 154 flag.IntVar(&testDepth, "tsd", 0, "Test Struc Depth") 155 flag.BoolVar(&testMapStringKeyOnly, "tsk", false, "use maps with string keys only") 156 } 157 158 func benchInitFlags() { 159 flag.BoolVar(&testBenchmarkNoConfig, "bnc", false, "benchmarks: do not make configuration changes for fair benchmarking") 160 // flags reproduced here for compatibility (duplicate some in testInitFlags) 161 flag.BoolVar(&testMapStringKeyOnly, "bs", false, "benchmarks: use maps with string keys only") 162 flag.IntVar(&testDepth, "bd", 1, "Benchmarks: Test Struc Depth") 163 } 164 165 func testHEDGet(h Handle) *testHED { 166 for i := range testHEDs { 167 v := &testHEDs[i] 168 if v.H == h { 169 return v 170 } 171 } 172 testHEDs = append(testHEDs, testHED{h, NewEncoder(nil, h), NewDecoder(nil, h)}) 173 return &testHEDs[len(testHEDs)-1] 174 } 175 176 func testReinit() { 177 testOnce = sync.Once{} 178 testHEDs = nil 179 } 180 181 func testInitAll() { 182 // only parse it once. 183 if !flag.Parsed() { 184 flag.Parse() 185 } 186 for _, f := range testPreInitFns { 187 f() 188 } 189 for _, f := range testPostInitFns { 190 f() 191 } 192 } 193 194 func testSharedCodecEncode(ts interface{}, bsIn []byte, fn func([]byte) *bytes.Buffer, 195 h Handle, bh *BasicHandle, useMust bool) (bs []byte, err error) { 196 // bs = make([]byte, 0, approxSize) 197 var e *Encoder 198 var buf *bytes.Buffer 199 if testUseReset && !testUseParallel { 200 e = testHEDGet(h).E 201 } else { 202 e = NewEncoder(nil, h) 203 } 204 var oldWriteBufferSize int 205 if testUseIoEncDec >= 0 { 206 buf = fn(bsIn) 207 // set the encode options for using a buffer 208 oldWriteBufferSize = bh.WriterBufferSize 209 bh.WriterBufferSize = testUseIoEncDec 210 if testUseIoWrapper { 211 e.Reset(ioWriterWrapper{buf}) 212 } else { 213 e.Reset(buf) 214 } 215 } else { 216 bs = bsIn 217 e.ResetBytes(&bs) 218 } 219 if useMust { 220 e.MustEncode(ts) 221 } else { 222 err = e.Encode(ts) 223 } 224 if testUseIoEncDec >= 0 { 225 bs = buf.Bytes() 226 bh.WriterBufferSize = oldWriteBufferSize 227 } 228 return 229 } 230 231 func testSharedCodecDecoder(bs []byte, h Handle, bh *BasicHandle) (d *Decoder, oldReadBufferSize int) { 232 // var buf *bytes.Reader 233 if testUseReset && !testUseParallel { 234 d = testHEDGet(h).D 235 } else { 236 d = NewDecoder(nil, h) 237 } 238 if testUseIoEncDec >= 0 { 239 buf := bytes.NewReader(bs) 240 oldReadBufferSize = bh.ReaderBufferSize 241 bh.ReaderBufferSize = testUseIoEncDec 242 if testUseIoWrapper { 243 d.Reset(ioReaderWrapper{buf}) 244 } else { 245 d.Reset(buf) 246 } 247 } else { 248 d.ResetBytes(bs) 249 } 250 return 251 } 252 253 func testSharedCodecDecoderAfter(d *Decoder, oldReadBufferSize int, bh *BasicHandle) { 254 if testUseIoEncDec >= 0 { 255 bh.ReaderBufferSize = oldReadBufferSize 256 } 257 } 258 259 func testSharedCodecDecode(bs []byte, ts interface{}, h Handle, bh *BasicHandle, useMust bool) (err error) { 260 d, oldReadBufferSize := testSharedCodecDecoder(bs, h, bh) 261 if useMust { 262 d.MustDecode(ts) 263 } else { 264 err = d.Decode(ts) 265 } 266 testSharedCodecDecoderAfter(d, oldReadBufferSize, bh) 267 return 268 } 269 270 // // --- functions below are used by both benchmarks and tests 271 272 // // log message only when testVerbose = true (ie go test ... -- -tv). 273 // // 274 // // These are for intormational messages that do not necessarily 275 // // help with diagnosing a failure, or which are too large. 276 // func logTv(x interface{}, format string, args ...interface{}) { 277 // if !testVerbose { 278 // return 279 // } 280 // if t, ok := x.(testing.TB); ok { // only available from go 1.9 281 // t.Helper() 282 // } 283 // logT(x, format, args...) 284 // } 285 286 // // logT logs messages when running as go test -v 287 // // 288 // // Use it for diagnostics messages that help diagnost failure, 289 // // and when the output is not too long ie shorter than like 100 characters. 290 // // 291 // // In general, any logT followed by failT should call this. 292 // func logT(x interface{}, format string, args ...interface{}) { 293 // if x == nil { 294 // if len(format) == 0 || format[len(format)-1] != '\n' { 295 // format = format + "\n" 296 // } 297 // fmt.Printf(format, args...) 298 // return 299 // } 300 // if t, ok := x.(testing.TB); ok { // only available from go 1.9 301 // t.Helper() 302 // t.Logf(format, args...) 303 // } 304 // } 305 306 // func failTv(x testing.TB, args ...interface{}) { 307 // x.Helper() 308 // if testVerbose { 309 // failTMsg(x, args...) 310 // } 311 // x.FailNow() 312 // } 313 314 // func failT(x testing.TB, args ...interface{}) { 315 // x.Helper() 316 // failTMsg(x, args...) 317 // x.FailNow() 318 // } 319 320 // func failTMsg(x testing.TB, args ...interface{}) { 321 // x.Helper() 322 // if len(args) > 0 { 323 // if format, ok := args[0].(string); ok { 324 // logT(x, format, args[1:]...) 325 // } else if len(args) == 1 { 326 // logT(x, "%v", args[0]) 327 // } else { 328 // logT(x, "%v", args) 329 // } 330 // } 331 // } 332 333 // --- functions below are used only by benchmarks alone 334 335 func fnBenchmarkByteBuf(bsIn []byte) (buf *bytes.Buffer) { 336 // var buf bytes.Buffer 337 // buf.Grow(approxSize) 338 buf = bytes.NewBuffer(bsIn) 339 buf.Truncate(0) 340 return 341 } 342 343 // func benchFnCodecEncode(ts interface{}, bsIn []byte, h Handle) (bs []byte, err error) { 344 // return testCodecEncode(ts, bsIn, fnBenchmarkByteBuf, h) 345 // } 346 347 // func benchFnCodecDecode(bs []byte, ts interface{}, h Handle) (err error) { 348 // return testCodecDecode(bs, ts, h) 349 // }