mishmash/mishmash_test.go
2025-05-25 16:05:35 -04:00

130 lines
3.1 KiB
Go

package mishmash
import (
"bufio"
"errors"
"fmt"
"hash"
"math/rand"
"os"
"strconv"
"strings"
"testing"
)
type HashedString struct {
s string
h32 uint32
h64 uint64
}
var (
TheCppOutputFile = "word_hashes.txt"
TheCppOutput = func() []HashedString {
f, err := os.Open(TheCppOutputFile)
if err != nil {
panic("error opening " + TheCppOutputFile + ": " + err.Error())
}
defer f.Close()
results := make([]HashedString, 0)
scanner := bufio.NewScanner(f)
for scanner.Scan() {
if line := strings.TrimSpace(scanner.Text()); len(line) > 0 {
fields := strings.Fields(line)
if len(fields) == 3 {
n1, err := strconv.ParseUint(fields[1], 16, 32)
if err != nil {
panic("error parsing " + fields[1] + ": " + err.Error())
}
n2, err := strconv.ParseUint(fields[2], 16, 64)
if err != nil {
panic("error parsing " + fields[2] + ": " + err.Error())
}
results = append(results, HashedString{fields[0], uint32(n1), n2})
}
}
}
return results
}()
RandomWordAndHash = func() HashedString {
return TheCppOutput[rand.Intn(len(TheCppOutput))]
}
)
func TestPrimes(t *testing.T) {
for _, kvp := range TheCppOutput {
if word, want, got := kvp.s, kvp.h32, MishmashString(kvp.s); want != got {
t.Fatalf("error: %s; wanted %08x; got %08x\n", word, want, got)
}
}
}
func TestHash32Interface(t *testing.T) {
for _, kvp := range TheCppOutput {
var h hash.Hash32 = &Mishmash32{}
word := kvp.s
h.Write([]byte(word))
if want, got := kvp.h32, h.Sum32(); want != got {
t.Fatalf("error: %s; wanted %08x; got %08x\n", word, want, got)
}
}
}
func TestHash64Interface(t *testing.T) {
for _, kvp := range TheCppOutput {
var h hash.Hash64 = &Mishmash64{}
word := kvp.s
h.Write([]byte(word))
if want, got := kvp.h64, h.Sum64(); want != got {
t.Fatalf("error: %s; wanted %016x; got %016x\n", word, want, got)
}
}
}
func TestHash32Collision(t *testing.T) {
m := make(map[uint32][]string, len(TheCppOutput))
for _, kvp := range TheCppOutput {
m[kvp.h32] = append(m[kvp.h32], kvp.s)
}
errs := make([]error, 0)
for hash, values := range m {
if len(values) > 1 {
errs = append(errs, fmt.Errorf("%08x: %s", hash, strings.Join(values, " ")))
}
}
if err := errors.Join(errs...); err != nil {
fmt.Println(err)
}
}
func BenchmarkLoadEmbededPrimes(b *testing.B) {
const filename = "mishmash_primes.txt"
for _ = range b.N {
if _, err := LoadPrimesSet(filename); err != nil {
panic("error: " + err.Error())
}
}
}
func BenchmarkMishmash32(b *testing.B) {
for _ = range b.N {
kvp := RandomWordAndHash()
var hash hash.Hash32 = &Mishmash32{}
hash.Write([]byte(kvp.s))
if want, got := kvp.h32, hash.Sum32(); want != got {
panic(fmt.Sprintf("error: %s; wanted %08x; got %08x\n", kvp.s, want, got))
}
}
}
func BenchmarkMishmash64(b *testing.B) {
for _ = range b.N {
kvp := RandomWordAndHash()
var hash hash.Hash64 = &Mishmash64{}
hash.Write([]byte(kvp.s))
if want, got := kvp.h64, hash.Sum64(); want != got {
panic(fmt.Sprintf("error: %s; wanted %016x; got %016x\n", kvp.s, want, got))
}
}
}