hanayo/vendor/github.com/ugorji/go/codec/shared_test.go
2019-02-23 13:29:15 +00:00

305 lines
7.9 KiB
Go

// Copyright (c) 2012-2018 Ugorji Nwoke. All rights reserved.
// Use of this source code is governed by a MIT license found in the LICENSE file.
package codec
// This file sets up the variables used, including testInitFns.
// Each file should add initialization that should be performed
// after flags are parsed.
//
// init is a multi-step process:
// - setup vars (handled by init functions in each file)
// - parse flags
// - setup derived vars (handled by pre-init registered functions - registered in init function)
// - post init (handled by post-init registered functions - registered in init function)
// This way, no one has to manage carefully control the initialization
// using file names, etc.
//
// Tests which require external dependencies need the -tag=x parameter.
// They should be run as:
// go test -tags=x -run=. <other parameters ...>
// Benchmarks should also take this parameter, to include the sereal, xdr, etc.
// To run against codecgen, etc, make sure you pass extra parameters.
// Example usage:
// go test "-tags=x codecgen" -bench=. <other parameters ...>
//
// To fully test everything:
// go test -tags=x -benchtime=100ms -tv -bg -bi -brw -bu -v -run=. -bench=.
// Handling flags
// codec_test.go will define a set of global flags for testing, including:
// - Use Reset
// - Use IO reader/writer (vs direct bytes)
// - Set Canonical
// - Set InternStrings
// - Use Symbols
//
// This way, we can test them all by running same set of tests with a different
// set of flags.
//
// Following this, all the benchmarks will utilize flags set by codec_test.go
// and will not redefine these "global" flags.
import (
"bytes"
"flag"
"fmt"
"io"
"io/ioutil"
"log"
"sync"
"testing"
)
// DO NOT REMOVE - replacement line for go-codec-bench import declaration tag //
type testHED struct {
H Handle
E *Encoder
D *Decoder
}
type ioReaderWrapper struct {
r io.Reader
}
func (x ioReaderWrapper) Read(p []byte) (n int, err error) {
return x.r.Read(p)
}
type ioWriterWrapper struct {
w io.Writer
}
func (x ioWriterWrapper) Write(p []byte) (n int, err error) {
return x.w.Write(p)
}
var (
// testNoopH = NoopHandle(8)
testMsgpackH = &MsgpackHandle{}
testBincH = &BincHandle{}
testSimpleH = &SimpleHandle{}
testCborH = &CborHandle{}
testJsonH = &JsonHandle{}
testHandles []Handle
testPreInitFns []func()
testPostInitFns []func()
testOnce sync.Once
testHEDs []testHED
)
// flag variables used by tests (and bench)
var (
testDepth int
testVerbose bool
testInitDebug bool
testStructToArray bool
testCanonical bool
testUseReset bool
testSkipIntf bool
testInternStr bool
testUseMust bool
testCheckCircRef bool
testUseIoEncDec int
testUseIoWrapper bool
testMaxInitLen int
testNumRepeatString int
testRpcBufsize int
)
// variables that are not flags, but which can configure the handles
var (
testEncodeOptions EncodeOptions
testDecodeOptions DecodeOptions
)
// flag variables used by bench
var (
benchDoInitBench bool
benchVerify bool
benchUnscientificRes bool = false
benchMapStringKeyOnly bool
//depth of 0 maps to ~400bytes json-encoded string, 1 maps to ~1400 bytes, etc
//For depth>1, we likely trigger stack growth for encoders, making benchmarking unreliable.
benchDepth int
benchInitDebug bool
)
func init() {
log.SetOutput(ioutil.Discard) // don't allow things log to standard out/err
testHEDs = make([]testHED, 0, 32)
testHandles = append(testHandles,
// testNoopH,
testMsgpackH, testBincH, testSimpleH,
testCborH, testJsonH)
testInitFlags()
benchInitFlags()
}
func testInitFlags() {
// delete(testDecOpts.ExtFuncs, timeTyp)
flag.IntVar(&testDepth, "tsd", 0, "Test Struc Depth")
flag.BoolVar(&testVerbose, "tv", false, "Test Verbose (no longer used - here for compatibility)")
flag.BoolVar(&testInitDebug, "tg", false, "Test Init Debug")
flag.IntVar(&testUseIoEncDec, "ti", -1, "Use IO Reader/Writer for Marshal/Unmarshal ie >= 0")
flag.BoolVar(&testUseIoWrapper, "tiw", false, "Wrap the IO Reader/Writer with a base pass-through reader/writer")
flag.BoolVar(&testStructToArray, "ts", false, "Set StructToArray option")
flag.BoolVar(&testCanonical, "tc", false, "Set Canonical option")
flag.BoolVar(&testInternStr, "te", false, "Set InternStr option")
flag.BoolVar(&testSkipIntf, "tf", false, "Skip Interfaces")
flag.BoolVar(&testUseReset, "tr", false, "Use Reset")
flag.IntVar(&testNumRepeatString, "trs", 8, "Create string variables by repeating a string N times")
flag.IntVar(&testMaxInitLen, "tx", 0, "Max Init Len")
flag.BoolVar(&testUseMust, "tm", true, "Use Must(En|De)code")
flag.BoolVar(&testCheckCircRef, "tl", false, "Use Check Circular Ref")
}
func benchInitFlags() {
flag.BoolVar(&benchMapStringKeyOnly, "bs", false, "Bench use maps with string keys only")
flag.BoolVar(&benchInitDebug, "bg", false, "Bench Debug")
flag.IntVar(&benchDepth, "bd", 1, "Bench Depth")
flag.BoolVar(&benchDoInitBench, "bi", false, "Run Bench Init")
flag.BoolVar(&benchVerify, "bv", false, "Verify Decoded Value during Benchmark")
flag.BoolVar(&benchUnscientificRes, "bu", false, "Show Unscientific Results during Benchmark")
}
func testHEDGet(h Handle) *testHED {
for i := range testHEDs {
v := &testHEDs[i]
if v.H == h {
return v
}
}
testHEDs = append(testHEDs, testHED{h, NewEncoder(nil, h), NewDecoder(nil, h)})
return &testHEDs[len(testHEDs)-1]
}
func testReinit() {
testOnce = sync.Once{}
testHEDs = nil
}
func testInitAll() {
// only parse it once.
if !flag.Parsed() {
flag.Parse()
}
for _, f := range testPreInitFns {
f()
}
for _, f := range testPostInitFns {
f()
}
}
func sTestCodecEncode(ts interface{}, bsIn []byte, fn func([]byte) *bytes.Buffer,
h Handle, bh *BasicHandle) (bs []byte, err error) {
// bs = make([]byte, 0, approxSize)
var e *Encoder
var buf *bytes.Buffer
if testUseReset {
e = testHEDGet(h).E
} else {
e = NewEncoder(nil, h)
}
var oldWriteBufferSize int
if testUseIoEncDec >= 0 {
buf = fn(bsIn)
// set the encode options for using a buffer
oldWriteBufferSize = bh.WriterBufferSize
bh.WriterBufferSize = testUseIoEncDec
if testUseIoWrapper {
e.Reset(ioWriterWrapper{buf})
} else {
e.Reset(buf)
}
} else {
bs = bsIn
e.ResetBytes(&bs)
}
if testUseMust {
e.MustEncode(ts)
} else {
err = e.Encode(ts)
}
if testUseIoEncDec >= 0 {
bs = buf.Bytes()
bh.WriterBufferSize = oldWriteBufferSize
}
return
}
func sTestCodecDecode(bs []byte, ts interface{}, h Handle, bh *BasicHandle) (err error) {
var d *Decoder
// var buf *bytes.Reader
if testUseReset {
d = testHEDGet(h).D
} else {
d = NewDecoder(nil, h)
}
var oldReadBufferSize int
if testUseIoEncDec >= 0 {
buf := bytes.NewReader(bs)
oldReadBufferSize = bh.ReaderBufferSize
bh.ReaderBufferSize = testUseIoEncDec
if testUseIoWrapper {
d.Reset(ioReaderWrapper{buf})
} else {
d.Reset(buf)
}
} else {
d.ResetBytes(bs)
}
if testUseMust {
d.MustDecode(ts)
} else {
err = d.Decode(ts)
}
if testUseIoEncDec >= 0 {
bh.ReaderBufferSize = oldReadBufferSize
}
return
}
// --- functions below are used by both benchmarks and tests
func logT(x interface{}, format string, args ...interface{}) {
if t, ok := x.(*testing.T); ok && t != nil {
t.Logf(format, args...)
} else if b, ok := x.(*testing.B); ok && b != nil {
b.Logf(format, args...)
} else { // if testing.Verbose() { // if testVerbose {
if len(format) == 0 || format[len(format)-1] != '\n' {
format = format + "\n"
}
fmt.Printf(format, args...)
}
}
// --- functions below are used only by benchmarks alone
func fnBenchmarkByteBuf(bsIn []byte) (buf *bytes.Buffer) {
// var buf bytes.Buffer
// buf.Grow(approxSize)
buf = bytes.NewBuffer(bsIn)
buf.Truncate(0)
return
}
// func benchFnCodecEncode(ts interface{}, bsIn []byte, h Handle) (bs []byte, err error) {
// return testCodecEncode(ts, bsIn, fnBenchmarkByteBuf, h)
// }
// func benchFnCodecDecode(bs []byte, ts interface{}, h Handle) (err error) {
// return testCodecDecode(bs, ts, h)
// }