17dd252788645e940eada959bdde927426e2531c9Paul Duffin/* 27dd252788645e940eada959bdde927426e2531c9Paul Duffin * Copyright (C) 2011 The Guava Authors 37dd252788645e940eada959bdde927426e2531c9Paul Duffin * 47dd252788645e940eada959bdde927426e2531c9Paul Duffin * Licensed under the Apache License, Version 2.0 (the "License"); 57dd252788645e940eada959bdde927426e2531c9Paul Duffin * you may not use this file except in compliance with the License. 67dd252788645e940eada959bdde927426e2531c9Paul Duffin * You may obtain a copy of the License at 77dd252788645e940eada959bdde927426e2531c9Paul Duffin * 87dd252788645e940eada959bdde927426e2531c9Paul Duffin * http://www.apache.org/licenses/LICENSE-2.0 97dd252788645e940eada959bdde927426e2531c9Paul Duffin * 107dd252788645e940eada959bdde927426e2531c9Paul Duffin * Unless required by applicable law or agreed to in writing, software 117dd252788645e940eada959bdde927426e2531c9Paul Duffin * distributed under the License is distributed on an "AS IS" BASIS, 127dd252788645e940eada959bdde927426e2531c9Paul Duffin * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 137dd252788645e940eada959bdde927426e2531c9Paul Duffin * See the License for the specific language governing permissions and 147dd252788645e940eada959bdde927426e2531c9Paul Duffin * limitations under the License. 157dd252788645e940eada959bdde927426e2531c9Paul Duffin */ 161d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 171d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertpackage com.google.common.hash; 181d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 197dd252788645e940eada959bdde927426e2531c9Paul Duffinimport static com.google.common.base.Charsets.UTF_16LE; 207dd252788645e940eada959bdde927426e2531c9Paul Duffin 211d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport com.google.common.collect.Iterables; 221d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport com.google.common.collect.Lists; 231d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport com.google.common.hash.AbstractStreamingHashFunction.AbstractStreamingHasher; 241d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport com.google.common.hash.HashTestUtils.RandomHasherAction; 251d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 261d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport junit.framework.TestCase; 271d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 281d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.io.ByteArrayOutputStream; 291d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.nio.ByteBuffer; 301d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.nio.ByteOrder; 311d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.nio.charset.Charset; 323ecfa412eddc4b084663f38d562537b86b9734d5Paul Duffinimport java.util.Arrays; 331d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.util.Collections; 341d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.util.List; 351d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.util.Random; 361d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 371d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert/** 387dd252788645e940eada959bdde927426e2531c9Paul Duffin * Tests for AbstractStreamingHasher. 397dd252788645e940eada959bdde927426e2531c9Paul Duffin * 407dd252788645e940eada959bdde927426e2531c9Paul Duffin * @author Dimitris Andreou 411d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */ 421d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertpublic class AbstractStreamingHasherTest extends TestCase { 431d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public void testBytes() { 441d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert Sink sink = new Sink(4); // byte order insignificant here 451d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert byte[] expected = { 1, 2, 3, 4, 5, 6, 7, 8 }; 461d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert sink.putByte((byte) 1); 471d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert sink.putBytes(new byte[] { 2, 3, 4, 5, 6 }); 481d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert sink.putByte((byte) 7); 497dd252788645e940eada959bdde927426e2531c9Paul Duffin sink.putBytes(new byte[] {}); 501d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert sink.putBytes(new byte[] { 8 }); 511d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert sink.hash(); 521d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert sink.assertInvariants(8); 531d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert sink.assertBytes(expected); 541d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 557dd252788645e940eada959bdde927426e2531c9Paul Duffin 561d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public void testShort() { 571d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert Sink sink = new Sink(4); 581d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert sink.putShort((short) 0x0201); 591d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert sink.hash(); 601d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert sink.assertInvariants(2); 611d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert sink.assertBytes(new byte[] { 1, 2, 0, 0 }); // padded with zeros 621d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 637dd252788645e940eada959bdde927426e2531c9Paul Duffin 641d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public void testInt() { 651d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert Sink sink = new Sink(4); 661d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert sink.putInt(0x04030201); 671d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert sink.hash(); 681d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert sink.assertInvariants(4); 691d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert sink.assertBytes(new byte[] { 1, 2, 3, 4 }); 701d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 717dd252788645e940eada959bdde927426e2531c9Paul Duffin 721d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public void testLong() { 731d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert Sink sink = new Sink(8); 741d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert sink.putLong(0x0807060504030201L); 751d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert sink.hash(); 761d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert sink.assertInvariants(8); 771d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert sink.assertBytes(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 }); 781d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 797dd252788645e940eada959bdde927426e2531c9Paul Duffin 801d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public void testChar() { 811d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert Sink sink = new Sink(4); 821d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert sink.putChar((char) 0x0201); 831d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert sink.hash(); 841d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert sink.assertInvariants(2); 851d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert sink.assertBytes(new byte[] { 1, 2, 0, 0 }); // padded with zeros 861d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 877dd252788645e940eada959bdde927426e2531c9Paul Duffin 883ecfa412eddc4b084663f38d562537b86b9734d5Paul Duffin public void testString() { 897dd252788645e940eada959bdde927426e2531c9Paul Duffin Random random = new Random(); 907dd252788645e940eada959bdde927426e2531c9Paul Duffin for (int i = 0; i < 100; i++) { 917dd252788645e940eada959bdde927426e2531c9Paul Duffin byte[] bytes = new byte[64]; 927dd252788645e940eada959bdde927426e2531c9Paul Duffin random.nextBytes(bytes); 933ecfa412eddc4b084663f38d562537b86b9734d5Paul Duffin String s = new String(bytes, UTF_16LE); // so all random strings are valid 947dd252788645e940eada959bdde927426e2531c9Paul Duffin assertEquals( 955cab40b862c21656c2ace19596874eb3ffe1b649Paul Duffin new Sink(4).putUnencodedChars(s).hash(), 963ecfa412eddc4b084663f38d562537b86b9734d5Paul Duffin new Sink(4).putBytes(s.getBytes(UTF_16LE)).hash()); 977dd252788645e940eada959bdde927426e2531c9Paul Duffin assertEquals( 985cab40b862c21656c2ace19596874eb3ffe1b649Paul Duffin new Sink(4).putUnencodedChars(s).hash(), 997dd252788645e940eada959bdde927426e2531c9Paul Duffin new Sink(4).putString(s, UTF_16LE).hash()); 1007dd252788645e940eada959bdde927426e2531c9Paul Duffin } 1017dd252788645e940eada959bdde927426e2531c9Paul Duffin } 1027dd252788645e940eada959bdde927426e2531c9Paul Duffin 1031d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public void testFloat() { 1041d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert Sink sink = new Sink(4); 1051d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert sink.putFloat(Float.intBitsToFloat(0x04030201)); 1061d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert sink.hash(); 1071d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert sink.assertInvariants(4); 1081d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert sink.assertBytes(new byte[] { 1, 2, 3, 4 }); 1091d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 1107dd252788645e940eada959bdde927426e2531c9Paul Duffin 1111d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public void testDouble() { 1121d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert Sink sink = new Sink(8); 1131d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert sink.putDouble(Double.longBitsToDouble(0x0807060504030201L)); 1141d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert sink.hash(); 1151d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert sink.assertInvariants(8); 1161d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert sink.assertBytes(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 }); 1171d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 1187dd252788645e940eada959bdde927426e2531c9Paul Duffin 1191d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public void testCorrectExceptions() { 1201d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert Sink sink = new Sink(4); 1211d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert try { 1221d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert sink.putBytes(new byte[8], -1, 4); 1231d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert fail(); 1241d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } catch (IndexOutOfBoundsException ok) {} 1251d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert try { 1261d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert sink.putBytes(new byte[8], 0, 16); 1271d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert fail(); 1281d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } catch (IndexOutOfBoundsException ok) {} 1291d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert try { 1301d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert sink.putBytes(new byte[8], 0, -1); 1311d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert fail(); 1321d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } catch (IndexOutOfBoundsException ok) {} 1331d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 1347dd252788645e940eada959bdde927426e2531c9Paul Duffin 1351d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert /** 1361d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * This test creates a long random sequence of inputs, then a lot of differently configured 1371d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * sinks process it; all should produce the same answer, the only difference should be the 1387dd252788645e940eada959bdde927426e2531c9Paul Duffin * number of process()/processRemaining() invocations, due to alignment. 1391d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */ 1401d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public void testExhaustive() throws Exception { 1411d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert Random random = new Random(0); // will iteratively make more debuggable, each time it breaks 1421d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert for (int totalInsertions = 0; totalInsertions < 200; totalInsertions++) { 1437dd252788645e940eada959bdde927426e2531c9Paul Duffin 1441d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert List<Sink> sinks = Lists.newArrayList(); 1451d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert for (int chunkSize = 4; chunkSize <= 32; chunkSize++) { 1461d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert for (int bufferSize = chunkSize; bufferSize <= chunkSize * 4; bufferSize += chunkSize) { 1471d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // yes, that's a lot of sinks! 1481d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert sinks.add(new Sink(chunkSize, bufferSize)); 1491d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // For convenience, testing only with big endianness, to match DataOutputStream. 1501d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // I regard highly unlikely that both the little endianness tests above and this one 1517dd252788645e940eada959bdde927426e2531c9Paul Duffin // passes, and there is still a little endianness bug lurking around. 1521d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 1531d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 1547dd252788645e940eada959bdde927426e2531c9Paul Duffin 1551d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert Control control = new Control(); 1561d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert Hasher controlSink = control.newHasher(1024); 1577dd252788645e940eada959bdde927426e2531c9Paul Duffin 1587dd252788645e940eada959bdde927426e2531c9Paul Duffin Iterable<Hasher> sinksAndControl = 1597dd252788645e940eada959bdde927426e2531c9Paul Duffin Iterables.concat(sinks, Collections.singleton(controlSink)); 1601d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert for (int insertion = 0; insertion < totalInsertions; insertion++) { 1617dd252788645e940eada959bdde927426e2531c9Paul Duffin RandomHasherAction.pickAtRandom(random).performAction(random, sinksAndControl); 1627dd252788645e940eada959bdde927426e2531c9Paul Duffin } 1637dd252788645e940eada959bdde927426e2531c9Paul Duffin // We need to ensure that at least 4 bytes have been put into the hasher or else 1647dd252788645e940eada959bdde927426e2531c9Paul Duffin // Hasher#hash will throw an ISE. 1657dd252788645e940eada959bdde927426e2531c9Paul Duffin int intToPut = random.nextInt(); 1667dd252788645e940eada959bdde927426e2531c9Paul Duffin for (Hasher hasher : sinksAndControl) { 1677dd252788645e940eada959bdde927426e2531c9Paul Duffin hasher.putInt(intToPut); 1681d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 1691d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert for (Sink sink : sinks) { 1701d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert sink.hash(); 1711d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 1727dd252788645e940eada959bdde927426e2531c9Paul Duffin 1731d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert byte[] expected = controlSink.hash().asBytes(); 1741d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert for (Sink sink : sinks) { 1751d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert sink.assertInvariants(expected.length); 1761d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert sink.assertBytes(expected); 1771d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 1781d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 1791d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 1807dd252788645e940eada959bdde927426e2531c9Paul Duffin 1811d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert private static class Sink extends AbstractStreamingHasher { 1821d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert final int chunkSize; 1831d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert final int bufferSize; 1841d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert final ByteArrayOutputStream out = new ByteArrayOutputStream(); 1857dd252788645e940eada959bdde927426e2531c9Paul Duffin 1861d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert int processCalled = 0; 1871d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert boolean remainingCalled = false; 1887dd252788645e940eada959bdde927426e2531c9Paul Duffin 1891d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert Sink(int chunkSize, int bufferSize) { 1901d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert super(chunkSize, bufferSize); 1911d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert this.chunkSize = chunkSize; 1921d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert this.bufferSize = bufferSize; 1931d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 1941d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1951d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert Sink(int chunkSize) { 1961d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert super(chunkSize); 1971d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert this.chunkSize = chunkSize; 1981d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert this.bufferSize = chunkSize; 1991d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 2001d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 2011d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert @Override HashCode makeHash() { 2020888a09821a98ac0680fad765217302858e70fa4Paul Duffin return HashCode.fromBytes(out.toByteArray()); 2031d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 2041d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 2051d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert @Override protected void process(ByteBuffer bb) { 2061d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert processCalled++; 2071d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertEquals(ByteOrder.LITTLE_ENDIAN, bb.order()); 2081d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertTrue(bb.remaining() >= chunkSize); 2091d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert for (int i = 0; i < chunkSize; i++) { 2101d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert out.write(bb.get()); 2111d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 2121d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 2137dd252788645e940eada959bdde927426e2531c9Paul Duffin 2141d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert @Override protected void processRemaining(ByteBuffer bb) { 2151d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertFalse(remainingCalled); 2161d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert remainingCalled = true; 2171d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertEquals(ByteOrder.LITTLE_ENDIAN, bb.order()); 2181d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertTrue(bb.remaining() > 0); 2191d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertTrue(bb.remaining() < bufferSize); 2201d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert int before = processCalled; 2211d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert super.processRemaining(bb); 2221d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert int after = processCalled; 2231d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertEquals(before + 1, after); // default implementation pads and calls process() 2241d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert processCalled--; // don't count the tail invocation (makes tests a bit more understandable) 2251d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 2267dd252788645e940eada959bdde927426e2531c9Paul Duffin 2271d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // ensures that the number of invocations looks sane 2281d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert void assertInvariants(int expectedBytes) { 2297dd252788645e940eada959bdde927426e2531c9Paul Duffin // we should have seen as many bytes as the next multiple of chunk after expectedBytes - 1 2301d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertEquals(out.toByteArray().length, ceilToMultiple(expectedBytes, chunkSize)); 2311d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertEquals(expectedBytes / chunkSize, processCalled); 2321d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertEquals(expectedBytes % chunkSize != 0, remainingCalled); 2331d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 2347dd252788645e940eada959bdde927426e2531c9Paul Duffin 2351d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // returns the minimum x such as x >= a && (x % b) == 0 2361d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert private static int ceilToMultiple(int a, int b) { 2371d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert int remainder = a % b; 2381d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return remainder == 0 ? a : a + b - remainder; 2391d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 2407dd252788645e940eada959bdde927426e2531c9Paul Duffin 2411d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert void assertBytes(byte[] expected) { 2421d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert byte[] got = out.toByteArray(); 2431d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert for (int i = 0; i < expected.length; i++) { 2441d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertEquals(expected[i], got[i]); 2451d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 2461d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 2471d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 2487dd252788645e940eada959bdde927426e2531c9Paul Duffin 2497dd252788645e940eada959bdde927426e2531c9Paul Duffin // Assumes that AbstractNonStreamingHashFunction works properly (must be tested elsewhere!) 2501d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert private static class Control extends AbstractNonStreamingHashFunction { 2511d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert @Override 2521d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public HashCode hashBytes(byte[] input) { 2530888a09821a98ac0680fad765217302858e70fa4Paul Duffin return HashCode.fromBytes(input); 2541d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 2557dd252788645e940eada959bdde927426e2531c9Paul Duffin 2561d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert @Override 2571d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public HashCode hashBytes(byte[] input, int off, int len) { 2581d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return hashBytes(Arrays.copyOfRange(input, off, off + len)); 2591d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 2601d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 2611d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert @Override 2621d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public int bits() { 2631d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert throw new UnsupportedOperationException(); 2641d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 2651d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 2661d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert @Override 2671d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public HashCode hashString(CharSequence input, Charset charset) { 2681d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert throw new UnsupportedOperationException(); 2691d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 2701d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 2711d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert @Override 2721d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public HashCode hashLong(long input) { 2731d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert throw new UnsupportedOperationException(); 2741d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 2757dd252788645e940eada959bdde927426e2531c9Paul Duffin 2767dd252788645e940eada959bdde927426e2531c9Paul Duffin @Override 2777dd252788645e940eada959bdde927426e2531c9Paul Duffin public HashCode hashInt(int input) { 2787dd252788645e940eada959bdde927426e2531c9Paul Duffin throw new UnsupportedOperationException(); 2797dd252788645e940eada959bdde927426e2531c9Paul Duffin } 2801d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 2811d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert} 282