Home | History | Annotate | Download | only in hash
      1 // Copyright 2011 Google Inc. All Rights Reserved.
      2 
      3 package com.google.common.hash;
      4 
      5 import com.google.common.collect.ImmutableList;
      6 
      7 import junit.framework.TestCase;
      8 
      9 import java.util.Arrays;
     10 
     11 /**
     12  * Tests for HashCodes, especially making sure that their endianness promises (big-endian)
     13  * are upheld.
     14  *
     15  * @author andreou (at) google.com (Dimitris Andreou)
     16  */
     17 public class HashCodesTest extends TestCase {
     18   // note: asInt(), asLong() are in little endian
     19   private static final ImmutableList<ExpectedHashCode> expectedHashCodes = ImmutableList.of(
     20       new ExpectedHashCode(new byte[] {
     21         (byte) 0xef, (byte) 0xcd, (byte) 0xab, (byte) 0x89,
     22         (byte) 0x67, (byte) 0x45, (byte) 0x23, (byte) 0x01},
     23         0x89abcdef, 0x0123456789abcdefL, "efcdab8967452301"),
     24 
     25       new ExpectedHashCode(new byte[] {
     26         (byte) 0xef, (byte) 0xcd, (byte) 0xab, (byte) 0x89,
     27         (byte) 0x67, (byte) 0x45, (byte) 0x23, (byte) 0x01, // up to here, same bytes as above
     28         (byte) 0x01, (byte) 0x02, (byte) 0x03, (byte) 0x04,
     29         (byte) 0x05, (byte) 0x06, (byte) 0x07, (byte) 0x08},
     30         0x89abcdef, 0x0123456789abcdefL, // asInt/asLong as above, due to equal eight first bytes
     31         "efcdab89674523010102030405060708"),
     32 
     33       new ExpectedHashCode(new byte[] { (byte) 0xdf, (byte) 0x9b, (byte) 0x57, (byte) 0x13 },
     34         0x13579bdf, null, "df9b5713"),
     35 
     36       new ExpectedHashCode(new byte[] {
     37           (byte) 0xcd, (byte) 0xab, (byte) 0x00, (byte) 0x00},
     38           0x0000abcd, null, "cdab0000"),
     39 
     40       new ExpectedHashCode(new byte[] {
     41           (byte) 0xef, (byte) 0xcd, (byte) 0xab, (byte) 0x00,
     42           (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00},
     43           0x00abcdef, 0x0000000000abcdefL, "efcdab0000000000")
     44     );
     45 
     46   // expectedHashCodes must contain at least one hash code with 4 bytes
     47   public void testFromInt() {
     48     for (ExpectedHashCode expected : expectedHashCodes) {
     49       if (expected.bytes.length == 4) {
     50         HashCode fromInt = HashCodes.fromInt(expected.asInt);
     51         assertExpectedHashCode(expected, fromInt);
     52       }
     53     }
     54   }
     55 
     56   // expectedHashCodes must contain at least one hash code with 8 bytes
     57   public void testFromLong() {
     58     for (ExpectedHashCode expected : expectedHashCodes) {
     59       if (expected.bytes.length == 8) {
     60         HashCode fromLong = HashCodes.fromLong(expected.asLong);
     61         assertExpectedHashCode(expected, fromLong);
     62       }
     63     }
     64   }
     65 
     66   public void testFromBytes() {
     67     for (ExpectedHashCode expected : expectedHashCodes) {
     68       HashCode fromBytes = HashCodes.fromBytes(expected.bytes);
     69       assertExpectedHashCode(expected, fromBytes);
     70     }
     71   }
     72 
     73   private void assertExpectedHashCode(ExpectedHashCode expected, HashCode hash) {
     74     assertTrue(Arrays.equals(expected.bytes, hash.asBytes()));
     75     byte[] bb = new byte[hash.bits() / 8];
     76     hash.writeBytesTo(bb, 0, bb.length);
     77     assertTrue(Arrays.equals(expected.bytes, bb));
     78     assertEquals(expected.asInt, hash.asInt());
     79     if (expected.asLong == null) {
     80       try {
     81         hash.asLong();
     82         fail();
     83       } catch (IllegalStateException ok) {}
     84     } else {
     85       assertEquals(expected.asLong.longValue(), hash.asLong());
     86     }
     87     assertEquals(expected.toString, hash.toString());
     88     assertSideEffectFree(hash);
     89     assertReadableBytes(hash);
     90   }
     91 
     92   private void assertSideEffectFree(HashCode hash) {
     93     byte[] original = hash.asBytes();
     94     byte[] mutated = hash.asBytes();
     95     mutated[0]++;
     96     assertTrue(Arrays.equals(original, hash.asBytes()));
     97   }
     98 
     99   private void assertReadableBytes(HashCode hashCode) {
    100     assertTrue(hashCode.bits() >= 32); // sanity
    101     byte[] hashBytes = hashCode.asBytes();
    102     int totalBytes = hashCode.bits() / 8;
    103 
    104     for (int bytes = 0; bytes < totalBytes; bytes++) {
    105       byte[] bb = new byte[bytes];
    106       hashCode.writeBytesTo(bb, 0, bb.length);
    107 
    108       assertTrue(Arrays.equals(Arrays.copyOf(hashBytes, bytes), bb));
    109     }
    110   }
    111 
    112   private static class ExpectedHashCode {
    113     final byte[] bytes;
    114     final int asInt;
    115     final Long asLong; // null means that asLong should throw an exception
    116     final String toString;
    117     ExpectedHashCode(byte[] bytes, int asInt, Long asLong, String toString) {
    118       this.bytes = bytes;
    119       this.asInt = asInt;
    120       this.asLong = asLong;
    121       this.toString = toString;
    122     }
    123   }
    124 }
    125