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