• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2011 The Guava Authors
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.google.common.hash;
18 
19 import static com.google.common.base.Charsets.UTF_8;
20 import static java.util.Arrays.asList;
21 
22 import com.google.common.collect.ImmutableList;
23 import com.google.common.collect.ImmutableTable;
24 import com.google.common.collect.Lists;
25 import com.google.common.collect.Table.Cell;
26 import com.google.common.primitives.Ints;
27 import com.google.common.testing.EqualsTester;
28 import com.google.common.testing.NullPointerTester;
29 import com.google.common.util.concurrent.AtomicLongMap;
30 import java.lang.reflect.Method;
31 import java.lang.reflect.Modifier;
32 import java.nio.ByteBuffer;
33 import java.util.Collections;
34 import java.util.List;
35 import java.util.Locale;
36 import java.util.Random;
37 import junit.framework.TestCase;
38 
39 /**
40  * Unit tests for {@link Hashing}.
41  *
42  * <p>TODO(b/33919189): Migrate repeated testing methods to {@link #HashTestUtils} and tweak unit
43  * tests to reference them from there.
44  *
45  * @author Dimitris Andreou
46  * @author Kurt Alfred Kluever
47  */
48 public class HashingTest extends TestCase {
testMd5()49   public void testMd5() {
50     HashTestUtils.checkAvalanche(Hashing.md5(), 100, 0.4);
51     HashTestUtils.checkNo2BitCharacteristics(Hashing.md5());
52     HashTestUtils.checkNoFunnels(Hashing.md5());
53     HashTestUtils.assertInvariants(Hashing.md5());
54     assertEquals("Hashing.md5()", Hashing.md5().toString());
55   }
56 
testSha1()57   public void testSha1() {
58     HashTestUtils.checkAvalanche(Hashing.sha1(), 100, 0.4);
59     HashTestUtils.checkNo2BitCharacteristics(Hashing.sha1());
60     HashTestUtils.checkNoFunnels(Hashing.sha1());
61     HashTestUtils.assertInvariants(Hashing.sha1());
62     assertEquals("Hashing.sha1()", Hashing.sha1().toString());
63   }
64 
testSha256()65   public void testSha256() {
66     HashTestUtils.checkAvalanche(Hashing.sha256(), 100, 0.4);
67     HashTestUtils.checkNo2BitCharacteristics(Hashing.sha256());
68     HashTestUtils.checkNoFunnels(Hashing.sha256());
69     HashTestUtils.assertInvariants(Hashing.sha256());
70     assertEquals("Hashing.sha256()", Hashing.sha256().toString());
71   }
72 
testSha384()73   public void testSha384() {
74     HashTestUtils.checkAvalanche(Hashing.sha384(), 100, 0.4);
75     HashTestUtils.checkNo2BitCharacteristics(Hashing.sha384());
76     HashTestUtils.checkNoFunnels(Hashing.sha384());
77     HashTestUtils.assertInvariants(Hashing.sha384());
78     assertEquals("Hashing.sha384()", Hashing.sha384().toString());
79   }
80 
testSha512()81   public void testSha512() {
82     HashTestUtils.checkAvalanche(Hashing.sha512(), 100, 0.4);
83     HashTestUtils.checkNo2BitCharacteristics(Hashing.sha512());
84     HashTestUtils.checkNoFunnels(Hashing.sha512());
85     HashTestUtils.assertInvariants(Hashing.sha512());
86     assertEquals("Hashing.sha512()", Hashing.sha512().toString());
87   }
88 
testCrc32()89   public void testCrc32() {
90     HashTestUtils.assertInvariants(Hashing.crc32());
91     assertEquals("Hashing.crc32()", Hashing.crc32().toString());
92   }
93 
testAdler32()94   public void testAdler32() {
95     HashTestUtils.assertInvariants(Hashing.adler32());
96     assertEquals("Hashing.adler32()", Hashing.adler32().toString());
97   }
98 
testMurmur3_128()99   public void testMurmur3_128() {
100     HashTestUtils.check2BitAvalanche(Hashing.murmur3_128(), 250, 0.20);
101     HashTestUtils.checkAvalanche(Hashing.murmur3_128(), 250, 0.17);
102     HashTestUtils.checkNo2BitCharacteristics(Hashing.murmur3_128());
103     HashTestUtils.checkNoFunnels(Hashing.murmur3_128());
104     HashTestUtils.assertInvariants(Hashing.murmur3_128());
105     assertEquals("Hashing.murmur3_128(0)", Hashing.murmur3_128().toString());
106   }
107 
testMurmur3_32()108   public void testMurmur3_32() {
109     HashTestUtils.check2BitAvalanche(Hashing.murmur3_32(), 250, 0.20);
110     HashTestUtils.checkAvalanche(Hashing.murmur3_32(), 250, 0.17);
111     HashTestUtils.checkNo2BitCharacteristics(Hashing.murmur3_32());
112     HashTestUtils.checkNoFunnels(Hashing.murmur3_32());
113     HashTestUtils.assertInvariants(Hashing.murmur3_32());
114     assertEquals("Hashing.murmur3_32(0)", Hashing.murmur3_32().toString());
115   }
116 
testSipHash24()117   public void testSipHash24() {
118     HashTestUtils.check2BitAvalanche(Hashing.sipHash24(), 250, 0.14);
119     HashTestUtils.checkAvalanche(Hashing.sipHash24(), 250, 0.10);
120     HashTestUtils.checkNo2BitCharacteristics(Hashing.sipHash24());
121     HashTestUtils.checkNoFunnels(Hashing.sipHash24());
122     HashTestUtils.assertInvariants(Hashing.sipHash24());
123     assertEquals(
124         "Hashing.sipHash24(506097522914230528, 1084818905618843912)",
125         Hashing.sipHash24().toString());
126   }
127 
128   @AndroidIncompatible // slow TODO(cpovirk): Maybe just reduce iterations under Android.
testGoodFastHash()129   public void testGoodFastHash() {
130     for (int i = 1; i < 200; i += 17) {
131       HashFunction hasher = Hashing.goodFastHash(i);
132       assertTrue(hasher.bits() >= i);
133       HashTestUtils.assertInvariants(hasher);
134     }
135   }
136 
137   // goodFastHash(32) uses Murmur3_32. Use the same epsilon bounds.
testGoodFastHash32()138   public void testGoodFastHash32() {
139     HashTestUtils.check2BitAvalanche(Hashing.goodFastHash(32), 250, 0.20);
140     HashTestUtils.checkAvalanche(Hashing.goodFastHash(32), 250, 0.17);
141     HashTestUtils.checkNo2BitCharacteristics(Hashing.goodFastHash(32));
142     HashTestUtils.checkNoFunnels(Hashing.goodFastHash(32));
143     HashTestUtils.assertInvariants(Hashing.goodFastHash(32));
144   }
145 
146   // goodFastHash(128) uses Murmur3_128. Use the same epsilon bounds.
testGoodFastHash128()147   public void testGoodFastHash128() {
148     HashTestUtils.check2BitAvalanche(Hashing.goodFastHash(128), 250, 0.20);
149     HashTestUtils.checkAvalanche(Hashing.goodFastHash(128), 500, 0.17);
150     HashTestUtils.checkNo2BitCharacteristics(Hashing.goodFastHash(128));
151     HashTestUtils.checkNoFunnels(Hashing.goodFastHash(128));
152     HashTestUtils.assertInvariants(Hashing.goodFastHash(128));
153   }
154 
155   // goodFastHash(256) uses Murmur3_128. Use the same epsilon bounds.
testGoodFastHash256()156   public void testGoodFastHash256() {
157     HashTestUtils.check2BitAvalanche(Hashing.goodFastHash(256), 250, 0.20);
158     HashTestUtils.checkAvalanche(Hashing.goodFastHash(256), 500, 0.17);
159     HashTestUtils.checkNo2BitCharacteristics(Hashing.goodFastHash(256));
160     HashTestUtils.checkNoFunnels(Hashing.goodFastHash(256));
161     HashTestUtils.assertInvariants(Hashing.goodFastHash(256));
162   }
163 
testConsistentHash_correctness()164   public void testConsistentHash_correctness() {
165     long[] interestingValues = {-1, 0, 1, 2, Long.MAX_VALUE, Long.MIN_VALUE};
166     for (long h : interestingValues) {
167       checkConsistentHashCorrectness(h);
168     }
169     Random r = new Random(7);
170     for (int i = 0; i < 20; i++) {
171       checkConsistentHashCorrectness(r.nextLong());
172     }
173   }
174 
checkConsistentHashCorrectness(long hashCode)175   private void checkConsistentHashCorrectness(long hashCode) {
176     int last = 0;
177     for (int shards = 1; shards <= 100000; shards++) {
178       int b = Hashing.consistentHash(hashCode, shards);
179       if (b != last) {
180         assertEquals(shards - 1, b);
181         last = b;
182       }
183     }
184   }
185 
testConsistentHash_probabilities()186   public void testConsistentHash_probabilities() {
187     AtomicLongMap<Integer> map = AtomicLongMap.create();
188     Random r = new Random(9);
189     for (int i = 0; i < ITERS; i++) {
190       countRemaps(r.nextLong(), map);
191     }
192     for (int shard = 2; shard <= MAX_SHARDS; shard++) {
193       // Rough: don't exceed 1.2x the expected number of remaps by more than 20
194       assertTrue(map.get(shard) <= 1.2 * ITERS / shard + 20);
195     }
196   }
197 
countRemaps(long h, AtomicLongMap<Integer> map)198   private void countRemaps(long h, AtomicLongMap<Integer> map) {
199     int last = 0;
200     for (int shards = 2; shards <= MAX_SHARDS; shards++) {
201       int chosen = Hashing.consistentHash(h, shards);
202       if (chosen != last) {
203         map.incrementAndGet(shards);
204         last = chosen;
205       }
206     }
207   }
208 
209   private static final int ITERS = 10000;
210   private static final int MAX_SHARDS = 500;
211 
testConsistentHash_outOfRange()212   public void testConsistentHash_outOfRange() {
213     try {
214       Hashing.consistentHash(5L, 0);
215       fail();
216     } catch (IllegalArgumentException expected) {
217     }
218   }
219 
testConsistentHash_ofHashCode()220   public void testConsistentHash_ofHashCode() {
221     checkSameResult(HashCode.fromLong(1), 1);
222     checkSameResult(HashCode.fromLong(0x9999999999999999L), 0x9999999999999999L);
223     checkSameResult(HashCode.fromInt(0x99999999), 0x0000000099999999L);
224   }
225 
checkSameResult(HashCode hashCode, long equivLong)226   public void checkSameResult(HashCode hashCode, long equivLong) {
227     assertEquals(Hashing.consistentHash(equivLong, 5555), Hashing.consistentHash(hashCode, 5555));
228   }
229 
230   /**
231    * Check a few "golden" values to see that implementations across languages are equivalent.
232    *
233    */
testConsistentHash_linearCongruentialGeneratorCompatibility()234   public void testConsistentHash_linearCongruentialGeneratorCompatibility() {
235     int[] golden100 = {
236       0, 55, 62, 8, 45, 59, 86, 97, 82, 59,
237       73, 37, 17, 56, 86, 21, 90, 37, 38, 83
238     };
239     for (int i = 0; i < golden100.length; i++) {
240       assertEquals(golden100[i], Hashing.consistentHash(i, 100));
241     }
242     assertEquals(6, Hashing.consistentHash(10863919174838991L, 11));
243     assertEquals(3, Hashing.consistentHash(2016238256797177309L, 11));
244     assertEquals(5, Hashing.consistentHash(1673758223894951030L, 11));
245     assertEquals(80343, Hashing.consistentHash(2, 100001));
246     assertEquals(22152, Hashing.consistentHash(2201, 100001));
247     assertEquals(15018, Hashing.consistentHash(2202, 100001));
248   }
249 
250   private static final double MAX_PERCENT_SPREAD = 0.5;
251   private static final long RANDOM_SEED = 177L;
252 
testCombineOrdered_empty()253   public void testCombineOrdered_empty() {
254     try {
255       Hashing.combineOrdered(Collections.<HashCode>emptySet());
256       fail();
257     } catch (IllegalArgumentException expected) {
258     }
259   }
260 
testCombineOrdered_differentBitLengths()261   public void testCombineOrdered_differentBitLengths() {
262     try {
263       HashCode unused =
264           Hashing.combineOrdered(ImmutableList.of(HashCode.fromInt(32), HashCode.fromLong(32L)));
265       fail();
266     } catch (IllegalArgumentException expected) {
267     }
268   }
269 
testCombineOrdered()270   public void testCombineOrdered() {
271     HashCode hash31 = HashCode.fromInt(31);
272     HashCode hash32 = HashCode.fromInt(32);
273     assertEquals(hash32, Hashing.combineOrdered(ImmutableList.of(hash32)));
274     assertEquals(
275         HashCode.fromBytes(new byte[] {(byte) 0x80, 0, 0, 0}),
276         Hashing.combineOrdered(ImmutableList.of(hash32, hash32)));
277     assertEquals(
278         HashCode.fromBytes(new byte[] {(byte) 0xa0, 0, 0, 0}),
279         Hashing.combineOrdered(ImmutableList.of(hash32, hash32, hash32)));
280     assertFalse(
281         Hashing.combineOrdered(ImmutableList.of(hash31, hash32))
282             .equals(Hashing.combineOrdered(ImmutableList.of(hash32, hash31))));
283   }
284 
testCombineOrdered_randomHashCodes()285   public void testCombineOrdered_randomHashCodes() {
286     Random random = new Random(7);
287     List<HashCode> hashCodes = Lists.newArrayList();
288     for (int i = 0; i < 10; i++) {
289       hashCodes.add(HashCode.fromLong(random.nextLong()));
290     }
291     HashCode hashCode1 = Hashing.combineOrdered(hashCodes);
292     Collections.shuffle(hashCodes, random);
293     HashCode hashCode2 = Hashing.combineOrdered(hashCodes);
294 
295     assertFalse(hashCode1.equals(hashCode2));
296   }
297 
testCombineUnordered_empty()298   public void testCombineUnordered_empty() {
299     try {
300       Hashing.combineUnordered(Collections.<HashCode>emptySet());
301       fail();
302     } catch (IllegalArgumentException expected) {
303     }
304   }
305 
testCombineUnordered_differentBitLengths()306   public void testCombineUnordered_differentBitLengths() {
307     try {
308       HashCode unused =
309           Hashing.combineUnordered(ImmutableList.of(HashCode.fromInt(32), HashCode.fromLong(32L)));
310       fail();
311     } catch (IllegalArgumentException expected) {
312     }
313   }
314 
testCombineUnordered()315   public void testCombineUnordered() {
316     HashCode hash31 = HashCode.fromInt(31);
317     HashCode hash32 = HashCode.fromInt(32);
318     assertEquals(hash32, Hashing.combineUnordered(ImmutableList.of(hash32)));
319     assertEquals(HashCode.fromInt(64), Hashing.combineUnordered(ImmutableList.of(hash32, hash32)));
320     assertEquals(
321         HashCode.fromInt(96), Hashing.combineUnordered(ImmutableList.of(hash32, hash32, hash32)));
322     assertEquals(
323         Hashing.combineUnordered(ImmutableList.of(hash31, hash32)),
324         Hashing.combineUnordered(ImmutableList.of(hash32, hash31)));
325   }
326 
testCombineUnordered_randomHashCodes()327   public void testCombineUnordered_randomHashCodes() {
328     Random random = new Random(RANDOM_SEED);
329     List<HashCode> hashCodes = Lists.newArrayList();
330     for (int i = 0; i < 10; i++) {
331       hashCodes.add(HashCode.fromLong(random.nextLong()));
332     }
333     HashCode hashCode1 = Hashing.combineUnordered(hashCodes);
334     Collections.shuffle(hashCodes);
335     HashCode hashCode2 = Hashing.combineUnordered(hashCodes);
336 
337     assertEquals(hashCode1, hashCode2);
338   }
339 
340   // This isn't specified by contract, but it'll still be nice to know if this behavior changes.
testConcatenating_equals()341   public void testConcatenating_equals() {
342     new EqualsTester()
343         .addEqualityGroup(Hashing.concatenating(asList(Hashing.md5())))
344         .addEqualityGroup(Hashing.concatenating(asList(Hashing.murmur3_32())))
345         .addEqualityGroup(
346             Hashing.concatenating(Hashing.md5(), Hashing.md5()),
347             Hashing.concatenating(asList(Hashing.md5(), Hashing.md5())))
348         .addEqualityGroup(
349             Hashing.concatenating(Hashing.murmur3_32(), Hashing.md5()),
350             Hashing.concatenating(asList(Hashing.murmur3_32(), Hashing.md5())))
351         .addEqualityGroup(
352             Hashing.concatenating(Hashing.md5(), Hashing.murmur3_32()),
353             Hashing.concatenating(asList(Hashing.md5(), Hashing.murmur3_32())))
354         .testEquals();
355   }
356 
testConcatenatingIterable_bits()357   public void testConcatenatingIterable_bits() {
358     assertEquals(
359         Hashing.md5().bits() + Hashing.md5().bits(),
360         Hashing.concatenating(asList(Hashing.md5(), Hashing.md5())).bits());
361     assertEquals(
362         Hashing.md5().bits() + Hashing.murmur3_32().bits(),
363         Hashing.concatenating(asList(Hashing.md5(), Hashing.murmur3_32())).bits());
364     assertEquals(
365         Hashing.md5().bits() + Hashing.murmur3_32().bits() + Hashing.murmur3_128().bits(),
366         Hashing.concatenating(asList(Hashing.md5(), Hashing.murmur3_32(), Hashing.murmur3_128()))
367             .bits());
368   }
369 
testConcatenatingVarArgs_bits()370   public void testConcatenatingVarArgs_bits() {
371     assertEquals(
372         Hashing.md5().bits() + Hashing.md5().bits(),
373         Hashing.concatenating(Hashing.md5(), Hashing.md5()).bits());
374     assertEquals(
375         Hashing.md5().bits() + Hashing.murmur3_32().bits(),
376         Hashing.concatenating(Hashing.md5(), Hashing.murmur3_32()).bits());
377     assertEquals(
378         Hashing.md5().bits() + Hashing.murmur3_32().bits() + Hashing.murmur3_128().bits(),
379         Hashing.concatenating(Hashing.md5(), Hashing.murmur3_32(), Hashing.murmur3_128()).bits());
380   }
381 
testConcatenatingHashFunction_makeHash()382   public void testConcatenatingHashFunction_makeHash() {
383     byte[] md5Hash = Hashing.md5().hashLong(42L).asBytes();
384     byte[] murmur3Hash = Hashing.murmur3_32().hashLong(42L).asBytes();
385     byte[] combined = new byte[md5Hash.length + murmur3Hash.length];
386     ByteBuffer buffer = ByteBuffer.wrap(combined);
387     buffer.put(md5Hash);
388     buffer.put(murmur3Hash);
389     HashCode expected = HashCode.fromBytes(combined);
390 
391     assertEquals(
392         expected, Hashing.concatenating(Hashing.md5(), Hashing.murmur3_32()).hashLong(42L));
393     assertEquals(
394         expected, Hashing.concatenating(asList(Hashing.md5(), Hashing.murmur3_32())).hashLong(42L));
395   }
396 
testHashIntReverseBytesVsHashBytesIntsToByteArray()397   public void testHashIntReverseBytesVsHashBytesIntsToByteArray() {
398     int input = 42;
399     assertEquals(
400         Hashing.md5().hashBytes(Ints.toByteArray(input)),
401         Hashing.md5().hashInt(Integer.reverseBytes(input)));
402   }
403 
testHashIntVsForLoop()404   public void testHashIntVsForLoop() {
405     int input = 42;
406     HashCode expected = Hashing.md5().hashInt(input);
407 
408     Hasher hasher = Hashing.md5().newHasher();
409     for (int i = 0; i < 32; i += 8) {
410       hasher.putByte((byte) (input >> i));
411     }
412     HashCode actual = hasher.hash();
413 
414     assertEquals(expected, actual);
415   }
416 
417   private static final String EMPTY_STRING = "";
418   private static final String TQBFJOTLD = "The quick brown fox jumps over the lazy dog";
419   private static final String TQBFJOTLDP = "The quick brown fox jumps over the lazy dog.";
420 
421   private static final ImmutableTable<HashFunction, String, String> KNOWN_HASHES =
422       ImmutableTable.<HashFunction, String, String>builder()
423           .put(Hashing.adler32(), EMPTY_STRING, "01000000")
424           .put(Hashing.adler32(), TQBFJOTLD, "da0fdc5b")
425           .put(Hashing.adler32(), TQBFJOTLDP, "0810e46b")
426           .put(Hashing.md5(), EMPTY_STRING, "d41d8cd98f00b204e9800998ecf8427e")
427           .put(Hashing.md5(), TQBFJOTLD, "9e107d9d372bb6826bd81d3542a419d6")
428           .put(Hashing.md5(), TQBFJOTLDP, "e4d909c290d0fb1ca068ffaddf22cbd0")
429           .put(Hashing.murmur3_128(), EMPTY_STRING, "00000000000000000000000000000000")
430           .put(Hashing.murmur3_128(), TQBFJOTLD, "6c1b07bc7bbc4be347939ac4a93c437a")
431           .put(Hashing.murmur3_128(), TQBFJOTLDP, "c902e99e1f4899cde7b68789a3a15d69")
432           .put(Hashing.murmur3_32(), EMPTY_STRING, "00000000")
433           .put(Hashing.murmur3_32(), TQBFJOTLD, "23f74f2e")
434           .put(Hashing.murmur3_32(), TQBFJOTLDP, "fc8bc4d5")
435           .put(Hashing.murmur3_32_fixed(), EMPTY_STRING, "00000000")
436           .put(Hashing.murmur3_32_fixed(), TQBFJOTLD, "23f74f2e")
437           .put(Hashing.murmur3_32_fixed(), TQBFJOTLDP, "fc8bc4d5")
438           .put(Hashing.sha1(), EMPTY_STRING, "da39a3ee5e6b4b0d3255bfef95601890afd80709")
439           .put(Hashing.sha1(), TQBFJOTLD, "2fd4e1c67a2d28fced849ee1bb76e7391b93eb12")
440           .put(Hashing.sha1(), TQBFJOTLDP, "408d94384216f890ff7a0c3528e8bed1e0b01621")
441           .put(
442               Hashing.sha256(),
443               EMPTY_STRING,
444               "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855")
445           .put(
446               Hashing.sha256(),
447               TQBFJOTLD,
448               "d7a8fbb307d7809469ca9abcb0082e4f8d5651e46d3cdb762d02d0bf37c9e592")
449           .put(
450               Hashing.sha256(),
451               TQBFJOTLDP,
452               "ef537f25c895bfa782526529a9b63d97aa631564d5d789c2b765448c8635fb6c")
453           .put(
454               Hashing.sha384(),
455               EMPTY_STRING,
456               "38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da2"
457                   + "74edebfe76f65fbd51ad2f14898b95b")
458           .put(
459               Hashing.sha384(),
460               TQBFJOTLD,
461               "ca737f1014a48f4c0b6dd43cb177b0afd9e5169367544c494011e3317dbf9a509"
462                   + "cb1e5dc1e85a941bbee3d7f2afbc9b1")
463           .put(
464               Hashing.sha384(),
465               TQBFJOTLDP,
466               "ed892481d8272ca6df370bf706e4d7bc1b5739fa2177aae6c50e946678718fc67"
467                   + "a7af2819a021c2fc34e91bdb63409d7")
468           .put(
469               Hashing.sha512(),
470               EMPTY_STRING,
471               "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce"
472                   + "47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e")
473           .put(
474               Hashing.sha512(),
475               TQBFJOTLD,
476               "07e547d9586f6a73f73fbac0435ed76951218fb7d0c8d788a309d785436bbb64"
477                   + "2e93a252a954f23912547d1e8a3b5ed6e1bfd7097821233fa0538f3db854fee6")
478           .put(
479               Hashing.sha512(),
480               TQBFJOTLDP,
481               "91ea1245f20d46ae9a037a989f54f1f790f0a47607eeb8a14d12890cea77a1bb"
482                   + "c6c7ed9cf205e67b7f2b8fd4c7dfd3a7a8617e45f3c463d481c7e586c39ac1ed")
483           .put(Hashing.crc32(), EMPTY_STRING, "00000000")
484           .put(Hashing.crc32(), TQBFJOTLD, "39a34f41")
485           .put(Hashing.crc32(), TQBFJOTLDP, "e9259051")
486           .put(Hashing.sipHash24(), EMPTY_STRING, "310e0edd47db6f72")
487           .put(Hashing.sipHash24(), TQBFJOTLD, "e46f1fdc05612752")
488           .put(Hashing.sipHash24(), TQBFJOTLDP, "9b602581fce4d4f8")
489           .put(Hashing.crc32c(), EMPTY_STRING, "00000000")
490           .put(Hashing.crc32c(), TQBFJOTLD, "04046222")
491           .put(Hashing.crc32c(), TQBFJOTLDP, "b3970019")
492           .put(Hashing.farmHashFingerprint64(), EMPTY_STRING, "4f40902f3b6ae19a")
493           .put(Hashing.farmHashFingerprint64(), TQBFJOTLD, "34511b3bf383beab")
494           .put(Hashing.farmHashFingerprint64(), TQBFJOTLDP, "737d7e5f8660653e")
495           .build();
496 
testAllHashFunctionsHaveKnownHashes()497   public void testAllHashFunctionsHaveKnownHashes() throws Exception {
498     // The following legacy hashing function methods have been covered by unit testing already.
499     List<String> legacyHashingMethodNames = ImmutableList.of("murmur2_64", "fprint96");
500     for (Method method : Hashing.class.getDeclaredMethods()) {
501       if (method.getReturnType().equals(HashFunction.class) // must return HashFunction
502           && Modifier.isPublic(method.getModifiers()) // only the public methods
503           && method.getParameterTypes().length == 0 // only the seed-less grapes^W hash functions
504           && !legacyHashingMethodNames.contains(method.getName())) {
505         HashFunction hashFunction = (HashFunction) method.invoke(Hashing.class);
506         assertTrue(
507             "There should be at least 3 entries in KNOWN_HASHES for " + hashFunction,
508             KNOWN_HASHES.row(hashFunction).size() >= 3);
509       }
510     }
511   }
512 
testKnownUtf8Hashing()513   public void testKnownUtf8Hashing() {
514     for (Cell<HashFunction, String, String> cell : KNOWN_HASHES.cellSet()) {
515       HashFunction func = cell.getRowKey();
516       String input = cell.getColumnKey();
517       String expected = cell.getValue();
518       assertEquals(
519           String.format(Locale.ROOT, "Known hash for hash(%s, UTF_8) failed", input),
520           expected,
521           func.hashString(input, UTF_8).toString());
522     }
523   }
524 
testNullPointers()525   public void testNullPointers() {
526     NullPointerTester tester =
527         new NullPointerTester()
528             .setDefault(byte[].class, "secret key".getBytes(UTF_8))
529             .setDefault(HashCode.class, HashCode.fromLong(0));
530     tester.testAllPublicStaticMethods(Hashing.class);
531   }
532 
testSeedlessHashFunctionEquals()533   public void testSeedlessHashFunctionEquals() throws Exception {
534     assertSeedlessHashFunctionEquals(Hashing.class);
535   }
536 
testSeededHashFunctionEquals()537   public void testSeededHashFunctionEquals() throws Exception {
538     assertSeededHashFunctionEquals(Hashing.class);
539   }
540 
541   /**
542    * Tests equality of {@link Hashing#goodFastHash} instances. This test must be separate from
543    * {@link #testSeededHashFunctionEquals} because the parameter to {@code goodFastHash} is a size,
544    * not a seed, and because that size is rounded up. Thus, {@code goodFastHash} instances with
545    * different parameters can be equal. That fact is a problem for {@code
546    * testSeededHashFunctionEquals}.
547    */
testGoodFastHashEquals()548   public void testGoodFastHashEquals() throws Exception {
549     HashFunction hashFunction1a = Hashing.goodFastHash(1);
550     HashFunction hashFunction1b = Hashing.goodFastHash(32);
551     HashFunction hashFunction2a = Hashing.goodFastHash(33);
552     HashFunction hashFunction2b = Hashing.goodFastHash(128);
553     HashFunction hashFunction3a = Hashing.goodFastHash(129);
554     HashFunction hashFunction3b = Hashing.goodFastHash(256);
555     HashFunction hashFunction4a = Hashing.goodFastHash(257);
556     HashFunction hashFunction4b = Hashing.goodFastHash(384);
557 
558     new EqualsTester()
559         .addEqualityGroup(hashFunction1a, hashFunction1b)
560         .addEqualityGroup(hashFunction2a, hashFunction2b)
561         .addEqualityGroup(hashFunction3a, hashFunction3b)
562         .addEqualityGroup(hashFunction4a, hashFunction4b)
563         .testEquals();
564 
565     assertEquals(hashFunction1a.toString(), hashFunction1b.toString());
566     assertEquals(hashFunction2a.toString(), hashFunction2b.toString());
567     assertEquals(hashFunction3a.toString(), hashFunction3b.toString());
568     assertEquals(hashFunction4a.toString(), hashFunction4b.toString());
569   }
570 
assertSeedlessHashFunctionEquals(Class<?> clazz)571   static void assertSeedlessHashFunctionEquals(Class<?> clazz) throws Exception {
572     for (Method method : clazz.getDeclaredMethods()) {
573       if (method.getReturnType().equals(HashFunction.class) // must return HashFunction
574           && Modifier.isPublic(method.getModifiers()) // only the public methods
575           && method.getParameterTypes().length == 0) { // only the seed-less hash functions
576         HashFunction hashFunction1a = (HashFunction) method.invoke(clazz);
577         HashFunction hashFunction1b = (HashFunction) method.invoke(clazz);
578 
579         new EqualsTester().addEqualityGroup(hashFunction1a, hashFunction1b).testEquals();
580 
581         // Make sure we're returning not only equal instances, but constants.
582         assertSame(hashFunction1a, hashFunction1b);
583 
584         assertEquals(hashFunction1a.toString(), hashFunction1b.toString());
585       }
586     }
587   }
588 
assertSeededHashFunctionEquals(Class<?> clazz)589   static void assertSeededHashFunctionEquals(Class<?> clazz) throws Exception {
590     Random random = new Random(RANDOM_SEED);
591     for (Method method : clazz.getDeclaredMethods()) {
592       if (method.getReturnType().equals(HashFunction.class) // must return HashFunction
593           && Modifier.isPublic(method.getModifiers()) // only the public methods
594           && method.getParameterTypes().length != 0 // only the seeded hash functions
595           && !method.getName().equals("concatenating") // don't test Hashing.concatenating()
596           && !method.getName().equals("goodFastHash") // tested in testGoodFastHashEquals
597           && !method.getName().startsWith("hmac")) { // skip hmac functions
598         Object[] params1 = new Object[method.getParameterTypes().length];
599         Object[] params2 = new Object[method.getParameterTypes().length];
600         for (int i = 0; i < params1.length; i++) {
601           if (method.getParameterTypes()[i] == int.class) {
602             params1[i] = random.nextInt();
603             params2[i] = random.nextInt();
604           } else if (method.getParameterTypes()[i] == long.class) {
605             params1[i] = random.nextLong();
606             params2[i] = random.nextLong();
607           } else {
608             fail("Unable to create a random parameter for " + method.getParameterTypes()[i]);
609           }
610         }
611         HashFunction hashFunction1a = (HashFunction) method.invoke(clazz, params1);
612         HashFunction hashFunction1b = (HashFunction) method.invoke(clazz, params1);
613         HashFunction hashFunction2 = (HashFunction) method.invoke(clazz, params2);
614 
615         new EqualsTester()
616             .addEqualityGroup(hashFunction1a, hashFunction1b)
617             .addEqualityGroup(hashFunction2)
618             .testEquals();
619 
620         assertEquals(hashFunction1a.toString(), hashFunction1b.toString());
621       }
622     }
623   }
624 
625   // Parity tests taken from //util/hash/hash_unittest.cc
626 }
627