github.com/comwrg/go/src@v0.0.0-20220319063731-c238d0440370/hash/maphash/maphash_test.go (about) 1 // Copyright 2019 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package maphash 6 7 import ( 8 "bytes" 9 "hash" 10 "testing" 11 ) 12 13 func TestUnseededHash(t *testing.T) { 14 m := map[uint64]struct{}{} 15 for i := 0; i < 1000; i++ { 16 h := new(Hash) 17 m[h.Sum64()] = struct{}{} 18 } 19 if len(m) < 900 { 20 t.Errorf("empty hash not sufficiently random: got %d, want 1000", len(m)) 21 } 22 } 23 24 func TestSeededHash(t *testing.T) { 25 s := MakeSeed() 26 m := map[uint64]struct{}{} 27 for i := 0; i < 1000; i++ { 28 h := new(Hash) 29 h.SetSeed(s) 30 m[h.Sum64()] = struct{}{} 31 } 32 if len(m) != 1 { 33 t.Errorf("seeded hash is random: got %d, want 1", len(m)) 34 } 35 } 36 37 func TestHashGrouping(t *testing.T) { 38 b := bytes.Repeat([]byte("foo"), 100) 39 hh := make([]*Hash, 7) 40 for i := range hh { 41 hh[i] = new(Hash) 42 } 43 for _, h := range hh[1:] { 44 h.SetSeed(hh[0].Seed()) 45 } 46 hh[0].Write(b) 47 hh[1].WriteString(string(b)) 48 49 writeByte := func(h *Hash, b byte) { 50 err := h.WriteByte(b) 51 if err != nil { 52 t.Fatalf("WriteByte: %v", err) 53 } 54 } 55 writeSingleByte := func(h *Hash, b byte) { 56 _, err := h.Write([]byte{b}) 57 if err != nil { 58 t.Fatalf("Write single byte: %v", err) 59 } 60 } 61 writeStringSingleByte := func(h *Hash, b byte) { 62 _, err := h.WriteString(string([]byte{b})) 63 if err != nil { 64 t.Fatalf("WriteString single byte: %v", err) 65 } 66 } 67 68 for i, x := range b { 69 writeByte(hh[2], x) 70 writeSingleByte(hh[3], x) 71 if i == 0 { 72 writeByte(hh[4], x) 73 } else { 74 writeSingleByte(hh[4], x) 75 } 76 writeStringSingleByte(hh[5], x) 77 if i == 0 { 78 writeByte(hh[6], x) 79 } else { 80 writeStringSingleByte(hh[6], x) 81 } 82 } 83 84 sum := hh[0].Sum64() 85 for i, h := range hh { 86 if sum != h.Sum64() { 87 t.Errorf("hash %d not identical to a single Write", i) 88 } 89 } 90 } 91 92 func TestHashBytesVsString(t *testing.T) { 93 s := "foo" 94 b := []byte(s) 95 h1 := new(Hash) 96 h2 := new(Hash) 97 h2.SetSeed(h1.Seed()) 98 n1, err1 := h1.WriteString(s) 99 if n1 != len(s) || err1 != nil { 100 t.Fatalf("WriteString(s) = %d, %v, want %d, nil", n1, err1, len(s)) 101 } 102 n2, err2 := h2.Write(b) 103 if n2 != len(b) || err2 != nil { 104 t.Fatalf("Write(b) = %d, %v, want %d, nil", n2, err2, len(b)) 105 } 106 if h1.Sum64() != h2.Sum64() { 107 t.Errorf("hash of string and bytes not identical") 108 } 109 } 110 111 func TestHashHighBytes(t *testing.T) { 112 // See issue 34925. 113 const N = 10 114 m := map[uint64]struct{}{} 115 for i := 0; i < N; i++ { 116 h := new(Hash) 117 h.WriteString("foo") 118 m[h.Sum64()>>32] = struct{}{} 119 } 120 if len(m) < N/2 { 121 t.Errorf("from %d seeds, wanted at least %d different hashes; got %d", N, N/2, len(m)) 122 } 123 } 124 125 func TestRepeat(t *testing.T) { 126 h1 := new(Hash) 127 h1.WriteString("testing") 128 sum1 := h1.Sum64() 129 130 h1.Reset() 131 h1.WriteString("testing") 132 sum2 := h1.Sum64() 133 134 if sum1 != sum2 { 135 t.Errorf("different sum after reseting: %#x != %#x", sum1, sum2) 136 } 137 138 h2 := new(Hash) 139 h2.SetSeed(h1.Seed()) 140 h2.WriteString("testing") 141 sum3 := h2.Sum64() 142 143 if sum1 != sum3 { 144 t.Errorf("different sum on the same seed: %#x != %#x", sum1, sum3) 145 } 146 } 147 148 func TestSeedFromSum64(t *testing.T) { 149 h1 := new(Hash) 150 h1.WriteString("foo") 151 x := h1.Sum64() // seed generated here 152 h2 := new(Hash) 153 h2.SetSeed(h1.Seed()) 154 h2.WriteString("foo") 155 y := h2.Sum64() 156 if x != y { 157 t.Errorf("hashes don't match: want %x, got %x", x, y) 158 } 159 } 160 161 func TestSeedFromSeed(t *testing.T) { 162 h1 := new(Hash) 163 h1.WriteString("foo") 164 _ = h1.Seed() // seed generated here 165 x := h1.Sum64() 166 h2 := new(Hash) 167 h2.SetSeed(h1.Seed()) 168 h2.WriteString("foo") 169 y := h2.Sum64() 170 if x != y { 171 t.Errorf("hashes don't match: want %x, got %x", x, y) 172 } 173 } 174 175 func TestSeedFromFlush(t *testing.T) { 176 b := make([]byte, 65) 177 h1 := new(Hash) 178 h1.Write(b) // seed generated here 179 x := h1.Sum64() 180 h2 := new(Hash) 181 h2.SetSeed(h1.Seed()) 182 h2.Write(b) 183 y := h2.Sum64() 184 if x != y { 185 t.Errorf("hashes don't match: want %x, got %x", x, y) 186 } 187 } 188 189 func TestSeedFromReset(t *testing.T) { 190 h1 := new(Hash) 191 h1.WriteString("foo") 192 h1.Reset() // seed generated here 193 h1.WriteString("foo") 194 x := h1.Sum64() 195 h2 := new(Hash) 196 h2.SetSeed(h1.Seed()) 197 h2.WriteString("foo") 198 y := h2.Sum64() 199 if x != y { 200 t.Errorf("hashes don't match: want %x, got %x", x, y) 201 } 202 } 203 204 // Make sure a Hash implements the hash.Hash and hash.Hash64 interfaces. 205 var _ hash.Hash = &Hash{} 206 var _ hash.Hash64 = &Hash{} 207 208 func benchmarkSize(b *testing.B, size int) { 209 h := &Hash{} 210 buf := make([]byte, size) 211 b.SetBytes(int64(size)) 212 b.ResetTimer() 213 214 for i := 0; i < b.N; i++ { 215 h.Reset() 216 h.Write(buf) 217 h.Sum64() 218 } 219 } 220 221 func BenchmarkHash8Bytes(b *testing.B) { 222 benchmarkSize(b, 8) 223 } 224 225 func BenchmarkHash320Bytes(b *testing.B) { 226 benchmarkSize(b, 320) 227 } 228 229 func BenchmarkHash1K(b *testing.B) { 230 benchmarkSize(b, 1024) 231 } 232 233 func BenchmarkHash8K(b *testing.B) { 234 benchmarkSize(b, 8192) 235 }