mtest->mrand: move rand functionality from mtest into its own package
This commit is contained in:
parent
f9ec4d7bce
commit
1be0072701
@ -7,7 +7,7 @@ import (
|
||||
"io/ioutil"
|
||||
. "testing"
|
||||
|
||||
"github.com/mediocregopher/mediocre-go-lib/mtest"
|
||||
"github.com/mediocregopher/mediocre-go-lib/mrand"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
@ -23,16 +23,16 @@ func randBBRTest(minBodySize, maxBodySize int) bbrTest {
|
||||
genWhitespace := func(n int) []byte {
|
||||
ws := make([]byte, n)
|
||||
for i := range ws {
|
||||
ws[i] = whitespace[mtest.Rand.Intn(len(whitespace))]
|
||||
ws[i] = whitespace[mrand.Intn(len(whitespace))]
|
||||
}
|
||||
return ws
|
||||
}
|
||||
|
||||
body := mtest.RandBytes(minBodySize + mtest.Rand.Intn(maxBodySize-minBodySize))
|
||||
body := mrand.Bytes(minBodySize + mrand.Intn(maxBodySize-minBodySize))
|
||||
return bbrTest{
|
||||
wsSuffix: genWhitespace(mtest.Rand.Intn(10)),
|
||||
wsSuffix: genWhitespace(mrand.Intn(10)),
|
||||
body: body,
|
||||
intoSize: 1 + mtest.Rand.Intn(len(body)+1),
|
||||
intoSize: 1 + mrand.Intn(len(body)+1),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -8,7 +8,7 @@ import (
|
||||
"sync"
|
||||
. "testing"
|
||||
|
||||
"github.com/mediocregopher/mediocre-go-lib/mtest"
|
||||
"github.com/mediocregopher/mediocre-go-lib/mrand"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
@ -45,7 +45,7 @@ func TestEncoderDecoder(t *T) {
|
||||
randTestCase = func(typ Type, cancelable bool) testCase {
|
||||
// if typ isn't given then use a random one
|
||||
if typ == "" {
|
||||
pick := mtest.Rand.Intn(5)
|
||||
pick := mrand.Intn(5)
|
||||
switch {
|
||||
case pick == 0:
|
||||
typ = TypeStream
|
||||
@ -58,24 +58,24 @@ func TestEncoderDecoder(t *T) {
|
||||
|
||||
tc := testCase{
|
||||
typ: typ,
|
||||
cancel: cancelable && mtest.Rand.Intn(10) == 0,
|
||||
cancel: cancelable && mrand.Intn(10) == 0,
|
||||
}
|
||||
|
||||
switch typ {
|
||||
case TypeJSONValue:
|
||||
tc.val = map[string]interface{}{
|
||||
mtest.RandHex(8): mtest.RandHex(8),
|
||||
mtest.RandHex(8): mtest.RandHex(8),
|
||||
mtest.RandHex(8): mtest.RandHex(8),
|
||||
mtest.RandHex(8): mtest.RandHex(8),
|
||||
mtest.RandHex(8): mtest.RandHex(8),
|
||||
mrand.Hex(8): mrand.Hex(8),
|
||||
mrand.Hex(8): mrand.Hex(8),
|
||||
mrand.Hex(8): mrand.Hex(8),
|
||||
mrand.Hex(8): mrand.Hex(8),
|
||||
mrand.Hex(8): mrand.Hex(8),
|
||||
}
|
||||
return tc
|
||||
case TypeByteBlob:
|
||||
tc.bytes = mtest.RandBytes(mtest.Rand.Intn(256))
|
||||
tc.bytes = mrand.Bytes(mrand.Intn(256))
|
||||
return tc
|
||||
case TypeStream:
|
||||
for i := mtest.Rand.Intn(10); i > 0; i-- {
|
||||
for i := mrand.Intn(10); i > 0; i-- {
|
||||
tc.stream = append(tc.stream, randTestCase("", true))
|
||||
}
|
||||
return tc
|
||||
|
@ -6,7 +6,7 @@ import (
|
||||
"strconv"
|
||||
. "testing"
|
||||
|
||||
"github.com/mediocregopher/mediocre-go-lib/mtest"
|
||||
"github.com/mediocregopher/mediocre-go-lib/mrand"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
@ -188,9 +188,9 @@ func TestSourceCLI(t *T) {
|
||||
}
|
||||
}
|
||||
|
||||
childName := mtest.RandHex(8)
|
||||
childDashName := mtest.RandHex(4) + "-" + mtest.RandHex(4)
|
||||
childEqName := mtest.RandHex(4) + "=" + mtest.RandHex(4)
|
||||
childName := mrand.Hex(8)
|
||||
childDashName := mrand.Hex(4) + "-" + mrand.Hex(4)
|
||||
childEqName := mrand.Hex(4) + "=" + mrand.Hex(4)
|
||||
|
||||
var args []string
|
||||
rootCfg := New()
|
||||
@ -204,11 +204,11 @@ func TestSourceCLI(t *T) {
|
||||
|
||||
switch tests[i].name {
|
||||
case "normal":
|
||||
pv.Name = mtest.RandHex(8)
|
||||
pv.Name = mrand.Hex(8)
|
||||
case "wDash":
|
||||
pv.Name = mtest.RandHex(4) + "-" + mtest.RandHex(4)
|
||||
pv.Name = mrand.Hex(4) + "-" + mrand.Hex(4)
|
||||
case "wEq":
|
||||
pv.Name = mtest.RandHex(4) + "=" + mtest.RandHex(4)
|
||||
pv.Name = mrand.Hex(4) + "=" + mrand.Hex(4)
|
||||
}
|
||||
|
||||
pv.IsBool = tests[i].isBool
|
||||
@ -242,18 +242,18 @@ func TestSourceCLI(t *T) {
|
||||
var val string
|
||||
switch tests[i].nonBoolType {
|
||||
case "int":
|
||||
val = strconv.Itoa(mtest.Rand.Int())
|
||||
val = strconv.Itoa(mrand.Int())
|
||||
pv.Value = json.RawMessage(val)
|
||||
case "str":
|
||||
switch tests[i].nonBoolStrValue {
|
||||
case "empty":
|
||||
// ez
|
||||
case "normal":
|
||||
val = mtest.RandHex(8)
|
||||
val = mrand.Hex(8)
|
||||
case "wDash":
|
||||
val = mtest.RandHex(4) + "-" + mtest.RandHex(4)
|
||||
val = mrand.Hex(4) + "-" + mrand.Hex(4)
|
||||
case "wEq":
|
||||
val = mtest.RandHex(4) + "=" + mtest.RandHex(4)
|
||||
val = mrand.Hex(4) + "=" + mrand.Hex(4)
|
||||
}
|
||||
pv.Value = json.RawMessage(`"` + val + `"`)
|
||||
}
|
||||
|
@ -3,7 +3,7 @@ package mcrypto
|
||||
import (
|
||||
. "testing"
|
||||
|
||||
"github.com/mediocregopher/mediocre-go-lib/mtest"
|
||||
"github.com/mediocregopher/mediocre-go-lib/mrand"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
@ -11,7 +11,7 @@ func TestKeyPair(t *T) {
|
||||
pub, priv := NewWeakKeyPair()
|
||||
|
||||
// test signing/verifying
|
||||
str := mtest.RandHex(512)
|
||||
str := mrand.Hex(512)
|
||||
sig := SignString(priv, str)
|
||||
assert.NoError(t, VerifyString(pub, sig, str))
|
||||
}
|
||||
|
@ -5,12 +5,12 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/ansel1/merry"
|
||||
"github.com/mediocregopher/mediocre-go-lib/mtest"
|
||||
"github.com/mediocregopher/mediocre-go-lib/mrand"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestSecretSignVerify(t *T) {
|
||||
secretRaw := mtest.RandBytes(16)
|
||||
secretRaw := mrand.Bytes(16)
|
||||
secret := NewSecret(secretRaw)
|
||||
weakSecret := NewWeakSecret(secretRaw)
|
||||
var prevStr string
|
||||
@ -20,7 +20,7 @@ func TestSecretSignVerify(t *T) {
|
||||
secret.testNow = now
|
||||
weakSecret.testNow = now
|
||||
|
||||
thisStr := mtest.RandHex(512)
|
||||
thisStr := mrand.Hex(512)
|
||||
thisSig := SignString(secret, thisStr)
|
||||
thisWeakSig := SignString(weakSecret, thisStr)
|
||||
thisSigStr, thisWeakSigStr := thisSig.String(), thisWeakSig.String()
|
||||
|
@ -5,19 +5,19 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/ansel1/merry"
|
||||
"github.com/mediocregopher/mediocre-go-lib/mtest"
|
||||
"github.com/mediocregopher/mediocre-go-lib/mrand"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestSignerVerifier(t *T) {
|
||||
secret := NewSecret(mtest.RandBytes(16))
|
||||
secret := NewSecret(mrand.Bytes(16))
|
||||
var prevStr string
|
||||
var prevSig Signature
|
||||
for i := 0; i < 10000; i++ {
|
||||
now := time.Now().Round(0)
|
||||
secret.testNow = now
|
||||
|
||||
thisStr := mtest.RandHex(512)
|
||||
thisStr := mrand.Hex(512)
|
||||
thisSig := SignString(secret, thisStr)
|
||||
thisSigStr := thisSig.String()
|
||||
|
||||
|
@ -6,7 +6,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/mediocregopher/mediocre-go-lib/mcfg"
|
||||
"github.com/mediocregopher/mediocre-go-lib/mtest"
|
||||
"github.com/mediocregopher/mediocre-go-lib/mrand"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
@ -21,7 +21,7 @@ func init() {
|
||||
|
||||
// this requires the pubsub emulator to be running
|
||||
func TestPubSub(t *T) {
|
||||
topicName := "testTopic_" + mtest.RandHex(8)
|
||||
topicName := "testTopic_" + mrand.Hex(8)
|
||||
ctx := context.Background()
|
||||
|
||||
// Topic shouldn't exist yet
|
||||
@ -51,7 +51,7 @@ func TestPubSub(t *T) {
|
||||
|
||||
func TestBatchPubSub(t *T) {
|
||||
ctx := context.Background()
|
||||
topicName := "testBatchTopic_" + mtest.RandHex(8)
|
||||
topicName := "testBatchTopic_" + mrand.Hex(8)
|
||||
topic, err := testPS.Topic(ctx, topicName, true)
|
||||
require.NoError(t, err)
|
||||
|
||||
|
91
mrand/mrand.go
Normal file
91
mrand/mrand.go
Normal file
@ -0,0 +1,91 @@
|
||||
// Package mrand implements extensions and conveniences for using the default
|
||||
// math/rand package.
|
||||
package mrand
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"math/rand"
|
||||
"reflect"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Rand extends the default rand.Rand type with extra functionality.
|
||||
type Rand struct {
|
||||
*rand.Rand
|
||||
}
|
||||
|
||||
// Bytes returns n random bytes.
|
||||
func (r Rand) Bytes(n int) []byte {
|
||||
b := make([]byte, n)
|
||||
if _, err := r.Read(b); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
// Hex returns a random hex string which is n characters long.
|
||||
func (r Rand) Hex(n int) string {
|
||||
b := r.Bytes(hex.DecodedLen(n))
|
||||
return hex.EncodeToString(b)
|
||||
}
|
||||
|
||||
// Element returns a random element from the given slice.
|
||||
//
|
||||
// If a weighting function is given then that function is used to weight each
|
||||
// element of the slice relative to the others, based on whatever metric and
|
||||
// scale is desired. The weight function must be able to be called more than
|
||||
// once on each element.
|
||||
func (r Rand) Element(slice interface{}, weight func(i int) uint64) interface{} {
|
||||
v := reflect.ValueOf(slice)
|
||||
l := v.Len()
|
||||
|
||||
if weight == nil {
|
||||
return v.Index(r.Intn(l)).Interface()
|
||||
}
|
||||
|
||||
var totalWeight uint64
|
||||
for i := 0; i < l; i++ {
|
||||
totalWeight += weight(i)
|
||||
}
|
||||
|
||||
target := r.Int63n(int64(totalWeight))
|
||||
for i := 0; i < l; i++ {
|
||||
w := int64(weight(i))
|
||||
target -= w
|
||||
if target < 0 {
|
||||
return v.Index(i).Interface()
|
||||
}
|
||||
}
|
||||
panic("should never get here, perhaps the weighting function is inconsistent?")
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// DefaultRand is an instance off Rand whose methods are directly exported by
|
||||
// this package for convenience.
|
||||
var DefaultRand = Rand{Rand: rand.New(rand.NewSource(time.Now().UnixNano()))}
|
||||
|
||||
// Methods off DefaultRand exported to the top level of this package.
|
||||
var (
|
||||
ExpFloat64 = DefaultRand.ExpFloat64
|
||||
Float32 = DefaultRand.Float32
|
||||
Float64 = DefaultRand.Float64
|
||||
Int = DefaultRand.Int
|
||||
Int31 = DefaultRand.Int31
|
||||
Int31n = DefaultRand.Int31n
|
||||
Int63 = DefaultRand.Int63
|
||||
Int63n = DefaultRand.Int63n
|
||||
Intn = DefaultRand.Intn
|
||||
NormFloat64 = DefaultRand.NormFloat64
|
||||
Perm = DefaultRand.Perm
|
||||
Read = DefaultRand.Read
|
||||
Seed = DefaultRand.Seed
|
||||
Shuffle = DefaultRand.Shuffle
|
||||
Uint32 = DefaultRand.Uint32
|
||||
Uint64 = DefaultRand.Uint64
|
||||
|
||||
// extended methods
|
||||
Bytes = DefaultRand.Bytes
|
||||
Hex = DefaultRand.Hex
|
||||
Element = DefaultRand.Element
|
||||
)
|
@ -1,4 +1,4 @@
|
||||
package mtest
|
||||
package mrand
|
||||
|
||||
import (
|
||||
. "testing"
|
||||
@ -9,7 +9,7 @@ import (
|
||||
func TestRandBytes(t *T) {
|
||||
var prev []byte
|
||||
for i := 0; i < 10000; i++ {
|
||||
curr := RandBytes(16)
|
||||
curr := Bytes(16)
|
||||
assert.Len(t, curr, 16)
|
||||
assert.NotEqual(t, prev, curr)
|
||||
prev = curr
|
||||
@ -19,7 +19,7 @@ func TestRandBytes(t *T) {
|
||||
func TestRandHex(t *T) {
|
||||
// RandHex is basically a wrapper of RandBytes, so we don't have to test it
|
||||
// much
|
||||
assert.Len(t, RandHex(16), 16)
|
||||
assert.Len(t, Hex(16), 16)
|
||||
}
|
||||
|
||||
func TestRandElement(t *T) {
|
||||
@ -35,7 +35,7 @@ func TestRandElement(t *T) {
|
||||
|
||||
iterations := 100000
|
||||
for i := 0; i < iterations; i++ {
|
||||
el := RandElement(slice, func(i int) uint64 { return slice[i] }).(uint64)
|
||||
el := Element(slice, func(i int) uint64 { return slice[i] }).(uint64)
|
||||
m[el]++
|
||||
}
|
||||
|
@ -4,7 +4,7 @@ import (
|
||||
"context"
|
||||
. "testing"
|
||||
|
||||
"github.com/mediocregopher/mediocre-go-lib/mtest"
|
||||
"github.com/mediocregopher/mediocre-go-lib/mrand"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
@ -28,14 +28,14 @@ func TestReflectClient(t *T) {
|
||||
}))
|
||||
|
||||
{ // test with arg being non-pointer
|
||||
in := mtest.RandHex(8)
|
||||
in := mrand.Hex(8)
|
||||
var res resT
|
||||
assert.NoError(t, client.CallRPC(ctx, &res, "foo", argT{In: in}))
|
||||
assert.Equal(t, in, res.Out)
|
||||
}
|
||||
|
||||
{ // test with arg being pointer
|
||||
in := mtest.RandHex(8)
|
||||
in := mrand.Hex(8)
|
||||
var res resT
|
||||
assert.NoError(t, client.CallRPC(ctx, &res, "foo", &argT{In: in}))
|
||||
assert.Equal(t, in, res.Out)
|
||||
@ -51,14 +51,14 @@ func TestReflectClient(t *T) {
|
||||
}))
|
||||
|
||||
{ // test with arg being non-pointer
|
||||
in := mtest.RandHex(8)
|
||||
in := mrand.Hex(8)
|
||||
var res resT
|
||||
assert.NoError(t, client.CallRPC(ctx, &res, "foo", argT{In: in}))
|
||||
assert.Equal(t, in, res.Out)
|
||||
}
|
||||
|
||||
{ // test with arg being pointer
|
||||
in := mtest.RandHex(8)
|
||||
in := mrand.Hex(8)
|
||||
var res resT
|
||||
assert.NoError(t, client.CallRPC(ctx, &res, "foo", &argT{In: in}))
|
||||
assert.Equal(t, in, res.Out)
|
||||
|
@ -1,60 +0,0 @@
|
||||
// Package mtest contains types and functions which are useful when writing
|
||||
// tests
|
||||
package mtest
|
||||
|
||||
import (
|
||||
crand "crypto/rand"
|
||||
"encoding/hex"
|
||||
"math/rand"
|
||||
"reflect"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Rand is a public instance of rand.Rand, seeded with the current
|
||||
// nano-timestamp
|
||||
var Rand = rand.New(rand.NewSource(time.Now().UnixNano()))
|
||||
|
||||
// RandBytes returns n random bytes
|
||||
func RandBytes(n int) []byte {
|
||||
b := make([]byte, n)
|
||||
if _, err := crand.Read(b); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
// RandHex returns a random hex string which is n characters long
|
||||
func RandHex(n int) string {
|
||||
b := RandBytes(hex.DecodedLen(n))
|
||||
return hex.EncodeToString(b)
|
||||
}
|
||||
|
||||
// RandElement returns a random element from the given slice.
|
||||
//
|
||||
// If a weighting function is given then that function is used to weight each
|
||||
// element of the slice relative to the others, based on whatever metric and
|
||||
// scale is desired. The weight function must be able to be called more than
|
||||
// once on each element.
|
||||
func RandElement(slice interface{}, weight func(i int) uint64) interface{} {
|
||||
v := reflect.ValueOf(slice)
|
||||
l := v.Len()
|
||||
|
||||
if weight == nil {
|
||||
return v.Index(Rand.Intn(l)).Interface()
|
||||
}
|
||||
|
||||
var totalWeight uint64
|
||||
for i := 0; i < l; i++ {
|
||||
totalWeight += weight(i)
|
||||
}
|
||||
|
||||
target := Rand.Int63n(int64(totalWeight))
|
||||
for i := 0; i < l; i++ {
|
||||
w := int64(weight(i))
|
||||
target -= w
|
||||
if target < 0 {
|
||||
return v.Index(i).Interface()
|
||||
}
|
||||
}
|
||||
panic("should never get here, perhaps the weighting function is inconsistent?")
|
||||
}
|
Loading…
Reference in New Issue
Block a user