• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2011 Google Inc. All Rights Reserved.
2 
3 package com.google.common.hash;
4 
5 import com.google.common.primitives.Ints;
6 
7 import org.junit.Assert;
8 
9 import java.nio.ByteBuffer;
10 import java.nio.ByteOrder;
11 import java.util.Arrays;
12 import java.util.Random;
13 
14 /**
15  * @author andreou@google.com (Dimitris Andreou)
16  */
17 class HashTestUtils {
HashTestUtils()18   private HashTestUtils() {}
19 
20   /**
21    * Converts a string, which should contain only ascii-representable characters, to a byte[].
22    */
ascii(String string)23   static byte[] ascii(String string) {
24     byte[] bytes = new byte[string.length()];
25     for (int i = 0; i < string.length(); i++) {
26       bytes[i] = (byte) string.charAt(i);
27     }
28     return bytes;
29   }
30 
31   /**
32    * Returns a byte array representation for a sequence of longs, in big-endian order.
33    */
toBytes(ByteOrder bo, long... longs)34   static byte[] toBytes(ByteOrder bo, long... longs) {
35     ByteBuffer bb = ByteBuffer.wrap(new byte[longs.length * 8]).order(bo);
36     for (long x : longs) {
37       bb.putLong(x);
38     }
39     return bb.array();
40   }
41 
42   interface HashFn {
hash(byte[] input, int seed)43     byte[] hash(byte[] input, int seed);
44   }
45 
verifyHashFunction(HashFn hashFunction, int hashbits, int expected)46   static void verifyHashFunction(HashFn hashFunction, int hashbits, int expected) {
47     int hashBytes = hashbits / 8;
48 
49     byte[] key = new byte[256];
50     byte[] hashes = new byte[hashBytes * 256];
51 
52     // Hash keys of the form {}, {0}, {0,1}, {0,1,2}... up to N=255,using 256-N as the seed
53     for (int i = 0; i < 256; i++) {
54       key[i] = (byte) i;
55       int seed = 256 - i;
56       byte[] hash = hashFunction.hash(Arrays.copyOf(key, i), seed);
57       System.arraycopy(hash, 0, hashes, i * hashBytes, hash.length);
58     }
59 
60     // Then hash the result array
61     byte[] result = hashFunction.hash(hashes, 0);
62 
63     // interpreted in little-endian order.
64     int verification = Integer.reverseBytes(Ints.fromByteArray(result));
65 
66     if (expected != verification) {
67       throw new AssertionError("Expected: " + Integer.toHexString(expected)
68           + " got: " + Integer.toHexString(verification));
69     }
70   }
71 
assertEqualHashes(byte[] expectedHash, byte[] actualHash)72   static void assertEqualHashes(byte[] expectedHash, byte[] actualHash) {
73     if (!Arrays.equals(expectedHash, actualHash)) {
74       Assert.fail(String.format("Should be: %x, was %x", expectedHash, actualHash));
75     }
76   }
77 
78   static final Funnel<Object> BAD_FUNNEL = new Funnel<Object>() {
79     @Override public void funnel(Object object, Sink byteSink) {
80       byteSink.putInt(object.hashCode());
81     }
82   };
83 
84   static enum RandomHasherAction {
PUT_BOOLEAN()85     PUT_BOOLEAN() {
86       @Override void performAction(Random random, Iterable<? extends Sink> sinks) {
87         boolean value = random.nextBoolean();
88         for (Sink sink : sinks) {
89           sink.putBoolean(value);
90         }
91       }
92     },
PUT_BYTE()93     PUT_BYTE() {
94       @Override void performAction(Random random, Iterable<? extends Sink> sinks) {
95         int value = random.nextInt();
96         for (Sink sink : sinks) {
97           sink.putByte((byte) value);
98         }
99       }
100     },
PUT_SHORT()101     PUT_SHORT() {
102       @Override void performAction(Random random, Iterable<? extends Sink> sinks) {
103         short value = (short) random.nextInt();
104         for (Sink sink : sinks) {
105           sink.putShort(value);
106         }
107       }
108     },
PUT_CHAR()109     PUT_CHAR() {
110       @Override void performAction(Random random, Iterable<? extends Sink> sinks) {
111         char value = (char) random.nextInt();
112         for (Sink sink : sinks) {
113           sink.putChar(value);
114         }
115       }
116     },
PUT_INT()117     PUT_INT() {
118       @Override void performAction(Random random, Iterable<? extends Sink> sinks) {
119         int value = random.nextInt();
120         for (Sink sink : sinks) {
121           sink.putInt(value);
122         }
123       }
124     },
PUT_LONG()125     PUT_LONG() {
126       @Override void performAction(Random random, Iterable<? extends Sink> sinks) {
127         long value = random.nextLong();
128         for (Sink sink : sinks) {
129           sink.putLong(value);
130         }
131       }
132     },
PUT_FLOAT()133     PUT_FLOAT() {
134       @Override void performAction(Random random, Iterable<? extends Sink> sinks) {
135         float value = random.nextFloat();
136         for (Sink sink : sinks) {
137           sink.putFloat(value);
138         }
139       }
140     },
PUT_DOUBLE()141     PUT_DOUBLE() {
142       @Override void performAction(Random random, Iterable<? extends Sink> sinks) {
143         double value = random.nextDouble();
144         for (Sink sink : sinks) {
145           sink.putDouble(value);
146         }
147       }
148     },
PUT_BYTES()149     PUT_BYTES() {
150       @Override void performAction(Random random, Iterable<? extends Sink> sinks) {
151         byte[] value = new byte[random.nextInt(128)];
152         random.nextBytes(value);
153         for (Sink sink : sinks) {
154           sink.putBytes(value);
155         }
156       }
157     },
PUT_BYTES_INT_INT()158     PUT_BYTES_INT_INT() {
159       @Override void performAction(Random random, Iterable<? extends Sink> sinks) {
160         byte[] value = new byte[random.nextInt(128)];
161         random.nextBytes(value);
162         int off = random.nextInt(value.length + 1);
163         int len = random.nextInt(value.length - off + 1);
164         for (Sink sink : sinks) {
165           sink.putBytes(value);
166         }
167       }
168     };
169 
performAction(Random random, Iterable<? extends Sink> sinks)170     abstract void performAction(Random random, Iterable<? extends Sink> sinks);
171 
172     private static final RandomHasherAction[] actions = values();
173 
pickAtRandom(Random random)174     static RandomHasherAction pickAtRandom(Random random) {
175       return actions[random.nextInt(actions.length)];
176     }
177   }
178 }
179