http://git-wip-us.apache.org/repos/asf/flink/blob/85bea23a/flink-runtime/src/test/java/org/apache/flink/runtime/io/network/buffer/AbstractByteBufTest.java ---------------------------------------------------------------------- diff --git a/flink-runtime/src/test/java/org/apache/flink/runtime/io/network/buffer/AbstractByteBufTest.java b/flink-runtime/src/test/java/org/apache/flink/runtime/io/network/buffer/AbstractByteBufTest.java new file mode 100644 index 0000000..8f19552 --- /dev/null +++ b/flink-runtime/src/test/java/org/apache/flink/runtime/io/network/buffer/AbstractByteBufTest.java @@ -0,0 +1,3077 @@ +/* + * Copyright 2012 The Netty Project + * Copy from netty 4.0.50.Final, changed to fit our use of netty 4.0.27. + * + * The Netty Project licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ + +package org.apache.flink.runtime.io.network.buffer; + +import org.apache.flink.shaded.netty4.io.netty.buffer.ByteBuf; +import org.apache.flink.shaded.netty4.io.netty.buffer.ByteBufProcessor; +import org.apache.flink.shaded.netty4.io.netty.buffer.ByteBufUtil; +import org.apache.flink.shaded.netty4.io.netty.util.CharsetUtil; +import org.apache.flink.shaded.netty4.io.netty.util.IllegalReferenceCountException; +import org.apache.flink.shaded.netty4.io.netty.util.internal.ThreadLocalRandom; + +import org.junit.After; +import org.junit.Before; +import org.junit.Ignore; +import org.junit.Test; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.ReadOnlyBufferException; +import java.nio.channels.Channels; +import java.nio.channels.GatheringByteChannel; +import java.nio.channels.ScatteringByteChannel; +import java.nio.channels.WritableByteChannel; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Random; +import java.util.Set; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.CyclicBarrier; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicReference; + +import static org.apache.flink.shaded.netty4.io.netty.buffer.Unpooled.LITTLE_ENDIAN; +import static org.apache.flink.shaded.netty4.io.netty.buffer.Unpooled.buffer; +import static org.apache.flink.shaded.netty4.io.netty.buffer.Unpooled.copiedBuffer; +import static org.apache.flink.shaded.netty4.io.netty.buffer.Unpooled.directBuffer; +import static org.apache.flink.shaded.netty4.io.netty.buffer.Unpooled.wrappedBuffer; +import static org.apache.flink.shaded.netty4.io.netty.util.internal.EmptyArrays.EMPTY_BYTES; +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import static org.junit.Assume.assumeTrue; + +/** + * An abstract test class for channel buffers. + * + * Copied from netty 4.0.50 with some changes to fit our netty version 4.0.27. + */ +public abstract class AbstractByteBufTest { + + private static final int CAPACITY = 4096; // Must be even + private static final int BLOCK_SIZE = 128; + private static final int JAVA_BYTEBUFFER_CONSISTENCY_ITERATIONS = 100; + + private long seed; + private Random random; + private ByteBuf buffer; + + protected final ByteBuf newBuffer(int capacity) { + return newBuffer(capacity, Integer.MAX_VALUE); + } + + protected abstract ByteBuf newBuffer(int capacity, int maxCapacity); + + protected boolean discardReadBytesDoesNotMoveWritableBytes() { + return true; + } + + @Before + public void init() { + buffer = newBuffer(CAPACITY); + seed = System.currentTimeMillis(); + random = new Random(seed); + } + + @After + public void dispose() { + if (buffer != null) { + assertThat(buffer.release(), is(true)); + assertThat(buffer.refCnt(), is(0)); + + try { + buffer.release(); + } catch (Exception e) { + // Ignore. + } + buffer = null; + } + } + + @Test + public void comparableInterfaceNotViolated() { + buffer.writerIndex(buffer.readerIndex()); + assumeTrue(buffer.writableBytes() >= 4); + + buffer.writeLong(0); + ByteBuf buffer2 = newBuffer(CAPACITY); + buffer2.writerIndex(buffer2.readerIndex()); + // Write an unsigned integer that will cause buffer.getUnsignedInt() - buffer2.getUnsignedInt() to underflow the + // int type and wrap around on the negative side. + buffer2.writeLong(0xF0000000L); + assertTrue(buffer.compareTo(buffer2) < 0); + assertTrue(buffer2.compareTo(buffer) > 0); + buffer2.release(); + } + + @Test + public void initialState() { + assertEquals(CAPACITY, buffer.capacity()); + assertEquals(0, buffer.readerIndex()); + } + + @Test(expected = IndexOutOfBoundsException.class) + public void readerIndexBoundaryCheck1() { + try { + buffer.writerIndex(0); + } catch (IndexOutOfBoundsException e) { + fail(); + } + buffer.readerIndex(-1); + } + + @Test(expected = IndexOutOfBoundsException.class) + public void readerIndexBoundaryCheck2() { + try { + buffer.writerIndex(buffer.capacity()); + } catch (IndexOutOfBoundsException e) { + fail(); + } + buffer.readerIndex(buffer.capacity() + 1); + } + + @Test(expected = IndexOutOfBoundsException.class) + public void readerIndexBoundaryCheck3() { + try { + buffer.writerIndex(CAPACITY / 2); + } catch (IndexOutOfBoundsException e) { + fail(); + } + buffer.readerIndex(CAPACITY * 3 / 2); + } + + @Test + public void readerIndexBoundaryCheck4() { + buffer.writerIndex(0); + buffer.readerIndex(0); + buffer.writerIndex(buffer.capacity()); + buffer.readerIndex(buffer.capacity()); + } + + @Test(expected = IndexOutOfBoundsException.class) + public void writerIndexBoundaryCheck1() { + buffer.writerIndex(-1); + } + + @Test(expected = IndexOutOfBoundsException.class) + public void writerIndexBoundaryCheck2() { + try { + buffer.writerIndex(CAPACITY); + buffer.readerIndex(CAPACITY); + } catch (IndexOutOfBoundsException e) { + fail(); + } + buffer.writerIndex(buffer.capacity() + 1); + } + + @Test(expected = IndexOutOfBoundsException.class) + public void writerIndexBoundaryCheck3() { + try { + buffer.writerIndex(CAPACITY); + buffer.readerIndex(CAPACITY / 2); + } catch (IndexOutOfBoundsException e) { + fail(); + } + buffer.writerIndex(CAPACITY / 4); + } + + @Test + public void writerIndexBoundaryCheck4() { + buffer.writerIndex(0); + buffer.readerIndex(0); + buffer.writerIndex(CAPACITY); + + buffer.writeBytes(ByteBuffer.wrap(EMPTY_BYTES)); + } + + @Test(expected = IndexOutOfBoundsException.class) + public void getBooleanBoundaryCheck1() { + buffer.getBoolean(-1); + } + + @Test(expected = IndexOutOfBoundsException.class) + public void getBooleanBoundaryCheck2() { + buffer.getBoolean(buffer.capacity()); + } + + @Test(expected = IndexOutOfBoundsException.class) + public void getByteBoundaryCheck1() { + buffer.getByte(-1); + } + + @Test(expected = IndexOutOfBoundsException.class) + public void getByteBoundaryCheck2() { + buffer.getByte(buffer.capacity()); + } + + @Test(expected = IndexOutOfBoundsException.class) + public void getShortBoundaryCheck1() { + buffer.getShort(-1); + } + + @Test(expected = IndexOutOfBoundsException.class) + public void getShortBoundaryCheck2() { + buffer.getShort(buffer.capacity() - 1); + } + + @Test(expected = IndexOutOfBoundsException.class) + public void getMediumBoundaryCheck1() { + buffer.getMedium(-1); + } + + @Test(expected = IndexOutOfBoundsException.class) + public void getMediumBoundaryCheck2() { + buffer.getMedium(buffer.capacity() - 2); + } + + @Test(expected = IndexOutOfBoundsException.class) + public void getIntBoundaryCheck1() { + buffer.getInt(-1); + } + + @Test(expected = IndexOutOfBoundsException.class) + public void getIntBoundaryCheck2() { + buffer.getInt(buffer.capacity() - 3); + } + + @Test(expected = IndexOutOfBoundsException.class) + public void getLongBoundaryCheck1() { + buffer.getLong(-1); + } + + @Test(expected = IndexOutOfBoundsException.class) + public void getLongBoundaryCheck2() { + buffer.getLong(buffer.capacity() - 7); + } + + @Test(expected = IndexOutOfBoundsException.class) + public void getByteArrayBoundaryCheck1() { + buffer.getBytes(-1, EMPTY_BYTES); + } + + @Test(expected = IndexOutOfBoundsException.class) + public void getByteArrayBoundaryCheck2() { + buffer.getBytes(-1, EMPTY_BYTES, 0, 0); + } + + @Test + public void getByteArrayBoundaryCheck3() { + byte[] dst = new byte[4]; + buffer.setInt(0, 0x01020304); + try { + buffer.getBytes(0, dst, -1, 4); + fail(); + } catch (IndexOutOfBoundsException e) { + // Success + } + + // No partial copy is expected. + assertEquals(0, dst[0]); + assertEquals(0, dst[1]); + assertEquals(0, dst[2]); + assertEquals(0, dst[3]); + } + + @Test + public void getByteArrayBoundaryCheck4() { + byte[] dst = new byte[4]; + buffer.setInt(0, 0x01020304); + try { + buffer.getBytes(0, dst, 1, 4); + fail(); + } catch (IndexOutOfBoundsException e) { + // Success + } + + // No partial copy is expected. + assertEquals(0, dst[0]); + assertEquals(0, dst[1]); + assertEquals(0, dst[2]); + assertEquals(0, dst[3]); + } + + @Test(expected = IndexOutOfBoundsException.class) + public void getByteBufferBoundaryCheck() { + buffer.getBytes(-1, ByteBuffer.allocate(0)); + } + + @Test(expected = IndexOutOfBoundsException.class) + public void copyBoundaryCheck1() { + buffer.copy(-1, 0); + } + + @Test(expected = IndexOutOfBoundsException.class) + public void copyBoundaryCheck2() { + buffer.copy(0, buffer.capacity() + 1); + } + + @Test(expected = IndexOutOfBoundsException.class) + public void copyBoundaryCheck3() { + buffer.copy(buffer.capacity() + 1, 0); + } + + @Test(expected = IndexOutOfBoundsException.class) + public void copyBoundaryCheck4() { + buffer.copy(buffer.capacity(), 1); + } + + @Test(expected = IndexOutOfBoundsException.class) + public void setIndexBoundaryCheck1() { + buffer.setIndex(-1, CAPACITY); + } + + @Test(expected = IndexOutOfBoundsException.class) + public void setIndexBoundaryCheck2() { + buffer.setIndex(CAPACITY / 2, CAPACITY / 4); + } + + @Test(expected = IndexOutOfBoundsException.class) + public void setIndexBoundaryCheck3() { + buffer.setIndex(0, CAPACITY + 1); + } + + @Test + public void getByteBufferState() { + ByteBuffer dst = ByteBuffer.allocate(4); + dst.position(1); + dst.limit(3); + + buffer.setByte(0, (byte) 1); + buffer.setByte(1, (byte) 2); + buffer.setByte(2, (byte) 3); + buffer.setByte(3, (byte) 4); + buffer.getBytes(1, dst); + + assertEquals(3, dst.position()); + assertEquals(3, dst.limit()); + + dst.clear(); + assertEquals(0, dst.get(0)); + assertEquals(2, dst.get(1)); + assertEquals(3, dst.get(2)); + assertEquals(0, dst.get(3)); + } + + @Test(expected = IndexOutOfBoundsException.class) + public void getDirectByteBufferBoundaryCheck() { + buffer.getBytes(-1, ByteBuffer.allocateDirect(0)); + } + + @Test + public void getDirectByteBufferState() { + ByteBuffer dst = ByteBuffer.allocateDirect(4); + dst.position(1); + dst.limit(3); + + buffer.setByte(0, (byte) 1); + buffer.setByte(1, (byte) 2); + buffer.setByte(2, (byte) 3); + buffer.setByte(3, (byte) 4); + buffer.getBytes(1, dst); + + assertEquals(3, dst.position()); + assertEquals(3, dst.limit()); + + dst.clear(); + assertEquals(0, dst.get(0)); + assertEquals(2, dst.get(1)); + assertEquals(3, dst.get(2)); + assertEquals(0, dst.get(3)); + } + + @Test + public void testRandomByteAccess() { + for (int i = 0; i < buffer.capacity(); i ++) { + byte value = (byte) random.nextInt(); + buffer.setByte(i, value); + } + + random.setSeed(seed); + for (int i = 0; i < buffer.capacity(); i ++) { + byte value = (byte) random.nextInt(); + assertEquals(value, buffer.getByte(i)); + } + } + + @Test + public void testRandomUnsignedByteAccess() { + for (int i = 0; i < buffer.capacity(); i ++) { + byte value = (byte) random.nextInt(); + buffer.setByte(i, value); + } + + random.setSeed(seed); + for (int i = 0; i < buffer.capacity(); i ++) { + int value = random.nextInt() & 0xFF; + assertEquals(value, buffer.getUnsignedByte(i)); + } + } + + @Test + public void testRandomShortAccess() { + for (int i = 0; i < buffer.capacity() - 1; i += 2) { + short value = (short) random.nextInt(); + buffer.setShort(i, value); + } + + random.setSeed(seed); + for (int i = 0; i < buffer.capacity() - 1; i += 2) { + short value = (short) random.nextInt(); + assertEquals(value, buffer.getShort(i)); + } + } + + @Test + public void testShortConsistentWithByteBuffer() { + testShortConsistentWithByteBuffer(true, true); + testShortConsistentWithByteBuffer(true, false); + testShortConsistentWithByteBuffer(false, true); + testShortConsistentWithByteBuffer(false, false); + } + + private void testShortConsistentWithByteBuffer(boolean direct, boolean testBigEndian) { + for (int i = 0; i < JAVA_BYTEBUFFER_CONSISTENCY_ITERATIONS; ++i) { + ByteBuffer javaBuffer = direct ? ByteBuffer.allocateDirect(buffer.capacity()) + : ByteBuffer.allocate(buffer.capacity()); + if (!testBigEndian) { + javaBuffer = javaBuffer.order(ByteOrder.LITTLE_ENDIAN); + } + + short expected = (short) (random.nextInt() & 0xFFFF); + javaBuffer.putShort(expected); + + final int bufferIndex = buffer.capacity() - 2; + if (!testBigEndian) { + buffer = buffer.order(ByteOrder.LITTLE_ENDIAN); + } + buffer.setShort(bufferIndex, expected); + javaBuffer.flip(); + + short javaActual = javaBuffer.getShort(); + assertEquals(expected, javaActual); + assertEquals(javaActual, buffer.getShort(bufferIndex)); + } + } + + @Test + public void testRandomUnsignedShortAccess() { + for (int i = 0; i < buffer.capacity() - 1; i += 2) { + short value = (short) random.nextInt(); + buffer.setShort(i, value); + } + + random.setSeed(seed); + for (int i = 0; i < buffer.capacity() - 1; i += 2) { + int value = random.nextInt() & 0xFFFF; + assertEquals(value, buffer.getUnsignedShort(i)); + } + } + + @Test + public void testRandomMediumAccess() { + for (int i = 0; i < buffer.capacity() - 2; i += 3) { + int value = random.nextInt(); + buffer.setMedium(i, value); + } + + random.setSeed(seed); + for (int i = 0; i < buffer.capacity() - 2; i += 3) { + int value = random.nextInt() << 8 >> 8; + assertEquals(value, buffer.getMedium(i)); + } + } + + @Test + public void testRandomUnsignedMediumAccess() { + for (int i = 0; i < buffer.capacity() - 2; i += 3) { + int value = random.nextInt(); + buffer.setMedium(i, value); + } + + random.setSeed(seed); + for (int i = 0; i < buffer.capacity() - 2; i += 3) { + int value = random.nextInt() & 0x00FFFFFF; + assertEquals(value, buffer.getUnsignedMedium(i)); + } + } + + @Test + public void testMediumConsistentWithByteBuffer() { + testMediumConsistentWithByteBuffer(true, true); + testMediumConsistentWithByteBuffer(true, false); + testMediumConsistentWithByteBuffer(false, true); + testMediumConsistentWithByteBuffer(false, false); + } + + private void testMediumConsistentWithByteBuffer(boolean direct, boolean testBigEndian) { + for (int i = 0; i < JAVA_BYTEBUFFER_CONSISTENCY_ITERATIONS; ++i) { + ByteBuffer javaBuffer = direct ? ByteBuffer.allocateDirect(buffer.capacity()) + : ByteBuffer.allocate(buffer.capacity()); + if (!testBigEndian) { + javaBuffer = javaBuffer.order(ByteOrder.LITTLE_ENDIAN); + } + + int expected = random.nextInt() & 0x00FFFFFF; + javaBuffer.putInt(expected); + + final int bufferIndex = buffer.capacity() - 3; + if (testBigEndian) { + buffer = buffer.order(ByteOrder.LITTLE_ENDIAN); + } + buffer.setMedium(bufferIndex, expected); + javaBuffer.flip(); + + int javaActual = javaBuffer.getInt(); + assertEquals(expected, javaActual); + assertEquals(javaActual, buffer.getUnsignedMedium(bufferIndex)); + } + } + + @Test + public void testRandomIntAccess() { + for (int i = 0; i < buffer.capacity() - 3; i += 4) { + int value = random.nextInt(); + buffer.setInt(i, value); + } + + random.setSeed(seed); + for (int i = 0; i < buffer.capacity() - 3; i += 4) { + int value = random.nextInt(); + assertEquals(value, buffer.getInt(i)); + } + } + + @Test + public void testIntConsistentWithByteBuffer() { + testIntConsistentWithByteBuffer(true, true); + testIntConsistentWithByteBuffer(true, false); + testIntConsistentWithByteBuffer(false, true); + testIntConsistentWithByteBuffer(false, false); + } + + private void testIntConsistentWithByteBuffer(boolean direct, boolean testBigEndian) { + for (int i = 0; i < JAVA_BYTEBUFFER_CONSISTENCY_ITERATIONS; ++i) { + ByteBuffer javaBuffer = direct ? ByteBuffer.allocateDirect(buffer.capacity()) + : ByteBuffer.allocate(buffer.capacity()); + if (!testBigEndian) { + javaBuffer = javaBuffer.order(ByteOrder.LITTLE_ENDIAN); + } + + int expected = random.nextInt(); + javaBuffer.putInt(expected); + + final int bufferIndex = buffer.capacity() - 4; + if (testBigEndian) { + buffer = buffer.order(ByteOrder.LITTLE_ENDIAN); + } + buffer.setInt(bufferIndex, expected); + javaBuffer.flip(); + + int javaActual = javaBuffer.getInt(); + assertEquals(expected, javaActual); + assertEquals(javaActual, buffer.getInt(bufferIndex)); + } + } + + @Test + public void testRandomUnsignedIntAccess() { + for (int i = 0; i < buffer.capacity() - 3; i += 4) { + int value = random.nextInt(); + buffer.setInt(i, value); + } + + random.setSeed(seed); + for (int i = 0; i < buffer.capacity() - 3; i += 4) { + long value = random.nextInt() & 0xFFFFFFFFL; + assertEquals(value, buffer.getUnsignedInt(i)); + } + } + + @Test + public void testRandomLongAccess() { + for (int i = 0; i < buffer.capacity() - 7; i += 8) { + long value = random.nextLong(); + buffer.setLong(i, value); + } + + random.setSeed(seed); + for (int i = 0; i < buffer.capacity() - 7; i += 8) { + long value = random.nextLong(); + assertEquals(value, buffer.getLong(i)); + } + } + + @Test + public void testSetZero() { + buffer.clear(); + while (buffer.isWritable()) { + buffer.writeByte((byte) 0xFF); + } + + for (int i = 0; i < buffer.capacity();) { + int length = Math.min(buffer.capacity() - i, random.nextInt(32)); + buffer.setZero(i, length); + i += length; + } + + for (int i = 0; i < buffer.capacity(); i ++) { + assertEquals(0, buffer.getByte(i)); + } + } + + @Test + public void testSequentialByteAccess() { + buffer.writerIndex(0); + for (int i = 0; i < buffer.capacity(); i ++) { + byte value = (byte) random.nextInt(); + assertEquals(i, buffer.writerIndex()); + assertTrue(buffer.isWritable()); + buffer.writeByte(value); + } + + assertEquals(0, buffer.readerIndex()); + assertEquals(buffer.capacity(), buffer.writerIndex()); + assertFalse(buffer.isWritable()); + + random.setSeed(seed); + for (int i = 0; i < buffer.capacity(); i ++) { + byte value = (byte) random.nextInt(); + assertEquals(i, buffer.readerIndex()); + assertTrue(buffer.isReadable()); + assertEquals(value, buffer.readByte()); + } + + assertEquals(buffer.capacity(), buffer.readerIndex()); + assertEquals(buffer.capacity(), buffer.writerIndex()); + assertFalse(buffer.isReadable()); + assertFalse(buffer.isWritable()); + } + + @Test + public void testSequentialUnsignedByteAccess() { + buffer.writerIndex(0); + for (int i = 0; i < buffer.capacity(); i ++) { + byte value = (byte) random.nextInt(); + assertEquals(i, buffer.writerIndex()); + assertTrue(buffer.isWritable()); + buffer.writeByte(value); + } + + assertEquals(0, buffer.readerIndex()); + assertEquals(buffer.capacity(), buffer.writerIndex()); + assertFalse(buffer.isWritable()); + + random.setSeed(seed); + for (int i = 0; i < buffer.capacity(); i ++) { + int value = random.nextInt() & 0xFF; + assertEquals(i, buffer.readerIndex()); + assertTrue(buffer.isReadable()); + assertEquals(value, buffer.readUnsignedByte()); + } + + assertEquals(buffer.capacity(), buffer.readerIndex()); + assertEquals(buffer.capacity(), buffer.writerIndex()); + assertFalse(buffer.isReadable()); + assertFalse(buffer.isWritable()); + } + + @Test + public void testSequentialShortAccess() { + buffer.writerIndex(0); + for (int i = 0; i < buffer.capacity(); i += 2) { + short value = (short) random.nextInt(); + assertEquals(i, buffer.writerIndex()); + assertTrue(buffer.isWritable()); + buffer.writeShort(value); + } + + assertEquals(0, buffer.readerIndex()); + assertEquals(buffer.capacity(), buffer.writerIndex()); + assertFalse(buffer.isWritable()); + + random.setSeed(seed); + for (int i = 0; i < buffer.capacity(); i += 2) { + short value = (short) random.nextInt(); + assertEquals(i, buffer.readerIndex()); + assertTrue(buffer.isReadable()); + assertEquals(value, buffer.readShort()); + } + + assertEquals(buffer.capacity(), buffer.readerIndex()); + assertEquals(buffer.capacity(), buffer.writerIndex()); + assertFalse(buffer.isReadable()); + assertFalse(buffer.isWritable()); + } + + @Test + public void testSequentialUnsignedShortAccess() { + buffer.writerIndex(0); + for (int i = 0; i < buffer.capacity(); i += 2) { + short value = (short) random.nextInt(); + assertEquals(i, buffer.writerIndex()); + assertTrue(buffer.isWritable()); + buffer.writeShort(value); + } + + assertEquals(0, buffer.readerIndex()); + assertEquals(buffer.capacity(), buffer.writerIndex()); + assertFalse(buffer.isWritable()); + + random.setSeed(seed); + for (int i = 0; i < buffer.capacity(); i += 2) { + int value = random.nextInt() & 0xFFFF; + assertEquals(i, buffer.readerIndex()); + assertTrue(buffer.isReadable()); + assertEquals(value, buffer.readUnsignedShort()); + } + + assertEquals(buffer.capacity(), buffer.readerIndex()); + assertEquals(buffer.capacity(), buffer.writerIndex()); + assertFalse(buffer.isReadable()); + assertFalse(buffer.isWritable()); + } + + @Test + public void testSequentialMediumAccess() { + buffer.writerIndex(0); + for (int i = 0; i < buffer.capacity() / 3 * 3; i += 3) { + int value = random.nextInt(); + assertEquals(i, buffer.writerIndex()); + assertTrue(buffer.isWritable()); + buffer.writeMedium(value); + } + + assertEquals(0, buffer.readerIndex()); + assertEquals(buffer.capacity() / 3 * 3, buffer.writerIndex()); + assertEquals(buffer.capacity() % 3, buffer.writableBytes()); + + random.setSeed(seed); + for (int i = 0; i < buffer.capacity() / 3 * 3; i += 3) { + int value = random.nextInt() << 8 >> 8; + assertEquals(i, buffer.readerIndex()); + assertTrue(buffer.isReadable()); + assertEquals(value, buffer.readMedium()); + } + + assertEquals(buffer.capacity() / 3 * 3, buffer.readerIndex()); + assertEquals(buffer.capacity() / 3 * 3, buffer.writerIndex()); + assertEquals(0, buffer.readableBytes()); + assertEquals(buffer.capacity() % 3, buffer.writableBytes()); + } + + @Test + public void testSequentialUnsignedMediumAccess() { + buffer.writerIndex(0); + for (int i = 0; i < buffer.capacity() / 3 * 3; i += 3) { + int value = random.nextInt() & 0x00FFFFFF; + assertEquals(i, buffer.writerIndex()); + assertTrue(buffer.isWritable()); + buffer.writeMedium(value); + } + + assertEquals(0, buffer.readerIndex()); + assertEquals(buffer.capacity() / 3 * 3, buffer.writerIndex()); + assertEquals(buffer.capacity() % 3, buffer.writableBytes()); + + random.setSeed(seed); + for (int i = 0; i < buffer.capacity() / 3 * 3; i += 3) { + int value = random.nextInt() & 0x00FFFFFF; + assertEquals(i, buffer.readerIndex()); + assertTrue(buffer.isReadable()); + assertEquals(value, buffer.readUnsignedMedium()); + } + + assertEquals(buffer.capacity() / 3 * 3, buffer.readerIndex()); + assertEquals(buffer.capacity() / 3 * 3, buffer.writerIndex()); + assertEquals(0, buffer.readableBytes()); + assertEquals(buffer.capacity() % 3, buffer.writableBytes()); + } + + @Test + public void testSequentialIntAccess() { + buffer.writerIndex(0); + for (int i = 0; i < buffer.capacity(); i += 4) { + int value = random.nextInt(); + assertEquals(i, buffer.writerIndex()); + assertTrue(buffer.isWritable()); + buffer.writeInt(value); + } + + assertEquals(0, buffer.readerIndex()); + assertEquals(buffer.capacity(), buffer.writerIndex()); + assertFalse(buffer.isWritable()); + + random.setSeed(seed); + for (int i = 0; i < buffer.capacity(); i += 4) { + int value = random.nextInt(); + assertEquals(i, buffer.readerIndex()); + assertTrue(buffer.isReadable()); + assertEquals(value, buffer.readInt()); + } + + assertEquals(buffer.capacity(), buffer.readerIndex()); + assertEquals(buffer.capacity(), buffer.writerIndex()); + assertFalse(buffer.isReadable()); + assertFalse(buffer.isWritable()); + } + + @Test + public void testSequentialUnsignedIntAccess() { + buffer.writerIndex(0); + for (int i = 0; i < buffer.capacity(); i += 4) { + int value = random.nextInt(); + assertEquals(i, buffer.writerIndex()); + assertTrue(buffer.isWritable()); + buffer.writeInt(value); + } + + assertEquals(0, buffer.readerIndex()); + assertEquals(buffer.capacity(), buffer.writerIndex()); + assertFalse(buffer.isWritable()); + + random.setSeed(seed); + for (int i = 0; i < buffer.capacity(); i += 4) { + long value = random.nextInt() & 0xFFFFFFFFL; + assertEquals(i, buffer.readerIndex()); + assertTrue(buffer.isReadable()); + assertEquals(value, buffer.readUnsignedInt()); + } + + assertEquals(buffer.capacity(), buffer.readerIndex()); + assertEquals(buffer.capacity(), buffer.writerIndex()); + assertFalse(buffer.isReadable()); + assertFalse(buffer.isWritable()); + } + + @Test + public void testSequentialLongAccess() { + buffer.writerIndex(0); + for (int i = 0; i < buffer.capacity(); i += 8) { + long value = random.nextLong(); + assertEquals(i, buffer.writerIndex()); + assertTrue(buffer.isWritable()); + buffer.writeLong(value); + } + + assertEquals(0, buffer.readerIndex()); + assertEquals(buffer.capacity(), buffer.writerIndex()); + assertFalse(buffer.isWritable()); + + random.setSeed(seed); + for (int i = 0; i < buffer.capacity(); i += 8) { + long value = random.nextLong(); + assertEquals(i, buffer.readerIndex()); + assertTrue(buffer.isReadable()); + assertEquals(value, buffer.readLong()); + } + + assertEquals(buffer.capacity(), buffer.readerIndex()); + assertEquals(buffer.capacity(), buffer.writerIndex()); + assertFalse(buffer.isReadable()); + assertFalse(buffer.isWritable()); + } + + @Test + public void testByteArrayTransfer() { + byte[] value = new byte[BLOCK_SIZE * 2]; + for (int i = 0; i < buffer.capacity() - BLOCK_SIZE + 1; i += BLOCK_SIZE) { + random.nextBytes(value); + buffer.setBytes(i, value, random.nextInt(BLOCK_SIZE), BLOCK_SIZE); + } + + random.setSeed(seed); + byte[] expectedValue = new byte[BLOCK_SIZE * 2]; + for (int i = 0; i < buffer.capacity() - BLOCK_SIZE + 1; i += BLOCK_SIZE) { + random.nextBytes(expectedValue); + int valueOffset = random.nextInt(BLOCK_SIZE); + buffer.getBytes(i, value, valueOffset, BLOCK_SIZE); + for (int j = valueOffset; j < valueOffset + BLOCK_SIZE; j ++) { + assertEquals(expectedValue[j], value[j]); + } + } + } + + @Test + public void testRandomByteArrayTransfer1() { + byte[] value = new byte[BLOCK_SIZE]; + for (int i = 0; i < buffer.capacity() - BLOCK_SIZE + 1; i += BLOCK_SIZE) { + random.nextBytes(value); + buffer.setBytes(i, value); + } + + random.setSeed(seed); + byte[] expectedValueContent = new byte[BLOCK_SIZE]; + ByteBuf expectedValue = wrappedBuffer(expectedValueContent); + for (int i = 0; i < buffer.capacity() - BLOCK_SIZE + 1; i += BLOCK_SIZE) { + random.nextBytes(expectedValueContent); + buffer.getBytes(i, value); + for (int j = 0; j < BLOCK_SIZE; j ++) { + assertEquals(expectedValue.getByte(j), value[j]); + } + } + } + + @Test + public void testRandomByteArrayTransfer2() { + byte[] value = new byte[BLOCK_SIZE * 2]; + for (int i = 0; i < buffer.capacity() - BLOCK_SIZE + 1; i += BLOCK_SIZE) { + random.nextBytes(value); + buffer.setBytes(i, value, random.nextInt(BLOCK_SIZE), BLOCK_SIZE); + } + + random.setSeed(seed); + byte[] expectedValueContent = new byte[BLOCK_SIZE * 2]; + ByteBuf expectedValue = wrappedBuffer(expectedValueContent); + for (int i = 0; i < buffer.capacity() - BLOCK_SIZE + 1; i += BLOCK_SIZE) { + random.nextBytes(expectedValueContent); + int valueOffset = random.nextInt(BLOCK_SIZE); + buffer.getBytes(i, value, valueOffset, BLOCK_SIZE); + for (int j = valueOffset; j < valueOffset + BLOCK_SIZE; j ++) { + assertEquals(expectedValue.getByte(j), value[j]); + } + } + } + + @Test + public void testRandomHeapBufferTransfer1() { + byte[] valueContent = new byte[BLOCK_SIZE]; + ByteBuf value = wrappedBuffer(valueContent); + for (int i = 0; i < buffer.capacity() - BLOCK_SIZE + 1; i += BLOCK_SIZE) { + random.nextBytes(valueContent); + value.setIndex(0, BLOCK_SIZE); + buffer.setBytes(i, value); + assertEquals(BLOCK_SIZE, value.readerIndex()); + assertEquals(BLOCK_SIZE, value.writerIndex()); + } + + random.setSeed(seed); + byte[] expectedValueContent = new byte[BLOCK_SIZE]; + ByteBuf expectedValue = wrappedBuffer(expectedValueContent); + for (int i = 0; i < buffer.capacity() - BLOCK_SIZE + 1; i += BLOCK_SIZE) { + random.nextBytes(expectedValueContent); + value.clear(); + buffer.getBytes(i, value); + assertEquals(0, value.readerIndex()); + assertEquals(BLOCK_SIZE, value.writerIndex()); + for (int j = 0; j < BLOCK_SIZE; j ++) { + assertEquals(expectedValue.getByte(j), value.getByte(j)); + } + } + } + + @Test + public void testRandomHeapBufferTransfer2() { + byte[] valueContent = new byte[BLOCK_SIZE * 2]; + ByteBuf value = wrappedBuffer(valueContent); + for (int i = 0; i < buffer.capacity() - BLOCK_SIZE + 1; i += BLOCK_SIZE) { + random.nextBytes(valueContent); + buffer.setBytes(i, value, random.nextInt(BLOCK_SIZE), BLOCK_SIZE); + } + + random.setSeed(seed); + byte[] expectedValueContent = new byte[BLOCK_SIZE * 2]; + ByteBuf expectedValue = wrappedBuffer(expectedValueContent); + for (int i = 0; i < buffer.capacity() - BLOCK_SIZE + 1; i += BLOCK_SIZE) { + random.nextBytes(expectedValueContent); + int valueOffset = random.nextInt(BLOCK_SIZE); + buffer.getBytes(i, value, valueOffset, BLOCK_SIZE); + for (int j = valueOffset; j < valueOffset + BLOCK_SIZE; j ++) { + assertEquals(expectedValue.getByte(j), value.getByte(j)); + } + } + } + + @Test + public void testRandomDirectBufferTransfer() { + byte[] tmp = new byte[BLOCK_SIZE * 2]; + ByteBuf value = directBuffer(BLOCK_SIZE * 2); + for (int i = 0; i < buffer.capacity() - BLOCK_SIZE + 1; i += BLOCK_SIZE) { + random.nextBytes(tmp); + value.setBytes(0, tmp, 0, value.capacity()); + buffer.setBytes(i, value, random.nextInt(BLOCK_SIZE), BLOCK_SIZE); + } + + random.setSeed(seed); + ByteBuf expectedValue = directBuffer(BLOCK_SIZE * 2); + for (int i = 0; i < buffer.capacity() - BLOCK_SIZE + 1; i += BLOCK_SIZE) { + random.nextBytes(tmp); + expectedValue.setBytes(0, tmp, 0, expectedValue.capacity()); + int valueOffset = random.nextInt(BLOCK_SIZE); + buffer.getBytes(i, value, valueOffset, BLOCK_SIZE); + for (int j = valueOffset; j < valueOffset + BLOCK_SIZE; j ++) { + assertEquals(expectedValue.getByte(j), value.getByte(j)); + } + } + value.release(); + expectedValue.release(); + } + + @Test + public void testRandomByteBufferTransfer() { + ByteBuffer value = ByteBuffer.allocate(BLOCK_SIZE * 2); + for (int i = 0; i < buffer.capacity() - BLOCK_SIZE + 1; i += BLOCK_SIZE) { + random.nextBytes(value.array()); + value.clear().position(random.nextInt(BLOCK_SIZE)); + value.limit(value.position() + BLOCK_SIZE); + buffer.setBytes(i, value); + } + + random.setSeed(seed); + ByteBuffer expectedValue = ByteBuffer.allocate(BLOCK_SIZE * 2); + for (int i = 0; i < buffer.capacity() - BLOCK_SIZE + 1; i += BLOCK_SIZE) { + random.nextBytes(expectedValue.array()); + int valueOffset = random.nextInt(BLOCK_SIZE); + value.clear().position(valueOffset).limit(valueOffset + BLOCK_SIZE); + buffer.getBytes(i, value); + assertEquals(valueOffset + BLOCK_SIZE, value.position()); + for (int j = valueOffset; j < valueOffset + BLOCK_SIZE; j ++) { + assertEquals(expectedValue.get(j), value.get(j)); + } + } + } + + @Test + public void testSequentialByteArrayTransfer1() { + byte[] value = new byte[BLOCK_SIZE]; + buffer.writerIndex(0); + for (int i = 0; i < buffer.capacity() - BLOCK_SIZE + 1; i += BLOCK_SIZE) { + random.nextBytes(value); + assertEquals(0, buffer.readerIndex()); + assertEquals(i, buffer.writerIndex()); + buffer.writeBytes(value); + } + + random.setSeed(seed); + byte[] expectedValue = new byte[BLOCK_SIZE]; + for (int i = 0; i < buffer.capacity() - BLOCK_SIZE + 1; i += BLOCK_SIZE) { + random.nextBytes(expectedValue); + assertEquals(i, buffer.readerIndex()); + assertEquals(CAPACITY, buffer.writerIndex()); + buffer.readBytes(value); + for (int j = 0; j < BLOCK_SIZE; j ++) { + assertEquals(expectedValue[j], value[j]); + } + } + } + + @Test + public void testSequentialByteArrayTransfer2() { + byte[] value = new byte[BLOCK_SIZE * 2]; + buffer.writerIndex(0); + for (int i = 0; i < buffer.capacity() - BLOCK_SIZE + 1; i += BLOCK_SIZE) { + random.nextBytes(value); + assertEquals(0, buffer.readerIndex()); + assertEquals(i, buffer.writerIndex()); + int readerIndex = random.nextInt(BLOCK_SIZE); + buffer.writeBytes(value, readerIndex, BLOCK_SIZE); + } + + random.setSeed(seed); + byte[] expectedValue = new byte[BLOCK_SIZE * 2]; + for (int i = 0; i < buffer.capacity() - BLOCK_SIZE + 1; i += BLOCK_SIZE) { + random.nextBytes(expectedValue); + int valueOffset = random.nextInt(BLOCK_SIZE); + assertEquals(i, buffer.readerIndex()); + assertEquals(CAPACITY, buffer.writerIndex()); + buffer.readBytes(value, valueOffset, BLOCK_SIZE); + for (int j = valueOffset; j < valueOffset + BLOCK_SIZE; j ++) { + assertEquals(expectedValue[j], value[j]); + } + } + } + + @Test + public void testSequentialHeapBufferTransfer1() { + byte[] valueContent = new byte[BLOCK_SIZE * 2]; + ByteBuf value = wrappedBuffer(valueContent); + buffer.writerIndex(0); + for (int i = 0; i < buffer.capacity() - BLOCK_SIZE + 1; i += BLOCK_SIZE) { + random.nextBytes(valueContent); + assertEquals(0, buffer.readerIndex()); + assertEquals(i, buffer.writerIndex()); + buffer.writeBytes(value, random.nextInt(BLOCK_SIZE), BLOCK_SIZE); + assertEquals(0, value.readerIndex()); + assertEquals(valueContent.length, value.writerIndex()); + } + + random.setSeed(seed); + byte[] expectedValueContent = new byte[BLOCK_SIZE * 2]; + ByteBuf expectedValue = wrappedBuffer(expectedValueContent); + for (int i = 0; i < buffer.capacity() - BLOCK_SIZE + 1; i += BLOCK_SIZE) { + random.nextBytes(expectedValueContent); + int valueOffset = random.nextInt(BLOCK_SIZE); + assertEquals(i, buffer.readerIndex()); + assertEquals(CAPACITY, buffer.writerIndex()); + buffer.readBytes(value, valueOffset, BLOCK_SIZE); + for (int j = valueOffset; j < valueOffset + BLOCK_SIZE; j ++) { + assertEquals(expectedValue.getByte(j), value.getByte(j)); + } + assertEquals(0, value.readerIndex()); + assertEquals(valueContent.length, value.writerIndex()); + } + } + + @Test + public void testSequentialHeapBufferTransfer2() { + byte[] valueContent = new byte[BLOCK_SIZE * 2]; + ByteBuf value = wrappedBuffer(valueContent); + buffer.writerIndex(0); + for (int i = 0; i < buffer.capacity() - BLOCK_SIZE + 1; i += BLOCK_SIZE) { + random.nextBytes(valueContent); + assertEquals(0, buffer.readerIndex()); + assertEquals(i, buffer.writerIndex()); + int readerIndex = random.nextInt(BLOCK_SIZE); + value.readerIndex(readerIndex); + value.writerIndex(readerIndex + BLOCK_SIZE); + buffer.writeBytes(value); + assertEquals(readerIndex + BLOCK_SIZE, value.writerIndex()); + assertEquals(value.writerIndex(), value.readerIndex()); + } + + random.setSeed(seed); + byte[] expectedValueContent = new byte[BLOCK_SIZE * 2]; + ByteBuf expectedValue = wrappedBuffer(expectedValueContent); + for (int i = 0; i < buffer.capacity() - BLOCK_SIZE + 1; i += BLOCK_SIZE) { + random.nextBytes(expectedValueContent); + int valueOffset = random.nextInt(BLOCK_SIZE); + assertEquals(i, buffer.readerIndex()); + assertEquals(CAPACITY, buffer.writerIndex()); + value.readerIndex(valueOffset); + value.writerIndex(valueOffset); + buffer.readBytes(value, BLOCK_SIZE); + for (int j = valueOffset; j < valueOffset + BLOCK_SIZE; j ++) { + assertEquals(expectedValue.getByte(j), value.getByte(j)); + } + assertEquals(valueOffset, value.readerIndex()); + assertEquals(valueOffset + BLOCK_SIZE, value.writerIndex()); + } + } + + @Test + public void testSequentialDirectBufferTransfer1() { + byte[] valueContent = new byte[BLOCK_SIZE * 2]; + ByteBuf value = directBuffer(BLOCK_SIZE * 2); + buffer.writerIndex(0); + for (int i = 0; i < buffer.capacity() - BLOCK_SIZE + 1; i += BLOCK_SIZE) { + random.nextBytes(valueContent); + value.setBytes(0, valueContent); + assertEquals(0, buffer.readerIndex()); + assertEquals(i, buffer.writerIndex()); + buffer.writeBytes(value, random.nextInt(BLOCK_SIZE), BLOCK_SIZE); + assertEquals(0, value.readerIndex()); + assertEquals(0, value.writerIndex()); + } + + random.setSeed(seed); + byte[] expectedValueContent = new byte[BLOCK_SIZE * 2]; + ByteBuf expectedValue = wrappedBuffer(expectedValueContent); + for (int i = 0; i < buffer.capacity() - BLOCK_SIZE + 1; i += BLOCK_SIZE) { + random.nextBytes(expectedValueContent); + int valueOffset = random.nextInt(BLOCK_SIZE); + value.setBytes(0, valueContent); + assertEquals(i, buffer.readerIndex()); + assertEquals(CAPACITY, buffer.writerIndex()); + buffer.readBytes(value, valueOffset, BLOCK_SIZE); + for (int j = valueOffset; j < valueOffset + BLOCK_SIZE; j ++) { + assertEquals(expectedValue.getByte(j), value.getByte(j)); + } + assertEquals(0, value.readerIndex()); + assertEquals(0, value.writerIndex()); + } + value.release(); + expectedValue.release(); + } + + @Test + public void testSequentialDirectBufferTransfer2() { + byte[] valueContent = new byte[BLOCK_SIZE * 2]; + ByteBuf value = directBuffer(BLOCK_SIZE * 2); + buffer.writerIndex(0); + for (int i = 0; i < buffer.capacity() - BLOCK_SIZE + 1; i += BLOCK_SIZE) { + random.nextBytes(valueContent); + value.setBytes(0, valueContent); + assertEquals(0, buffer.readerIndex()); + assertEquals(i, buffer.writerIndex()); + int readerIndex = random.nextInt(BLOCK_SIZE); + value.readerIndex(0); + value.writerIndex(readerIndex + BLOCK_SIZE); + value.readerIndex(readerIndex); + buffer.writeBytes(value); + assertEquals(readerIndex + BLOCK_SIZE, value.writerIndex()); + assertEquals(value.writerIndex(), value.readerIndex()); + } + + random.setSeed(seed); + byte[] expectedValueContent = new byte[BLOCK_SIZE * 2]; + ByteBuf expectedValue = wrappedBuffer(expectedValueContent); + for (int i = 0; i < buffer.capacity() - BLOCK_SIZE + 1; i += BLOCK_SIZE) { + random.nextBytes(expectedValueContent); + value.setBytes(0, valueContent); + int valueOffset = random.nextInt(BLOCK_SIZE); + assertEquals(i, buffer.readerIndex()); + assertEquals(CAPACITY, buffer.writerIndex()); + value.readerIndex(valueOffset); + value.writerIndex(valueOffset); + buffer.readBytes(value, BLOCK_SIZE); + for (int j = valueOffset; j < valueOffset + BLOCK_SIZE; j ++) { + assertEquals(expectedValue.getByte(j), value.getByte(j)); + } + assertEquals(valueOffset, value.readerIndex()); + assertEquals(valueOffset + BLOCK_SIZE, value.writerIndex()); + } + value.release(); + expectedValue.release(); + } + + @Test + public void testSequentialByteBufferBackedHeapBufferTransfer1() { + byte[] valueContent = new byte[BLOCK_SIZE * 2]; + ByteBuf value = wrappedBuffer(ByteBuffer.allocate(BLOCK_SIZE * 2)); + value.writerIndex(0); + buffer.writerIndex(0); + for (int i = 0; i < buffer.capacity() - BLOCK_SIZE + 1; i += BLOCK_SIZE) { + random.nextBytes(valueContent); + value.setBytes(0, valueContent); + assertEquals(0, buffer.readerIndex()); + assertEquals(i, buffer.writerIndex()); + buffer.writeBytes(value, random.nextInt(BLOCK_SIZE), BLOCK_SIZE); + assertEquals(0, value.readerIndex()); + assertEquals(0, value.writerIndex()); + } + + random.setSeed(seed); + byte[] expectedValueContent = new byte[BLOCK_SIZE * 2]; + ByteBuf expectedValue = wrappedBuffer(expectedValueContent); + for (int i = 0; i < buffer.capacity() - BLOCK_SIZE + 1; i += BLOCK_SIZE) { + random.nextBytes(expectedValueContent); + int valueOffset = random.nextInt(BLOCK_SIZE); + value.setBytes(0, valueContent); + assertEquals(i, buffer.readerIndex()); + assertEquals(CAPACITY, buffer.writerIndex()); + buffer.readBytes(value, valueOffset, BLOCK_SIZE); + for (int j = valueOffset; j < valueOffset + BLOCK_SIZE; j ++) { + assertEquals(expectedValue.getByte(j), value.getByte(j)); + } + assertEquals(0, value.readerIndex()); + assertEquals(0, value.writerIndex()); + } + } + + @Test + public void testSequentialByteBufferBackedHeapBufferTransfer2() { + byte[] valueContent = new byte[BLOCK_SIZE * 2]; + ByteBuf value = wrappedBuffer(ByteBuffer.allocate(BLOCK_SIZE * 2)); + value.writerIndex(0); + buffer.writerIndex(0); + for (int i = 0; i < buffer.capacity() - BLOCK_SIZE + 1; i += BLOCK_SIZE) { + random.nextBytes(valueContent); + value.setBytes(0, valueContent); + assertEquals(0, buffer.readerIndex()); + assertEquals(i, buffer.writerIndex()); + int readerIndex = random.nextInt(BLOCK_SIZE); + value.readerIndex(0); + value.writerIndex(readerIndex + BLOCK_SIZE); + value.readerIndex(readerIndex); + buffer.writeBytes(value); + assertEquals(readerIndex + BLOCK_SIZE, value.writerIndex()); + assertEquals(value.writerIndex(), value.readerIndex()); + } + + random.setSeed(seed); + byte[] expectedValueContent = new byte[BLOCK_SIZE * 2]; + ByteBuf expectedValue = wrappedBuffer(expectedValueContent); + for (int i = 0; i < buffer.capacity() - BLOCK_SIZE + 1; i += BLOCK_SIZE) { + random.nextBytes(expectedValueContent); + value.setBytes(0, valueContent); + int valueOffset = random.nextInt(BLOCK_SIZE); + assertEquals(i, buffer.readerIndex()); + assertEquals(CAPACITY, buffer.writerIndex()); + value.readerIndex(valueOffset); + value.writerIndex(valueOffset); + buffer.readBytes(value, BLOCK_SIZE); + for (int j = valueOffset; j < valueOffset + BLOCK_SIZE; j ++) { + assertEquals(expectedValue.getByte(j), value.getByte(j)); + } + assertEquals(valueOffset, value.readerIndex()); + assertEquals(valueOffset + BLOCK_SIZE, value.writerIndex()); + } + } + + @Test + public void testSequentialByteBufferTransfer() { + buffer.writerIndex(0); + ByteBuffer value = ByteBuffer.allocate(BLOCK_SIZE * 2); + for (int i = 0; i < buffer.capacity() - BLOCK_SIZE + 1; i += BLOCK_SIZE) { + random.nextBytes(value.array()); + value.clear().position(random.nextInt(BLOCK_SIZE)); + value.limit(value.position() + BLOCK_SIZE); + buffer.writeBytes(value); + } + + random.setSeed(seed); + ByteBuffer expectedValue = ByteBuffer.allocate(BLOCK_SIZE * 2); + for (int i = 0; i < buffer.capacity() - BLOCK_SIZE + 1; i += BLOCK_SIZE) { + random.nextBytes(expectedValue.array()); + int valueOffset = random.nextInt(BLOCK_SIZE); + value.clear().position(valueOffset).limit(valueOffset + BLOCK_SIZE); + buffer.readBytes(value); + assertEquals(valueOffset + BLOCK_SIZE, value.position()); + for (int j = valueOffset; j < valueOffset + BLOCK_SIZE; j ++) { + assertEquals(expectedValue.get(j), value.get(j)); + } + } + } + + @Test + public void testSequentialCopiedBufferTransfer1() { + buffer.writerIndex(0); + for (int i = 0; i < buffer.capacity() - BLOCK_SIZE + 1; i += BLOCK_SIZE) { + byte[] value = new byte[BLOCK_SIZE]; + random.nextBytes(value); + assertEquals(0, buffer.readerIndex()); + assertEquals(i, buffer.writerIndex()); + buffer.writeBytes(value); + } + + random.setSeed(seed); + byte[] expectedValue = new byte[BLOCK_SIZE]; + for (int i = 0; i < buffer.capacity() - BLOCK_SIZE + 1; i += BLOCK_SIZE) { + random.nextBytes(expectedValue); + assertEquals(i, buffer.readerIndex()); + assertEquals(CAPACITY, buffer.writerIndex()); + ByteBuf actualValue = buffer.readBytes(BLOCK_SIZE); + assertEquals(wrappedBuffer(expectedValue), actualValue); + + // Make sure if it is a copied buffer. + actualValue.setByte(0, (byte) (actualValue.getByte(0) + 1)); + assertFalse(buffer.getByte(i) == actualValue.getByte(0)); + actualValue.release(); + } + } + + @Test + public void testSequentialSlice1() { + buffer.writerIndex(0); + for (int i = 0; i < buffer.capacity() - BLOCK_SIZE + 1; i += BLOCK_SIZE) { + byte[] value = new byte[BLOCK_SIZE]; + random.nextBytes(value); + assertEquals(0, buffer.readerIndex()); + assertEquals(i, buffer.writerIndex()); + buffer.writeBytes(value); + } + + random.setSeed(seed); + byte[] expectedValue = new byte[BLOCK_SIZE]; + for (int i = 0; i < buffer.capacity() - BLOCK_SIZE + 1; i += BLOCK_SIZE) { + random.nextBytes(expectedValue); + assertEquals(i, buffer.readerIndex()); + assertEquals(CAPACITY, buffer.writerIndex()); + ByteBuf actualValue = buffer.readSlice(BLOCK_SIZE); + assertEquals(buffer.order(), actualValue.order()); + assertEquals(wrappedBuffer(expectedValue), actualValue); + + // Make sure if it is a sliced buffer. + actualValue.setByte(0, (byte) (actualValue.getByte(0) + 1)); + assertEquals(buffer.getByte(i), actualValue.getByte(0)); + } + } + + @Test + public void testWriteZero() { + try { + buffer.writeZero(-1); + fail(); + } catch (IllegalArgumentException e) { + // Expected + } + + buffer.clear(); + while (buffer.isWritable()) { + buffer.writeByte((byte) 0xFF); + } + + buffer.clear(); + for (int i = 0; i < buffer.capacity();) { + int length = Math.min(buffer.capacity() - i, random.nextInt(32)); + buffer.writeZero(length); + i += length; + } + + assertEquals(0, buffer.readerIndex()); + assertEquals(buffer.capacity(), buffer.writerIndex()); + + for (int i = 0; i < buffer.capacity(); i ++) { + assertEquals(0, buffer.getByte(i)); + } + } + + @Test + public void testDiscardReadBytes() { + buffer.writerIndex(0); + for (int i = 0; i < buffer.capacity(); i += 4) { + buffer.writeInt(i); + } + ByteBuf copy = copiedBuffer(buffer); + + // Make sure there's no effect if called when readerIndex is 0. + buffer.readerIndex(CAPACITY / 4); + buffer.markReaderIndex(); + buffer.writerIndex(CAPACITY / 3); + buffer.markWriterIndex(); + buffer.readerIndex(0); + buffer.writerIndex(CAPACITY / 2); + buffer.discardReadBytes(); + + assertEquals(0, buffer.readerIndex()); + assertEquals(CAPACITY / 2, buffer.writerIndex()); + assertEquals(copy.slice(0, CAPACITY / 2), buffer.slice(0, CAPACITY / 2)); + buffer.resetReaderIndex(); + assertEquals(CAPACITY / 4, buffer.readerIndex()); + buffer.resetWriterIndex(); + assertEquals(CAPACITY / 3, buffer.writerIndex()); + + // Make sure bytes after writerIndex is not copied. + buffer.readerIndex(1); + buffer.writerIndex(CAPACITY / 2); + buffer.discardReadBytes(); + + assertEquals(0, buffer.readerIndex()); + assertEquals(CAPACITY / 2 - 1, buffer.writerIndex()); + assertEquals(copy.slice(1, CAPACITY / 2 - 1), buffer.slice(0, CAPACITY / 2 - 1)); + + if (discardReadBytesDoesNotMoveWritableBytes()) { + // If writable bytes were copied, the test should fail to avoid unnecessary memory bandwidth consumption. + assertFalse(copy.slice(CAPACITY / 2, CAPACITY / 2).equals(buffer.slice(CAPACITY / 2 - 1, CAPACITY / 2))); + } else { + assertEquals(copy.slice(CAPACITY / 2, CAPACITY / 2), buffer.slice(CAPACITY / 2 - 1, CAPACITY / 2)); + } + + // Marks also should be relocated. + buffer.resetReaderIndex(); + assertEquals(CAPACITY / 4 - 1, buffer.readerIndex()); + buffer.resetWriterIndex(); + assertEquals(CAPACITY / 3 - 1, buffer.writerIndex()); + copy.release(); + } + + /** + * The similar test case with {@link #testDiscardReadBytes()} but this one + * discards a large chunk at once. + */ + @Test + public void testDiscardReadBytes2() { + buffer.writerIndex(0); + for (int i = 0; i < buffer.capacity(); i ++) { + buffer.writeByte((byte) i); + } + ByteBuf copy = copiedBuffer(buffer); + + // Discard the first (CAPACITY / 2 - 1) bytes. + buffer.setIndex(CAPACITY / 2 - 1, CAPACITY - 1); + buffer.discardReadBytes(); + assertEquals(0, buffer.readerIndex()); + assertEquals(CAPACITY / 2, buffer.writerIndex()); + for (int i = 0; i < CAPACITY / 2; i ++) { + assertEquals(copy.slice(CAPACITY / 2 - 1 + i, CAPACITY / 2 - i), buffer.slice(i, CAPACITY / 2 - i)); + } + copy.release(); + } + + @Test + public void testStreamTransfer1() throws Exception { + byte[] expected = new byte[buffer.capacity()]; + random.nextBytes(expected); + + for (int i = 0; i < buffer.capacity() - BLOCK_SIZE + 1; i += BLOCK_SIZE) { + ByteArrayInputStream in = new ByteArrayInputStream(expected, i, BLOCK_SIZE); + assertEquals(BLOCK_SIZE, buffer.setBytes(i, in, BLOCK_SIZE)); + assertEquals(-1, buffer.setBytes(i, in, 0)); + } + + ByteArrayOutputStream out = new ByteArrayOutputStream(); + for (int i = 0; i < buffer.capacity() - BLOCK_SIZE + 1; i += BLOCK_SIZE) { + buffer.getBytes(i, out, BLOCK_SIZE); + } + + assertTrue(Arrays.equals(expected, out.toByteArray())); + } + + @Test + public void testStreamTransfer2() throws Exception { + byte[] expected = new byte[buffer.capacity()]; + random.nextBytes(expected); + buffer.clear(); + + for (int i = 0; i < buffer.capacity() - BLOCK_SIZE + 1; i += BLOCK_SIZE) { + ByteArrayInputStream in = new ByteArrayInputStream(expected, i, BLOCK_SIZE); + assertEquals(i, buffer.writerIndex()); + buffer.writeBytes(in, BLOCK_SIZE); + assertEquals(i + BLOCK_SIZE, buffer.writerIndex()); + } + + ByteArrayOutputStream out = new ByteArrayOutputStream(); + for (int i = 0; i < buffer.capacity() - BLOCK_SIZE + 1; i += BLOCK_SIZE) { + assertEquals(i, buffer.readerIndex()); + buffer.readBytes(out, BLOCK_SIZE); + assertEquals(i + BLOCK_SIZE, buffer.readerIndex()); + } + + assertTrue(Arrays.equals(expected, out.toByteArray())); + } + + @Test + public void testCopy() { + for (int i = 0; i < buffer.capacity(); i ++) { + byte value = (byte) random.nextInt(); + buffer.setByte(i, value); + } + + final int readerIndex = CAPACITY / 3; + final int writerIndex = CAPACITY * 2 / 3; + buffer.setIndex(readerIndex, writerIndex); + + // Make sure all properties are copied. + ByteBuf copy = buffer.copy(); + assertEquals(0, copy.readerIndex()); + assertEquals(buffer.readableBytes(), copy.writerIndex()); + assertEquals(buffer.readableBytes(), copy.capacity()); + assertSame(buffer.order(), copy.order()); + for (int i = 0; i < copy.capacity(); i ++) { + assertEquals(buffer.getByte(i + readerIndex), copy.getByte(i)); + } + + // Make sure the buffer content is independent from each other. + buffer.setByte(readerIndex, (byte) (buffer.getByte(readerIndex) + 1)); + assertTrue(buffer.getByte(readerIndex) != copy.getByte(0)); + copy.setByte(1, (byte) (copy.getByte(1) + 1)); + assertTrue(buffer.getByte(readerIndex + 1) != copy.getByte(1)); + copy.release(); + } + + @Test + public void testDuplicate() { + for (int i = 0; i < buffer.capacity(); i ++) { + byte value = (byte) random.nextInt(); + buffer.setByte(i, value); + } + + final int readerIndex = CAPACITY / 3; + final int writerIndex = CAPACITY * 2 / 3; + buffer.setIndex(readerIndex, writerIndex); + + // Make sure all properties are copied. + ByteBuf duplicate = buffer.duplicate(); + assertSame(buffer.order(), duplicate.order()); + assertEquals(buffer.readableBytes(), duplicate.readableBytes()); + assertEquals(0, buffer.compareTo(duplicate)); + + // Make sure the buffer content is shared. + buffer.setByte(readerIndex, (byte) (buffer.getByte(readerIndex) + 1)); + assertEquals(buffer.getByte(readerIndex), duplicate.getByte(duplicate.readerIndex())); + duplicate.setByte(duplicate.readerIndex(), (byte) (duplicate.getByte(duplicate.readerIndex()) + 1)); + assertEquals(buffer.getByte(readerIndex), duplicate.getByte(duplicate.readerIndex())); + } + + @Test + public void testSliceEndianness() throws Exception { + assertEquals(buffer.order(), buffer.slice(0, buffer.capacity()).order()); + assertEquals(buffer.order(), buffer.slice(0, buffer.capacity() - 1).order()); + assertEquals(buffer.order(), buffer.slice(1, buffer.capacity() - 1).order()); + assertEquals(buffer.order(), buffer.slice(1, buffer.capacity() - 2).order()); + } + + @Test + public void testSliceIndex() throws Exception { + assertEquals(0, buffer.slice(0, buffer.capacity()).readerIndex()); + assertEquals(0, buffer.slice(0, buffer.capacity() - 1).readerIndex()); + assertEquals(0, buffer.slice(1, buffer.capacity() - 1).readerIndex()); + assertEquals(0, buffer.slice(1, buffer.capacity() - 2).readerIndex()); + + assertEquals(buffer.capacity(), buffer.slice(0, buffer.capacity()).writerIndex()); + assertEquals(buffer.capacity() - 1, buffer.slice(0, buffer.capacity() - 1).writerIndex()); + assertEquals(buffer.capacity() - 1, buffer.slice(1, buffer.capacity() - 1).writerIndex()); + assertEquals(buffer.capacity() - 2, buffer.slice(1, buffer.capacity() - 2).writerIndex()); + } + + @Test + @SuppressWarnings("ObjectEqualsNull") + public void testEquals() { + assertFalse(buffer.equals(null)); + assertFalse(buffer.equals(new Object())); + + byte[] value = new byte[32]; + buffer.setIndex(0, value.length); + random.nextBytes(value); + buffer.setBytes(0, value); + + assertEquals(buffer, wrappedBuffer(value)); + assertEquals(buffer, wrappedBuffer(value).order(LITTLE_ENDIAN)); + + value[0] ++; + assertFalse(buffer.equals(wrappedBuffer(value))); + assertFalse(buffer.equals(wrappedBuffer(value).order(LITTLE_ENDIAN))); + } + + @Test + public void testCompareTo() { + try { + buffer.compareTo(null); + fail(); + } catch (NullPointerException e) { + // Expected + } + + // Fill the random stuff + byte[] value = new byte[32]; + random.nextBytes(value); + // Prevent overflow / underflow + if (value[0] == 0) { + value[0]++; + } else if (value[0] == -1) { + value[0]--; + } + + buffer.setIndex(0, value.length); + buffer.setBytes(0, value); + + assertEquals(0, buffer.compareTo(wrappedBuffer(value))); + assertEquals(0, buffer.compareTo(wrappedBuffer(value).order(LITTLE_ENDIAN))); + + value[0]++; + assertTrue(buffer.compareTo(wrappedBuffer(value)) < 0); + assertTrue(buffer.compareTo(wrappedBuffer(value).order(LITTLE_ENDIAN)) < 0); + value[0] -= 2; + assertTrue(buffer.compareTo(wrappedBuffer(value)) > 0); + assertTrue(buffer.compareTo(wrappedBuffer(value).order(LITTLE_ENDIAN)) > 0); + value[0]++; + + assertTrue(buffer.compareTo(wrappedBuffer(value, 0, 31)) > 0); + assertTrue(buffer.compareTo(wrappedBuffer(value, 0, 31).order(LITTLE_ENDIAN)) > 0); + assertTrue(buffer.slice(0, 31).compareTo(wrappedBuffer(value)) < 0); + assertTrue(buffer.slice(0, 31).compareTo(wrappedBuffer(value).order(LITTLE_ENDIAN)) < 0); + } + + @Test + @Ignore("Behaviour was changed after 4.0.27, this test is newer but we should keep the old behaviour to be consistent with the netty version we use.") + public void testCompareTo2() { + byte[] bytes = {1, 2, 3, 4}; + byte[] bytesReversed = {4, 3, 2, 1}; + + ByteBuf buf1 = newBuffer(4).clear().writeBytes(bytes).order(ByteOrder.LITTLE_ENDIAN); + ByteBuf buf2 = newBuffer(4).clear().writeBytes(bytesReversed).order(ByteOrder.LITTLE_ENDIAN); + ByteBuf buf3 = newBuffer(4).clear().writeBytes(bytes).order(ByteOrder.BIG_ENDIAN); + ByteBuf buf4 = newBuffer(4).clear().writeBytes(bytesReversed).order(ByteOrder.BIG_ENDIAN); + try { + assertEquals(buf1.compareTo(buf2), buf3.compareTo(buf4)); + assertEquals(buf2.compareTo(buf1), buf4.compareTo(buf3)); + assertEquals(buf1.compareTo(buf3), buf2.compareTo(buf4)); + assertEquals(buf3.compareTo(buf1), buf4.compareTo(buf2)); + } finally { + buf1.release(); + buf2.release(); + buf3.release(); + buf4.release(); + } + } + + @Test + public void testToString() { + ByteBuf copied = copiedBuffer("Hello, World!", CharsetUtil.ISO_8859_1); + buffer.clear(); + buffer.writeBytes(copied); + assertEquals("Hello, World!", buffer.toString(CharsetUtil.ISO_8859_1)); + copied.release(); + } + + @Test + public void testIndexOf() { + buffer.clear(); + buffer.writeByte((byte) 1); + buffer.writeByte((byte) 2); + buffer.writeByte((byte) 3); + buffer.writeByte((byte) 2); + buffer.writeByte((byte) 1); + + assertEquals(-1, buffer.indexOf(1, 4, (byte) 1)); + assertEquals(-1, buffer.indexOf(4, 1, (byte) 1)); + assertEquals(1, buffer.indexOf(1, 4, (byte) 2)); + assertEquals(3, buffer.indexOf(4, 1, (byte) 2)); + } + + @Test + public void testNioBuffer1() { + assumeTrue(buffer.nioBufferCount() == 1); + + byte[] value = new byte[buffer.capacity()]; + random.nextBytes(value); + buffer.clear(); + buffer.writeBytes(value); + + assertRemainingEquals(ByteBuffer.wrap(value), buffer.nioBuffer()); + } + + @Test + public void testToByteBuffer2() { + assumeTrue(buffer.nioBufferCount() == 1); + + byte[] value = new byte[buffer.capacity()]; + random.nextBytes(value); + buffer.clear(); + buffer.writeBytes(value); + + for (int i = 0; i < buffer.capacity() - BLOCK_SIZE + 1; i += BLOCK_SIZE) { + assertRemainingEquals(ByteBuffer.wrap(value, i, BLOCK_SIZE), buffer.nioBuffer(i, BLOCK_SIZE)); + } + } + + private static void assertRemainingEquals(ByteBuffer expected, ByteBuffer actual) { + int remaining = expected.remaining(); + int remaining2 = actual.remaining(); + + assertEquals(remaining, remaining2); + byte[] array1 = new byte[remaining]; + byte[] array2 = new byte[remaining2]; + expected.get(array1); + actual.get(array2); + assertArrayEquals(array1, array2); + } + + @Test + public void testToByteBuffer3() { + assumeTrue(buffer.nioBufferCount() == 1); + + assertEquals(buffer.order(), buffer.nioBuffer().order()); + } + + @Test + public void testSkipBytes1() { + buffer.setIndex(CAPACITY / 4, CAPACITY / 2); + + buffer.skipBytes(CAPACITY / 4); + assertEquals(CAPACITY / 4 * 2, buffer.readerIndex()); + + try { + buffer.skipBytes(CAPACITY / 4 + 1); + fail(); + } catch (IndexOutOfBoundsException e) { + // Expected + } + + // Should remain unchanged. + assertEquals(CAPACITY / 4 * 2, buffer.readerIndex()); + } + + @Test + public void testHashCode() { + ByteBuf elemA = buffer(15); + ByteBuf elemB = directBuffer(15); + elemA.writeBytes(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5 }); + elemB.writeBytes(new byte[] { 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 9 }); + + Set<ByteBuf> set = new HashSet<ByteBuf>(); + set.add(elemA); + set.add(elemB); + + assertEquals(2, set.size()); + ByteBuf elemACopy = elemA.copy(); + assertTrue(set.contains(elemACopy)); + + ByteBuf elemBCopy = elemB.copy(); + assertTrue(set.contains(elemBCopy)); + + buffer.clear(); + buffer.writeBytes(elemA.duplicate()); + + assertTrue(set.remove(buffer)); + assertFalse(set.contains(elemA)); + assertEquals(1, set.size()); + + buffer.clear(); + buffer.writeBytes(elemB.duplicate()); + assertTrue(set.remove(buffer)); + assertFalse(set.contains(elemB)); + assertEquals(0, set.size()); + elemA.release(); + elemB.release(); + elemACopy.release(); + elemBCopy.release(); + } + + // Test case for https://github.com/netty/netty/issues/325 + @Test + public void testDiscardAllReadBytes() { + buffer.writerIndex(buffer.capacity()); + buffer.readerIndex(buffer.writerIndex()); + buffer.discardReadBytes(); + } + + @Test + public void testForEachByte() { + buffer.clear(); + for (int i = 0; i < CAPACITY; i ++) { + buffer.writeByte(i + 1); + } + + final AtomicInteger lastIndex = new AtomicInteger(); + buffer.setIndex(CAPACITY / 4, CAPACITY * 3 / 4); + assertThat(buffer.forEachByte(new ByteBufProcessor() { + int i = CAPACITY / 4; + + @Override + public boolean process(byte value) throws Exception { + assertThat(value, is((byte) (i + 1))); + lastIndex.set(i); + i ++; + return true; + } + }), is(-1)); + + assertThat(lastIndex.get(), is(CAPACITY * 3 / 4 - 1)); + } + + @Test + public void testForEachByteAbort() { + buffer.clear(); + for (int i = 0; i < CAPACITY; i ++) { + buffer.writeByte(i + 1); + } + + final int stop = CAPACITY / 2; + assertThat(buffer.forEachByte(CAPACITY / 3, CAPACITY / 3, new ByteBufProcessor() { + int i = CAPACITY / 3; + + @Override + public boolean process(byte value) throws Exception { + assertThat(value, is((byte) (i + 1))); + if (i == stop) { + return false; + } + + i++; + return true; + } + }), is(stop)); + } + + @Test + public void testForEachByteDesc() { + buffer.clear(); + for (int i = 0; i < CAPACITY; i ++) { + buffer.writeByte(i + 1); + } + + final AtomicInteger lastIndex = new AtomicInteger(); + assertThat(buffer.forEachByteDesc(CAPACITY / 4, CAPACITY * 2 / 4, new ByteBufProcessor() { + int i = CAPACITY * 3 / 4 - 1; + + @Override + public boolean process(byte value) throws Exception { + assertThat(value, is((byte) (i + 1))); + lastIndex.set(i); + i --; + return true; + } + }), is(-1)); + + assertThat(lastIndex.get(), is(CAPACITY / 4)); + } + + @Test + public void testInternalNioBuffer() { + testInternalNioBuffer(128); + testInternalNioBuffer(1024); + testInternalNioBuffer(4 * 1024); + testInternalNioBuffer(64 * 1024); + testInternalNioBuffer(32 * 1024 * 1024); + testInternalNioBuffer(64 * 1024 * 1024); + } + + private void testInternalNioBuffer(int a) { + ByteBuf buffer = newBuffer(2); + ByteBuffer buf = buffer.internalNioBuffer(buffer.readerIndex(), 1); + assertEquals(1, buf.remaining()); + + byte[] data = new byte[a]; + ThreadLocalRandom.current().nextBytes(data); + buffer.writeBytes(data); + + buf = buffer.internalNioBuffer(buffer.readerIndex(), a); + assertEquals(a, buf.remaining()); + + for (int i = 0; i < a; i++) { + assertEquals(data[i], buf.get()); + } + assertFalse(buf.hasRemaining()); + buffer.release(); + } + + @Test + public void testDuplicateReadGatheringByteChannelMultipleThreads() throws Exception { + testReadGatheringByteChannelMultipleThreads(false); + } + + @Test + public void testSliceReadGatheringByteChannelMultipleThreads() throws Exception { + testReadGatheringByteChannelMultipleThreads(true); + } + + private void testReadGatheringByteChannelMultipleThreads(final boolean slice) throws Exception { + final byte[] bytes = new byte[8]; + random.nextBytes(bytes); + + final ByteBuf buffer = newBuffer(8); + buffer.writeBytes(bytes); + final CountDownLatch latch = new CountDownLatch(60000); + final CyclicBarrier barrier = new CyclicBarrier(11); + for (int i = 0; i < 10; i++) { + new Thread(new Runnable() { + @Override + public void run() { + while (latch.getCount() > 0) { + ByteBuf buf; + if (slice) { + buf = buffer.slice(); + } else { + buf = buffer.duplicate(); + } + TestGatheringByteChannel channel = new TestGatheringByteChannel(); + + while (buf.isReadable()) { + try { + buf.readBytes(channel, buf.readableBytes()); + } catch (IOException e) { + // Never happens + return; + } + } + assertArrayEquals(bytes, channel.writtenBytes()); + latch.countDown(); + } + try { + barrier.await(); + } catch (Exception e) { + // ignore + } + } + }).start(); + } + latch.await(10, TimeUnit.SECONDS); + barrier.await(5, TimeUnit.SECONDS); + buffer.release(); + } + + @Test + public void testDuplicateReadOutputStreamMultipleThreads() throws Exception { + testReadOutputStreamMultipleThreads(false); + } + + @Test + public void testSliceReadOutputStreamMultipleThreads() throws Exception { + testReadOutputStreamMultipleThreads(true); + } + + private void testReadOutputStreamMultipleThreads(final boolean slice) throws Exception { + final byte[] bytes = new byte[8]; + random.nextBytes(bytes); + + final ByteBuf buffer = newBuffer(8); + buffer.writeBytes(bytes); + final CountDownLatch latch = new CountDownLatch(60000); + final CyclicBarrier barrier = new CyclicBarrier(11); + for (int i = 0; i < 10; i++) { + new Thread(new Runnable() { + @Override + public void run() { + while (latch.getCount() > 0) { + ByteBuf buf; + if (slice) { + buf = buffer.slice(); + } else { + buf = buffer.duplicate(); + } + ByteArrayOutputStream out = new ByteArrayOutputStream(); + + while (buf.isReadable()) { + try { + buf.readBytes(out, buf.readableBytes()); + } catch (IOException e) { + // Never happens + return; + } + } + assertArrayEquals(bytes, out.toByteArray()); + latch.countDown(); + } + try { + barrier.await(); + } catch (Exception e) { + // ignore + } + } + }).start(); + } + latch.await(10, TimeUnit.SECONDS); + barrier.await(5, TimeUnit.SECONDS); + buffer.release(); + } + + @Test + public void testDuplicateBytesInArrayMultipleThreads() throws Exception { + testBytesInArrayMultipleThreads(false); + } + + @Test + public void testSliceBytesInArrayMultipleThreads() throws Exception { + testBytesInArrayMultipleThreads(true); + } + + private void testBytesInArrayMultipleThreads(final boolean slice) throws Exception { + final byte[] bytes = new byte[8]; + random.nextBytes(bytes); + + final ByteBuf buffer = newBuffer(8); + buffer.writeBytes(bytes); + final AtomicReference<Throwable> cause = new AtomicReference<Throwable>(); + final CountDownLatch latch = new CountDownLatch(60000); + final CyclicBarrier barrier = new CyclicBarrier(11); + for (int i = 0; i < 10; i++) { + new Thread(new Runnable() { + @Override + public void run() { + while (cause.get() == null && latch.getCount() > 0) { + ByteBuf buf; + if (slice) { + buf = buffer.slice(); + } else { + buf = buffer.duplicate(); + } + + byte[] array = new byte[8]; + buf.readBytes(array); + + assertArrayEquals(bytes, array); + + Arrays.fill(array, (byte) 0); + buf.getBytes(0, array); + assertArrayEquals(bytes, array); + + latch.countDown(); + } + try { + barrier.await(); + } catch (Exception e) { + // ignore + } + } + }).start(); + } + latch.await(10, TimeUnit.SECONDS); + barrier.await(5, TimeUnit.SECONDS); + assertNull(cause.get()); + buffer.release(); + } + + @Test(expected = IndexOutOfBoundsException.class) + public void readByteThrowsIndexOutOfBoundsException() { + final ByteBuf buffer = newBuffer(8); + try { + buffer.writeByte(0); + assertEquals((byte) 0, buffer.readByte()); + buffer.readByte(); + } finally { + buffer.release(); + } + } + + @Test + @SuppressWarnings("ForLoopThatDoesntUseLoopVariable") + public void testNioBufferExposeOnlyRegion() { + final ByteBuf buffer = newBuffer(8); + byte[] data = new byte[8]; + random.nextBytes(data); + buffer.writeBytes(data); + + ByteBuffer nioBuf = buffer.nioBuffer(1, data.length - 2); + assertEquals(0, nioBuf.position()); + assertEquals(6, nioBuf.remaining()); + + for (int i = 1; nioBuf.hasRemaining(); i++) { + assertEquals(data[i], nioBuf.get()); + } + buffer.release(); + } + + @Test + public void ensureWritableWithForceDoesNotThrow() { + ensureWritableDoesNotThrow(true); + } + + @Test + public void ensureWritableWithOutForceDoesNotThrow() { + ensureWritableDoesNotThrow(false); + } + + private void ensureWritableDoesNotThrow(boolean force) { + final ByteBuf buffer = newBuffer(8); + buffer.writerIndex(buffer.capacity()); + buffer.ensureWritable(8, force); + buffer.release(); + } + + // See: + // - https://github.com/netty/netty/issues/2587 + // - https://github.com/netty/netty/issues/2580 + @Test + public void testLittleEndianWithExpand() { + ByteBuf buffer = newBuffer(0).order(LITTLE_ENDIAN); + buffer.writeInt(0x12345678); + assertEquals("78563412", ByteBufUtil.hexDump(buffer)); + buffer.release(); + } + + private ByteBuf releasedBuffer() { + ByteBuf buffer = newBuffer(8); + // Clear the buffer so we are sure the reader and writer indices are 0. + // This is important as we may return a slice from newBuffer(...). + buffer.clear(); + + assertTrue(buffer.release()); + return buffer; + } + + @Test(expected = IllegalReferenceCountException.class) + public void testDiscardReadBytesAfterRelease() { + releasedBuffer().discardReadBytes(); + } + + @Test(expected = IllegalReferenceCountException.class) + public void testDiscardSomeReadBytesAfterRelease() { + releasedBuffer().discardSomeReadBytes(); + } + + @Test(expected = IllegalReferenceCountException.class) + public void testEnsureWritableAfterRelease() { + releasedBuffer().ensureWritable(16); + } + + @Test(expected = IllegalReferenceCountException.class) + public void testGetBooleanAfterRelease() { + releasedBuffer().getBoolean(0); + } + + @Test(expected = IllegalReferenceCountException.class) + public void testGetByteAfterRelease() { + releasedBuffer().getByte(0); + } + + @Test(expected = IllegalReferenceCountException.class) + public void testGetUnsignedByteAfterRelease() { + releasedBuffer().getUnsignedByte(0); + } + + @Test(expected = IllegalReferenceCountException.class) + public void testGetShortAfterRelease() { + releasedBuffer().getShort(0); + } + + @Test(expected = IllegalReferenceCountException.class) + public void testGetUnsignedShortAfterRelease() { + releasedBuffer().getUnsignedShort(0); + } + + @Test(expected = IllegalReferenceCountException.class) + public void testGetMediumAfterRelease() { + releasedBuffer().getMedium(0); + } + + @Test(expected = IllegalReferenceCountException.class) + public void testGetUnsignedMediumAfterRelease() { + releasedBuffer().getUnsignedMedium(0); + } + + @Test(expected = IllegalReferenceCountException.class) + public void testGetIntAfterRelease() { + releasedBuffer().getInt(0); + } + + @Test(expected = IllegalReferenceCountException.class) + public void testGetUnsignedIntAfterRelease() { + releasedBuffer().getUnsignedInt(0); + } + + @Test(expected = IllegalReferenceCountException.class) + public void testGetLongAfterRelease() { + releasedBuffer().getLong(0); + } + + @Test(expected = IllegalReferenceCountException.class) + public void testGetCharAfterRelease() { + releasedBuffer().getChar(0); + } + + @Test(expected = IllegalReferenceCountException.class) + public void testGetFloatAfterRelease() { + releasedBuffer().getFloat(0); + } + + @Test(expected = IllegalReferenceCountException.class) + public void testGetDoubleAfterRelease() { + releasedBuffer().getDouble(0); + } + + @Test(expected = IllegalReferenceCountException.class) + public void testGetBytesAfterRelease() { + ByteBuf buffer = buffer(8); + try { + releasedBuffer().getBytes(0, buffer); + } finally { + buffer.release(); + } + } + + @Test(expected = IllegalReferenceCountException.class) + public void testGetBytesAfterRelease2() { + ByteBuf buffer = buffer(); + try { + releasedBuffer().getBytes(0, buffer, 1); + } finally { + buffer.release(); + } + } + + @Test(expected = IllegalReferenceCountException.class) + public void testGetBytesAfterRelease3() { + ByteBuf buffer = buffer(); + try { + releasedBuffer().getBytes(0, buffer, 0, 1); + } finally { + buffer.release(); + } + } + + @Test(expected = IllegalReferenceCountException.class) + public void testGetBytesAfterRelease4() { + releasedBuffer().getBytes(0, new byte[8]); + } + + @Test(expected = IllegalReferenceCountException.class) + public void testGetBytesAfterRelease5() { + releasedBuffer().getBytes(0, new byte[8], 0, 1); + } + + @Test(expected = IllegalReferenceCountException.class) + public void testGetBytesAfterRelease6() { + releasedBuffer().getBytes(0, ByteBuffer.allocate(8)); + } + + @Test(expected = IllegalReferenceCountException.class) + public void testGetBytesAfterRelease7() throws IOException { + releasedBuffer().getBytes(0, new ByteArrayOutputStream(), 1); + } + + @Test(expected = IllegalReferenceCountException.class) + public void testGetBytesAfterRelease8() throws IOException { + releasedBuffer().getBytes(0, new DevNullGatheringByteChannel(), 1); + } + + @Test(expected = IllegalReferenceCountException.class) + public void testSetBooleanAfterRelease() { + releasedBuffer().setBoolean(0, true); + } + + @Test(expected = IllegalReferenceCountException.class) + public void testSetByteAfterRelease() { + releasedBuffer().setByte(0, 1); + } + + @Test(expected = IllegalReferenceCountException.class) + public void testSetShortAfterRelease() { + releasedBuffer().setShort(0, 1); + } + + @Test(expected = IllegalReferenceCountException.class) + public void testSetMediumAfterRelease() { + releasedBuffer().setMedium(0, 1); + } + + @Test(expected = IllegalReferenceCountException.class) + public void testSetIntAfterRelease() { + releasedBuffer().setInt(0, 1); + } + + @Test(expected = IllegalReferenceCountException.class) + public void testSetLongAfterRelease() { + releasedBuffer().setLong(0, 1); + } + + @Test(expected = IllegalReferenceCountException.class) + public void testSetCharAfterRelease() { + releasedBuffer().setChar(0, 1); + } + + @Test(expected = IllegalReferenceCountException.class) + public void testSetFloatAfterRelease() { + releasedBuffer().setFloat(0, 1); + } + + @Test(expected = IllegalReferenceCountException.class) + public void testSetDoubleAfterRelease() { + releasedBuffer().setDouble(0, 1); + } + + @Test(expected = IllegalReferenceCountException.class) + public void testSetBytesAfterRelease() { + ByteBuf buffer = buffer(); + try { + releasedBuffer().setBytes(0, buffer); + } finally { + buffer.release(); + } + } + + @Test(expected = IllegalReferenceCountException.class) + public void testSetBytesAfterRelease2() { + ByteBuf buffer = buffer(); + try { + releasedBuffer().setBytes(0, buffer, 1); + } finally { + buffer.release(); + } + } + + @Test(expected = IllegalReferenceCountException.class) + public void testSetBytesAfterRelease3() { + ByteBuf buffer = buffer(); + try { + releasedBuffer().setBytes(0, buffer, 0, 1); + } finally { + buffer.release(); + } + } + + @Test(expected = IllegalReferenceCountException.class) + public void testSetBytesAfterRelease4() { + releasedBuffer().setBytes(0, new byte[8]); + } + + @Test(expected = IllegalReferenceCountException.class) + public void testSetBytesAfterRelease5() { + releasedBuffer().setBytes(0, new byte[8], 0, 1); + } + + @Test(expected = IllegalReferenceCountException.class) + public void testSetBytesAfterRelease6() { + releasedBuffer().setBytes(0, ByteBuffer.allocate(8)); + } + + @Test(expected = IllegalReferenceCountException.class) + public void testSetBytesAfterRelease7() throws IOException { + releasedBuffer().setBytes(0, new ByteArrayInputStream(new byte[8]), 1); + } + + @Test(expected = IllegalReferenceCountException.class) + public void testSetBytesAfterRelease8() throws IOException { + releasedBuffer().setBytes(0, new TestScatteringByteChannel(), 1); + } + + @Test(expected = IllegalReferenceCountException.class)
<TRUNCATED>