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