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"
|
"io/ioutil"
|
||||||
. "testing"
|
. "testing"
|
||||||
|
|
||||||
"github.com/mediocregopher/mediocre-go-lib/mtest"
|
"github.com/mediocregopher/mediocre-go-lib/mrand"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -23,16 +23,16 @@ func randBBRTest(minBodySize, maxBodySize int) bbrTest {
|
|||||||
genWhitespace := func(n int) []byte {
|
genWhitespace := func(n int) []byte {
|
||||||
ws := make([]byte, n)
|
ws := make([]byte, n)
|
||||||
for i := range ws {
|
for i := range ws {
|
||||||
ws[i] = whitespace[mtest.Rand.Intn(len(whitespace))]
|
ws[i] = whitespace[mrand.Intn(len(whitespace))]
|
||||||
}
|
}
|
||||||
return ws
|
return ws
|
||||||
}
|
}
|
||||||
|
|
||||||
body := mtest.RandBytes(minBodySize + mtest.Rand.Intn(maxBodySize-minBodySize))
|
body := mrand.Bytes(minBodySize + mrand.Intn(maxBodySize-minBodySize))
|
||||||
return bbrTest{
|
return bbrTest{
|
||||||
wsSuffix: genWhitespace(mtest.Rand.Intn(10)),
|
wsSuffix: genWhitespace(mrand.Intn(10)),
|
||||||
body: body,
|
body: body,
|
||||||
intoSize: 1 + mtest.Rand.Intn(len(body)+1),
|
intoSize: 1 + mrand.Intn(len(body)+1),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
. "testing"
|
. "testing"
|
||||||
|
|
||||||
"github.com/mediocregopher/mediocre-go-lib/mtest"
|
"github.com/mediocregopher/mediocre-go-lib/mrand"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -45,7 +45,7 @@ func TestEncoderDecoder(t *T) {
|
|||||||
randTestCase = func(typ Type, cancelable bool) testCase {
|
randTestCase = func(typ Type, cancelable bool) testCase {
|
||||||
// if typ isn't given then use a random one
|
// if typ isn't given then use a random one
|
||||||
if typ == "" {
|
if typ == "" {
|
||||||
pick := mtest.Rand.Intn(5)
|
pick := mrand.Intn(5)
|
||||||
switch {
|
switch {
|
||||||
case pick == 0:
|
case pick == 0:
|
||||||
typ = TypeStream
|
typ = TypeStream
|
||||||
@ -58,24 +58,24 @@ func TestEncoderDecoder(t *T) {
|
|||||||
|
|
||||||
tc := testCase{
|
tc := testCase{
|
||||||
typ: typ,
|
typ: typ,
|
||||||
cancel: cancelable && mtest.Rand.Intn(10) == 0,
|
cancel: cancelable && mrand.Intn(10) == 0,
|
||||||
}
|
}
|
||||||
|
|
||||||
switch typ {
|
switch typ {
|
||||||
case TypeJSONValue:
|
case TypeJSONValue:
|
||||||
tc.val = map[string]interface{}{
|
tc.val = map[string]interface{}{
|
||||||
mtest.RandHex(8): mtest.RandHex(8),
|
mrand.Hex(8): mrand.Hex(8),
|
||||||
mtest.RandHex(8): mtest.RandHex(8),
|
mrand.Hex(8): mrand.Hex(8),
|
||||||
mtest.RandHex(8): mtest.RandHex(8),
|
mrand.Hex(8): mrand.Hex(8),
|
||||||
mtest.RandHex(8): mtest.RandHex(8),
|
mrand.Hex(8): mrand.Hex(8),
|
||||||
mtest.RandHex(8): mtest.RandHex(8),
|
mrand.Hex(8): mrand.Hex(8),
|
||||||
}
|
}
|
||||||
return tc
|
return tc
|
||||||
case TypeByteBlob:
|
case TypeByteBlob:
|
||||||
tc.bytes = mtest.RandBytes(mtest.Rand.Intn(256))
|
tc.bytes = mrand.Bytes(mrand.Intn(256))
|
||||||
return tc
|
return tc
|
||||||
case TypeStream:
|
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))
|
tc.stream = append(tc.stream, randTestCase("", true))
|
||||||
}
|
}
|
||||||
return tc
|
return tc
|
||||||
|
@ -6,7 +6,7 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
. "testing"
|
. "testing"
|
||||||
|
|
||||||
"github.com/mediocregopher/mediocre-go-lib/mtest"
|
"github.com/mediocregopher/mediocre-go-lib/mrand"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
@ -188,9 +188,9 @@ func TestSourceCLI(t *T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
childName := mtest.RandHex(8)
|
childName := mrand.Hex(8)
|
||||||
childDashName := mtest.RandHex(4) + "-" + mtest.RandHex(4)
|
childDashName := mrand.Hex(4) + "-" + mrand.Hex(4)
|
||||||
childEqName := mtest.RandHex(4) + "=" + mtest.RandHex(4)
|
childEqName := mrand.Hex(4) + "=" + mrand.Hex(4)
|
||||||
|
|
||||||
var args []string
|
var args []string
|
||||||
rootCfg := New()
|
rootCfg := New()
|
||||||
@ -204,11 +204,11 @@ func TestSourceCLI(t *T) {
|
|||||||
|
|
||||||
switch tests[i].name {
|
switch tests[i].name {
|
||||||
case "normal":
|
case "normal":
|
||||||
pv.Name = mtest.RandHex(8)
|
pv.Name = mrand.Hex(8)
|
||||||
case "wDash":
|
case "wDash":
|
||||||
pv.Name = mtest.RandHex(4) + "-" + mtest.RandHex(4)
|
pv.Name = mrand.Hex(4) + "-" + mrand.Hex(4)
|
||||||
case "wEq":
|
case "wEq":
|
||||||
pv.Name = mtest.RandHex(4) + "=" + mtest.RandHex(4)
|
pv.Name = mrand.Hex(4) + "=" + mrand.Hex(4)
|
||||||
}
|
}
|
||||||
|
|
||||||
pv.IsBool = tests[i].isBool
|
pv.IsBool = tests[i].isBool
|
||||||
@ -242,18 +242,18 @@ func TestSourceCLI(t *T) {
|
|||||||
var val string
|
var val string
|
||||||
switch tests[i].nonBoolType {
|
switch tests[i].nonBoolType {
|
||||||
case "int":
|
case "int":
|
||||||
val = strconv.Itoa(mtest.Rand.Int())
|
val = strconv.Itoa(mrand.Int())
|
||||||
pv.Value = json.RawMessage(val)
|
pv.Value = json.RawMessage(val)
|
||||||
case "str":
|
case "str":
|
||||||
switch tests[i].nonBoolStrValue {
|
switch tests[i].nonBoolStrValue {
|
||||||
case "empty":
|
case "empty":
|
||||||
// ez
|
// ez
|
||||||
case "normal":
|
case "normal":
|
||||||
val = mtest.RandHex(8)
|
val = mrand.Hex(8)
|
||||||
case "wDash":
|
case "wDash":
|
||||||
val = mtest.RandHex(4) + "-" + mtest.RandHex(4)
|
val = mrand.Hex(4) + "-" + mrand.Hex(4)
|
||||||
case "wEq":
|
case "wEq":
|
||||||
val = mtest.RandHex(4) + "=" + mtest.RandHex(4)
|
val = mrand.Hex(4) + "=" + mrand.Hex(4)
|
||||||
}
|
}
|
||||||
pv.Value = json.RawMessage(`"` + val + `"`)
|
pv.Value = json.RawMessage(`"` + val + `"`)
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@ package mcrypto
|
|||||||
import (
|
import (
|
||||||
. "testing"
|
. "testing"
|
||||||
|
|
||||||
"github.com/mediocregopher/mediocre-go-lib/mtest"
|
"github.com/mediocregopher/mediocre-go-lib/mrand"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -11,7 +11,7 @@ func TestKeyPair(t *T) {
|
|||||||
pub, priv := NewWeakKeyPair()
|
pub, priv := NewWeakKeyPair()
|
||||||
|
|
||||||
// test signing/verifying
|
// test signing/verifying
|
||||||
str := mtest.RandHex(512)
|
str := mrand.Hex(512)
|
||||||
sig := SignString(priv, str)
|
sig := SignString(priv, str)
|
||||||
assert.NoError(t, VerifyString(pub, sig, str))
|
assert.NoError(t, VerifyString(pub, sig, str))
|
||||||
}
|
}
|
||||||
|
@ -5,12 +5,12 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/ansel1/merry"
|
"github.com/ansel1/merry"
|
||||||
"github.com/mediocregopher/mediocre-go-lib/mtest"
|
"github.com/mediocregopher/mediocre-go-lib/mrand"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestSecretSignVerify(t *T) {
|
func TestSecretSignVerify(t *T) {
|
||||||
secretRaw := mtest.RandBytes(16)
|
secretRaw := mrand.Bytes(16)
|
||||||
secret := NewSecret(secretRaw)
|
secret := NewSecret(secretRaw)
|
||||||
weakSecret := NewWeakSecret(secretRaw)
|
weakSecret := NewWeakSecret(secretRaw)
|
||||||
var prevStr string
|
var prevStr string
|
||||||
@ -20,7 +20,7 @@ func TestSecretSignVerify(t *T) {
|
|||||||
secret.testNow = now
|
secret.testNow = now
|
||||||
weakSecret.testNow = now
|
weakSecret.testNow = now
|
||||||
|
|
||||||
thisStr := mtest.RandHex(512)
|
thisStr := mrand.Hex(512)
|
||||||
thisSig := SignString(secret, thisStr)
|
thisSig := SignString(secret, thisStr)
|
||||||
thisWeakSig := SignString(weakSecret, thisStr)
|
thisWeakSig := SignString(weakSecret, thisStr)
|
||||||
thisSigStr, thisWeakSigStr := thisSig.String(), thisWeakSig.String()
|
thisSigStr, thisWeakSigStr := thisSig.String(), thisWeakSig.String()
|
||||||
|
@ -5,19 +5,19 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/ansel1/merry"
|
"github.com/ansel1/merry"
|
||||||
"github.com/mediocregopher/mediocre-go-lib/mtest"
|
"github.com/mediocregopher/mediocre-go-lib/mrand"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestSignerVerifier(t *T) {
|
func TestSignerVerifier(t *T) {
|
||||||
secret := NewSecret(mtest.RandBytes(16))
|
secret := NewSecret(mrand.Bytes(16))
|
||||||
var prevStr string
|
var prevStr string
|
||||||
var prevSig Signature
|
var prevSig Signature
|
||||||
for i := 0; i < 10000; i++ {
|
for i := 0; i < 10000; i++ {
|
||||||
now := time.Now().Round(0)
|
now := time.Now().Round(0)
|
||||||
secret.testNow = now
|
secret.testNow = now
|
||||||
|
|
||||||
thisStr := mtest.RandHex(512)
|
thisStr := mrand.Hex(512)
|
||||||
thisSig := SignString(secret, thisStr)
|
thisSig := SignString(secret, thisStr)
|
||||||
thisSigStr := thisSig.String()
|
thisSigStr := thisSig.String()
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/mediocregopher/mediocre-go-lib/mcfg"
|
"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/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
@ -21,7 +21,7 @@ func init() {
|
|||||||
|
|
||||||
// this requires the pubsub emulator to be running
|
// this requires the pubsub emulator to be running
|
||||||
func TestPubSub(t *T) {
|
func TestPubSub(t *T) {
|
||||||
topicName := "testTopic_" + mtest.RandHex(8)
|
topicName := "testTopic_" + mrand.Hex(8)
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
|
||||||
// Topic shouldn't exist yet
|
// Topic shouldn't exist yet
|
||||||
@ -51,7 +51,7 @@ func TestPubSub(t *T) {
|
|||||||
|
|
||||||
func TestBatchPubSub(t *T) {
|
func TestBatchPubSub(t *T) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
topicName := "testBatchTopic_" + mtest.RandHex(8)
|
topicName := "testBatchTopic_" + mrand.Hex(8)
|
||||||
topic, err := testPS.Topic(ctx, topicName, true)
|
topic, err := testPS.Topic(ctx, topicName, true)
|
||||||
require.NoError(t, err)
|
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 (
|
import (
|
||||||
. "testing"
|
. "testing"
|
||||||
@ -9,7 +9,7 @@ import (
|
|||||||
func TestRandBytes(t *T) {
|
func TestRandBytes(t *T) {
|
||||||
var prev []byte
|
var prev []byte
|
||||||
for i := 0; i < 10000; i++ {
|
for i := 0; i < 10000; i++ {
|
||||||
curr := RandBytes(16)
|
curr := Bytes(16)
|
||||||
assert.Len(t, curr, 16)
|
assert.Len(t, curr, 16)
|
||||||
assert.NotEqual(t, prev, curr)
|
assert.NotEqual(t, prev, curr)
|
||||||
prev = curr
|
prev = curr
|
||||||
@ -19,7 +19,7 @@ func TestRandBytes(t *T) {
|
|||||||
func TestRandHex(t *T) {
|
func TestRandHex(t *T) {
|
||||||
// RandHex is basically a wrapper of RandBytes, so we don't have to test it
|
// RandHex is basically a wrapper of RandBytes, so we don't have to test it
|
||||||
// much
|
// much
|
||||||
assert.Len(t, RandHex(16), 16)
|
assert.Len(t, Hex(16), 16)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRandElement(t *T) {
|
func TestRandElement(t *T) {
|
||||||
@ -35,7 +35,7 @@ func TestRandElement(t *T) {
|
|||||||
|
|
||||||
iterations := 100000
|
iterations := 100000
|
||||||
for i := 0; i < iterations; i++ {
|
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]++
|
m[el]++
|
||||||
}
|
}
|
||||||
|
|
@ -4,7 +4,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
. "testing"
|
. "testing"
|
||||||
|
|
||||||
"github.com/mediocregopher/mediocre-go-lib/mtest"
|
"github.com/mediocregopher/mediocre-go-lib/mrand"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -28,14 +28,14 @@ func TestReflectClient(t *T) {
|
|||||||
}))
|
}))
|
||||||
|
|
||||||
{ // test with arg being non-pointer
|
{ // test with arg being non-pointer
|
||||||
in := mtest.RandHex(8)
|
in := mrand.Hex(8)
|
||||||
var res resT
|
var res resT
|
||||||
assert.NoError(t, client.CallRPC(ctx, &res, "foo", argT{In: in}))
|
assert.NoError(t, client.CallRPC(ctx, &res, "foo", argT{In: in}))
|
||||||
assert.Equal(t, in, res.Out)
|
assert.Equal(t, in, res.Out)
|
||||||
}
|
}
|
||||||
|
|
||||||
{ // test with arg being pointer
|
{ // test with arg being pointer
|
||||||
in := mtest.RandHex(8)
|
in := mrand.Hex(8)
|
||||||
var res resT
|
var res resT
|
||||||
assert.NoError(t, client.CallRPC(ctx, &res, "foo", &argT{In: in}))
|
assert.NoError(t, client.CallRPC(ctx, &res, "foo", &argT{In: in}))
|
||||||
assert.Equal(t, in, res.Out)
|
assert.Equal(t, in, res.Out)
|
||||||
@ -51,14 +51,14 @@ func TestReflectClient(t *T) {
|
|||||||
}))
|
}))
|
||||||
|
|
||||||
{ // test with arg being non-pointer
|
{ // test with arg being non-pointer
|
||||||
in := mtest.RandHex(8)
|
in := mrand.Hex(8)
|
||||||
var res resT
|
var res resT
|
||||||
assert.NoError(t, client.CallRPC(ctx, &res, "foo", argT{In: in}))
|
assert.NoError(t, client.CallRPC(ctx, &res, "foo", argT{In: in}))
|
||||||
assert.Equal(t, in, res.Out)
|
assert.Equal(t, in, res.Out)
|
||||||
}
|
}
|
||||||
|
|
||||||
{ // test with arg being pointer
|
{ // test with arg being pointer
|
||||||
in := mtest.RandHex(8)
|
in := mrand.Hex(8)
|
||||||
var res resT
|
var res resT
|
||||||
assert.NoError(t, client.CallRPC(ctx, &res, "foo", &argT{In: in}))
|
assert.NoError(t, client.CallRPC(ctx, &res, "foo", &argT{In: in}))
|
||||||
assert.Equal(t, in, res.Out)
|
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