Files
go-cuckoo/cuckoo_fuzz_test.go
M.V. Hutz 56b1982f8a
All checks were successful
CI / Makefile Lint (push) Successful in 16s
CI / Go Lint (push) Successful in 21s
CI / Unit Tests (push) Successful in 15s
CI / Fuzz Tests (push) Successful in 49s
CI / Mutation Tests (push) Successful in 55s
feat: add drop key functionality (#6)
Currently, the `Table.Drop()` function is deprecated because it is not implemented yet. Let's add that functionality.

- Adds true drop functionality to the table, through `Table.Drop()`.
- Adds tests for functionality.
- Rewrites fuzz test using `go_fuzz_utils`, to test arbitrary usage patterns.
- Rewrite `bucket` to allow a capacity of zero.
- Rename `Table.Capacity()` to `Table.TotalCapacity()`, to reflect to different between the capacity of the buckets vs. the whole table.
- Enforce 100% mutation test coverage.

Reviewed-on: #6
Co-authored-by: M.V. Hutz <git@maximhutz.me>
Co-committed-by: M.V. Hutz <git@maximhutz.me>
2026-03-20 01:59:54 +00:00

79 lines
1.5 KiB
Go

package cuckoo_test
import (
"maps"
"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
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
}
actual := cuckoo.NewCustomTable[uint32, uint32](
offsetHash(scenario.seedA),
offsetHash(scenario.seedB),
func(a, b uint32) bool { return a == b },
)
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()))
}
})
}