github.com/fluhus/gostuff@v0.4.1-0.20240331134726-be71864f2b5d/rhash/common_test.go (about) 1 // A generic test suite for rolling hashes. 2 3 package rhash 4 5 import ( 6 "crypto/rand" 7 "hash" 8 "testing" 9 10 "github.com/fluhus/gostuff/sets" 11 ) 12 13 // Runs the test suite for a hash64. 14 func test64(t *testing.T, f func(n int) hash.Hash64) { 15 t.Run("basic", func(t *testing.T) { test64basic(t, f) }) 16 t.Run("cyclic", func(t *testing.T) { test64cyclic(t, f) }) 17 t.Run("big-n", func(t *testing.T) { test64bigN(t, f) }) 18 } 19 20 func test64basic(t *testing.T, f func(n int) hash.Hash64) { 21 data := []byte("amitamit") 22 tests := []struct { 23 n int 24 wantSize []int 25 wantEq []int 26 }{ 27 {2, []int{1, 2, 3, 4, 5, 5, 5, 5}, []int{-1, -1, -1, -1, -1, 1, 2, 3}}, 28 {3, []int{1, 2, 3, 4, 5, 6, 6, 6}, []int{-1, -1, -1, -1, -1, -1, 2, 3}}, 29 } 30 for _, test := range tests { 31 slice := []uint64{} 32 set := sets.Set[uint64]{} 33 h := f(test.n) 34 for i := range data { 35 h.Write(data[i : i+1]) 36 slice = append(slice, h.Sum64()) 37 set.Add(h.Sum64()) 38 if len(set) != test.wantSize[i] { 39 t.Fatalf("n=%d #%d: set size=%v, want %v", 40 test.n, i, len(set), test.wantSize[i]) 41 } 42 if test.wantEq[i] != -1 && h.Sum64() != slice[test.wantEq[i]] { 43 t.Fatalf("n=%d #%d: Sum64()=%d, want %d", 44 test.n, i, h.Sum64(), slice[test.wantEq[i]]) 45 } 46 } 47 } 48 } 49 50 func test64cyclic(t *testing.T, f func(n int) hash.Hash64) { 51 inputs := []string{ 52 "asdjadasdk", 53 "uioewrmnoc", 54 "wiewuwikxa", 55 "mfhddl/lcc", 56 "28n9789dkd", 57 } 58 h := f(10) 59 for _, input := range inputs { 60 h.Write([]byte(input)) 61 h2 := f(10) 62 h2.Write([]byte(input)) 63 got, want := h.Sum64(), h2.Sum64() 64 if got != want { 65 t.Fatalf("Sum64(%q)=%v, want %v", input, got, want) 66 } 67 } 68 } 69 70 func test64bigN(t *testing.T, f func(n int) hash.Hash64) { 71 const n = 100 72 73 // Create random input. 74 buf := make([]byte, n) 75 _, err := rand.Read(buf) 76 if err != nil { 77 t.Fatalf("rand.Read() failed: %v", err) 78 } 79 80 // Repeat 3 times. 81 buf = append(buf, buf...) 82 buf = append(buf, buf...) 83 84 h := f(n) 85 hashes := sets.Set[uint64]{} 86 for i := range buf { 87 h.Write(buf[i : i+1]) 88 hashes.Add(h.Sum64()) 89 want := min(i+1, n*2-1) 90 if len(hashes) != want { 91 t.Fatalf("got %d unique hashes, want %d", len(hashes), want) 92 } 93 } 94 } 95 96 // Runs the test suite for a hash32. 97 func test32(t *testing.T, f func(n int) hash.Hash32) { 98 t.Run("basic", func(t *testing.T) { test32basic(t, f) }) 99 t.Run("cyclic", func(t *testing.T) { test32cyclic(t, f) }) 100 t.Run("big-n", func(t *testing.T) { test32bigN(t, f) }) 101 } 102 103 func test32basic(t *testing.T, f func(n int) hash.Hash32) { 104 data := []byte("amitamit") 105 tests := []struct { 106 n int 107 wantSize []int 108 wantEq []int 109 }{ 110 {2, []int{1, 2, 3, 4, 5, 5, 5, 5}, []int{-1, -1, -1, -1, -1, 1, 2, 3}}, 111 {3, []int{1, 2, 3, 4, 5, 6, 6, 6}, []int{-1, -1, -1, -1, -1, -1, 2, 3}}, 112 } 113 for _, test := range tests { 114 slice := []uint32{} 115 set := sets.Set[uint32]{} 116 h := f(test.n) 117 for i := range data { 118 h.Write(data[i : i+1]) 119 slice = append(slice, h.Sum32()) 120 set.Add(h.Sum32()) 121 if len(set) != test.wantSize[i] { 122 t.Fatalf("n=%d #%d: set size=%v, want %v", 123 test.n, i, len(set), test.wantSize[i]) 124 } 125 if test.wantEq[i] != -1 && h.Sum32() != slice[test.wantEq[i]] { 126 t.Fatalf("n=%d #%d: Sum32()=%d, want %d", 127 test.n, i, h.Sum32(), slice[test.wantEq[i]]) 128 } 129 } 130 } 131 } 132 133 func test32cyclic(t *testing.T, f func(n int) hash.Hash32) { 134 inputs := []string{ 135 "asdjadasdk", 136 "uioewrmnoc", 137 "wiewuwikxa", 138 "mfhddl/lcc", 139 "28n9789dkd", 140 } 141 h := f(10) 142 for _, input := range inputs { 143 h.Write([]byte(input)) 144 h2 := f(10) 145 h2.Write([]byte(input)) 146 got, want := h.Sum32(), h2.Sum32() 147 if got != want { 148 t.Fatalf("Sum32(%q)=%v, want %v", input, got, want) 149 } 150 } 151 } 152 153 func test32bigN(t *testing.T, f func(n int) hash.Hash32) { 154 const n = 100 155 156 // Create random input. 157 buf := make([]byte, n) 158 _, err := rand.Read(buf) 159 if err != nil { 160 t.Fatalf("rand.Read() failed: %v", err) 161 } 162 163 // Repeat 3 times. 164 buf = append(buf, buf...) 165 buf = append(buf, buf...) 166 167 h := f(n) 168 hashes := sets.Set[uint32]{} 169 for i := range buf { 170 h.Write(buf[i : i+1]) 171 hashes.Add(h.Sum32()) 172 want := min(i+1, n*2-1) 173 if len(hashes) != want { 174 t.Fatalf("got %d unique hashes, want %d", len(hashes), want) 175 } 176 } 177 }