1 package xxhash
2
3 import (
4 "bytes"
5 "encoding/binary"
6 "fmt"
7 "math"
8 "strings"
9 "testing"
10 )
11
12 func TestAll(t *testing.T) {
13
14 const s63 = "Call me Ishmael. Some years ago--never mind how long precisely-"
15 for _, tt := range []struct {
16 input string
17 seed uint64
18 want uint64
19 }{
20 {"", 0, 0xef46db3751d8e999},
21 {"a", 0, 0xd24ec4f1a98c6e5b},
22 {"as", 0, 0x1c330fb2d66be179},
23 {"asd", 0, 0x631c37ce72a97393},
24 {"asdf", 0, 0x415872f599cea71e},
25 {s63, 0, 0x02a2e85470d6fd96},
26
27 {"", 123, 0xe0db84de91f3e198},
28 {"asdf", math.MaxUint64, 0x9a2fd8473be539b6},
29 {s63, 54321, 0x1736d186daf5d1cd},
30 } {
31 lastChunkSize := len(tt.input)
32 if lastChunkSize == 0 {
33 lastChunkSize = 1
34 }
35 var name string
36 if tt.input == "" {
37 name = "input=empty"
38 } else if len(tt.input) > 10 {
39 name = fmt.Sprintf("input=len-%d", len(tt.input))
40 } else {
41 name = fmt.Sprintf("input=%q", tt.input)
42 }
43 if tt.seed != 0 {
44 name += fmt.Sprintf(",seed=%d", tt.seed)
45 }
46 for chunkSize := 1; chunkSize <= lastChunkSize; chunkSize++ {
47 name := fmt.Sprintf("%s,chunkSize=%d", name, chunkSize)
48 t.Run(name, func(t *testing.T) {
49 testDigest(t, tt.input, tt.seed, chunkSize, tt.want)
50 })
51 }
52 if tt.seed == 0 {
53 t.Run(name, func(t *testing.T) { testSum(t, tt.input, tt.want) })
54 }
55 }
56 }
57
58 func testDigest(t *testing.T, input string, seed uint64, chunkSize int, want uint64) {
59 d := NewWithSeed(seed)
60 ds := NewWithSeed(seed)
61 for i := 0; i < len(input); i += chunkSize {
62 chunk := input[i:]
63 if len(chunk) > chunkSize {
64 chunk = chunk[:chunkSize]
65 }
66 n, err := d.Write([]byte(chunk))
67 if err != nil || n != len(chunk) {
68 t.Fatalf("Digest.Write: got (%d, %v); want (%d, nil)", n, err, len(chunk))
69 }
70 n, err = ds.WriteString(chunk)
71 if err != nil || n != len(chunk) {
72 t.Fatalf("Digest.WriteString: got (%d, %v); want (%d, nil)", n, err, len(chunk))
73 }
74 }
75 if got := d.Sum64(); got != want {
76 t.Fatalf("Digest.Sum64: got 0x%x; want 0x%x", got, want)
77 }
78 if got := ds.Sum64(); got != want {
79 t.Fatalf("Digest.Sum64 (WriteString): got 0x%x; want 0x%x", got, want)
80 }
81 var b [8]byte
82 binary.BigEndian.PutUint64(b[:], want)
83 if got := d.Sum(nil); !bytes.Equal(got, b[:]) {
84 t.Fatalf("Sum: got %v; want %v", got, b[:])
85 }
86 }
87
88 func testSum(t *testing.T, input string, want uint64) {
89 if got := Sum64([]byte(input)); got != want {
90 t.Fatalf("Sum64: got 0x%x; want 0x%x", got, want)
91 }
92 if got := Sum64String(input); got != want {
93 t.Fatalf("Sum64String: got 0x%x; want 0x%x", got, want)
94 }
95 }
96
97 func TestReset(t *testing.T) {
98 parts := []string{"The quic", "k br", "o", "wn fox jumps", " ov", "er the lazy ", "dog."}
99 d := New()
100 for _, part := range parts {
101 d.Write([]byte(part))
102 }
103 h0 := d.Sum64()
104
105 d.Reset()
106 d.Write([]byte(strings.Join(parts, "")))
107 h1 := d.Sum64()
108
109 if h0 != h1 {
110 t.Errorf("0x%x != 0x%x", h0, h1)
111 }
112 }
113
114 func TestResetWithSeed(t *testing.T) {
115 parts := []string{"The quic", "k br", "o", "wn fox jumps", " ov", "er the lazy ", "dog."}
116 d := NewWithSeed(123)
117 for _, part := range parts {
118 d.Write([]byte(part))
119 }
120 h0 := d.Sum64()
121
122 d.ResetWithSeed(123)
123 d.Write([]byte(strings.Join(parts, "")))
124 h1 := d.Sum64()
125
126 if h0 != h1 {
127 t.Errorf("0x%x != 0x%x", h0, h1)
128 }
129 }
130
131 func TestBinaryMarshaling(t *testing.T) {
132 d := New()
133 d.WriteString("abc")
134 b, err := d.MarshalBinary()
135 if err != nil {
136 t.Fatal(err)
137 }
138 d = New()
139 d.WriteString("junk")
140 if err := d.UnmarshalBinary(b); err != nil {
141 t.Fatal(err)
142 }
143 d.WriteString("def")
144 if got, want := d.Sum64(), Sum64String("abcdef"); got != want {
145 t.Fatalf("after MarshalBinary+UnmarshalBinary, got 0x%x; want 0x%x", got, want)
146 }
147
148 d0 := New()
149 d1 := New()
150 for i := 0; i < 64; i++ {
151 b, err := d0.MarshalBinary()
152 if err != nil {
153 t.Fatal(err)
154 }
155 d0 = new(Digest)
156 if err := d0.UnmarshalBinary(b); err != nil {
157 t.Fatal(err)
158 }
159 if got, want := d0.Sum64(), d1.Sum64(); got != want {
160 t.Fatalf("after %d Writes, unmarshaled Digest gave sum 0x%x; want 0x%x", i, got, want)
161 }
162
163 d0.Write([]byte{'a'})
164 d1.Write([]byte{'a'})
165 }
166 }
167
168 var sink uint64
169
170 func TestAllocs(t *testing.T) {
171 const shortStr = "abcdefghijklmnop"
172
173
174
175 t.Run("Sum64", func(t *testing.T) {
176 testAllocs(t, func() {
177 sink = Sum64([]byte(shortStr))
178 })
179 })
180
181
182
183 t.Run("Digest", func(t *testing.T) {
184 b := []byte("asdf")
185 testAllocs(t, func() {
186 d := New()
187 d.Write(b)
188 sink = d.Sum64()
189 })
190 })
191 }
192
193 func testAllocs(t *testing.T, fn func()) {
194 t.Helper()
195 if allocs := int(testing.AllocsPerRun(10, fn)); allocs > 0 {
196 t.Fatalf("got %d allocation(s) (want zero)", allocs)
197 }
198 }
199
View as plain text