mediocre-go-lib/mtest/mtest.go

61 lines
1.5 KiB
Go
Raw Normal View History

2018-02-11 16:05:36 +00:00
// Package mtest contains types and functions which are useful when writing
// tests
package mtest
import (
crand "crypto/rand"
"encoding/hex"
"math/rand"
2018-07-02 23:42:54 +00:00
"reflect"
2018-02-11 16:05:36 +00:00
"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)
}
2018-07-02 23:42:54 +00:00
// 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?")
}