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