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