android13/external/guava/guava-tests/test/com/google/common/hash/Crc32cHashFunctionTest.java

214 lines
6.5 KiB
Java

/*
* Copyright (C) 2011 The Guava Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.common.hash;
import static com.google.common.base.Charsets.UTF_8;
import java.util.Arrays;
import java.util.Random;
import junit.framework.TestCase;
/**
* Unit tests for {@link Crc32c}. Known test values are from RFC 3720, Section B.4.
*
* @author Patrick Costello
* @author Kurt Alfred Kluever
*/
public class Crc32cHashFunctionTest extends TestCase {
public void testEmpty() {
assertCrc(0, new byte[0]);
}
public void testZeros() {
// Test 32 byte array of 0x00.
byte[] zeros = new byte[32];
assertCrc(0x8a9136aa, zeros);
}
public void testZeros100() {
// Test 100 byte array of 0x00.
byte[] zeros = new byte[100];
assertCrc(0x07cb9ff6, zeros);
}
public void testFull() {
// Test 32 byte array of 0xFF.
byte[] fulls = new byte[32];
Arrays.fill(fulls, (byte) 0xFF);
assertCrc(0x62a8ab43, fulls);
}
public void testFull100() {
// Test 100 byte array of 0xFF.
byte[] fulls = new byte[100];
Arrays.fill(fulls, (byte) 0xFF);
assertCrc(0xbc753add, fulls);
}
public void testAscending() {
// Test 32 byte arrays of ascending.
byte[] ascending = new byte[32];
for (int i = 0; i < 32; i++) {
ascending[i] = (byte) i;
}
assertCrc(0x46dd794e, ascending);
}
public void testDescending() {
// Test 32 byte arrays of descending.
byte[] descending = new byte[32];
for (int i = 0; i < 32; i++) {
descending[i] = (byte) (31 - i);
}
assertCrc(0x113fdb5c, descending);
}
public void testDescending100() {
// Test 100 byte arrays of descending.
byte[] descending = new byte[100];
for (int i = 0; i < 100; i++) {
descending[i] = (byte) (99 - i);
}
assertCrc(0xd022db97, descending);
}
public void testScsiReadCommand() {
// Test SCSI read command.
byte[] scsiReadCommand =
new byte[] {
0x01, (byte) 0xc0, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x14, 0x00, 0x00, 0x00,
0x00, 0x00, 0x04, 0x00,
0x00, 0x00, 0x00, 0x14,
0x00, 0x00, 0x00, 0x18,
0x28, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x02, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00
};
assertCrc(0xd9963a56, scsiReadCommand);
}
// Known values from http://www.evanjones.ca/crc32c.html
public void testSomeOtherKnownValues() {
assertCrc(0x22620404, "The quick brown fox jumps over the lazy dog".getBytes(UTF_8));
assertCrc(0xE3069283, "123456789".getBytes(UTF_8));
assertCrc(0xf3dbd4fe, "1234567890".getBytes(UTF_8));
assertCrc(0xBFE92A83, "23456789".getBytes(UTF_8));
}
public void testAgainstSimplerImplementation() {
Random r = new Random(1234567);
for (int length = 0; length < 1000; length++) {
byte[] bytes = new byte[length];
r.nextBytes(bytes);
assertCrc(referenceCrc(bytes), bytes);
}
}
private static int referenceCrc(byte[] bytes) {
int crc = ~0;
for (byte b : bytes) {
crc = (crc >>> 8) ^ Crc32cHashFunction.Crc32cHasher.BYTE_TABLE[(crc ^ b) & 0xFF];
}
return ~crc;
}
/**
* Verifies that the crc of an array of byte data matches the expected value.
*
* @param expectedCrc the expected crc value.
* @param data the data to run the checksum on.
*/
private static void assertCrc(int expectedCrc, byte[] data) {
int actualCrc = Hashing.crc32c().hashBytes(data).asInt();
assertEquals(
String.format("expected: %08x, actual: %08x", expectedCrc, actualCrc),
expectedCrc,
actualCrc);
int actualCrcHasher = Hashing.crc32c().newHasher().putBytes(data).hash().asInt();
assertEquals(
String.format("expected: %08x, actual: %08x", expectedCrc, actualCrc),
expectedCrc,
actualCrcHasher);
}
// From RFC 3720, Section 12.1, the polynomial generator is 0x11EDC6F41.
// We calculate the constant below by:
// 1. Omitting the most significant bit (because it's always 1). => 0x1EDC6F41
// 2. Flipping the bits of the constant so we can process a byte at a time. => 0x82F63B78
private static final int CRC32C_GENERATOR = 0x1EDC6F41; // 0x11EDC6F41
private static final int CRC32C_GENERATOR_FLIPPED = Integer.reverse(CRC32C_GENERATOR);
public void testCrc32cByteTable() {
// See Hacker's Delight 2nd Edition, Figure 14-7.
int[] expected = new int[256];
for (int i = 0; i < expected.length; i++) {
int crc = i;
for (int j = 7; j >= 0; j--) {
int mask = -(crc & 1);
crc = ((crc >>> 1) ^ (CRC32C_GENERATOR_FLIPPED & mask));
}
expected[i] = crc;
}
int[] actual = Crc32cHashFunction.Crc32cHasher.BYTE_TABLE;
assertTrue(
"Expected: \n" + Arrays.toString(expected) + "\nActual:\n" + Arrays.toString(actual),
Arrays.equals(expected, actual));
}
static int advanceOneBit(int next) {
if ((next & 1) != 0) {
return (next >>> 1) ^ CRC32C_GENERATOR_FLIPPED;
} else {
return next >>> 1;
}
}
public void testCrc32cStrideTable() {
int next = CRC32C_GENERATOR_FLIPPED;
for (int i = 0; i < 12; i++) { // for 3 ints = 12 bytes in between each stride window
next = (next >>> 8) ^ Crc32cHashFunction.Crc32cHasher.BYTE_TABLE[next & 0xFF];
}
int[][] expected = new int[4][256];
for (int b = 0; b < 4; ++b) {
for (int bit = 128; bit != 0; bit >>= 1) {
expected[b][bit] = next;
next = advanceOneBit(next);
}
}
for (int b = 0; b < 4; ++b) {
expected[b][0] = 0;
for (int bit = 2; bit < 256; bit <<= 1) {
for (int i = bit + 1; i < (bit << 1); i++) {
expected[b][i] = expected[b][bit] ^ expected[b][i ^ bit];
}
}
}
int[][] actual = Crc32cHashFunction.Crc32cHasher.STRIDE_TABLE;
assertTrue(
"Expected: \n"
+ Arrays.deepToString(expected)
+ "\nActual:\n"
+ Arrays.deepToString(actual),
Arrays.deepEquals(expected, actual));
}
}