package common
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"fmt"
|
|
"io"
|
|
mrand "math/rand"
|
|
"sync"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
)
|
|
|
|
func TestRandStr(t *testing.T) {
|
|
l := 243
|
|
s := RandStr(l)
|
|
assert.Equal(t, l, len(s))
|
|
}
|
|
|
|
func TestRandBytes(t *testing.T) {
|
|
l := 243
|
|
b := RandBytes(l)
|
|
assert.Equal(t, l, len(b))
|
|
}
|
|
|
|
func TestRandIntn(t *testing.T) {
|
|
n := 243
|
|
for i := 0; i < 100; i++ {
|
|
x := RandIntn(n)
|
|
assert.True(t, x < n)
|
|
}
|
|
}
|
|
|
|
// It is essential that these tests run and never repeat their outputs
|
|
// lest we've been pwned and the behavior of our randomness is controlled.
|
|
// See Issues:
|
|
// * https://github.com/tendermint/tmlibs/issues/99
|
|
// * https://github.com/tendermint/tendermint/issues/973
|
|
func TestUniqueRng(t *testing.T) {
|
|
buf := new(bytes.Buffer)
|
|
outputs := make(map[string][]int)
|
|
for i := 0; i < 100; i++ {
|
|
testThemAll(buf)
|
|
output := buf.String()
|
|
buf.Reset()
|
|
runs, seen := outputs[output]
|
|
if seen {
|
|
t.Errorf("Run #%d's output was already seen in previous runs: %v", i, runs)
|
|
}
|
|
outputs[output] = append(outputs[output], i)
|
|
}
|
|
}
|
|
|
|
func testThemAll(out io.Writer) {
|
|
// Reset the internal PRNG
|
|
reset()
|
|
|
|
// Set math/rand's Seed so that any direct invocations
|
|
// of math/rand will reveal themselves.
|
|
mrand.Seed(1)
|
|
perm := RandPerm(10)
|
|
blob, _ := json.Marshal(perm)
|
|
fmt.Fprintf(out, "perm: %s\n", blob)
|
|
|
|
fmt.Fprintf(out, "randInt: %d\n", RandInt())
|
|
fmt.Fprintf(out, "randUint: %d\n", RandUint())
|
|
fmt.Fprintf(out, "randIntn: %d\n", RandIntn(97))
|
|
fmt.Fprintf(out, "randInt31: %d\n", RandInt31())
|
|
fmt.Fprintf(out, "randInt32: %d\n", RandInt32())
|
|
fmt.Fprintf(out, "randInt63: %d\n", RandInt63())
|
|
fmt.Fprintf(out, "randInt64: %d\n", RandInt64())
|
|
fmt.Fprintf(out, "randUint32: %d\n", RandUint32())
|
|
fmt.Fprintf(out, "randUint64: %d\n", RandUint64())
|
|
fmt.Fprintf(out, "randUint16Exp: %d\n", RandUint16Exp())
|
|
fmt.Fprintf(out, "randUint32Exp: %d\n", RandUint32Exp())
|
|
fmt.Fprintf(out, "randUint64Exp: %d\n", RandUint64Exp())
|
|
}
|
|
|
|
func TestRngConcurrencySafety(t *testing.T) {
|
|
var wg sync.WaitGroup
|
|
for i := 0; i < 100; i++ {
|
|
wg.Add(1)
|
|
go func() {
|
|
defer wg.Done()
|
|
|
|
_ = RandUint64()
|
|
<-time.After(time.Millisecond * time.Duration(RandIntn(100)))
|
|
_ = RandPerm(3)
|
|
}()
|
|
}
|
|
wg.Wait()
|
|
}
|
|
|
|
func BenchmarkRandBytes10B(b *testing.B) {
|
|
benchmarkRandBytes(b, 10)
|
|
}
|
|
func BenchmarkRandBytes100B(b *testing.B) {
|
|
benchmarkRandBytes(b, 100)
|
|
}
|
|
func BenchmarkRandBytes1KiB(b *testing.B) {
|
|
benchmarkRandBytes(b, 1024)
|
|
}
|
|
func BenchmarkRandBytes10KiB(b *testing.B) {
|
|
benchmarkRandBytes(b, 10*1024)
|
|
}
|
|
func BenchmarkRandBytes100KiB(b *testing.B) {
|
|
benchmarkRandBytes(b, 100*1024)
|
|
}
|
|
func BenchmarkRandBytes1MiB(b *testing.B) {
|
|
benchmarkRandBytes(b, 1024*1024)
|
|
}
|
|
|
|
func benchmarkRandBytes(b *testing.B, n int) {
|
|
for i := 0; i < b.N; i++ {
|
|
_ = RandBytes(n)
|
|
}
|
|
b.ReportAllocs()
|
|
}
|