@Test public void writeInt() throws Exception { OkBuffer data = new OkBuffer(); data.writeInt(0xabcdef01); data.writeInt(0x87654321); assertEquals("OkBuffer[size=8 data=abcdef0187654321]", data.toString()); }
@Test public void writeShort() throws Exception { OkBuffer data = new OkBuffer(); data.writeShort(0xabcd); data.writeShort(0x4321); assertEquals("OkBuffer[size=4 data=abcd4321]", data.toString()); }
@Override public String readUtf8Line(boolean throwOnEof) throws IOException { long start = 0; long newline; while ((newline = buffer.indexOf((byte) '\n', start)) == -1) { start = buffer.size; if (source.read(buffer, Segment.SIZE) == -1) { if (throwOnEof) throw new EOFException(); return buffer.size != 0 ? readUtf8((int) buffer.size) : null; } } if (newline > 0 && buffer.getByte(newline - 1) == '\r') { // Read everything until '\r\n', then skip the '\r\n'. String result = readUtf8((int) (newline - 1)); skip(2); return result; } else { // Read everything until '\n', then skip the '\n'. String result = readUtf8((int) (newline)); skip(1); return result; } }
@Test public void originalDoesNotObserveWritesToClone() throws Exception { OkBuffer original = new OkBuffer(); OkBuffer clone = original.clone(); clone.writeUtf8("abc"); assertEquals(0, original.size()); }
@Test public void testEqualsAndHashCodeEmpty() throws Exception { OkBuffer a = new OkBuffer(); OkBuffer b = new OkBuffer(); assertTrue(a.equals(b)); assertTrue(a.hashCode() == b.hashCode()); }
@Test public void writeBytes() throws Exception { OkBuffer data = new OkBuffer(); data.writeByte(0xab); data.writeByte(0xcd); assertEquals("OkBuffer[size=2 data=abcd]", data.toString()); }
@Test public void readUtf8SpansSegments() throws Exception { OkBuffer buffer = new OkBuffer(); buffer.writeUtf8(repeat('a', Segment.SIZE * 2)); buffer.readUtf8(Segment.SIZE - 1); assertEquals("aa", buffer.readUtf8(2)); }
@Test public void readShort() throws Exception { OkBuffer data = new OkBuffer(); data.write(new byte[] {(byte) 0xab, (byte) 0xcd, (byte) 0xef, (byte) 0x01}); assertEquals((short) 0xabcd, data.readShort()); assertEquals((short) 0xef01, data.readShort()); assertEquals(0, data.size()); }
@Test public void testWritePrefixToEmptyBuffer() { OkBuffer sink = new OkBuffer(); OkBuffer source = new OkBuffer(); source.writeUtf8("abcd"); sink.write(source, 2); assertEquals("ab", sink.readUtf8(2)); }
@Test public void readByte() throws Exception { OkBuffer data = new OkBuffer(); data.write(new byte[] {(byte) 0xab, (byte) 0xcd}); assertEquals(0xab, data.readByte() & 0xff); assertEquals(0xcd, data.readByte() & 0xff); assertEquals(0, data.size()); }
@Test public void getByteOfEmptyBuffer() throws Exception { OkBuffer buffer = new OkBuffer(); try { buffer.getByte(0); fail(); } catch (IndexOutOfBoundsException expected) { } }
@Override public void skip(long byteCount) throws IOException { while (byteCount > 0) { if (buffer.size == 0 && source.read(buffer, Segment.SIZE) == -1) { throw new EOFException(); } long toSkip = Math.min(byteCount, buffer.size()); buffer.skip(toSkip); byteCount -= toSkip; } }
@Test public void readInt() throws Exception { OkBuffer data = new OkBuffer(); data.write( new byte[] { (byte) 0xab, (byte) 0xcd, (byte) 0xef, (byte) 0x01, (byte) 0x87, (byte) 0x65, (byte) 0x43, (byte) 0x21 }); assertEquals(0xabcdef01, data.readInt()); assertEquals(0x87654321, data.readInt()); assertEquals(0, data.size()); }
@Test public void skip() throws Exception { OkBuffer buffer = new OkBuffer(); buffer.writeUtf8("a"); buffer.writeUtf8(repeat('b', Segment.SIZE)); buffer.writeUtf8("c"); buffer.skip(1); assertEquals('b', buffer.readByte() & 0xff); buffer.skip(Segment.SIZE - 2); assertEquals('b', buffer.readByte() & 0xff); buffer.skip(1); assertEquals(0, buffer.size()); }
@Test public void testEqualsAndHashCode() throws Exception { OkBuffer a = new OkBuffer().writeUtf8("dog"); OkBuffer b = new OkBuffer().writeUtf8("hotdog"); assertFalse(a.equals(b)); assertFalse(a.hashCode() == b.hashCode()); b.readUtf8(3); // Leaves b containing 'dog'. assertTrue(a.equals(b)); assertTrue(a.hashCode() == b.hashCode()); }
@Test public void writePrefixDoesntSplitButRequiresCompact() throws Exception { OkBuffer sink = new OkBuffer(); sink.writeUtf8(repeat('b', Segment.SIZE - 10)); // limit = size - 10 sink.readUtf8(Segment.SIZE - 20); // pos = size = 20 OkBuffer source = new OkBuffer(); source.writeUtf8(repeat('a', Segment.SIZE * 2)); sink.write(source, 20); assertEquals(asList(30), sink.segmentSizes()); assertEquals(asList(Segment.SIZE - 20, Segment.SIZE), source.segmentSizes()); assertEquals(30, sink.size()); assertEquals(Segment.SIZE * 2 - 20, source.size()); }
@Override public void close() throws IOException { if (closed) return; closed = true; source.close(); buffer.clear(); }
@Test public void readAndWriteUtf8() throws Exception { OkBuffer buffer = new OkBuffer(); buffer.writeUtf8("ab"); assertEquals(2, buffer.size()); buffer.writeUtf8("cdef"); assertEquals(6, buffer.size()); assertEquals("abcd", buffer.readUtf8(4)); assertEquals(2, buffer.size()); assertEquals("ef", buffer.readUtf8(2)); assertEquals(0, buffer.size()); try { buffer.readUtf8(1); fail(); } catch (ArrayIndexOutOfBoundsException expected) { } }
@Test public void writePrefixDoesntSplit() throws Exception { OkBuffer sink = new OkBuffer(); sink.writeUtf8(repeat('b', 10)); OkBuffer source = new OkBuffer(); source.writeUtf8(repeat('a', Segment.SIZE * 2)); sink.write(source, 20); assertEquals(asList(30), sink.segmentSizes()); assertEquals(asList(Segment.SIZE - 20, Segment.SIZE), source.segmentSizes()); assertEquals(30, sink.size()); assertEquals(Segment.SIZE * 2 - 20, source.size()); }
@Override public long seek(byte b) throws IOException { long start = 0; long index; while ((index = buffer.indexOf(b, start)) == -1) { start = buffer.size; if (source.read(buffer, Segment.SIZE) == -1) throw new EOFException(); } return index; }
@Test public void testEqualsAndHashCodeSpanningSegments() throws Exception { byte[] data = new byte[1024 * 1024]; Random dice = new Random(0); dice.nextBytes(data); OkBuffer a = bufferWithRandomSegmentLayout(dice, data); OkBuffer b = bufferWithRandomSegmentLayout(dice, data); assertTrue(a.equals(b)); assertTrue(a.hashCode() == b.hashCode()); data[data.length / 2]++; // Change a single byte. OkBuffer c = bufferWithRandomSegmentLayout(dice, data); assertFalse(a.equals(c)); assertFalse(a.hashCode() == c.hashCode()); }
@Test public void originalDoesNotObserveReadsFromClone() throws Exception { OkBuffer original = new OkBuffer(); original.writeUtf8("abc"); OkBuffer clone = original.clone(); assertEquals("abc", clone.readUtf8(3)); assertEquals(3, original.size()); assertEquals("ab", original.readUtf8(2)); }
@Test public void moveFewerThanRequestedBytesWithRead() throws Exception { OkBuffer sink = new OkBuffer(); sink.writeUtf8(repeat('a', 10)); OkBuffer source = new OkBuffer(); source.writeUtf8(repeat('b', 20)); assertEquals(20, source.read(sink, 25)); assertEquals(30, sink.size()); assertEquals(0, source.size()); assertEquals(repeat('a', 10) + repeat('b', 20), sink.readUtf8(30)); }
@Test public void indexOfWithOffset() throws Exception { OkBuffer buffer = new OkBuffer(); int halfSegment = Segment.SIZE / 2; buffer.writeUtf8(repeat('a', halfSegment)); buffer.writeUtf8(repeat('b', halfSegment)); buffer.writeUtf8(repeat('c', halfSegment)); buffer.writeUtf8(repeat('d', halfSegment)); assertEquals(0, buffer.indexOf((byte) 'a', 0)); assertEquals(halfSegment - 1, buffer.indexOf((byte) 'a', halfSegment - 1)); assertEquals(halfSegment, buffer.indexOf((byte) 'b', halfSegment - 1)); assertEquals(halfSegment * 2, buffer.indexOf((byte) 'c', halfSegment - 1)); assertEquals(halfSegment * 3, buffer.indexOf((byte) 'd', halfSegment - 1)); assertEquals(halfSegment * 3, buffer.indexOf((byte) 'd', halfSegment * 2)); assertEquals(halfSegment * 3, buffer.indexOf((byte) 'd', halfSegment * 3)); assertEquals(halfSegment * 4 - 1, buffer.indexOf((byte) 'd', halfSegment * 4 - 1)); }
@Test public void fillAndDrainPool() throws Exception { OkBuffer buffer = new OkBuffer(); // Take 2 * MAX_SIZE segments. This will drain the pool, even if other tests filled it. buffer.write(new byte[(int) SegmentPool.MAX_SIZE]); buffer.write(new byte[(int) SegmentPool.MAX_SIZE]); assertEquals(0, SegmentPool.INSTANCE.byteCount); // Recycle MAX_SIZE segments. They're all in the pool. buffer.readByteString(SegmentPool.MAX_SIZE); assertEquals(SegmentPool.MAX_SIZE, SegmentPool.INSTANCE.byteCount); // Recycle MAX_SIZE more segments. The pool is full so they get garbage collected. buffer.readByteString(SegmentPool.MAX_SIZE); assertEquals(SegmentPool.MAX_SIZE, SegmentPool.INSTANCE.byteCount); // Take MAX_SIZE segments to drain the pool. buffer.write(new byte[(int) SegmentPool.MAX_SIZE]); assertEquals(0, SegmentPool.INSTANCE.byteCount); // Take MAX_SIZE more segments. The pool is drained so these will need to be allocated. buffer.write(new byte[(int) SegmentPool.MAX_SIZE]); assertEquals(0, SegmentPool.INSTANCE.byteCount); }
@Override public long read(OkBuffer sink, long byteCount) throws IOException { if (byteCount < 0) throw new IllegalArgumentException("byteCount < 0: " + byteCount); if (closed) throw new IllegalStateException("closed"); if (buffer.size == 0) { long read = source.read(buffer, Segment.SIZE); if (read == -1) return -1; } long toRead = Math.min(byteCount, buffer.size); return buffer.read(sink, toRead); }
@Test public void cloneMultipleSegments() throws Exception { OkBuffer original = new OkBuffer(); original.writeUtf8(repeat('a', Segment.SIZE * 3)); OkBuffer clone = original.clone(); original.writeUtf8(repeat('b', Segment.SIZE * 3)); clone.writeUtf8(repeat('c', Segment.SIZE * 3)); assertEquals( repeat('a', Segment.SIZE * 3) + repeat('b', Segment.SIZE * 3), original.readUtf8(Segment.SIZE * 6)); assertEquals( repeat('a', Segment.SIZE * 3) + repeat('c', Segment.SIZE * 3), clone.readUtf8(Segment.SIZE * 6)); }
@Test public void byteAt() throws Exception { OkBuffer buffer = new OkBuffer(); buffer.writeUtf8("a"); buffer.writeUtf8(repeat('b', Segment.SIZE)); buffer.writeUtf8("c"); assertEquals('a', buffer.getByte(0)); assertEquals('a', buffer.getByte(0)); // getByte doesn't mutate! assertEquals('c', buffer.getByte(buffer.size - 1)); assertEquals('b', buffer.getByte(buffer.size - 2)); assertEquals('b', buffer.getByte(buffer.size - 3)); }
@Test public void readShortSplitAcrossMultipleSegments() throws Exception { OkBuffer data = new OkBuffer(); data.writeUtf8(repeat('a', Segment.SIZE - 1)); data.write(new byte[] {(byte) 0xab, (byte) 0xcd}); data.readUtf8(Segment.SIZE - 1); assertEquals((short) 0xabcd, data.readShort()); assertEquals(0, data.size()); }
@Test public void readIntSplitAcrossMultipleSegments() throws Exception { OkBuffer data = new OkBuffer(); data.writeUtf8(repeat('a', Segment.SIZE - 3)); data.write(new byte[] {(byte) 0xab, (byte) 0xcd, (byte) 0xef, (byte) 0x01}); data.readUtf8(Segment.SIZE - 3); assertEquals(0xabcdef01, data.readInt()); assertEquals(0, data.size()); }