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  }