View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  package org.apache.commons.codec.digest;
19  
20  import static org.junit.jupiter.api.Assertions.assertArrayEquals;
21  import static org.junit.jupiter.api.Assertions.assertEquals;
22  import static org.junit.jupiter.api.Assertions.assertNotEquals;
23  import static org.junit.jupiter.api.Assertions.assertTrue;
24  import static org.junit.jupiter.api.Assumptions.assumeTrue;
25  
26  import java.nio.ByteBuffer;
27  import java.util.Arrays;
28  import java.util.concurrent.ThreadLocalRandom;
29  
30  import org.apache.commons.codec.binary.StringUtils;
31  import org.apache.commons.codec.digest.MurmurHash3.IncrementalHash32;
32  import org.apache.commons.codec.digest.MurmurHash3.IncrementalHash32x86;
33  import org.junit.jupiter.api.Test;
34  
35  /**
36   * Test for {@link MurmurHash3}.
37   */
38  @SuppressWarnings("deprecation")
39  public class MurmurHash3Test {
40  
41      /** Test data for the hash64 method. */
42      private static final String TEST_HASH64 = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur?";
43  
44      /**
45       * 256 integers in the range [0,255] arranged in random order.
46       * This ensures all bytes are covered in a full hash of the bytes.
47       *
48       * <p>To create test data using the python library mmh3 (which invokes the c++ code):</p>
49       *
50       * <pre>
51       * import mmh3
52       * import numpy as np
53       * # Put random bytes in here:
54       * bytes = np.uint8([46,246,249,184,247,84,99,144,62,77,195,220,92,20,150,159,38,40,124,252,185,28,63,13,213,172,85,198,118,74,109,157,132,216,76,177,173,23,140,86,146,95,54,176,114,179,234,174,183,141,122,12,60,116,200,142,6,167,59,240,33,29,165,111,243,30,219,110,255,53,32,35,64,225,96,152,70,41,133,80,244,127,57,199,5,164,151,49,26,180,203,83,108,39,126,208,42,206,178,19,69,223,71,231,250,125,211,232,189,55,44,82,48,221,43,192,241,103,155,27,51,163,21,169,91,94,217,191,78,72,93,102,104,105,8,113,100,143,89,245,227,120,160,251,153,145,45,218,168,233,229,253,67,22,182,98,137,128,135,11,214,66,73,171,188,170,131,207,79,106,24,75,237,194,7,129,215,81,248,242,16,25,136,147,156,97,52,10,181,17,205,58,101,68,230,1,37,0,222,88,130,148,224,47,50,197,34,212,196,209,14,36,139,228,154,31,175,202,236,161,3,162,190,254,134,119,4,61,65,117,186,107,204,9,187,201,90,149,226,56,239,238,235,112,87,18,121,115,138,123,210,2,193,166,158,15])
55       * # Seed as appropriate. The default seed in mmh3 is zero.
56       * seed = 789
57       * # Output data. Adjust as appropriate.
58       * for x in range(0, 256):
59       *   # 32-bit hash
60       *   mmh3.hash(bytes[:x])
61       *   mmh3.hash(bytes[:x], seed)
62       *   # 128-bit hash as two 64 bit signed ints
63       *   mmh3.hash64(bytes[:x])
64       *   mmh3.hash64(bytes[:x], seed)
65       * # Sub-arrays: lower inclusive, upper exclusive:
66       * mmh3.hash(bytes[13:15])
67       * </pre>
68       */
69      private static final int[] RANDOM_INTS = { 46, 246, 249, 184, 247, 84, 99, 144, 62, 77, 195, 220, 92, 20, 150, 159, 38, 40, 124, 252, 185, 28, 63, 13, 213,
70              172, 85, 198, 118, 74, 109, 157, 132, 216, 76, 177, 173, 23, 140, 86, 146, 95, 54, 176, 114, 179, 234, 174, 183, 141, 122, 12, 60, 116, 200, 142, 6,
71              167, 59, 240, 33, 29, 165, 111, 243, 30, 219, 110, 255, 53, 32, 35, 64, 225, 96, 152, 70, 41, 133, 80, 244, 127, 57, 199, 5, 164, 151, 49, 26, 180,
72              203, 83, 108, 39, 126, 208, 42, 206, 178, 19, 69, 223, 71, 231, 250, 125, 211, 232, 189, 55, 44, 82, 48, 221, 43, 192, 241, 103, 155, 27, 51, 163,
73              21, 169, 91, 94, 217, 191, 78, 72, 93, 102, 104, 105, 8, 113, 100, 143, 89, 245, 227, 120, 160, 251, 153, 145, 45, 218, 168, 233, 229, 253, 67, 22,
74              182, 98, 137, 128, 135, 11, 214, 66, 73, 171, 188, 170, 131, 207, 79, 106, 24, 75, 237, 194, 7, 129, 215, 81, 248, 242, 16, 25, 136, 147, 156, 97,
75              52, 10, 181, 17, 205, 58, 101, 68, 230, 1, 37, 0, 222, 88, 130, 148, 224, 47, 50, 197, 34, 212, 196, 209, 14, 36, 139, 228, 154, 31, 175, 202, 236,
76              161, 3, 162, 190, 254, 134, 119, 4, 61, 65, 117, 186, 107, 204, 9, 187, 201, 90, 149, 226, 56, 239, 238, 235, 112, 87, 18, 121, 115, 138, 123, 210,
77              2, 193, 166, 158, 15 };
78  
79      /**
80       * 256 bytes in the range [0,255] arranged in random order.
81       * This ensures all bytes are covered in a full hash of the bytes.
82       */
83      private static final byte[] RANDOM_BYTES;
84  
85      static {
86          RANDOM_BYTES = new byte[RANDOM_INTS.length];
87          for (int i = 0; i < RANDOM_BYTES.length; i++) {
88              RANDOM_BYTES[i] = (byte) RANDOM_INTS[i];
89          }
90      }
91  
92      // Tests match the declared order of the class:
93      // hash32
94      // hash64
95      // hash128
96      // IncrementalHash32
97      //
98      // There is no reference for the hash64 method. It is not in the original murmurhash3 code.
99      // Thus hash64 is not extensively tested and the reference results are assumed to be from the
100     // Apache Hive project which was the source of the method.
101 
102     /**
103      * Assert {@link IncrementalHash32} returns the same values as
104      * {@link MurmurHash3#hash32(byte[], int, int, int)}.
105      *
106      * <p>The bytes are added to the incremental hash in the given blocks.</p>
107      *
108      * @param bytes the bytes
109      * @param seed the seed
110      * @param blocks the blocks
111      */
112     private static void assertIncrementalHash32(final byte[] bytes, final int seed, final int... blocks) {
113         int offset = 0;
114         int total = 0;
115         final IncrementalHash32 inc = new IncrementalHash32();
116         inc.start(seed);
117         for (final int block : blocks) {
118             total += block;
119             final int h1 = MurmurHash3.hash32(bytes, 0, total, seed);
120             inc.add(bytes, offset, block);
121             offset += block;
122             final int h2 = inc.end();
123             assertEquals(h1, h2, "Hashes differ");
124             assertEquals(h1, inc.end(), "Hashes differ after no additional data");
125         }
126     }
127 
128     /**
129      * Assert {@link IncrementalHash32x86} returns the same values as
130      * {@link MurmurHash3#hash32x86(byte[], int, int, int)}.
131      *
132      * <p>The bytes are added to the incremental hash in the given blocks.</p>
133      *
134      * @param bytes the bytes
135      * @param seed the seed
136      * @param blocks the blocks
137      */
138     private static void assertIncrementalHash32x86(final byte[] bytes, final int seed, final int... blocks) {
139         int offset = 0;
140         int total = 0;
141         final IncrementalHash32x86 inc = new IncrementalHash32x86();
142         inc.start(seed);
143         for (final int block : blocks) {
144             total += block;
145             final int h1 = MurmurHash3.hash32x86(bytes, 0, total, seed);
146             inc.add(bytes, offset, block);
147             offset += block;
148             final int h2 = inc.end();
149             assertEquals(h1, h2, "Hashes differ");
150             assertEquals(h1, inc.end(), "Hashes differ after no additional data");
151         }
152     }
153 
154     /**
155      * Creates a set of long values to test the hash utility methods.
156      *
157      * @return the data
158      */
159     private static long[] createLongTestData() {
160         final long[] data = new long[100];
161         // Edge cases:
162         data[0] = 0;
163         data[1] = Long.MIN_VALUE;
164         data[2] = Long.MAX_VALUE;
165         data[3] = -1L;
166         for (int i = 4; i < data.length; i++) {
167             data[i] = ThreadLocalRandom.current().nextLong();
168         }
169         return data;
170     }
171 
172     /**
173      * Creates the random blocks of data to process up to max length.
174      *
175      * @param maxLength the max length
176      * @return the blocks
177      */
178     private static int[] createRandomBlocks(final int maxLength) {
179         final int[] blocks = new int[20];
180         int count = 0;
181         int length = 0;
182         while (count < blocks.length && length < maxLength) {
183             // range of 1 to 8 for up to two 4 byte blocks
184             final int size = ThreadLocalRandom.current().nextInt(1, 9);
185             blocks[count++] = size;
186             length += size;
187         }
188         return Arrays.copyOf(blocks, count);
189     }
190 
191     /**
192      * Check if the bytes are negative in the given range.
193      *
194      * @param bytes the bytes
195      * @param start the start
196      * @param length the length
197      * @return true, if negative bytes exist
198      */
199     private static boolean negativeBytes(final byte[] bytes, final int start, final int length) {
200         for (int i = start; i < start + length; i++) {
201             if (bytes[i] < 0) {
202                 return true;
203             }
204         }
205         return false;
206     }
207 
208     /**
209      * Test the {@link MurmurHash3#hash128(byte[])} algorithm.
210      *
211      * <p>Reference data is taken from the Python library {@code mmh3}.</p>
212      *
213      * @see <a href="https://pypi.org/project/mmh3/">mmh3</a>
214      */
215     @Test
216     public void testHash128() {
217         // mmh3.hash64(bytes, 104729)
218         assertArrayEquals(new long[] {-5614308156300707300L, -4165733009867452172L},
219             MurmurHash3.hash128(RANDOM_BYTES));
220 
221         // Test with all sizes up to 31 bytes. This ensures a full round of 16-bytes plus up to
222         // 15 bytes remaining.
223         // for x in range(0, 32):
224         //   print(mmh3.hash64(bytes[:x], 104729), ',')
225         final long[][] answers = {
226             {-7122613646888064702L, -8341524471658347240L}, {5659994275039884826L, -962335545730945195L},
227             {-7641758224504050283L, 4083131074855072837L}, {-9123564721037921804L, -3321998102976419641L},
228             {-7999620158275145567L, -7769992740725283391L}, {2419143614837736468L, -5474637306496300103L},
229             {7781591175729494939L, -9023178611551692650L}, {-3431043156265556247L, -6589990064676612981L},
230             {6315693694262400182L, -6219942557302821890L}, {-8249934145502892979L, -5646083202776239948L},
231             {7500109050276796947L, 5350477981718987260L}, {-6102338673930022315L, 3413065069102535261L},
232             {-6440683413407781313L, -2374360388921904146L}, {-3071236194203069122L, 7531604855739305895L},
233             {-7629408037856591130L, -4070301959951145257L}, {860008171111471563L, -9026008285726889896L},
234             {8059667613600971894L, 3236009436748930210L}, {1833746055900036985L, 1418052485321768916L},
235             {8161230977297923537L, -2668130155009407119L}, {3653111839268905630L, 5525563908135615453L},
236             {-9163026480602019754L, 6819447647029564735L}, {1102346610654592779L, -6881918401879761029L},
237             {-3109499571828331931L, -3782255367340446228L}, {-7467915444290531104L, 4704551260862209500L},
238             {1237530251176898868L, 6144786892208594932L}, {2347717913548230384L, -7461066668225718223L},
239             {-7963311463560798404L, 8435801462986138227L}, {-7493166089060196513L, 8163503673197886404L},
240             {6807249306539951962L, -1438886581269648819L}, {6752656991043418179L, 6334147827922066123L},
241             {-4534351735605790331L, -4530801663887858236L}, {-7886946241830957955L, -6261339648449285315L}
242         };
243         for (int i = 0; i < answers.length; i++) {
244             final byte[] bytes = Arrays.copyOf(RANDOM_BYTES, i);
245             assertArrayEquals(answers[i], MurmurHash3.hash128(bytes));
246         }
247     }
248 
249     /**
250      * Test the {@link MurmurHash3#hash128(String)} algorithm. This only tests it can return
251      * the same value as {@link MurmurHash3#hash128(byte[], int, int, int)} if the string
252      * is converted to bytes using the method {@link String#getBytes()}.
253      *
254      * <p>The test uses random strings created with random unicode code points.</p>
255      */
256     @Test
257     public void testHash128String() {
258         final int seed = 104729;
259         // Range is end exclusive so this is random strings of length 1-10
260         final int minSize = 1;
261         final int maxSize = 11;
262         // The Unicode Standard, Version 7.0, contains 112,956 characters
263         final int codePoints = 112956;
264         final char[] chars = new char[(maxSize - minSize) * 2];
265         for (int i = 0; i < 1000; i++) {
266             int pos = 0;
267             final int size = ThreadLocalRandom.current().nextInt(minSize, maxSize);
268             for (int j = 0; j < size; j++) {
269                 final int codePoint = ThreadLocalRandom.current().nextInt(codePoints);
270                 pos += Character.toChars(codePoint, chars, pos);
271             }
272             final String text = String.copyValueOf(chars, 0, pos);
273             final byte[] bytes = StringUtils.getBytesUtf8(text);
274             final long[] h1 = MurmurHash3.hash128(bytes, 0, bytes.length, seed);
275             final long[] h2 = MurmurHash3.hash128(text);
276             assertArrayEquals(h1, h2);
277         }
278     }
279 
280     /**
281      * Test the {@link MurmurHash3#hash128(byte[], int, int, int)} algorithm.
282      *
283      * <p>Explicit test for a negative seed. The original implementation has a sign extension error
284      * for negative seeds. This test is here to maintain behavioral compatibility of the
285      * broken deprecated method.
286      */
287     @Test
288     public void testHash128WithOffsetLengthAndNegativeSeed() {
289         // Seed can be negative
290         final int seed = -42;
291         final int offset = 13;
292 
293         // Test with all sizes up to 31 bytes. This ensures a full round of 16-bytes plus up to
294         // 15 bytes remaining.
295         final long[][] answers = {
296                 {5954234972212089025L, 3342108296337967352L},
297                 {8501094764898402923L, 7873951092908129427L}, {-3334322685492296196L, -2842715922956549478L},
298                 {-2177918982459519644L, -1612349961980368636L}, {4172870320608886992L, -4177375712254136503L},
299                 {7546965006884307324L, -5222114032564054641L}, {-2885083166621537267L, -2069868899915344482L},
300                 {-2397098497873118851L, 4990578036999888806L}, {-706479374719025018L, 7531201699171849870L},
301                 {6487943141157228609L, 3576221902299447884L}, {6671331646806999453L, -3428049860825046360L},
302                 {-8700221138601237020L, -2748450904559980545L}, {-9028762509863648063L, 6130259301750313402L},
303                 {729958512305702590L, -36367317333638988L}, {-3803232241584178983L, -4257744207892929651L},
304                 {5734013720237474696L, -760784490666078990L}, {-6097477411153026656L, 625288777006549065L},
305                 {1320365359996757504L, -2251971390373072541L}, {5551441703887653022L, -3516892619809375941L},
306                 {698875391638415033L, 3456972931370496131L}, {5874956830271303805L, -6074126509360777023L},
307                 {-7030758398537734781L, -3174643657101295554L}, {6835789852786226556L, 7245353136839389595L},
308                 {-7755767580598793204L, -6680491060945077989L}, {-3099789923710523185L, -2751080516924952518L},
309                 {-7772046549951435453L, 5263206145535830491L}, {7458715941971015543L, 5470582752171544854L},
310                 {-7753394773760064468L, -2330157750295630617L}, {-5899278942232791979L, 6235686401271389982L},
311                 {4881732293467626532L, 2617335658565007304L}, {-5722863941703478257L, -5424475653939430258L},
312                 {-3703319768293496315L, -2124426428486426443L}
313         };
314         for (int i = 0; i < answers.length; i++) {
315             assertArrayEquals(answers[i], MurmurHash3.hash128(RANDOM_BYTES, offset, i, seed), "Length: " + i);
316         }
317     }
318 
319     /**
320      * Test the {@link MurmurHash3#hash128(byte[], int, int, int)} algorithm.
321      *
322      * <p>Reference data is taken from the Python library {@code mmh3}.</p>
323      *
324      * @see <a href="https://pypi.org/project/mmh3/">mmh3</a>
325      */
326     @Test
327     public void testHash128WithOffsetLengthAndSeed() {
328         // Seed must be positive
329         final int seed = 42;
330         final int offset = 13;
331 
332         // Test with all sizes up to 31 bytes. This ensures a full round of 16-bytes plus up to
333         // 15 bytes remaining.
334         // for x in range(0, 32):
335         //   print(mmh3.hash64(bytes[13:x+13], 42), ',')
336         final long[][] answers = {
337             {-1140915396076141277L, -3386313222241793095L},
338             {2745805417334040752L, -3045882272665292331L}, {6807939080212835946L, -1975749467247671127L},
339             {-7924884987449335214L, -4468571497642087939L}, {3005389733967167773L, -5809440073240597398L},
340             {8032745196600164727L, 4545709434702374224L}, {2095398623732573832L, 1778447136435513908L},
341             {4492723708121417255L, -7411125500882394867L}, {8467397417110552178L, -1503802302645548949L},
342             {4189760269121918355L, -8004336343217265057L}, {4939298084211301953L, -8419135013628844658L},
343             {5497136916151148085L, -394028342910298191L}, {3405983294878231737L, -3216533807498089078L},
344             {5833223403351466775L, -1792451370239813325L}, {7730583391236194819L, 5356157313842354092L},
345             {3111977482488580945L, -3119414725698132191L}, {3314524606404365027L, -1923219843083192742L},
346             {7299569240140613949L, 4176392429810027494L}, {6398084683727166117L, 7703960505857395788L},
347             {-8594572031068184774L, 4394224719145783692L}, {-7589785442804461713L, 4110439243215224554L},
348             {-5343610105946840628L, -4423992782020122809L}, {-522490326525787270L, 289136460641968781L},
349             {-5320637070354802556L, -7845553044730489027L}, {1344456408744313334L, 3803048032054968586L},
350             {1131205296221907191L, -6256656049039287019L}, {8583339267101027117L, 8934225022848628726L},
351             {-6379552869905441749L, 8973517768420051734L}, {5076646564516328801L, 8561479196844000567L},
352             {-4610341636137642517L, -6694266039505142069L}, {-758896383254029789L, 4050360662271552727L},
353             {-6123628195475753507L, 4283875822581966645L}
354         };
355         for (int i = 0; i < answers.length; i++) {
356             assertArrayEquals(answers[i], MurmurHash3.hash128(RANDOM_BYTES, offset, i, seed), "Length: " + i);
357         }
358     }
359 
360     /**
361      * Test the {@link MurmurHash3#hash128x64(byte[])} algorithm.
362      *
363      * <p>Reference data is taken from the Python library {@code mmh3}.</p>
364      *
365      * @see <a href="https://pypi.org/project/mmh3/">mmh3</a>
366      */
367     @Test
368     public void testHash128x64() {
369         // Note: Default seed is zero.
370 
371         // mmh3.hash64(bytes, 0)
372         assertArrayEquals(new long[] {1972113670104592209L, 5171809317673151911L},
373             MurmurHash3.hash128x64(RANDOM_BYTES));
374 
375         // Test with all sizes up to 31 bytes. This ensures a full round of 16-bytes plus up to
376         // 15 bytes remaining.
377         // for x in range(0, 32):
378         //   print(mmh3.hash64(bytes[:x], 0), ',')
379         final long[][] answers = {
380             {0L, 0L}, {-2808653841080383123L, -2531784594030660343L},
381             {-1284575471001240306L, -8226941173794461820L}, {1645529003294647142L, 4109127559758330427L},
382             {-4117979116203940765L, -8362902660322042742L}, {2559943399590596158L, 4738005461125350075L},
383             {-1651760031591552651L, -5386079254924224461L}, {-6208043960690815609L, 7862371518025305074L},
384             {-5150023478423646337L, 8346305334874564507L}, {7658274117911906792L, -4962914659382404165L},
385             {1309458104226302269L, 570003296096149119L}, {7440169453173347487L, -3489345781066813740L},
386             {-5698784298612201352L, 3595618450161835420L}, {-3822574792738072442L, 6878153771369862041L},
387             {3705084673301918328L, 3202155281274291907L}, {-6797166743928506931L, -4447271093653551597L},
388             {5240533565589385084L, -5575481185288758327L}, {-8467620131382649428L, -6450630367251114468L},
389             {3632866961828686471L, -5957695976089313500L}, {-6450283648077271139L, -7908632714374518059L},
390             {226350826556351719L, 8225586794606475685L}, {-2382996224496980401L, 2188369078123678011L},
391             {-1337544762358780825L, 7004253486151757299L}, {2889033453638709716L, -4099509333153901374L},
392             {-8644950936809596954L, -5144522919639618331L}, {-5628571865255520773L, -839021001655132087L},
393             {-5226774667293212446L, -505255961194269502L}, {1337107025517938142L, 3260952073019398505L},
394             {9149852874328582511L, 1880188360994521535L}, {-4035957988359881846L, -7709057850766490780L},
395             {-3842593823306330815L, 3805147088291453755L}, {4030161393619149616L, -2813603781312455238L}
396         };
397         for (int i = 0; i < answers.length; i++) {
398             final byte[] bytes = Arrays.copyOf(RANDOM_BYTES, i);
399             assertArrayEquals(answers[i], MurmurHash3.hash128x64(bytes));
400         }
401     }
402 
403     /**
404      * Test the {@link MurmurHash3#hash128x64(byte[], int, int, int)} algorithm.
405      *
406      * <p>Explicit test for a negative seed. The original implementation has a sign extension error
407      * for negative seeds.
408      *
409      * <p>Reference data is taken from the Python library {@code mmh3}.</p>
410      *
411      * @see <a href="https://pypi.org/project/mmh3/">mmh3</a>
412      */
413     @Test
414     public void testHash128x64WithOffsetLengthAndNegativeSeed() {
415         // Seed can be negative
416         final int seed = -42;
417         final int offset = 13;
418 
419         // Test with all sizes up to 31 bytes. This ensures a full round of 16-bytes plus up to
420         // 15 bytes remaining.
421         // for x in range(0, 32):
422         //   print(mmh3.hash64(bytes[13:x+13], -42), ',')
423         final long[][] answers = {
424             {7182599573337898253L, -6490979146667806054L},
425             {-461284136738605467L, 7073284964362976233L}, {-3090354666589400212L, 2978755180788824810L},
426             {5052807367580803906L, -4497188744879598335L}, {5003711854877353474L, -6616808651483337088L},
427             {2043501804923817748L, -760668448196918637L}, {6813003268375229932L, -1818545210475363684L},
428             {4488070015393027916L, 8520186429078977003L}, {4709278711722456062L, -2262080641289046033L},
429             {-5944514262756048380L, 5968714500873552518L}, {-2304397529301122510L, 6451500469518446488L},
430             {-1054078041081348909L, -915114408909600132L}, {1300471646869277217L, -399493387666437046L},
431             {-2821780479886030222L, -9061571187511294733L}, {8005764841242557505L, 4135287855434326053L},
432             {318307346637037498L, -5355856739901286522L}, {3380719536119187025L, 1890890833937151467L},
433             {2691044185935730001L, 7963546423617895734L}, {-5277462388534000227L, 3613853764390780573L},
434             {8504421722476165699L, 2058020162708103700L}, {-6578421288092422241L, 3311200163790829579L},
435             {-5915037218487974215L, -7385137075895184179L}, {659642911937398022L, 854071824595671049L},
436             {-7007237968866727198L, 1372258010932080058L}, {622891376282772539L, -4140783491297489868L},
437             {8357110718969014985L, -4737117827581590306L}, {2208857857926305405L, -8360240839768465042L},
438             {858120048221036376L, -5822288789703639119L}, {-1988334009458340679L, 1262479472434068698L},
439             {-8580307083590783934L, 3634449965473715778L}, {6705664584730187559L, 5192304951463791556L},
440             {-6426410954037604142L, -1579122709247558101L}
441         };
442         for (int i = 0; i < answers.length; i++) {
443             assertArrayEquals(answers[i], MurmurHash3.hash128x64(RANDOM_BYTES, offset, i, seed), "Length: " + i);
444         }
445     }
446 
447     /**
448      * Test the {@link MurmurHash3#hash128x64(byte[], int, int, int)} algorithm.
449      *
450      * <p>Reference data is taken from the Python library {@code mmh3}.</p>
451      *
452      * @see <a href="https://pypi.org/project/mmh3/">mmh3</a>
453      */
454     @Test
455     public void testHash128x64WithOffsetLengthAndSeed() {
456         // Seed can be positive
457         final int seed = 42;
458         final int offset = 13;
459 
460         // Test with all sizes up to 31 bytes. This ensures a full round of 16-bytes plus up to
461         // 15 bytes remaining.
462         // for x in range(0, 32):
463         //   print(mmh3.hash64(bytes[13:x+13], 42), ',')
464         final long[][] answers = {
465             {-1140915396076141277L, -3386313222241793095L},
466             {2745805417334040752L, -3045882272665292331L}, {6807939080212835946L, -1975749467247671127L},
467             {-7924884987449335214L, -4468571497642087939L}, {3005389733967167773L, -5809440073240597398L},
468             {8032745196600164727L, 4545709434702374224L}, {2095398623732573832L, 1778447136435513908L},
469             {4492723708121417255L, -7411125500882394867L}, {8467397417110552178L, -1503802302645548949L},
470             {4189760269121918355L, -8004336343217265057L}, {4939298084211301953L, -8419135013628844658L},
471             {5497136916151148085L, -394028342910298191L}, {3405983294878231737L, -3216533807498089078L},
472             {5833223403351466775L, -1792451370239813325L}, {7730583391236194819L, 5356157313842354092L},
473             {3111977482488580945L, -3119414725698132191L}, {3314524606404365027L, -1923219843083192742L},
474             {7299569240140613949L, 4176392429810027494L}, {6398084683727166117L, 7703960505857395788L},
475             {-8594572031068184774L, 4394224719145783692L}, {-7589785442804461713L, 4110439243215224554L},
476             {-5343610105946840628L, -4423992782020122809L}, {-522490326525787270L, 289136460641968781L},
477             {-5320637070354802556L, -7845553044730489027L}, {1344456408744313334L, 3803048032054968586L},
478             {1131205296221907191L, -6256656049039287019L}, {8583339267101027117L, 8934225022848628726L},
479             {-6379552869905441749L, 8973517768420051734L}, {5076646564516328801L, 8561479196844000567L},
480             {-4610341636137642517L, -6694266039505142069L}, {-758896383254029789L, 4050360662271552727L},
481             {-6123628195475753507L, 4283875822581966645L}
482         };
483         for (int i = 0; i < answers.length; i++) {
484             assertArrayEquals(answers[i], MurmurHash3.hash128x64(RANDOM_BYTES, offset, i, seed), "Length: " + i);
485         }
486     }
487 
488     /**
489      * Test the {@link MurmurHash3#hash32(byte[])} algorithm.
490      *
491      * <p>
492      * Reference data is taken from the Python library {@code mmh3}.
493      * </p>
494      *
495      * @see <a href="https://pypi.org/project/mmh3/">mmh3</a>
496      */
497     @Test
498     public void testHash32() {
499         // mmh3.hash(bytes, 104729)
500         assertEquals(1905657630, MurmurHash3.hash32(RANDOM_BYTES));
501 
502         // Test with all sizes up to 31 bytes. This ensures a full round of 16-bytes plus up to
503         // 15 bytes remaining.
504         // for x in range(0, 32):
505         // print(mmh3.hash(bytes[:x], 104729), ',')
506         final int[] answers = { -965378730, 418246248, 1175981702, -616767012, -12304673, 1697005142, -1212417875, -420043393, -826068069, -1721451528,
507                 -544986914, 892942691, 27535194, 974863697, 1835661694, -894915836, 1826914566, -677571679, 1218764493, -375719050, -1320048170, -503583763,
508                 1321750696, -175065786, -496878386, -12065683, 512351473, 716560510, -1944803590, 10253199, 1105638211, 525704533, };
509         for (int i = 0; i < answers.length; i++) {
510             final byte[] bytes = Arrays.copyOf(RANDOM_BYTES, i);
511             // Known bug: Incorrect result for non modulus of 4 byte arrays if there are
512             // negative bytes
513             if (i % 4 == 0 || !negativeBytes(bytes, i / 4 * 4, i % 4)) {
514                 assertEquals(answers[i], MurmurHash3.hash32(bytes));
515             } else {
516                 assertNotEquals(answers[i], MurmurHash3.hash32(bytes));
517             }
518         }
519     }
520 
521     /**
522      * Test the convenience method {@link MurmurHash3#hash32(long)} works as documented.
523      */
524     @Test
525     public void testHash32Long() {
526         // As described in the Javadoc
527         final int offset = 0;
528         final int seed = 104729;
529 
530         final int length = Long.BYTES;
531         final ByteBuffer buffer = ByteBuffer.allocate(length);
532         final byte[] bytes = buffer.array();
533         final long[] data = createLongTestData();
534         for (final long i : data) {
535             buffer.putLong(0, i);
536             assertEquals(MurmurHash3.hash32x86(bytes, offset, length, seed), MurmurHash3.hash32(i));
537         }
538     }
539 
540     /**
541      * Test the convenience method {@link MurmurHash3#hash32(long, long)} works as documented.
542      */
543     @Test
544     public void testHash32LongLong() {
545         // As described in the Javadoc
546         final int offset = 0;
547         final int seed = 104729;
548 
549         final int length = Long.BYTES * 2;
550         final ByteBuffer buffer = ByteBuffer.allocate(length);
551         final byte[] bytes = buffer.array();
552         final long[] data = createLongTestData();
553         for (final long i : data) {
554             for (final long j : data) {
555                 buffer.putLong(0, i);
556                 buffer.putLong(Long.BYTES, j);
557                 assertEquals(MurmurHash3.hash32x86(bytes, offset, length, seed), MurmurHash3.hash32(i, j));
558             }
559         }
560     }
561 
562     /**
563      * Test the convenience method {@link MurmurHash3#hash32(long, long, int)} works as documented.
564      */
565     @Test
566     public void testHash32LongLongSeed() {
567         // As described in the Javadoc
568         final int offset = 0;
569         final int seed = 104729;
570 
571         final int length = Long.BYTES * 2;
572         final ByteBuffer buffer = ByteBuffer.allocate(length);
573         final byte[] bytes = buffer.array();
574         final long[] data = createLongTestData();
575         for (final long i : data) {
576             for (final long j : data) {
577                 buffer.putLong(0, i);
578                 buffer.putLong(Long.BYTES, j);
579                 assertEquals(MurmurHash3.hash32x86(bytes, offset, length, seed), MurmurHash3.hash32(i, j, seed));
580             }
581         }
582     }
583 
584     /**
585      * Test the convenience method {@link MurmurHash3#hash32(long, int)} works as documented.
586      */
587     @Test
588     public void testHash32LongSeed() {
589         // As described in the Javadoc
590         final int offset = 0;
591         final int seed = 104729;
592 
593         final int length = Long.BYTES;
594         final ByteBuffer buffer = ByteBuffer.allocate(length);
595         final byte[] bytes = buffer.array();
596         final long[] data = createLongTestData();
597         for (final long i : data) {
598             buffer.putLong(0, i);
599             assertEquals(MurmurHash3.hash32x86(bytes, offset, length, seed), MurmurHash3.hash32(i, seed));
600         }
601     }
602 
603     /**
604      * Test the {@link MurmurHash3#hash32(String)} algorithm. This only tests it can return the same value as {@link MurmurHash3#hash32(byte[], int, int, int)}
605      * if the string is converted to bytes using the method {@link String#getBytes()}.
606      *
607      * <p>
608      * The test uses random strings created with random unicode code points.
609      * </p>
610      */
611     @Test
612     public void testHash32String() {
613         final int seed = 104729;
614         // Range is end exclusive so this is random strings of length 1-10
615         final int minSize = 1;
616         final int maxSize = 11;
617         // The Unicode Standard, Version 7.0, contains 112,956 characters
618         final int codePoints = 112956;
619         final char[] chars = new char[(maxSize - minSize) * 2];
620         for (int i = 0; i < 1000; i++) {
621             int pos = 0;
622             final int size = ThreadLocalRandom.current().nextInt(minSize, maxSize);
623             for (int j = 0; j < size; j++) {
624                 final int codePoint = ThreadLocalRandom.current().nextInt(codePoints);
625                 pos += Character.toChars(codePoint, chars, pos);
626             }
627             final String text = String.copyValueOf(chars, 0, pos);
628             final byte[] bytes = StringUtils.getBytesUtf8(text);
629             final int h1 = MurmurHash3.hash32(bytes, 0, bytes.length, seed);
630             final int h2 = MurmurHash3.hash32(text);
631             assertEquals(h1, h2);
632         }
633     }
634 
635     /**
636      * Test the {@link MurmurHash3#hash32(byte[], int)} algorithm.
637      *
638      * <p>
639      * Reference data is taken from the Python library {@code mmh3}.
640      * </p>
641      *
642      * @see <a href="https://pypi.org/project/mmh3/">mmh3</a>
643      */
644     @Test
645     public void testHash32WithLength() {
646         // mmh3.hash(bytes, 104729)
647         assertEquals(1905657630, MurmurHash3.hash32(RANDOM_BYTES, RANDOM_BYTES.length));
648 
649         // Test with all sizes up to 31 bytes. This ensures a full round of 16-bytes plus up to
650         // 15 bytes remaining.
651         // for x in range(0, 32):
652         // print(mmh3.hash(bytes[:x], 104729), ',')
653         final int[] answers = { -965378730, 418246248, 1175981702, -616767012, -12304673, 1697005142, -1212417875, -420043393, -826068069, -1721451528,
654                 -544986914, 892942691, 27535194, 974863697, 1835661694, -894915836, 1826914566, -677571679, 1218764493, -375719050, -1320048170, -503583763,
655                 1321750696, -175065786, -496878386, -12065683, 512351473, 716560510, -1944803590, 10253199, 1105638211, 525704533, };
656         for (int i = 0; i < answers.length; i++) {
657             // Known bug: Incorrect result for non modulus of 4 byte arrays if there are
658             // negative bytes
659             if (i % 4 == 0 || !negativeBytes(RANDOM_BYTES, i / 4 * 4, i % 4)) {
660                 assertEquals(answers[i], MurmurHash3.hash32(RANDOM_BYTES, i));
661             } else {
662                 assertNotEquals(answers[i], MurmurHash3.hash32(RANDOM_BYTES, i));
663             }
664         }
665     }
666 
667     /**
668      * Test the {@link MurmurHash3#hash32(byte[], int, int)} algorithm.
669      *
670      * <p>
671      * Reference data is taken from the Python library {@code mmh3}.
672      * </p>
673      *
674      * @see <a href="https://pypi.org/project/mmh3/">mmh3</a>
675      */
676     @Test
677     public void testHash32WithLengthAndSeed() {
678         final int seed = -42;
679         // mmh3.hash(bytes, -42)
680         assertEquals(1693958011, MurmurHash3.hash32(RANDOM_BYTES, RANDOM_BYTES.length, seed));
681 
682         // Test with all sizes up to 31 bytes. This ensures a full round of 16-bytes plus up to
683         // 15 bytes remaining.
684         // for x in range(0, 32):
685         // print(mmh3.hash(bytes[:x], -42), ',')
686         final int[] answers = { 192929823, 7537536, -99368911, -1261039957, -1719251056, -399594848, 372285930, -80756529, 1770924588, -1071759082, 1832217706,
687                 1921413466, 1701676113, 675584253, 1620634486, 427719405, -973727623, 533209078, 136016960, 1947798330, 428635832, -1125743884, 793211715,
688                 -2068889169, -136818786, -720841364, -891446378, 1990860976, -710528065, -1602505694, -1493714677, 1911121524, };
689         for (int i = 0; i < answers.length; i++) {
690             // Known bug: Incorrect result for non modulus of 4 byte arrays if there are
691             // negative bytes
692             if (i % 4 == 0 || !negativeBytes(RANDOM_BYTES, i / 4 * 4, i % 4)) {
693                 assertEquals(answers[i], MurmurHash3.hash32(RANDOM_BYTES, i, seed));
694             } else {
695                 assertNotEquals(answers[i], MurmurHash3.hash32(RANDOM_BYTES, i, seed));
696             }
697         }
698     }
699 
700     /**
701      * Test the {@link MurmurHash3#hash32(byte[], int, int, int)} algorithm.
702      *
703      * <p>
704      * Reference data is taken from the Python library {@code mmh3}.
705      * </p>
706      *
707      * @see <a href="https://pypi.org/project/mmh3/">mmh3</a>
708      */
709     @Test
710     public void testHash32WithOffsetLengthAndSeed() {
711         final int seed = -42;
712         final int offset = 13;
713 
714         // Test with all sizes up to 31 bytes. This ensures a full round of 16-bytes plus up to
715         // 15 bytes remaining.
716         // for x in range(0, 32):
717         // print(mmh3.hash(bytes[13:x+13], -42), ',')
718         final int[] answers = { 192929823, -27171978, -1282326280, -816314453, -1176217753, -1904531247, 1962794233, -1302316624, -1151850323, -1464386748,
719                 -369299427, 972232488, 1747314487, 2137398916, 690986564, -1985866226, -678669121, -2123325690, -253319081, 46181235, 656058278, 1401175653,
720                 1750113912, -1567219725, 2032742772, -2024269989, -305340794, 1161737942, -661265418, 172838872, -650122718, -1934812417, };
721         for (int i = 0; i < answers.length; i++) {
722             // Known bug: Incorrect result for non modulus of 4 byte arrays if there are
723             // negative bytes
724             if (i % 4 == 0 || !negativeBytes(RANDOM_BYTES, offset + i / 4 * 4, i % 4)) {
725                 assertEquals(answers[i], MurmurHash3.hash32(RANDOM_BYTES, offset, i, seed));
726             } else {
727                 assertNotEquals(answers[i], MurmurHash3.hash32(RANDOM_BYTES, offset, i, seed));
728             }
729         }
730     }
731 
732     /**
733      * Test to demonstrate the errors in {@link MurmurHash3#hash32(byte[], int, int, int)} if the final 1, 2, or 3 bytes are negative.
734      */
735     @Test
736     public void testHash32WithTrailingNegativeSignedBytesIsInvalid() {
737         // import mmh3
738         // import numpy as np
739         // mmh3.hash(np.uint8([-1]))
740         // mmh3.hash(np.uint8([0, -1]))
741         // mmh3.hash(np.uint8([0, 0, -1]))
742         // mmh3.hash(np.uint8([-1, 0]))
743         // mmh3.hash(np.uint8([-1, 0, 0]))
744         // mmh3.hash(np.uint8([0, -1, 0]))
745         assertNotEquals(-43192051, MurmurHash3.hash32(new byte[] { -1 }, 0, 1, 0));
746         assertNotEquals(-582037868, MurmurHash3.hash32(new byte[] { 0, -1 }, 0, 2, 0));
747         assertNotEquals(922088087, MurmurHash3.hash32(new byte[] { 0, 0, -1 }, 0, 3, 0));
748         assertNotEquals(-1309567588, MurmurHash3.hash32(new byte[] { -1, 0 }, 0, 2, 0));
749         assertNotEquals(-363779670, MurmurHash3.hash32(new byte[] { -1, 0, 0 }, 0, 3, 0));
750         assertNotEquals(-225068062, MurmurHash3.hash32(new byte[] { 0, -1, 0 }, 0, 3, 0));
751     }
752 
753     /**
754      * Test the {@link MurmurHash3#hash32x86(byte[])} algorithm.
755      *
756      * <p>
757      * Reference data is taken from the Python library {@code mmh3}.
758      * </p>
759      *
760      * @see <a href="https://pypi.org/project/mmh3/">mmh3</a>
761      */
762     @Test
763     public void testHash32x86() {
764         // Note: Default seed is zero.
765 
766         // mmh3.hash(bytes, 0)
767         assertEquals(1546271276, MurmurHash3.hash32x86(RANDOM_BYTES));
768 
769         // Test with all sizes up to 31 bytes. This ensures a full round of 16-bytes plus up to
770         // 15 bytes remaining.
771         // for x in range(0, 32):
772         // print(mmh3.hash(bytes[:x], 0), ',')
773         final int[] answers = { 0, -1353253853, 915381745, -734983419, 1271125654, -1042265893, -1204521619, 735845843, 138310876, -1918938664, 1399647898,
774                 -1126342309, 2067593280, 1220975287, 1941281084, -1289513180, 942412060, -618173583, -269546647, -1645631262, 1162379906, -1960125577,
775                 -1856773195, 1980513522, 1174612855, 905810751, 1044578220, -1758486689, -491393913, 839836946, -435014415, 2044851178 };
776         for (int i = 0; i < answers.length; i++) {
777             final byte[] bytes = Arrays.copyOf(RANDOM_BYTES, i);
778             assertEquals(answers[i], MurmurHash3.hash32x86(bytes));
779         }
780     }
781 
782     /**
783      * Test the {@link MurmurHash3#hash32x86(byte[], int, int, int)} algorithm.
784      *
785      * <p>
786      * Reference data is taken from the Python library {@code mmh3}.
787      * </p>
788      *
789      * @see <a href="https://pypi.org/project/mmh3/">mmh3</a>
790      */
791     @Test
792     public void testHash32x86WithOffsetLengthAndSeed() {
793         // Data as above for testing MurmurHash3.hash32(byte[], int, int, int).
794         final int seed = -42;
795         final int offset = 13;
796         final int[] answers = { 192929823, -27171978, -1282326280, -816314453, -1176217753, -1904531247, 1962794233, -1302316624, -1151850323, -1464386748,
797                 -369299427, 972232488, 1747314487, 2137398916, 690986564, -1985866226, -678669121, -2123325690, -253319081, 46181235, 656058278, 1401175653,
798                 1750113912, -1567219725, 2032742772, -2024269989, -305340794, 1161737942, -661265418, 172838872, -650122718, -1934812417 };
799         for (int i = 0; i < answers.length; i++) {
800             assertEquals(answers[i], MurmurHash3.hash32x86(RANDOM_BYTES, offset, i, seed));
801         }
802     }
803 
804     /**
805      * Test to demonstrate {@link MurmurHash3#hash32x86(byte[], int, int, int)} is OK if the final 1, 2, or 3 bytes are negative.
806      */
807     @Test
808     public void testHash32x86WithTrailingNegativeSignedBytes() {
809         // Data as above for testing MurmurHash3.hash32(byte[], int, int, int).
810         // This test uses assertEquals().
811         assertEquals(-43192051, MurmurHash3.hash32x86(new byte[] { -1 }, 0, 1, 0));
812         assertEquals(-582037868, MurmurHash3.hash32x86(new byte[] { 0, -1 }, 0, 2, 0));
813         assertEquals(922088087, MurmurHash3.hash32x86(new byte[] { 0, 0, -1 }, 0, 3, 0));
814         assertEquals(-1309567588, MurmurHash3.hash32x86(new byte[] { -1, 0 }, 0, 2, 0));
815         assertEquals(-363779670, MurmurHash3.hash32x86(new byte[] { -1, 0, 0 }, 0, 3, 0));
816         assertEquals(-225068062, MurmurHash3.hash32x86(new byte[] { 0, -1, 0 }, 0, 3, 0));
817     }
818 
819     /**
820      * Test the {@link MurmurHash3#hash64(byte[])} algorithm. Unknown origin of test data. It may be from the Apache Hive project.
821      */
822     @Test
823     public void testHash64() {
824         final byte[] origin = StringUtils.getBytesUtf8(TEST_HASH64);
825         final long hash = MurmurHash3.hash64(origin);
826         assertEquals(5785358552565094607L, hash);
827     }
828 
829     /**
830      * Test the {@link MurmurHash3#hash64(byte[])} method is Murmur3-like but does not match the bits returned from {@link MurmurHash3#hash128(byte[])}.
831      *
832      * <p>
833      * The hash64 method is not in the MurmurHash3 reference code and has been inherited from the port from Apache Hive.
834      * <p>
835      */
836     @Test
837     public void testHash64InNotEqualToHash128() {
838         for (int i = 0; i < 32; i++) {
839             final byte[] bytes = Arrays.copyOf(RANDOM_BYTES, i);
840             final long h1 = MurmurHash3.hash64(bytes);
841             final long[] hash = MurmurHash3.hash128(bytes);
842             assertNotEquals(hash[0], h1, "Did not expect hash64 to match upper bits of hash128");
843             assertNotEquals(hash[1], h1, "Did not expect hash64 to match lower bits of hash128");
844         }
845     }
846 
847     /**
848      * Test the {@link MurmurHash3#hash64(byte[], int, int)} algorithm. Unknown origin of test data. It may be from the Apache Hive project.
849      */
850     @Test
851     public void testHash64WithOffsetAndLength() {
852         final byte[] origin = StringUtils.getBytesUtf8(TEST_HASH64);
853         final byte[] originOffset = new byte[origin.length + 150];
854         Arrays.fill(originOffset, (byte) 123);
855         System.arraycopy(origin, 0, originOffset, 150, origin.length);
856         final long hash = MurmurHash3.hash64(originOffset, 150, origin.length);
857         assertEquals(5785358552565094607L, hash);
858     }
859 
860     /**
861      * Test the hash64() helper methods that work directly on primitives work as documented. This test the methods return the same value as
862      * {@link MurmurHash3#hash64(byte[])} with the byte[] created from the same primitive data via a {@link ByteBuffer}.
863      */
864     @Test
865     public void testHash64WithPrimitives() {
866         // As described in the Javadoc
867         final int offset = 0;
868         final int seed = 104729;
869 
870         final int iters = 1000;
871         final ByteBuffer shortBuffer = ByteBuffer.allocate(Short.BYTES);
872         final ByteBuffer intBuffer = ByteBuffer.allocate(Integer.BYTES);
873         final ByteBuffer longBuffer = ByteBuffer.allocate(Long.BYTES);
874         final byte[] shortBytes = shortBuffer.array();
875         final byte[] intBytes = intBuffer.array();
876         final byte[] longBytes = longBuffer.array();
877         for (int i = 0; i < iters; ++i) {
878             final long ln = ThreadLocalRandom.current().nextLong();
879             // Shift bits to bet different bytes
880             final int in = (int) (ln >>> 3);
881             final short sn = (short) (ln >>> 5);
882             shortBuffer.putShort(0, sn);
883             assertEquals(MurmurHash3.hash64(shortBytes, offset, shortBytes.length, seed), MurmurHash3.hash64(sn));
884             intBuffer.putInt(0, in);
885             assertEquals(MurmurHash3.hash64(intBytes, offset, intBytes.length, seed), MurmurHash3.hash64(in));
886             longBuffer.putLong(0, ln);
887             assertEquals(MurmurHash3.hash64(longBytes, offset, longBytes.length, seed), MurmurHash3.hash64(ln));
888         }
889     }
890 
891     /**
892      * Test {@link IncrementalHash32} returns the same values as {@link MurmurHash3#hash32(byte[], int, int, int)}.
893      */
894     @Test
895     public void testIncrementalHash32() {
896         final byte[] bytes = new byte[1023];
897         ThreadLocalRandom.current().nextBytes(bytes);
898         // The seed does not matter
899         for (final int seed : new int[] { -567, 0, 6787990 }) {
900             // Cases are constructed to hit all edge cases of processing:
901             // Nothing added
902             assertIncrementalHash32(bytes, seed, 0, 0);
903             // Add single bytes
904             assertIncrementalHash32(bytes, seed, 1, 1, 1, 1, 1, 1, 1, 1);
905             // Leading unprocessed 1, 2, 3
906             assertIncrementalHash32(bytes, seed, 1, 4);
907             assertIncrementalHash32(bytes, seed, 2, 4);
908             assertIncrementalHash32(bytes, seed, 3, 4);
909             // Trailing unprocessed 1, 2, 3
910             assertIncrementalHash32(bytes, seed, 4, 1);
911             assertIncrementalHash32(bytes, seed, 4, 2);
912             assertIncrementalHash32(bytes, seed, 4, 3);
913             // Complete blocks
914             assertIncrementalHash32(bytes, seed, 4, 16, 64);
915             // Some random blocks
916             for (int i = 0; i < 10; i++) {
917                 assertIncrementalHash32x86(bytes, seed, createRandomBlocks(bytes.length));
918             }
919         }
920     }
921 
922     /**
923      * Test {@link IncrementalHash32x86} returns the same values as {@link MurmurHash3#hash32x86(byte[], int, int, int)}.
924      */
925     @Test
926     public void testIncrementalHash32x86() {
927         final byte[] bytes = new byte[1023];
928         ThreadLocalRandom.current().nextBytes(bytes);
929         // The seed does not matter
930         for (final int seed : new int[] { -567, 0, 6787990 }) {
931             // Cases are constructed to hit all edge cases of processing:
932             // Nothing added
933             assertIncrementalHash32x86(bytes, seed, 0, 0);
934             // Add single bytes
935             assertIncrementalHash32x86(bytes, seed, 1, 1, 1, 1, 1, 1, 1, 1);
936             // Leading unprocessed 1, 2, 3
937             assertIncrementalHash32x86(bytes, seed, 1, 4);
938             assertIncrementalHash32x86(bytes, seed, 2, 4);
939             assertIncrementalHash32x86(bytes, seed, 3, 4);
940             // Trailing unprocessed 1, 2, 3
941             assertIncrementalHash32x86(bytes, seed, 4, 1);
942             assertIncrementalHash32x86(bytes, seed, 4, 2);
943             assertIncrementalHash32x86(bytes, seed, 4, 3);
944             // Complete blocks
945             assertIncrementalHash32x86(bytes, seed, 4, 16, 64);
946             // Some random blocks
947             for (int i = 0; i < 10; i++) {
948                 assertIncrementalHash32x86(bytes, seed, createRandomBlocks(bytes.length));
949             }
950         }
951     }
952 
953     /**
954      * This test hits an edge case where a very large number of bytes is added to the incremental hash. The data is constructed so that an integer counter of
955      * unprocessed bytes will overflow. If this is not handled correctly then the code throws an exception when it copies more data into the unprocessed bytes
956      * array.
957      */
958     @Test
959     public void testIncrementalHashWithUnprocessedBytesAndHugeLengthArray() {
960         // Assert the test precondition that a large array added to unprocessed bytes
961         // will overflow an integer counter. We use the smallest hugeLength possible
962         // as some VMs cannot allocate maximum length arrays.
963         final int unprocessedSize = 3;
964         final int hugeLength = Integer.MAX_VALUE - 2;
965         assertTrue(unprocessedSize + hugeLength < 4, "This should overflow to negative");
966 
967         // Check the test can be run
968         byte[] bytes = null;
969         try {
970             bytes = new byte[hugeLength];
971         } catch (final OutOfMemoryError ignore) {
972             // Some VMs cannot allocate an array this large.
973             // Some test environments may not have enough available memory for this.
974         }
975         assumeTrue(bytes != null, "Cannot allocate array of length " + hugeLength);
976 
977         final IncrementalHash32x86 inc = new IncrementalHash32x86();
978         inc.start(0);
979         // Add bytes that should be unprocessed
980         inc.add(bytes, 0, unprocessedSize);
981         // Add a huge number of bytes to overflow an integer counter of unprocessed bytes.
982         inc.add(bytes, 0, hugeLength);
983     }
984 }