github.com/dolthub/maphash@v0.1.0/hasher_test.go (about) 1 // Copyright 2022 Dolthub, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package maphash 16 17 import ( 18 "math" 19 "testing" 20 "time" 21 22 "github.com/stretchr/testify/assert" 23 ) 24 25 func FuzzStringHasher(f *testing.F) { 26 f.Add("") 27 f.Add("hello world") 28 f.Add("github.com/dolthub/maphash") 29 f.Fuzz(func(t *testing.T, key string) { 30 testHasher(t, key) 31 }) 32 } 33 34 func FuzzRuneHasher(f *testing.F) { 35 f.Add('a') 36 f.Add('z') 37 f.Add('A') 38 f.Add('Z') 39 f.Fuzz(func(t *testing.T, key rune) { 40 testHasher(t, key) 41 }) 42 } 43 44 func FuzzIntHasher(f *testing.F) { 45 f.Add(int(0)) 46 f.Add(int(math.MaxInt32)) 47 f.Fuzz(func(t *testing.T, key int) { 48 testHasher(t, key) 49 }) 50 } 51 52 func FuzzInt8Hasher(f *testing.F) { 53 f.Add(int8(0)) 54 f.Add(int8(math.MaxInt8)) 55 f.Fuzz(func(t *testing.T, key int8) { 56 testHasher(t, key) 57 }) 58 } 59 60 func FuzzInt16Hasher(f *testing.F) { 61 f.Add(int16(0)) 62 f.Add(int16(math.MaxInt16)) 63 f.Fuzz(func(t *testing.T, key int16) { 64 testHasher(t, key) 65 }) 66 } 67 68 func FuzzInt32Hasher(f *testing.F) { 69 f.Add(int32(0)) 70 f.Add(int32(math.MaxInt32)) 71 f.Fuzz(func(t *testing.T, key int32) { 72 testHasher(t, key) 73 }) 74 } 75 76 func FuzzInt64Hasher(f *testing.F) { 77 f.Add(int64(0)) 78 f.Add(int64(math.MaxInt64)) 79 f.Fuzz(func(t *testing.T, key int64) { 80 testHasher(t, key) 81 }) 82 } 83 84 func FuzzUintHasher(f *testing.F) { 85 f.Add(uint(0)) 86 f.Add(uint(math.MaxUint32)) 87 f.Fuzz(func(t *testing.T, key uint) { 88 testHasher(t, key) 89 }) 90 } 91 92 func FuzzUint8Hasher(f *testing.F) { 93 f.Add(uint8(0)) 94 f.Add(uint8(math.MaxUint8)) 95 f.Fuzz(func(t *testing.T, key uint8) { 96 testHasher(t, key) 97 }) 98 } 99 100 func FuzzUint16Hasher(f *testing.F) { 101 f.Add(uint16(0)) 102 f.Add(uint16(math.MaxUint16)) 103 f.Fuzz(func(t *testing.T, key uint16) { 104 testHasher(t, key) 105 }) 106 } 107 108 func FuzzUint32Hasher(f *testing.F) { 109 f.Add(uint32(0)) 110 f.Add(uint32(math.MaxUint32)) 111 f.Fuzz(func(t *testing.T, key uint32) { 112 testHasher(t, key) 113 }) 114 } 115 116 func FuzzUint64Hasher(f *testing.F) { 117 f.Add(uint64(0)) 118 f.Add(uint64(math.MaxUint64)) 119 f.Fuzz(func(t *testing.T, key uint64) { 120 testHasher(t, key) 121 }) 122 } 123 124 func FuzzFloat32Hasher(f *testing.F) { 125 f.Add(float32(0)) 126 f.Add(float32(math.Pi)) 127 f.Add(float32(math.E)) 128 f.Fuzz(func(t *testing.T, key float32) { 129 testHasher(t, key) 130 }) 131 } 132 133 func FuzzFloat64Hasher(f *testing.F) { 134 f.Add(float64(0)) 135 f.Add(float64(math.Pi)) 136 f.Add(float64(math.E)) 137 f.Fuzz(func(t *testing.T, key float64) { 138 testHasher(t, key) 139 }) 140 } 141 142 func FuzzArrayHasher(f *testing.F) { 143 f.Add(0, 0) 144 f.Add(1, -1) 145 f.Fuzz(func(t *testing.T, a, b int) { 146 testHasher(t, [2]int{a, b}) 147 }) 148 } 149 150 func FuzzStructHasher(f *testing.F) { 151 type obj struct { 152 i int 153 f float32 154 t time.Time 155 } 156 f.Add(int(0), float32(0), int64(0)) 157 f.Add(int(-1), float32(-1), int64(-1)) 158 f.Fuzz(func(t *testing.T, i int, f float32, m int64) { 159 o := obj{i: i, f: f, t: time.UnixMicro(m)} 160 testHasher(t, o) 161 }) 162 } 163 164 func FuzzStringPairHasher(f *testing.F) { 165 type pair struct { 166 a, b string 167 } 168 f.Add("", "") 169 f.Add("a", "b") 170 f.Add("hello", "world") 171 f.Fuzz(func(t *testing.T, a, b string) { 172 testHasher(t, pair{a, b}) 173 }) 174 } 175 176 func testHasher[K comparable](t *testing.T, key K) { 177 h1, h2 := NewHasher[K](), NewHasher[K]() 178 assert.Equal(t, h1.Hash(key), h1.Hash(key)) 179 assert.Equal(t, h2.Hash(key), h2.Hash(key)) 180 assert.NotEqual(t, h1.Hash(key), h2.Hash(key)) 181 h3, h4 := NewSeed[K](h1), NewSeed[K](h2) 182 assert.Equal(t, h3.Hash(key), h3.Hash(key)) 183 assert.Equal(t, h4.Hash(key), h4.Hash(key)) 184 assert.NotEqual(t, h1.Hash(key), h3.Hash(key)) 185 assert.NotEqual(t, h2.Hash(key), h4.Hash(key)) 186 assert.NotEqual(t, h3.Hash(key), h4.Hash(key)) 187 } 188 189 func TestRefAllocs(t *testing.T) { 190 t.Run("*int", func(t *testing.T) { 191 x := int(42) 192 testNoAllocs(t, NewHasher[*int](), &x) 193 }) 194 t.Run("*uint", func(t *testing.T) { 195 x := uint(42) 196 testNoAllocs(t, NewHasher[*uint](), &x) 197 }) 198 t.Run("*float", func(t *testing.T) { 199 x := float64(math.E) 200 testNoAllocs(t, NewHasher[*float64](), &x) 201 }) 202 t.Run("*string", func(t *testing.T) { 203 x := string("asdf") 204 testNoAllocs(t, NewHasher[*string](), &x) 205 }) 206 } 207 208 func TestNoValueAllocs(t *testing.T) { 209 t.Run("int", func(t *testing.T) { 210 testNoAllocs(t, NewHasher[int](), 42) 211 }) 212 t.Run("uint", func(t *testing.T) { 213 testNoAllocs(t, NewHasher[uint](), 42) 214 }) 215 t.Run("float", func(t *testing.T) { 216 testNoAllocs(t, NewHasher[float64](), math.E) 217 }) 218 t.Run("string", func(t *testing.T) { 219 testNoAllocs(t, NewHasher[string](), "asdf") 220 }) 221 type uuid [16]byte 222 t.Run("uuid", func(t *testing.T) { 223 testNoAllocs(t, NewHasher[uuid](), uuid{}) 224 }) 225 t.Run("time", func(t *testing.T) { 226 testNoAllocs(t, NewHasher[time.Time](), time.Now()) 227 }) 228 } 229 230 func testNoAllocs[K comparable](t *testing.T, h Hasher[K], key K) { 231 a := testing.AllocsPerRun(64, func() { 232 h.Hash(key) 233 }) 234 assert.Equal(t, 0.0, a) 235 }