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 com.google.common.collect.ImmutableList; 20 import com.google.common.hash.HashTestUtils.RandomHasherAction; 21 import java.io.ByteArrayOutputStream; 22 import java.nio.ByteBuffer; 23 import java.util.Arrays; 24 import java.util.List; 25 import java.util.Random; 26 import junit.framework.TestCase; 27 28 /** Tests for AbstractNonStreamingHashFunction. */ 29 public class AbstractNonStreamingHashFunctionTest extends TestCase { 30 /** 31 * Constructs two trivial HashFunctions (output := input), one streaming and one non-streaming, 32 * and checks that their results are identical, no matter which newHasher version we used. 33 */ testExhaustive()34 public void testExhaustive() { 35 List<Hasher> hashers = 36 ImmutableList.of( 37 new StreamingVersion().newHasher(), 38 new StreamingVersion().newHasher(52), 39 new NonStreamingVersion().newHasher(), 40 new NonStreamingVersion().newHasher(123)); 41 Random random = new Random(0); 42 for (int i = 0; i < 200; i++) { 43 RandomHasherAction.pickAtRandom(random).performAction(random, hashers); 44 } 45 HashCode[] codes = new HashCode[hashers.size()]; 46 for (int i = 0; i < hashers.size(); i++) { 47 codes[i] = hashers.get(i).hash(); 48 } 49 for (int i = 1; i < codes.length; i++) { 50 assertEquals(codes[i - 1], codes[i]); 51 } 52 } 53 testPutStringWithLowSurrogate()54 public void testPutStringWithLowSurrogate() { 55 // we pad because the dummy hash function we use to test this, merely copies the input into 56 // the output, so the input must be at least 32 bits, since the output has to be that long 57 assertPutString(new char[] {'p', HashTestUtils.randomLowSurrogate(new Random())}); 58 } 59 testPutStringWithHighSurrogate()60 public void testPutStringWithHighSurrogate() { 61 // we pad because the dummy hash function we use to test this, merely copies the input into 62 // the output, so the input must be at least 32 bits, since the output has to be that long 63 assertPutString(new char[] {'p', HashTestUtils.randomHighSurrogate(new Random())}); 64 } 65 testPutStringWithLowHighSurrogate()66 public void testPutStringWithLowHighSurrogate() { 67 assertPutString( 68 new char[] { 69 HashTestUtils.randomLowSurrogate(new Random()), 70 HashTestUtils.randomHighSurrogate(new Random()) 71 }); 72 } 73 testPutStringWithHighLowSurrogate()74 public void testPutStringWithHighLowSurrogate() { 75 assertPutString( 76 new char[] { 77 HashTestUtils.randomHighSurrogate(new Random()), 78 HashTestUtils.randomLowSurrogate(new Random()) 79 }); 80 } 81 assertPutString(char[] chars)82 private static void assertPutString(char[] chars) { 83 Hasher h1 = new NonStreamingVersion().newHasher(); 84 Hasher h2 = new NonStreamingVersion().newHasher(); 85 String s = new String(chars); 86 // this is the correct implementation of the spec 87 for (int i = 0; i < s.length(); i++) { 88 h1.putChar(s.charAt(i)); 89 } 90 h2.putUnencodedChars(s); 91 assertEquals(h1.hash(), h2.hash()); 92 } 93 94 static class StreamingVersion extends AbstractHashFunction { 95 @Override bits()96 public int bits() { 97 return 32; 98 } 99 100 @Override newHasher()101 public Hasher newHasher() { 102 return new AbstractStreamingHasher(4, 4) { 103 final ByteArrayOutputStream out = new ByteArrayOutputStream(); 104 105 @Override 106 protected HashCode makeHash() { 107 return HashCode.fromBytes(out.toByteArray()); 108 } 109 110 @Override 111 protected void process(ByteBuffer bb) { 112 while (bb.hasRemaining()) { 113 out.write(bb.get()); 114 } 115 } 116 117 @Override 118 protected void processRemaining(ByteBuffer bb) { 119 while (bb.hasRemaining()) { 120 out.write(bb.get()); 121 } 122 } 123 }; 124 } 125 } 126 127 static class NonStreamingVersion extends AbstractNonStreamingHashFunction { 128 @Override bits()129 public int bits() { 130 return 32; 131 } 132 133 @Override hashBytes(byte[] input, int off, int len)134 public HashCode hashBytes(byte[] input, int off, int len) { 135 return HashCode.fromBytes(Arrays.copyOfRange(input, off, off + len)); 136 } 137 } 138 } 139