package net.contrapunctus.rngzip.util; import java.io.BufferedOutputStream; import java.io.BufferedReader; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.EOFException; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.PrintStream; import java.util.Formatter; import java.util.Random; import org.junit.Test; import static org.junit.Assert.*; /** * Test suite for the Multiplex* classes. */ public class MultiplexBlockTest { @Test public void testExamples() throws IOException { testEnc(0,12121,new byte[]{(byte)0x5E,(byte)0x59}); testDec(0,12121,new byte[]{(byte)0x5E,(byte)0x59}); testDec(0,12121,new byte[]{(byte)0x00,(byte)0xDE,(byte)0x59}); testDec(0,12121,new byte[]{(byte)0xC0,(byte)0x5E,(byte)0x59}); testDec(0,12121,new byte[]{(byte)0x00,(byte)0x80,(byte)0xAF,(byte)0x59}); testDec(0,12121,new byte[]{(byte)0xC0,(byte)0x00,(byte)0xAF,(byte)0x59}); testEnc(0,1350449,new byte[]{(byte)0x52,(byte)0xB6,(byte)0x31}); testDec(0,1350449,new byte[]{(byte)0x52,(byte)0xB6,(byte)0x31}); testDec(0,1350449,new byte[]{(byte)0x00,(byte)0xA9,(byte)0x9B,(byte)0x31}); testDec(0,1350449,new byte[]{(byte)0xC0,(byte)0x29,(byte)0x9B,(byte)0x31}); testEnc(0,6723355,new byte[]{(byte)0x01,(byte)0xCD,(byte)0x97,(byte)0x1B}); testDec(0,6723355,new byte[]{(byte)0x01,(byte)0xCD,(byte)0x97,(byte)0x1B}); testDec(0,6723355,new byte[]{(byte)0xC0,(byte)0xCD,(byte)0x97,(byte)0x1B}); testEnc(3,2000,new byte[]{(byte)0xAF,(byte)0x50}); testDec(3,2000,new byte[]{(byte)0xAF,(byte)0x50}); testDec(3,2000,new byte[]{(byte)0xA0,(byte)0x8F,(byte)0x50}); testDec(3,2000,new byte[]{(byte)0xC3,(byte)0x0F,(byte)0x50}); testDec(3,2000,new byte[]{(byte)0xA0,(byte)0x80,(byte)0x87,(byte)0xD0}); testDec(3,2000,new byte[]{(byte)0xC3,(byte)0x00,(byte)0x87,(byte)0xD0}); testEnc(2,250042,new byte[]{(byte)0x9F,(byte)0xA1,(byte)0x3A}); testDec(2,250042,new byte[]{(byte)0x9F,(byte)0xA1,(byte)0x3A}); testDec(2,250042,new byte[]{(byte)0x90,(byte)0x87,(byte)0xD0,(byte)0xBA}); testDec(2,250042,new byte[]{(byte)0xC2,(byte)0x07,(byte)0xD0,(byte)0xBA}); testEnc(4,8385630,new byte[]{(byte)0xB1,(byte)0xFF,(byte)0xF4,(byte)0x5E}); testDec(4,8385630,new byte[]{(byte)0xB1,(byte)0xFF,(byte)0xF4,(byte)0x5E}); testDec(4,8385630,new byte[]{(byte)0xC4,(byte)0xFF,(byte)0xF4,(byte)0x5E}); testEnc(42,10222,new byte[]{(byte)0xEA,(byte)0x4F,(byte)0x6E}); testDec(42,10222,new byte[]{(byte)0xEA,(byte)0x4F,(byte)0x6E}); testDec(42,10222,new byte[]{(byte)0xEA,(byte)0x00,(byte)0xA7,(byte)0xEE}); testEnc(60,4874941,new byte[]{(byte)0xFC,(byte)0x94,(byte)0xE2,(byte)0xBD}); testDec(60,4874941,new byte[]{(byte)0xFC,(byte)0x94,(byte)0xE2,(byte)0xBD}); } private void testEnc(int sid, int size, byte[] bs) throws IOException { ByteArrayOutputStream bo = new ByteArrayOutputStream(); MultiplexBlockRep ro = new MultiplexBlockRep(bo, sid); ro.encode(size); byte[] rs = bo.toByteArray(); assert(bs.length == rs.length); for(int i = 0; i < bs.length; i++) { assert(bs[i] == rs[i]); } } private void testDec(int sid, int size, byte[] bs) throws IOException { ByteArrayInputStream bi = new ByteArrayInputStream(bs); MultiplexBlockRep ri = new MultiplexBlockRep(bi); int sz = ri.decode(); assert(sid == ri.streamID); assert(size == sz); } @Test public void roundTrip() throws IOException { Random r = new Random(); for(int i = 0; i < 100; i++) { int sid = r.nextInt(MultiplexBlockRep.MAX_STREAM_ID); int size = r.nextInt(MultiplexBlockRep.MAX_BLOCK_SIZE); ByteArrayOutputStream bo = new ByteArrayOutputStream(); MultiplexBlockRep ro = new MultiplexBlockRep(bo, sid); ro.encode(size); byte[] rs = bo.toByteArray(); ByteArrayInputStream bi = new ByteArrayInputStream(rs); MultiplexBlockRep ri = new MultiplexBlockRep(bi); int sz = ri.decode(); if( sid != ri.streamID || size != sz ) { /* construct error message */ StringBuilder sb = new StringBuilder(); Formatter fm = new Formatter(sb); fm.format("streamID %d != %d or size %d != %d: ", ri.streamID, sid, sz, size); for(int j = 0; j < rs.length; j++) { fm.format("%02x ", rs[j]); } throw new IOException(sb.toString()); } } } @Test public void testBlockLimit() throws IOException { /* create a huge array */ int size = MultiplexBlockRep.MAX_BLOCK_SIZE * 2; byte[] buf = new byte [size]; buf[8] = 36; buf[MultiplexBlockRep.MAX_BLOCK_SIZE] = 71; buf[MultiplexBlockRep.MAX_BLOCK_SIZE+71] = 108; /* write it in big chunks */ ByteArrayOutputStream bo = new ByteArrayOutputStream(); MultiplexOutputStream mo = new MultiplexOutputStream(bo, 0); OutputStream os = mo.open(0, new OutputStreamFilter<OutputStream>() { public OutputStream wrap(OutputStream out) { return out; } }); int off = 0, len = size; os.write(buf, off, 1 << 16); off += 1 << 16; len -= 1 << 16; os.write(buf, off, 1 << 8); off += 1 << 8; len -= 1 << 8; os.write(buf, off, len); mo.close(); } @Test public void testStreams() throws IOException { /* first write */ ByteArrayOutputStream bo = new ByteArrayOutputStream(); MultiplexOutputStream mo = new MultiplexOutputStream(bo, 0xDEADBEEF); PrintStream pr = mo.open(0, new OutputStreamFilter<PrintStream>() { public PrintStream wrap(OutputStream out) throws IOException { return new PrintStream(out); }}); DataOutputStream dat = mo.open(1, new OutputStreamFilter<DataOutputStream>() { public DataOutputStream wrap(OutputStream out) throws IOException { return new DataOutputStream(new BufferedOutputStream(out)); }}); pr.println("Hello, world"); dat.writeInt(0xCAFEBABE); dat.writeShort(0xBEEF); pr.println("Here now"); mo.flush(); dat.writeInt(0x12345678); pr.println("The end."); mo.close(); /* show it */ byte[] buf = bo.toByteArray(); hexdump(buf, System.err); /* then read */ ByteArrayInputStream bi = new ByteArrayInputStream(buf); MultiplexInputStream mi = new MultiplexInputStream(bi); assert(0xDEADBEEF == mi.magic()); DataInputStream di = new DataInputStream(mi.open(1)); BufferedReader br = new BufferedReader(new InputStreamReader(mi.open(0))); assert("Hello, world".equals(br.readLine())); assert("Here now".equals(br.readLine())); assert(0xCAFEBABE == di.readInt()); assert(0xBEEF == di.readUnsignedShort()); assert(0x12345678 == di.readInt()); assert("The end.".equals( br.readLine())); assertNull(br.readLine()); try { di.readByte(); assertTrue(false); } catch(EOFException e) { } finally { //mi.close(); } } public static void hexdump(byte[] buf, PrintStream out) { if(System.getProperty("VERBOSE_test") == null) return; byte[] asc = new byte[16]; int n; /* find the next multiple of 16 */ for(n = buf.length + 1; n % 16 != 0; n++) { } boolean valid; for(int i = 0; i <= n; i++) { valid = i < buf.length; if(i % 16 == 0) { if(i > 0) { out.print(" |"); for(byte c : asc) { out.print(Character.isISOControl(c)? '.' : (char)c); } out.print('|'); } out.println(); if(valid) { out.printf("%04X ", i); } } if(i % 8 == 0) { out.print(' '); } if(valid) { asc[i % 16] = buf[i]; out.printf("%02X ", buf[i]); } else { asc[i % 16] = 0; out.print(" "); } } out.println(); } }