From d07f76207b54dd98505d06cb4e9f01a311399cd5 Mon Sep 17 00:00:00 2001 From: "M.V. Hutz" Date: Sat, 21 Mar 2026 13:07:11 -0400 Subject: [PATCH] feat: add options to fuzz testing - Added the options to `fuzzScenario`. - They are clamped to non-panic values, so it only tests viable combinations. --- cuckoo_fuzz_test.go | 24 ++++++++++++++++++++---- settings.go | 18 ++++++++++++++++-- 2 files changed, 36 insertions(+), 6 deletions(-) diff --git a/cuckoo_fuzz_test.go b/cuckoo_fuzz_test.go index fd97b2f..cfc6b73 100644 --- a/cuckoo_fuzz_test.go +++ b/cuckoo_fuzz_test.go @@ -1,7 +1,10 @@ package cuckoo_test import ( + "fmt" "maps" + "math" + "os" "testing" "github.com/stretchr/testify/assert" @@ -25,8 +28,10 @@ type fuzzStep struct { } type fuzzScenario struct { - seedA, seedB uint32 - steps []fuzzStep + seedA, seedB uint32 + capacity, growthFactor uint8 + load float64 + steps []fuzzStep } func FuzzInsertLookup(f *testing.F) { @@ -44,10 +49,21 @@ func FuzzInsertLookup(f *testing.F) { 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(scenario.seedA), - offsetHash(scenario.seedB), + 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{} diff --git a/settings.go b/settings.go index c96ee45..b9f78cc 100644 --- a/settings.go +++ b/settings.go @@ -1,5 +1,7 @@ package cuckoo +import "fmt" + // DefaultCapacity is the initial capacity of a [Table]. It is inspired from // Java's [HashMap] implementation, which also uses 16. // @@ -27,19 +29,31 @@ type settings struct { type Option func(*settings) // Capacity modifies the starting capacity of each bucket of the [Table]. The -// value must be greater than 0. +// value must be non-negative. func Capacity(value int) Option { + if value < 0 { + panic(fmt.Sprintf("go-cuckoo: Capacity must be non-negative, got %d", value)) + } + return func(s *settings) { s.bucketSize = uint64(value) } } // MinimumLoad modifies the [DefaultMinimumLoad] of the [Table]. The value must // be between 0.00 and 1.00. func MinimumLoad(value float64) Option { + if value < 0.00 || value > 1.00 { + panic(fmt.Sprintf("go-cuckoo: MinimumLoad must be between 0.00 and 1.00, got %f", value)) + } + return func(s *settings) { s.minLoadFactor = value } } // GrowthFactor controls how much the capacity of the [Table] multiplies when -// it must resize. The value must be greater than 1. +// it must resize. The value must be greater than 0. func GrowthFactor(value int) Option { + if value <= 0 { + panic(fmt.Sprintf("go-cuckoo: GrowthFactor must be greater than 0, got %d", value)) + } + return func(s *settings) { s.growthFactor = uint64(value) } }