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