- Added the options to `fuzzScenario`. - They are clamped to non-panic values, so it only tests viable combinations.
95 lines
2.1 KiB
Go
95 lines
2.1 KiB
Go
package cuckoo_test
|
|
|
|
import (
|
|
"fmt"
|
|
"maps"
|
|
"math"
|
|
"os"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
go_fuzz_utils "github.com/trailofbits/go-fuzz-utils"
|
|
|
|
"git.maximhutz.com/tools/go-cuckoo"
|
|
)
|
|
|
|
func offsetHash(seed uint32) cuckoo.Hash[uint32] {
|
|
return func(x uint32) uint64 {
|
|
v := uint64(x) ^ uint64(seed)
|
|
v = (v ^ (v >> 30)) * 0xbf58476d1ce4e5b9
|
|
v = (v ^ (v >> 27)) * 0x94d049bb133111eb
|
|
return v ^ (v >> 31)
|
|
}
|
|
}
|
|
|
|
type fuzzStep struct {
|
|
drop bool
|
|
key, value uint32
|
|
}
|
|
|
|
type fuzzScenario struct {
|
|
seedA, seedB uint32
|
|
capacity, growthFactor uint8
|
|
load float64
|
|
steps []fuzzStep
|
|
}
|
|
|
|
func FuzzInsertLookup(f *testing.F) {
|
|
f.Fuzz(func(t *testing.T, data []byte) {
|
|
var scenario fuzzScenario
|
|
assert := assert.New(t)
|
|
|
|
if tp, err := go_fuzz_utils.NewTypeProvider(data); err != nil {
|
|
return
|
|
} else if err := tp.Fill(&scenario); err != nil {
|
|
return
|
|
}
|
|
|
|
if scenario.seedA == scenario.seedB {
|
|
return
|
|
}
|
|
|
|
seedA, seedB := scenario.seedA, scenario.seedB
|
|
growthFactor := max(1, int(scenario.growthFactor))
|
|
capacity := int(scenario.capacity)
|
|
minimumLoad := math.Abs(math.Mod(scenario.load, 1.0))
|
|
|
|
fmt.Fprintf(os.Stderr, "seedA=%d seedB=%d capacity=%d growthFactor=%d minimumLoad=%f\n",
|
|
seedA, seedB, capacity, growthFactor, minimumLoad)
|
|
|
|
actual := cuckoo.NewCustomTable[uint32, uint32](
|
|
offsetHash(seedA),
|
|
offsetHash(seedB),
|
|
func(a, b uint32) bool { return a == b },
|
|
cuckoo.Capacity(capacity),
|
|
cuckoo.GrowthFactor(growthFactor),
|
|
cuckoo.MinimumLoad(minimumLoad),
|
|
)
|
|
|
|
expected := map[uint32]uint32{}
|
|
|
|
for _, step := range scenario.steps {
|
|
if step.drop {
|
|
err := actual.Drop(step.key)
|
|
assert.NoError(err)
|
|
|
|
delete(expected, step.key)
|
|
|
|
_, err = actual.Get(step.key)
|
|
assert.Error(err)
|
|
} else {
|
|
err := actual.Put(step.key, step.value)
|
|
assert.NoError(err)
|
|
|
|
expected[step.key] = step.value
|
|
|
|
found, err := actual.Get(step.key)
|
|
assert.NoError(err)
|
|
assert.Equal(step.value, found)
|
|
}
|
|
|
|
assert.Equal(expected, maps.Collect(actual.Entries()))
|
|
}
|
|
})
|
|
}
|