Source file src/hash/maphash/maphash_test.go

     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  }
   236  

View as plain text