/* * Copyright 2004-2014 H2 Group. Multiple-Licensed under the MPL 2.0, * and the EPL 1.0 (http://h2database.com/html/license.html). * Initial Developer: H2 Group */ package org.h2.test.unit; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.util.Random; import org.h2.dev.util.BitStream; import org.h2.dev.util.BitStream.In; import org.h2.dev.util.BitStream.Out; import org.h2.test.TestBase; /** * Test the bit stream (Golomb code and Huffman code) utility. */ public class TestBitStream extends TestBase { /** * Run just this test. * * @param a ignored */ public static void main(String... a) throws Exception { TestBase.createCaller().init().test(); } @Override public void test() throws Exception { testHuffmanRandomized(); testHuffman(); testBitStream(); testGolomb("11110010", 10, 42); testGolomb("00", 3, 0); testGolomb("010", 3, 1); testGolomb("011", 3, 2); testGolomb("100", 3, 3); testGolomb("1010", 3, 4); testGolombRandomized(); } private void testHuffmanRandomized() { Random r = new Random(1); int[] freq = new int[r.nextInt(200) + 1]; for (int i = 0; i < freq.length; i++) { freq[i] = r.nextInt(1000) + 1; } int seed = r.nextInt(); r.setSeed(seed); BitStream.Huffman huff = new BitStream.Huffman(freq); ByteArrayOutputStream byteOut = new ByteArrayOutputStream(); BitStream.Out out = new BitStream.Out(byteOut); for (int i = 0; i < 10000; i++) { huff.write(out, r.nextInt(freq.length)); } out.close(); BitStream.In in = new BitStream.In(new ByteArrayInputStream(byteOut.toByteArray())); r.setSeed(seed); for (int i = 0; i < 10000; i++) { int expected = r.nextInt(freq.length); assertEquals(expected, huff.read(in)); } } private void testHuffman() { int[] freq = { 36, 18, 12, 9, 7, 6, 5, 4 }; BitStream.Huffman huff = new BitStream.Huffman(freq); final StringBuilder buff = new StringBuilder(); Out o = new Out(null) { @Override public void writeBit(int bit) { buff.append(bit == 0 ? '0' : '1'); } }; for (int i = 0; i < freq.length; i++) { buff.append(i + ": "); huff.write(o, i); buff.append("\n"); } assertEquals( "0: 0\n" + "1: 110\n" + "2: 100\n" + "3: 1110\n" + "4: 1011\n" + "5: 1010\n" + "6: 11111\n" + "7: 11110\n", buff.toString()); } private void testGolomb(String expected, int div, int value) { final StringBuilder buff = new StringBuilder(); Out o = new Out(null) { @Override public void writeBit(int bit) { buff.append(bit == 0 ? '0' : '1'); } }; o.writeGolomb(div, value); int size = Out.getGolombSize(div, value); String got = buff.toString(); assertEquals(size, got.length()); assertEquals(expected, got); } private void testGolombRandomized() { ByteArrayOutputStream out = new ByteArrayOutputStream(); Out bitOut = new Out(out); Random r = new Random(1); int len = 1000; for (int i = 0; i < len; i++) { int div = r.nextInt(100) + 1; int value = r.nextInt(1000000); bitOut.writeGolomb(div, value); } bitOut.flush(); bitOut.close(); byte[] data = out.toByteArray(); ByteArrayInputStream in = new ByteArrayInputStream(data); In bitIn = new In(in); r.setSeed(1); for (int i = 0; i < len; i++) { int div = r.nextInt(100) + 1; int value = r.nextInt(1000000); int v = bitIn.readGolomb(div); assertEquals("i=" + i + " div=" + div, value, v); } } private void testBitStream() { Random r = new Random(); for (int test = 0; test < 10000; test++) { ByteArrayOutputStream buff = new ByteArrayOutputStream(); int len = r.nextInt(40); Out out = new Out(buff); long seed = r.nextLong(); Random r2 = new Random(seed); for (int i = 0; i < len; i++) { out.writeBit(r2.nextBoolean() ? 1 : 0); } out.close(); In in = new In(new ByteArrayInputStream( buff.toByteArray())); r2 = new Random(seed); int i = 0; for (; i < len; i++) { int expected = r2.nextBoolean() ? 1 : 0; assertEquals(expected, in.readBit()); } for (; i % 8 != 0; i++) { assertEquals(0, in.readBit()); } assertEquals(-1, in.readBit()); } } }