package com.limegroup.gnutella.connection;
import java.io.*;
import java.nio.ByteBuffer;
import java.nio.channels.ReadableByteChannel;
import java.util.*;
import java.util.zip.*;
import java.net.*;
import junit.framework.Test;
import com.limegroup.gnutella.*;
import com.limegroup.gnutella.io.InterestReadChannel;
import com.limegroup.gnutella.messages.*;
import com.limegroup.gnutella.util.*;
/**
* Tests that InflaterReader inflates the source channel correctly.
*/
public final class InflaterReaderTest extends BaseTestCase {
private Inflater INFLATER = new Inflater();
private InflaterReader READER = new InflaterReader(INFLATER);
public InflaterReaderTest(String name) {
super(name);
}
public static Test suite() {
return buildTestSuite(InflaterReaderTest.class);
}
public static void main(String[] args) {
junit.textui.TestRunner.run(suite());
}
public void testChannelMethods() throws Exception {
try {
READER.setReadChannel(null);
fail("expected NPE");
} catch(NullPointerException expected) {}
InterestReadChannel channel = new ReadBufferChannel(new byte[0]);
READER.setReadChannel(channel);
assertSame(channel, READER.getReadChannel());
try {
new InflaterReader(null);
fail("expected NPE");
} catch(NullPointerException expected) {}
READER = new InflaterReader(channel, INFLATER);
assertSame(channel, READER.getReadChannel());
READER = new InflaterReader(null, INFLATER);
assertNull(READER.getReadChannel());
}
public void testClosing() throws Exception {
ReadBufferChannel source = new ReadBufferChannel();
assertTrue(source.isOpen());
READER.setReadChannel(source);
assertTrue(READER.isOpen());
source.setClosed(true);
assertFalse(READER.isOpen());
source.setClosed(false);
assertTrue(READER.isOpen());
assertTrue(source.isOpen());
READER.close();
assertFalse(source.isOpen());
}
public void testFinishedInflation() throws Exception {
byte[] out = new byte[] { 1, (byte)2, (byte)3, (byte)-127, (byte)7, (byte)6 };
ByteBuffer b = deflate(out);
READER.setReadChannel(channel(b));
ByteBuffer in = ByteBuffer.allocate(out.length + 1);
assertEquals(out.length, READER.read(in));
assertEquals(out.length, in.position());
assertEquals(buffer(out), in.flip());
// Since the deflater finished the stream, the next read should return -1.
in.limit(out.length + 1);
assertEquals("should have seen finished stream", -1, READER.read(in));
}
public void testStreamedInflation() throws Exception {
byte[] out = new byte[] { 1, (byte)2, (byte)3, (byte)-127, (byte)7, (byte)6 };
ByteBuffer b = stream(out);
READER.setReadChannel(channel(b));
ByteBuffer in = ByteBuffer.allocate(out.length + 1);
assertEquals(out.length, READER.read(in));
assertEquals(out.length, in.position());
assertEquals(buffer(out), in.flip());
// Since the deflater didn't finish the stream, the next read should return 0.
in.limit(out.length + 1);
assertEquals("stream shouldn't have ended", 0, READER.read(in));
}
public void testLargeInput() throws Exception {
byte[] out = new byte[128 * 1024];
new Random().nextBytes(out);
ByteBuffer b = stream(out);
assertGreaterThan("deflated data too small", 20 * 1024, b.remaining());
READER.setReadChannel(channel(b));
ByteBuffer in = ByteBuffer.allocate(out.length + 1);
assertEquals("input buffer: " + b, out.length, READER.read(in));
assertEquals(out.length, in.position());
assertEquals(buffer(out), in.flip());
// Since the deflater didn't finish the stream, the next read should return 0.
in.limit(out.length + 1);
assertEquals("stream shouldn't have ended", 0, READER.read(in));
}
public void testEOFWithStream() throws Exception {
byte[] out = new byte[1024];
new Random().nextBytes(out);
ByteBuffer b = stream(out);
READER.setReadChannel(eof(b));
ByteBuffer in = ByteBuffer.allocate(out.length + 1);
assertEquals("input buffer: " + b, out.length, READER.read(in));
assertEquals(out.length, in.position());
assertEquals(buffer(out), in.flip());
// Even though there's data the deflater is waiting on, the stream EOF'd.
in.limit(out.length + 1);
assertEquals("stream should have EOF'd", -1, READER.read(in));
}
public void testPartialReads() throws Exception {
byte[] out = new byte[64 * 1024];
new Random().nextBytes(out);
ByteBuffer b1 = stream(out);
ByteBuffer b2 = b1.duplicate();
ByteBuffer b3 = b2.duplicate();
ByteBuffer b4 = b3.duplicate();
b1.limit(500);
b2.position(500).limit(2000);
b3.position(2000).limit(8000);
b4.position(8000);
ByteBuffer in = ByteBuffer.allocate(out.length + 1);
// The data is going to be deflated randomly,
// according to what sections are decompressable and what aren't.
int read = 0;
READER.setReadChannel(channel(b1));
assertTrue(b1.hasRemaining());
read += READER.read(in);
assertEquals(read, in.position());
assertFalse(b1.hasRemaining());
READER.setReadChannel(channel(b2));
assertTrue(b2.hasRemaining());
read += READER.read(in);
assertEquals(read, in.position());
assertFalse(b2.hasRemaining());
READER.setReadChannel(channel(b3));
assertTrue(b3.hasRemaining());
read += READER.read(in);
assertEquals(read, in.position());
assertFalse(b3.hasRemaining());
READER.setReadChannel(channel(b4));
assertTrue(b4.hasRemaining());
read += READER.read(in);
assertEquals(out.length, in.position());
assertEquals(out.length, read);
assertFalse(b4.hasRemaining());
assertEquals(buffer(out), in.flip());
// Still another chunk that may come...
in.limit(out.length + 1);
assertEquals("stream shouldn't have ended.", 0, READER.read(in));
}
private InterestReadChannel channel(ByteBuffer buffer) throws Exception {
return new ReadBufferChannel(buffer);
}
private InterestReadChannel eof(ByteBuffer buffer) throws Exception {
return new ReadBufferChannel(buffer, true);
}
private ByteBuffer deflate(byte[] data) throws Exception {
OutputStream dos = null;
try {
ByteArrayOutputStream baos=new ByteArrayOutputStream();
dos = new DeflaterOutputStream(baos);
dos.write(data, 0, data.length);
dos.close(); //flushes bytes
return buffer(baos.toByteArray());
} finally {
if(dos != null)
try { dos.close(); } catch(IOException x) {}
}
}
private ByteBuffer stream(byte[] data) throws Exception {
OutputStream dos = null;
Deflater def = new Deflater();
try {
ByteArrayOutputStream baos=new ByteArrayOutputStream();
dos = new CompressingOutputStream(baos, def);
dos.write(data, 0, data.length);
dos.flush();
return buffer(baos.toByteArray());
} finally {
if(dos != null)
try { dos.close(); } catch(IOException x) {}
def.end();
}
}
private ByteBuffer buffer(byte[] b) throws Exception {
return ByteBuffer.wrap(b);
}
}