mirror of
https://github.com/luxfi/node.git
synced 2026-07-27 03:39:39 +00:00
231 lines
3.9 KiB
Go
231 lines
3.9 KiB
Go
// Copyright (C) 2019-2025, Lux Industries Inc. All rights reserved.
|
|
// See the file LICENSE for licensing terms.
|
|
|
|
package sampler
|
|
|
|
import (
|
|
"math"
|
|
"math/rand"
|
|
"strconv"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
"github.com/thepudds/fzgen/fuzzer"
|
|
"gonum.org/v1/gonum/mathext/prng"
|
|
)
|
|
|
|
type testSource struct {
|
|
onInvalid func()
|
|
nums []uint64
|
|
}
|
|
|
|
func (s *testSource) Seed(uint64) {
|
|
s.onInvalid()
|
|
}
|
|
|
|
func (s *testSource) Uint64() uint64 {
|
|
if len(s.nums) == 0 {
|
|
s.onInvalid()
|
|
return 0
|
|
}
|
|
num := s.nums[0]
|
|
s.nums = s.nums[1:]
|
|
return num
|
|
}
|
|
|
|
type testSTDSource struct {
|
|
onInvalid func()
|
|
nums []uint64
|
|
}
|
|
|
|
func (s *testSTDSource) Seed(int64) {
|
|
s.onInvalid()
|
|
}
|
|
|
|
func (s *testSTDSource) Int63() int64 {
|
|
return int64(s.Uint64() & (1<<63 - 1))
|
|
}
|
|
|
|
func (s *testSTDSource) Uint64() uint64 {
|
|
if len(s.nums) == 0 {
|
|
s.onInvalid()
|
|
return 0
|
|
}
|
|
num := s.nums[0]
|
|
s.nums = s.nums[1:]
|
|
return num
|
|
}
|
|
|
|
func TestRNG(t *testing.T) {
|
|
tests := []struct {
|
|
maximum uint64
|
|
nums []uint64
|
|
expected uint64
|
|
}{
|
|
{
|
|
maximum: math.MaxUint64,
|
|
nums: []uint64{
|
|
0x01,
|
|
},
|
|
expected: 0x01,
|
|
},
|
|
{
|
|
maximum: math.MaxUint64,
|
|
nums: []uint64{
|
|
0x0102030405060708,
|
|
},
|
|
expected: 0x0102030405060708,
|
|
},
|
|
{
|
|
maximum: math.MaxUint64,
|
|
nums: []uint64{
|
|
0xF102030405060708,
|
|
},
|
|
expected: 0xF102030405060708,
|
|
},
|
|
{
|
|
maximum: math.MaxInt64,
|
|
nums: []uint64{
|
|
0x01,
|
|
},
|
|
expected: 0x01,
|
|
},
|
|
{
|
|
maximum: math.MaxInt64,
|
|
nums: []uint64{
|
|
0x0102030405060708,
|
|
},
|
|
expected: 0x0102030405060708,
|
|
},
|
|
{
|
|
maximum: math.MaxInt64,
|
|
nums: []uint64{
|
|
0x8102030405060708,
|
|
},
|
|
expected: 0x0102030405060708,
|
|
},
|
|
{
|
|
maximum: 15,
|
|
nums: []uint64{
|
|
0x810203040506071a,
|
|
},
|
|
expected: 0x0a,
|
|
},
|
|
{
|
|
maximum: math.MaxInt64 + 1,
|
|
nums: []uint64{
|
|
math.MaxInt64 + 1,
|
|
},
|
|
expected: math.MaxInt64 + 1,
|
|
},
|
|
{
|
|
maximum: math.MaxInt64 + 1,
|
|
nums: []uint64{
|
|
math.MaxInt64 + 2,
|
|
0,
|
|
},
|
|
expected: 0,
|
|
},
|
|
{
|
|
maximum: math.MaxInt64 + 1,
|
|
nums: []uint64{
|
|
math.MaxInt64 + 2,
|
|
0x0102030405060708,
|
|
},
|
|
expected: 0x0102030405060708,
|
|
},
|
|
{
|
|
maximum: 2,
|
|
nums: []uint64{
|
|
math.MaxInt64 - 2,
|
|
},
|
|
expected: 0x02,
|
|
},
|
|
{
|
|
maximum: 2,
|
|
nums: []uint64{
|
|
math.MaxInt64 - 1,
|
|
0x01,
|
|
},
|
|
expected: 0x01,
|
|
},
|
|
}
|
|
for i, test := range tests {
|
|
t.Run(strconv.Itoa(i), func(t *testing.T) {
|
|
require := require.New(t)
|
|
|
|
source := &testSource{
|
|
onInvalid: t.FailNow,
|
|
nums: test.nums,
|
|
}
|
|
r := &rng{rng: source}
|
|
val := r.Uint64Inclusive(test.maximum)
|
|
require.Equal(test.expected, val)
|
|
require.Empty(source.nums)
|
|
|
|
if test.maximum >= math.MaxInt64 {
|
|
return
|
|
}
|
|
|
|
stdSource := &testSTDSource{
|
|
onInvalid: t.FailNow,
|
|
nums: test.nums,
|
|
}
|
|
mathRNG := rand.New(stdSource) //#nosec G404
|
|
stdVal := mathRNG.Int63n(int64(test.maximum + 1))
|
|
require.Equal(test.expected, uint64(stdVal))
|
|
require.Empty(source.nums)
|
|
})
|
|
}
|
|
}
|
|
|
|
func FuzzRNG(f *testing.F) {
|
|
f.Fuzz(func(t *testing.T, data []byte) {
|
|
require := require.New(t)
|
|
|
|
var (
|
|
maximum uint64
|
|
sourceNums []uint64
|
|
)
|
|
fz := fuzzer.NewFuzzer(data)
|
|
fz.Fill(&maximum, &sourceNums)
|
|
if maximum >= math.MaxInt64 {
|
|
t.SkipNow()
|
|
}
|
|
|
|
source := &testSource{
|
|
onInvalid: func() { /* Invalid input - continue test */ },
|
|
nums: sourceNums,
|
|
}
|
|
r := &rng{rng: source}
|
|
val := r.Uint64Inclusive(maximum)
|
|
|
|
stdSource := &testSTDSource{
|
|
onInvalid: func() { /* Invalid input - continue test */ },
|
|
nums: sourceNums,
|
|
}
|
|
mathRNG := rand.New(stdSource) //#nosec G404
|
|
stdVal := mathRNG.Int63n(int64(maximum + 1))
|
|
require.Equal(val, uint64(stdVal))
|
|
require.Len(stdSource.nums, len(source.nums))
|
|
})
|
|
}
|
|
|
|
func BenchmarkSeed32(b *testing.B) {
|
|
source := prng.NewMT19937()
|
|
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
source.Seed(0)
|
|
}
|
|
}
|
|
|
|
func BenchmarkSeed64(b *testing.B) {
|
|
source := prng.NewMT19937_64()
|
|
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
source.Seed(0)
|
|
}
|
|
}
|