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>
79 lines
1.5 KiB
Go
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()))
|
|
}
|
|
})
|
|
}
|