package org.limewire.nio;
import java.nio.BufferOverflowException;
import java.nio.BufferUnderflowException;
import java.nio.ByteBuffer;
import java.nio.channels.ReadableByteChannel;
import java.nio.channels.WritableByteChannel;
import junit.framework.Test;
import org.limewire.nio.channel.ReadBufferChannel;
import org.limewire.nio.channel.WriteBufferChannel;
import org.limewire.util.BaseTestCase;
import org.limewire.util.ByteUtils;
/**
* Tests some of the functionality of the Circular buffer.
*
*/
public class CircularByteBufferTest extends BaseTestCase {
public CircularByteBufferTest(String name) {
super(name);
}
public static Test suite() {
return buildTestSuite(CircularByteBufferTest.class);
}
static StubCache cache;
@Override
public void setUp() {
cache = new StubCache();
}
public void testBasic() throws Exception {
byte [] in = new byte[]{(byte)1,(byte)2};
CircularByteBuffer buf = new CircularByteBuffer(2,cache);
assertEquals(2,buf.remainingIn());
assertEquals(0,buf.remainingOut());
buf.put(ByteBuffer.wrap(in));
assertEquals(0,buf.remainingIn());
assertEquals(2,buf.remainingOut());
byte [] out = new byte[2];
buf.get(out);
assertEquals(2,buf.remainingIn());
assertEquals(0,buf.remainingOut());
assertEquals(in[0],out[0]);
assertEquals(in[1],out[1]);
}
public void testOverflow() throws Exception {
byte [] in = new byte[]{(byte)1,(byte)2};
CircularByteBuffer buf = new CircularByteBuffer(1,cache);
assertEquals(1,buf.remainingIn());
assertEquals(0,buf.remainingOut());
try {
buf.put(ByteBuffer.wrap(in));
fail(" should have overflown");
} catch (BufferOverflowException expected) {}
assertEquals(1,buf.remainingIn());
assertEquals(0,buf.remainingOut());
}
public void testUnderflow() throws Exception {
byte [] in = new byte[]{(byte)1,(byte)2};
CircularByteBuffer buf = new CircularByteBuffer(2,cache);
buf.put(ByteBuffer.wrap(in));
assertEquals(0,buf.remainingIn());
assertEquals(2,buf.remainingOut());
byte [] out = new byte[3];
try {
buf.get(out);
fail("should have underflown");
} catch (BufferUnderflowException expected) {}
assertEquals(0,buf.remainingIn());
assertEquals(2,buf.remainingOut());
}
public void testWrapAround() throws Exception {
byte [] in = new byte[30];
for(int i = 0;i < 20;i++) in[i]=(byte)i;
CircularByteBuffer buf = new CircularByteBuffer(5,cache);
ReadableByteChannel source = new ReadBufferChannel(in);
// R1 R2 R3 R4 R5
assertEquals(5,buf.read(source));
assertEquals(0,buf.remainingIn());
assertEquals(5,buf.remainingOut());
assertEquals(5, buf.size());
// R1 R2 - - -
buf.get();buf.get();
assertEquals(2,buf.remainingIn());
assertEquals(3,buf.remainingOut());
assertEquals(2,buf.read(source));
assertEquals(0,buf.remainingIn());
assertEquals(5,buf.remainingOut());
// W1 W2 W3 W4 W5
WritableByteChannel sink = new WriteBufferChannel(20);
assertEquals(5,buf.write(sink));
assertEquals(5,buf.read(source));
// - - W1 W2 W3
buf.get();buf.get();
assertEquals(3,buf.write(sink));
assertEquals(5,buf.read(source));
// W5 W1 W2 W3 W4
buf.get();
assertEquals(1,buf.read(source));
assertEquals(5,buf.write(sink));
// R5 R1 R2 R3 R4
assertEquals(5,buf.read(source));
}
/**
* tests getting of int with varying endinanness.
*/
public static void testGetInt() throws Exception {
CircularByteBuffer buf = new CircularByteBuffer(4, cache);
byte [] data = new byte[4];
ByteUtils.int2leb(50, data, 0);
ReadableByteChannel source = new ReadBufferChannel(data);
buf.read(source);
// default order should be big endian
assertNotEquals(50,buf.getInt());
buf.order(java.nio.ByteOrder.LITTLE_ENDIAN);
source = new ReadBufferChannel(data);
buf.read(source);
assertEquals(50, buf.getInt());
ByteUtils.int2beb(50, data, 0);
buf.order(java.nio.ByteOrder.BIG_ENDIAN);
source = new ReadBufferChannel(data);
buf.read(source);
assertEquals(50, buf.getInt());
}
/**
* tests that the buffer uses the provided cache.
*/
public static void testUsesCache() throws Exception {
// at first, the cache has not checked out any buffers.
assertNull(cache.checkedOut);
CircularByteBuffer buf = new CircularByteBuffer(4, cache);
byte [] data = new byte[4];
ByteUtils.int2leb(50, data, 0);
ReadableByteChannel source = new ReadBufferChannel(data);
buf.read(source);
// after we read, something does get checked out.
assertNotNull(cache.checkedOut);
ByteBuffer used = cache.checkedOut;
// read some more, but not all. Buffer should be still checked out.
buf.get();buf.get();
assertEquals(2, buf.size());
assertSame(used, cache.checkedOut);
// read everything
buf.get();buf.get();
assertEquals(0,buf.size());
assertNull(cache.checkedOut);
}
/**
* tests the discarding of data.
*/
public static void testDiscard() throws Exception {
CircularByteBuffer buf = new CircularByteBuffer(4, cache);
byte [] data = new byte[4];
ByteUtils.int2leb(50, data, 0);
ReadableByteChannel source = new ReadBufferChannel(data);
buf.read(source);
assertEquals(4, buf.size());
buf.discard(3);
assertEquals(1, buf.size());
try {
buf.discard(2);
fail("bue expected");
} catch (BufferUnderflowException expected){}
buf.discard(1);
assertEquals(0,buf.size());
}
private static class StubCache extends ByteBufferCache {
ByteBuffer checkedOut;
public StubCache() {}
@Override
public void clearCache() {}
@Override
public ByteBuffer getDirect() {
return null;
}
@Override
public ByteBuffer getHeap() {
fail(" illegal method invocation");
return null;
}
@Override
public ByteBuffer getHeap(int size) {
assertNull(checkedOut);
checkedOut = ByteBuffer.allocate(size);
return checkedOut;
}
@Override
public long getHeapCacheSize() {
return 0;
}
@Override
public void release(ByteBuffer buffer) {
assertSame(checkedOut, buffer);
checkedOut = null;
}
}
}