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