1686 lines
57 KiB
Java
1686 lines
57 KiB
Java
/*
|
|
* Copyright 2012 The Netty Project
|
|
*
|
|
* 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:
|
|
*
|
|
* https://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 io.netty5.buffer;
|
|
|
|
import static io.netty5.buffer.Unpooled.EMPTY_BUFFER;
|
|
import static io.netty5.buffer.Unpooled.buffer;
|
|
import static io.netty5.buffer.Unpooled.compositeBuffer;
|
|
import static io.netty5.buffer.Unpooled.directBuffer;
|
|
import static io.netty5.buffer.Unpooled.wrappedBuffer;
|
|
import static io.netty5.util.internal.EmptyArrays.EMPTY_BYTES;
|
|
import static org.hamcrest.CoreMatchers.instanceOf;
|
|
import static org.hamcrest.CoreMatchers.is;
|
|
import static org.hamcrest.MatcherAssert.assertThat;
|
|
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
|
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
|
import static org.junit.jupiter.api.Assertions.assertFalse;
|
|
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
|
import static org.junit.jupiter.api.Assertions.assertNotSame;
|
|
import static org.junit.jupiter.api.Assertions.assertSame;
|
|
import static org.junit.jupiter.api.Assertions.assertThrows;
|
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
|
import static org.junit.jupiter.api.Assertions.fail;
|
|
|
|
import io.netty5.util.ReferenceCountUtil;
|
|
import java.nio.ByteBuffer;
|
|
import java.nio.ByteOrder;
|
|
import java.util.ArrayList;
|
|
import java.util.Collections;
|
|
import java.util.ConcurrentModificationException;
|
|
import java.util.Iterator;
|
|
import java.util.List;
|
|
import java.util.NoSuchElementException;
|
|
import java.util.Objects;
|
|
import java.util.concurrent.ThreadLocalRandom;
|
|
import org.junit.jupiter.api.Assumptions;
|
|
import org.junit.jupiter.api.Test;
|
|
|
|
/**
|
|
* An abstract test class for composite channel buffers
|
|
*/
|
|
public abstract class AbstractCompositeByteBufTest extends AbstractByteBufTest {
|
|
|
|
private static final ByteBufAllocator ALLOC = UnpooledByteBufAllocator.DEFAULT;
|
|
|
|
private final ByteOrder order;
|
|
|
|
protected AbstractCompositeByteBufTest(ByteOrder order) {
|
|
this.order = Objects.requireNonNull(order, "order");
|
|
}
|
|
|
|
@Override
|
|
protected ByteBuf newBuffer(int length, int maxCapacity) {
|
|
Assumptions.assumeTrue(maxCapacity == Integer.MAX_VALUE);
|
|
|
|
List<ByteBuf> buffers = new ArrayList<>();
|
|
for (int i = 0; i < length + 45; i += 45) {
|
|
buffers.add(EMPTY_BUFFER);
|
|
buffers.add(wrappedBuffer(new byte[1]));
|
|
buffers.add(EMPTY_BUFFER);
|
|
buffers.add(wrappedBuffer(new byte[2]));
|
|
buffers.add(EMPTY_BUFFER);
|
|
buffers.add(wrappedBuffer(new byte[3]));
|
|
buffers.add(EMPTY_BUFFER);
|
|
buffers.add(wrappedBuffer(new byte[4]));
|
|
buffers.add(EMPTY_BUFFER);
|
|
buffers.add(wrappedBuffer(new byte[5]));
|
|
buffers.add(EMPTY_BUFFER);
|
|
buffers.add(wrappedBuffer(new byte[6]));
|
|
buffers.add(EMPTY_BUFFER);
|
|
buffers.add(wrappedBuffer(new byte[7]));
|
|
buffers.add(EMPTY_BUFFER);
|
|
buffers.add(wrappedBuffer(new byte[8]));
|
|
buffers.add(EMPTY_BUFFER);
|
|
buffers.add(wrappedBuffer(new byte[9]));
|
|
buffers.add(EMPTY_BUFFER);
|
|
}
|
|
|
|
ByteBuf buffer;
|
|
// Ensure that we are really testing a CompositeByteBuf
|
|
switch (buffers.size()) {
|
|
case 0:
|
|
buffer = compositeBuffer(Integer.MAX_VALUE);
|
|
break;
|
|
case 1:
|
|
buffer = compositeBuffer(Integer.MAX_VALUE).addComponent(buffers.get(0));
|
|
break;
|
|
default:
|
|
buffer = wrappedBuffer(Integer.MAX_VALUE, buffers.toArray(new ByteBuf[0]));
|
|
break;
|
|
}
|
|
buffer = buffer.order(order);
|
|
|
|
// Truncate to the requested capacity.
|
|
buffer.capacity(length);
|
|
|
|
assertEquals(length, buffer.capacity());
|
|
assertEquals(length, buffer.readableBytes());
|
|
assertFalse(buffer.isWritable());
|
|
buffer.writerIndex(0);
|
|
return buffer;
|
|
}
|
|
|
|
protected CompositeByteBuf newCompositeBuffer() {
|
|
return compositeBuffer();
|
|
}
|
|
|
|
// Composite buffer does not waste bandwidth on discardReadBytes, but
|
|
// the test will fail in strict mode.
|
|
@Override
|
|
protected boolean discardReadBytesDoesNotMoveWritableBytes() {
|
|
return false;
|
|
}
|
|
|
|
@Test
|
|
public void testIsContiguous() {
|
|
ByteBuf buf = newBuffer(4);
|
|
assertFalse(buf.isContiguous());
|
|
buf.release();
|
|
}
|
|
|
|
/**
|
|
* Tests the "getBufferFor" method
|
|
*/
|
|
@Test
|
|
public void testComponentAtOffset() {
|
|
CompositeByteBuf buf = (CompositeByteBuf) wrappedBuffer(new byte[]{1, 2, 3, 4, 5},
|
|
new byte[]{4, 5, 6, 7, 8, 9, 26});
|
|
|
|
//Ensure that a random place will be fine
|
|
assertEquals(5, buf.componentAtOffset(2).capacity());
|
|
|
|
//Loop through each byte
|
|
|
|
byte index = 0;
|
|
|
|
while (index < buf.capacity()) {
|
|
ByteBuf _buf = buf.componentAtOffset(index++);
|
|
assertNotNull(_buf);
|
|
assertTrue(_buf.capacity() > 0);
|
|
assertNotNull(_buf.getByte(0));
|
|
assertNotNull(_buf.getByte(_buf.readableBytes() - 1));
|
|
}
|
|
|
|
buf.release();
|
|
}
|
|
|
|
@Test
|
|
public void testToComponentIndex() {
|
|
CompositeByteBuf buf = (CompositeByteBuf) wrappedBuffer(new byte[]{1, 2, 3, 4, 5},
|
|
new byte[]{4, 5, 6, 7, 8, 9, 26}, new byte[]{10, 9, 8, 7, 6, 5, 33});
|
|
|
|
// spot checks
|
|
assertEquals(0, buf.toComponentIndex(4));
|
|
assertEquals(1, buf.toComponentIndex(5));
|
|
assertEquals(2, buf.toComponentIndex(15));
|
|
|
|
//Loop through each byte
|
|
|
|
byte index = 0;
|
|
|
|
while (index < buf.capacity()) {
|
|
int cindex = buf.toComponentIndex(index++);
|
|
assertTrue(cindex >= 0 && cindex < buf.numComponents());
|
|
}
|
|
|
|
buf.release();
|
|
}
|
|
|
|
@Test
|
|
public void testToByteIndex() {
|
|
CompositeByteBuf buf = (CompositeByteBuf) wrappedBuffer(new byte[]{1, 2, 3, 4, 5},
|
|
new byte[]{4, 5, 6, 7, 8, 9, 26}, new byte[]{10, 9, 8, 7, 6, 5, 33});
|
|
|
|
// spot checks
|
|
assertEquals(0, buf.toByteIndex(0));
|
|
assertEquals(5, buf.toByteIndex(1));
|
|
assertEquals(12, buf.toByteIndex(2));
|
|
|
|
buf.release();
|
|
}
|
|
|
|
@Test
|
|
public void testDiscardReadBytes3() {
|
|
ByteBuf a, b;
|
|
a = wrappedBuffer(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }).order(order);
|
|
b = wrappedBuffer(
|
|
wrappedBuffer(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }, 0, 5).order(order),
|
|
wrappedBuffer(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }, 5, 5).order(order));
|
|
a.skipBytes(6);
|
|
b.skipBytes(6);
|
|
assertEquals(a.readerIndex(), b.readerIndex());
|
|
a.readerIndex(a.readerIndex() - 1);
|
|
b.readerIndex(b.readerIndex() - 1);
|
|
assertEquals(a.readerIndex(), b.readerIndex());
|
|
a.writerIndex(a.writerIndex() - 1);
|
|
b.writerIndex(b.writerIndex() - 1);
|
|
assertEquals(a.writerIndex(), b.writerIndex());
|
|
a.writerIndex(a.writerIndex() + 1);
|
|
b.writerIndex(b.writerIndex() + 1);
|
|
assertEquals(a.writerIndex(), b.writerIndex());
|
|
assertTrue(ByteBufUtil.equals(a, b));
|
|
// now discard
|
|
a.discardReadBytes();
|
|
b.discardReadBytes();
|
|
assertEquals(a.readerIndex(), b.readerIndex());
|
|
assertEquals(a.writerIndex(), b.writerIndex());
|
|
assertTrue(ByteBufUtil.equals(a, b));
|
|
assertTrue(ByteBufUtil.equals(a, b));
|
|
|
|
a.release();
|
|
b.release();
|
|
}
|
|
|
|
@Test
|
|
public void testAutoConsolidation() {
|
|
CompositeByteBuf buf = compositeBuffer(2);
|
|
|
|
buf.addComponent(wrappedBuffer(new byte[] { 1 }));
|
|
assertEquals(1, buf.numComponents());
|
|
|
|
buf.addComponent(wrappedBuffer(new byte[] { 2, 3 }));
|
|
assertEquals(2, buf.numComponents());
|
|
|
|
buf.addComponent(wrappedBuffer(new byte[] { 4, 5, 6 }));
|
|
|
|
assertEquals(1, buf.numComponents());
|
|
assertTrue(buf.hasArray());
|
|
assertNotNull(buf.array());
|
|
assertEquals(0, buf.arrayOffset());
|
|
|
|
buf.release();
|
|
}
|
|
|
|
@Test
|
|
public void testCompositeToSingleBuffer() {
|
|
CompositeByteBuf buf = compositeBuffer(3);
|
|
|
|
buf.addComponent(wrappedBuffer(new byte[] {1, 2, 3}));
|
|
assertEquals(1, buf.numComponents());
|
|
|
|
buf.addComponent(wrappedBuffer(new byte[] {4}));
|
|
assertEquals(2, buf.numComponents());
|
|
|
|
buf.addComponent(wrappedBuffer(new byte[] {5, 6}));
|
|
assertEquals(3, buf.numComponents());
|
|
|
|
// NOTE: hard-coding 6 here, since it seems like addComponent doesn't bump the writer index.
|
|
// I'm unsure as to whether or not this is correct behavior
|
|
ByteBuffer nioBuffer = buf.nioBuffer(0, 6);
|
|
byte[] bytes = nioBuffer.array();
|
|
assertEquals(6, bytes.length);
|
|
assertArrayEquals(new byte[] {1, 2, 3, 4, 5, 6}, bytes);
|
|
|
|
buf.release();
|
|
}
|
|
|
|
@Test
|
|
public void testFullConsolidation() {
|
|
CompositeByteBuf buf = compositeBuffer(Integer.MAX_VALUE);
|
|
buf.addComponent(wrappedBuffer(new byte[] { 1 }));
|
|
buf.addComponent(wrappedBuffer(new byte[] { 2, 3 }));
|
|
buf.addComponent(wrappedBuffer(new byte[] { 4, 5, 6 }));
|
|
buf.consolidate();
|
|
|
|
assertEquals(1, buf.numComponents());
|
|
assertTrue(buf.hasArray());
|
|
assertNotNull(buf.array());
|
|
assertEquals(0, buf.arrayOffset());
|
|
|
|
buf.release();
|
|
}
|
|
|
|
@Test
|
|
public void testRangedConsolidation() {
|
|
CompositeByteBuf buf = compositeBuffer(Integer.MAX_VALUE);
|
|
buf.addComponent(wrappedBuffer(new byte[] { 1 }));
|
|
buf.addComponent(wrappedBuffer(new byte[] { 2, 3 }));
|
|
buf.addComponent(wrappedBuffer(new byte[] { 4, 5, 6 }));
|
|
buf.addComponent(wrappedBuffer(new byte[] { 7, 8, 9, 10 }));
|
|
buf.consolidate(1, 2);
|
|
|
|
assertEquals(3, buf.numComponents());
|
|
assertEquals(wrappedBuffer(new byte[] { 1 }), buf.component(0));
|
|
assertEquals(wrappedBuffer(new byte[] { 2, 3, 4, 5, 6 }), buf.component(1));
|
|
assertEquals(wrappedBuffer(new byte[] { 7, 8, 9, 10 }), buf.component(2));
|
|
|
|
buf.release();
|
|
}
|
|
|
|
@Test
|
|
public void testCompositeWrappedBuffer() {
|
|
ByteBuf header = buffer(12).order(order);
|
|
ByteBuf payload = buffer(512).order(order);
|
|
|
|
header.writeBytes(new byte[12]);
|
|
payload.writeBytes(new byte[512]);
|
|
|
|
ByteBuf buffer = wrappedBuffer(header, payload);
|
|
|
|
assertEquals(12, header.readableBytes());
|
|
assertEquals(512, payload.readableBytes());
|
|
|
|
assertEquals(12 + 512, buffer.readableBytes());
|
|
assertEquals(2, buffer.nioBufferCount());
|
|
|
|
buffer.release();
|
|
}
|
|
|
|
@Test
|
|
public void testSeveralBuffersEquals() {
|
|
ByteBuf a, b;
|
|
// XXX Same tests with several buffers in wrappedCheckedBuffer
|
|
// Different length.
|
|
a = wrappedBuffer(new byte[] { 1 }).order(order);
|
|
b = wrappedBuffer(
|
|
wrappedBuffer(new byte[] { 1 }).order(order),
|
|
wrappedBuffer(new byte[] { 2 }).order(order));
|
|
assertFalse(ByteBufUtil.equals(a, b));
|
|
|
|
a.release();
|
|
b.release();
|
|
|
|
// Same content, same firstIndex, short length.
|
|
a = wrappedBuffer(new byte[] { 1, 2, 3 }).order(order);
|
|
b = wrappedBuffer(
|
|
wrappedBuffer(new byte[]{1}).order(order),
|
|
wrappedBuffer(new byte[]{2}).order(order),
|
|
wrappedBuffer(new byte[]{3}).order(order));
|
|
assertTrue(ByteBufUtil.equals(a, b));
|
|
|
|
a.release();
|
|
b.release();
|
|
|
|
// Same content, different firstIndex, short length.
|
|
a = wrappedBuffer(new byte[] { 1, 2, 3 }).order(order);
|
|
b = wrappedBuffer(
|
|
wrappedBuffer(new byte[] { 0, 1, 2, 3, 4 }, 1, 2).order(order),
|
|
wrappedBuffer(new byte[] { 0, 1, 2, 3, 4 }, 3, 1).order(order));
|
|
assertTrue(ByteBufUtil.equals(a, b));
|
|
|
|
a.release();
|
|
b.release();
|
|
|
|
// Different content, same firstIndex, short length.
|
|
a = wrappedBuffer(new byte[] { 1, 2, 3 }).order(order);
|
|
b = wrappedBuffer(
|
|
wrappedBuffer(new byte[] { 1, 2 }).order(order),
|
|
wrappedBuffer(new byte[] { 4 }).order(order));
|
|
assertFalse(ByteBufUtil.equals(a, b));
|
|
|
|
a.release();
|
|
b.release();
|
|
|
|
// Different content, different firstIndex, short length.
|
|
a = wrappedBuffer(new byte[] { 1, 2, 3 }).order(order);
|
|
b = wrappedBuffer(
|
|
wrappedBuffer(new byte[] { 0, 1, 2, 4, 5 }, 1, 2).order(order),
|
|
wrappedBuffer(new byte[] { 0, 1, 2, 4, 5 }, 3, 1).order(order));
|
|
assertFalse(ByteBufUtil.equals(a, b));
|
|
|
|
a.release();
|
|
b.release();
|
|
|
|
// Same content, same firstIndex, long length.
|
|
a = wrappedBuffer(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }).order(order);
|
|
b = wrappedBuffer(
|
|
wrappedBuffer(new byte[] { 1, 2, 3 }).order(order),
|
|
wrappedBuffer(new byte[] { 4, 5, 6 }).order(order),
|
|
wrappedBuffer(new byte[] { 7, 8, 9, 10 }).order(order));
|
|
assertTrue(ByteBufUtil.equals(a, b));
|
|
|
|
a.release();
|
|
b.release();
|
|
|
|
// Same content, different firstIndex, long length.
|
|
a = wrappedBuffer(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }).order(order);
|
|
b = wrappedBuffer(
|
|
wrappedBuffer(new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, 1, 5).order(order),
|
|
wrappedBuffer(new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, 6, 5).order(order));
|
|
assertTrue(ByteBufUtil.equals(a, b));
|
|
|
|
a.release();
|
|
b.release();
|
|
|
|
// Different content, same firstIndex, long length.
|
|
a = wrappedBuffer(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }).order(order);
|
|
b = wrappedBuffer(
|
|
wrappedBuffer(new byte[] { 1, 2, 3, 4, 6 }).order(order),
|
|
wrappedBuffer(new byte[] { 7, 8, 5, 9, 10 }).order(order));
|
|
assertFalse(ByteBufUtil.equals(a, b));
|
|
|
|
a.release();
|
|
b.release();
|
|
|
|
// Different content, different firstIndex, long length.
|
|
a = wrappedBuffer(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }).order(order);
|
|
b = wrappedBuffer(
|
|
wrappedBuffer(new byte[] { 0, 1, 2, 3, 4, 6, 7, 8, 5, 9, 10, 11 }, 1, 5).order(order),
|
|
wrappedBuffer(new byte[] { 0, 1, 2, 3, 4, 6, 7, 8, 5, 9, 10, 11 }, 6, 5).order(order));
|
|
assertFalse(ByteBufUtil.equals(a, b));
|
|
|
|
a.release();
|
|
b.release();
|
|
}
|
|
|
|
@Test
|
|
public void testWrappedBuffer() {
|
|
|
|
ByteBuf a = wrappedBuffer(wrappedBuffer(ByteBuffer.allocateDirect(16)));
|
|
assertEquals(16, a.capacity());
|
|
a.release();
|
|
|
|
a = wrappedBuffer(wrappedBuffer(new byte[] { 1, 2, 3 }).order(order));
|
|
ByteBuf b = wrappedBuffer(wrappedBuffer(new byte[][] { new byte[] { 1, 2, 3 } }).order(order));
|
|
assertEquals(a, b);
|
|
|
|
a.release();
|
|
b.release();
|
|
|
|
a = wrappedBuffer(wrappedBuffer(new byte[] { 1, 2, 3 }).order(order));
|
|
b = wrappedBuffer(wrappedBuffer(
|
|
new byte[] { 1 },
|
|
new byte[] { 2 },
|
|
new byte[] { 3 }).order(order));
|
|
assertEquals(a, b);
|
|
|
|
a.release();
|
|
b.release();
|
|
|
|
a = wrappedBuffer(wrappedBuffer(new byte[] { 1, 2, 3 }).order(order));
|
|
b = wrappedBuffer(new ByteBuf[] {
|
|
wrappedBuffer(new byte[] { 1, 2, 3 }).order(order)
|
|
});
|
|
assertEquals(a, b);
|
|
|
|
a.release();
|
|
b.release();
|
|
|
|
a = wrappedBuffer(wrappedBuffer(new byte[] { 1, 2, 3 }).order(order));
|
|
b = wrappedBuffer(
|
|
wrappedBuffer(new byte[] { 1 }).order(order),
|
|
wrappedBuffer(new byte[] { 2 }).order(order),
|
|
wrappedBuffer(new byte[] { 3 }).order(order));
|
|
assertEquals(a, b);
|
|
|
|
a.release();
|
|
b.release();
|
|
|
|
a = wrappedBuffer(wrappedBuffer(new byte[] { 1, 2, 3 })).order(order);
|
|
b = wrappedBuffer(wrappedBuffer(new ByteBuffer[] {
|
|
ByteBuffer.wrap(new byte[] { 1, 2, 3 })
|
|
}));
|
|
assertEquals(a, b);
|
|
|
|
a.release();
|
|
b.release();
|
|
|
|
a = wrappedBuffer(wrappedBuffer(new byte[] { 1, 2, 3 }).order(order));
|
|
b = wrappedBuffer(wrappedBuffer(
|
|
ByteBuffer.wrap(new byte[] { 1 }),
|
|
ByteBuffer.wrap(new byte[] { 2 }),
|
|
ByteBuffer.wrap(new byte[] { 3 })));
|
|
assertEquals(a, b);
|
|
|
|
a.release();
|
|
b.release();
|
|
}
|
|
|
|
@Test
|
|
public void testWrittenBuffersEquals() {
|
|
//XXX Same tests than testEquals with written AggregateChannelBuffers
|
|
ByteBuf a, b, c;
|
|
// Different length.
|
|
a = wrappedBuffer(new byte[] { 1 }).order(order);
|
|
b = wrappedBuffer(wrappedBuffer(new byte[] { 1 }, new byte[1])).order(order);
|
|
c = wrappedBuffer(new byte[] { 2 }).order(order);
|
|
|
|
// to enable writeBytes
|
|
b.writerIndex(b.writerIndex() - 1);
|
|
b.writeBytes(c);
|
|
assertFalse(ByteBufUtil.equals(a, b));
|
|
|
|
a.release();
|
|
b.release();
|
|
c.release();
|
|
|
|
// Same content, same firstIndex, short length.
|
|
a = wrappedBuffer(new byte[] { 1, 2, 3 }).order(order);
|
|
b = wrappedBuffer(wrappedBuffer(new byte[] { 1 }, new byte[2])).order(order);
|
|
c = wrappedBuffer(new byte[] { 2 }).order(order);
|
|
|
|
// to enable writeBytes
|
|
b.writerIndex(b.writerIndex() - 2);
|
|
b.writeBytes(c);
|
|
c.release();
|
|
c = wrappedBuffer(new byte[] { 3 }).order(order);
|
|
|
|
b.writeBytes(c);
|
|
assertTrue(ByteBufUtil.equals(a, b));
|
|
|
|
a.release();
|
|
b.release();
|
|
c.release();
|
|
|
|
// Same content, different firstIndex, short length.
|
|
a = wrappedBuffer(new byte[] { 1, 2, 3 }).order(order);
|
|
b = wrappedBuffer(wrappedBuffer(new byte[] { 0, 1, 2, 3, 4 }, 1, 3)).order(order);
|
|
c = wrappedBuffer(new byte[] { 0, 1, 2, 3, 4 }, 3, 1).order(order);
|
|
// to enable writeBytes
|
|
b.writerIndex(b.writerIndex() - 1);
|
|
b.writeBytes(c);
|
|
assertTrue(ByteBufUtil.equals(a, b));
|
|
|
|
a.release();
|
|
b.release();
|
|
c.release();
|
|
|
|
// Different content, same firstIndex, short length.
|
|
a = wrappedBuffer(new byte[] { 1, 2, 3 }).order(order);
|
|
b = wrappedBuffer(wrappedBuffer(new byte[] { 1, 2 }, new byte[1])).order(order);
|
|
c = wrappedBuffer(new byte[] { 4 }).order(order);
|
|
// to enable writeBytes
|
|
b.writerIndex(b.writerIndex() - 1);
|
|
b.writeBytes(c);
|
|
assertFalse(ByteBufUtil.equals(a, b));
|
|
|
|
a.release();
|
|
b.release();
|
|
c.release();
|
|
|
|
// Different content, different firstIndex, short length.
|
|
a = wrappedBuffer(new byte[] { 1, 2, 3 }).order(order);
|
|
b = wrappedBuffer(wrappedBuffer(new byte[] { 0, 1, 2, 4, 5 }, 1, 3)).order(order);
|
|
c = wrappedBuffer(new byte[] { 0, 1, 2, 4, 5 }, 3, 1).order(order);
|
|
// to enable writeBytes
|
|
b.writerIndex(b.writerIndex() - 1);
|
|
b.writeBytes(c);
|
|
assertFalse(ByteBufUtil.equals(a, b));
|
|
|
|
a.release();
|
|
b.release();
|
|
c.release();
|
|
|
|
// Same content, same firstIndex, long length.
|
|
a = wrappedBuffer(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }).order(order);
|
|
b = wrappedBuffer(wrappedBuffer(new byte[] { 1, 2, 3 }, new byte[7])).order(order);
|
|
c = wrappedBuffer(new byte[] { 4, 5, 6 }).order(order);
|
|
|
|
// to enable writeBytes
|
|
b.writerIndex(b.writerIndex() - 7);
|
|
b.writeBytes(c);
|
|
c.release();
|
|
c = wrappedBuffer(new byte[] { 7, 8, 9, 10 }).order(order);
|
|
b.writeBytes(c);
|
|
assertTrue(ByteBufUtil.equals(a, b));
|
|
|
|
a.release();
|
|
b.release();
|
|
c.release();
|
|
|
|
// Same content, different firstIndex, long length.
|
|
a = wrappedBuffer(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }).order(order);
|
|
b = wrappedBuffer(
|
|
wrappedBuffer(new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, 1, 10)).order(order);
|
|
c = wrappedBuffer(new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, 6, 5).order(order);
|
|
// to enable writeBytes
|
|
b.writerIndex(b.writerIndex() - 5);
|
|
b.writeBytes(c);
|
|
assertTrue(ByteBufUtil.equals(a, b));
|
|
|
|
a.release();
|
|
b.release();
|
|
c.release();
|
|
|
|
// Different content, same firstIndex, long length.
|
|
a = wrappedBuffer(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }).order(order);
|
|
b = wrappedBuffer(wrappedBuffer(new byte[] { 1, 2, 3, 4, 6 }, new byte[5])).order(order);
|
|
c = wrappedBuffer(new byte[] { 7, 8, 5, 9, 10 }).order(order);
|
|
// to enable writeBytes
|
|
b.writerIndex(b.writerIndex() - 5);
|
|
b.writeBytes(c);
|
|
assertFalse(ByteBufUtil.equals(a, b));
|
|
|
|
a.release();
|
|
b.release();
|
|
c.release();
|
|
|
|
// Different content, different firstIndex, long length.
|
|
a = wrappedBuffer(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }).order(order);
|
|
b = wrappedBuffer(
|
|
wrappedBuffer(new byte[] { 0, 1, 2, 3, 4, 6, 7, 8, 5, 9, 10, 11 }, 1, 10)).order(order);
|
|
c = wrappedBuffer(new byte[] { 0, 1, 2, 3, 4, 6, 7, 8, 5, 9, 10, 11 }, 6, 5).order(order);
|
|
// to enable writeBytes
|
|
b.writerIndex(b.writerIndex() - 5);
|
|
b.writeBytes(c);
|
|
assertFalse(ByteBufUtil.equals(a, b));
|
|
|
|
a.release();
|
|
b.release();
|
|
c.release();
|
|
}
|
|
|
|
@Test
|
|
public void testEmptyBuffer() {
|
|
ByteBuf b = wrappedBuffer(new byte[]{1, 2}, new byte[]{3, 4});
|
|
b.readBytes(new byte[4]);
|
|
b.readBytes(EMPTY_BYTES);
|
|
b.release();
|
|
}
|
|
|
|
// Test for https://github.com/netty/netty/issues/1060
|
|
@Test
|
|
public void testReadWithEmptyCompositeBuffer() {
|
|
ByteBuf buf = compositeBuffer();
|
|
int n = 65;
|
|
for (int i = 0; i < n; i ++) {
|
|
buf.writeByte(1);
|
|
assertEquals(1, buf.readByte());
|
|
}
|
|
buf.release();
|
|
}
|
|
|
|
@SuppressWarnings("deprecation")
|
|
@Test
|
|
public void testComponentMustBeDuplicate() {
|
|
CompositeByteBuf buf = compositeBuffer();
|
|
buf.addComponent(buffer(4, 6).setIndex(1, 3));
|
|
assertThat(buf.component(0), is(instanceOf(AbstractDerivedByteBuf.class)));
|
|
assertThat(buf.component(0).capacity(), is(4));
|
|
assertThat(buf.component(0).maxCapacity(), is(6));
|
|
assertThat(buf.component(0).readableBytes(), is(2));
|
|
buf.release();
|
|
}
|
|
|
|
@Test
|
|
public void testReferenceCounts1() {
|
|
ByteBuf c1 = buffer().writeByte(1);
|
|
ByteBuf c2 = buffer().writeByte(2).retain();
|
|
ByteBuf c3 = buffer().writeByte(3).retain(2);
|
|
|
|
CompositeByteBuf buf = compositeBuffer();
|
|
assertThat(buf.refCnt(), is(1));
|
|
buf.addComponents(c1, c2, c3);
|
|
|
|
assertThat(buf.refCnt(), is(1));
|
|
|
|
// Ensure that c[123]'s refCount did not change.
|
|
assertThat(c1.refCnt(), is(1));
|
|
assertThat(c2.refCnt(), is(2));
|
|
assertThat(c3.refCnt(), is(3));
|
|
|
|
assertThat(buf.component(0).refCnt(), is(1));
|
|
assertThat(buf.component(1).refCnt(), is(2));
|
|
assertThat(buf.component(2).refCnt(), is(3));
|
|
|
|
c3.release(2);
|
|
c2.release();
|
|
buf.release();
|
|
}
|
|
|
|
@Test
|
|
public void testReferenceCounts2() {
|
|
ByteBuf c1 = buffer().writeByte(1);
|
|
ByteBuf c2 = buffer().writeByte(2).retain();
|
|
ByteBuf c3 = buffer().writeByte(3).retain(2);
|
|
|
|
CompositeByteBuf bufA = compositeBuffer();
|
|
bufA.addComponents(c1, c2, c3).writerIndex(3);
|
|
|
|
CompositeByteBuf bufB = compositeBuffer();
|
|
bufB.addComponents(bufA);
|
|
|
|
// Ensure that bufA.refCnt() did not change.
|
|
assertThat(bufA.refCnt(), is(1));
|
|
|
|
// Ensure that c[123]'s refCnt did not change.
|
|
assertThat(c1.refCnt(), is(1));
|
|
assertThat(c2.refCnt(), is(2));
|
|
assertThat(c3.refCnt(), is(3));
|
|
|
|
// This should decrease bufA.refCnt().
|
|
bufB.release();
|
|
assertThat(bufB.refCnt(), is(0));
|
|
|
|
// Ensure bufA.refCnt() changed.
|
|
assertThat(bufA.refCnt(), is(0));
|
|
|
|
// Ensure that c[123]'s refCnt also changed due to the deallocation of bufA.
|
|
assertThat(c1.refCnt(), is(0));
|
|
assertThat(c2.refCnt(), is(1));
|
|
assertThat(c3.refCnt(), is(2));
|
|
|
|
c3.release(2);
|
|
c2.release();
|
|
}
|
|
|
|
@Test
|
|
public void testReferenceCounts3() {
|
|
ByteBuf c1 = buffer().writeByte(1);
|
|
ByteBuf c2 = buffer().writeByte(2).retain();
|
|
ByteBuf c3 = buffer().writeByte(3).retain(2);
|
|
|
|
CompositeByteBuf buf = compositeBuffer();
|
|
assertThat(buf.refCnt(), is(1));
|
|
|
|
List<ByteBuf> components = new ArrayList<>();
|
|
Collections.addAll(components, c1, c2, c3);
|
|
buf.addComponents(components);
|
|
|
|
// Ensure that c[123]'s refCount did not change.
|
|
assertThat(c1.refCnt(), is(1));
|
|
assertThat(c2.refCnt(), is(2));
|
|
assertThat(c3.refCnt(), is(3));
|
|
|
|
assertThat(buf.component(0).refCnt(), is(1));
|
|
assertThat(buf.component(1).refCnt(), is(2));
|
|
assertThat(buf.component(2).refCnt(), is(3));
|
|
|
|
c3.release(2);
|
|
c2.release();
|
|
buf.release();
|
|
}
|
|
|
|
@Test
|
|
public void testNestedLayout() {
|
|
CompositeByteBuf buf = compositeBuffer();
|
|
buf.addComponent(
|
|
compositeBuffer()
|
|
.addComponent(wrappedBuffer(new byte[]{1, 2}))
|
|
.addComponent(wrappedBuffer(new byte[]{3, 4})).slice(1, 2));
|
|
|
|
ByteBuffer[] nioBuffers = buf.nioBuffers(0, 2);
|
|
assertThat(nioBuffers.length, is(2));
|
|
assertThat(nioBuffers[0].remaining(), is(1));
|
|
assertThat(nioBuffers[0].get(), is((byte) 2));
|
|
assertThat(nioBuffers[1].remaining(), is(1));
|
|
assertThat(nioBuffers[1].get(), is((byte) 3));
|
|
|
|
buf.release();
|
|
}
|
|
|
|
@Test
|
|
public void testRemoveLastComponent() {
|
|
CompositeByteBuf buf = compositeBuffer();
|
|
buf.addComponent(wrappedBuffer(new byte[]{1, 2}));
|
|
assertEquals(1, buf.numComponents());
|
|
buf.removeComponent(0);
|
|
assertEquals(0, buf.numComponents());
|
|
buf.release();
|
|
}
|
|
|
|
@Test
|
|
public void testCopyEmpty() {
|
|
CompositeByteBuf buf = compositeBuffer();
|
|
assertEquals(0, buf.numComponents());
|
|
|
|
ByteBuf copy = buf.copy();
|
|
assertEquals(0, copy.readableBytes());
|
|
|
|
buf.release();
|
|
copy.release();
|
|
}
|
|
|
|
@Test
|
|
public void testDuplicateEmpty() {
|
|
CompositeByteBuf buf = compositeBuffer();
|
|
assertEquals(0, buf.numComponents());
|
|
assertEquals(0, buf.duplicate().readableBytes());
|
|
|
|
buf.release();
|
|
}
|
|
|
|
@Test
|
|
public void testRemoveLastComponentWithOthersLeft() {
|
|
CompositeByteBuf buf = compositeBuffer();
|
|
buf.addComponent(wrappedBuffer(new byte[]{1, 2}));
|
|
buf.addComponent(wrappedBuffer(new byte[]{1, 2}));
|
|
assertEquals(2, buf.numComponents());
|
|
buf.removeComponent(1);
|
|
assertEquals(1, buf.numComponents());
|
|
buf.release();
|
|
}
|
|
|
|
@Test
|
|
public void testRemoveComponents() {
|
|
CompositeByteBuf buf = compositeBuffer();
|
|
for (int i = 0; i < 10; i++) {
|
|
buf.addComponent(wrappedBuffer(new byte[]{1, 2}));
|
|
}
|
|
assertEquals(10, buf.numComponents());
|
|
assertEquals(20, buf.capacity());
|
|
buf.removeComponents(4, 3);
|
|
assertEquals(7, buf.numComponents());
|
|
assertEquals(14, buf.capacity());
|
|
buf.release();
|
|
}
|
|
|
|
@Test
|
|
public void testGatheringWritesHeap() throws Exception {
|
|
testGatheringWrites(buffer().order(order), buffer().order(order));
|
|
}
|
|
|
|
@Test
|
|
public void testGatheringWritesDirect() throws Exception {
|
|
testGatheringWrites(directBuffer().order(order), directBuffer().order(order));
|
|
}
|
|
|
|
@Test
|
|
public void testGatheringWritesMixes() throws Exception {
|
|
testGatheringWrites(buffer().order(order), directBuffer().order(order));
|
|
}
|
|
|
|
@Test
|
|
public void testGatheringWritesHeapPooled() throws Exception {
|
|
testGatheringWrites(PooledByteBufAllocator.DEFAULT.heapBuffer().order(order),
|
|
PooledByteBufAllocator.DEFAULT.heapBuffer().order(order));
|
|
}
|
|
|
|
@Test
|
|
public void testGatheringWritesDirectPooled() throws Exception {
|
|
testGatheringWrites(PooledByteBufAllocator.DEFAULT.directBuffer().order(order),
|
|
PooledByteBufAllocator.DEFAULT.directBuffer().order(order));
|
|
}
|
|
|
|
@Test
|
|
public void testGatheringWritesMixesPooled() throws Exception {
|
|
testGatheringWrites(PooledByteBufAllocator.DEFAULT.heapBuffer().order(order),
|
|
PooledByteBufAllocator.DEFAULT.directBuffer().order(order));
|
|
}
|
|
|
|
private static void testGatheringWrites(ByteBuf buf1, ByteBuf buf2) throws Exception {
|
|
CompositeByteBuf buf = compositeBuffer();
|
|
buf.addComponent(buf1.writeBytes(new byte[]{1, 2}));
|
|
buf.addComponent(buf2.writeBytes(new byte[]{1, 2}));
|
|
buf.writerIndex(3);
|
|
buf.readerIndex(1);
|
|
|
|
TestGatheringByteChannel channel = new TestGatheringByteChannel();
|
|
|
|
buf.readBytes(channel, 2);
|
|
|
|
byte[] data = new byte[2];
|
|
buf.getBytes(1, data);
|
|
assertArrayEquals(data, channel.writtenBytes());
|
|
|
|
buf.release();
|
|
}
|
|
|
|
@Test
|
|
public void testGatheringWritesPartialHeap() throws Exception {
|
|
testGatheringWritesPartial(buffer().order(order), buffer().order(order), false);
|
|
}
|
|
|
|
@Test
|
|
public void testGatheringWritesPartialDirect() throws Exception {
|
|
testGatheringWritesPartial(directBuffer().order(order), directBuffer().order(order), false);
|
|
}
|
|
|
|
@Test
|
|
public void testGatheringWritesPartialMixes() throws Exception {
|
|
testGatheringWritesPartial(buffer().order(order), directBuffer().order(order), false);
|
|
}
|
|
|
|
@Test
|
|
public void testGatheringWritesPartialHeapSlice() throws Exception {
|
|
testGatheringWritesPartial(buffer().order(order), buffer().order(order), true);
|
|
}
|
|
|
|
@Test
|
|
public void testGatheringWritesPartialDirectSlice() throws Exception {
|
|
testGatheringWritesPartial(directBuffer().order(order), directBuffer().order(order), true);
|
|
}
|
|
|
|
@Test
|
|
public void testGatheringWritesPartialMixesSlice() throws Exception {
|
|
testGatheringWritesPartial(buffer().order(order), directBuffer().order(order), true);
|
|
}
|
|
|
|
@Test
|
|
public void testGatheringWritesPartialHeapPooled() throws Exception {
|
|
testGatheringWritesPartial(PooledByteBufAllocator.DEFAULT.heapBuffer().order(order),
|
|
PooledByteBufAllocator.DEFAULT.heapBuffer().order(order), false);
|
|
}
|
|
|
|
@Test
|
|
public void testGatheringWritesPartialDirectPooled() throws Exception {
|
|
testGatheringWritesPartial(PooledByteBufAllocator.DEFAULT.directBuffer().order(order),
|
|
PooledByteBufAllocator.DEFAULT.directBuffer().order(order), false);
|
|
}
|
|
|
|
@Test
|
|
public void testGatheringWritesPartialMixesPooled() throws Exception {
|
|
testGatheringWritesPartial(PooledByteBufAllocator.DEFAULT.heapBuffer().order(order),
|
|
PooledByteBufAllocator.DEFAULT.directBuffer().order(order), false);
|
|
}
|
|
|
|
@Test
|
|
public void testGatheringWritesPartialHeapPooledSliced() throws Exception {
|
|
testGatheringWritesPartial(PooledByteBufAllocator.DEFAULT.heapBuffer().order(order),
|
|
PooledByteBufAllocator.DEFAULT.heapBuffer().order(order), true);
|
|
}
|
|
|
|
@Test
|
|
public void testGatheringWritesPartialDirectPooledSliced() throws Exception {
|
|
testGatheringWritesPartial(PooledByteBufAllocator.DEFAULT.directBuffer().order(order),
|
|
PooledByteBufAllocator.DEFAULT.directBuffer().order(order), true);
|
|
}
|
|
|
|
@Test
|
|
public void testGatheringWritesPartialMixesPooledSliced() throws Exception {
|
|
testGatheringWritesPartial(PooledByteBufAllocator.DEFAULT.heapBuffer().order(order),
|
|
PooledByteBufAllocator.DEFAULT.directBuffer().order(order), true);
|
|
}
|
|
|
|
private static void testGatheringWritesPartial(ByteBuf buf1, ByteBuf buf2, boolean slice) throws Exception {
|
|
CompositeByteBuf buf = compositeBuffer();
|
|
buf1.writeBytes(new byte[]{1, 2, 3, 4});
|
|
buf2.writeBytes(new byte[]{1, 2, 3, 4});
|
|
if (slice) {
|
|
buf1 = buf1.readerIndex(1).slice();
|
|
buf2 = buf2.writerIndex(3).slice();
|
|
buf.addComponent(buf1);
|
|
buf.addComponent(buf2);
|
|
buf.writerIndex(6);
|
|
} else {
|
|
buf.addComponent(buf1);
|
|
buf.addComponent(buf2);
|
|
buf.writerIndex(7);
|
|
buf.readerIndex(1);
|
|
}
|
|
|
|
TestGatheringByteChannel channel = new TestGatheringByteChannel(1);
|
|
|
|
while (buf.isReadable()) {
|
|
buf.readBytes(channel, buf.readableBytes());
|
|
}
|
|
|
|
byte[] data = new byte[6];
|
|
|
|
if (slice) {
|
|
buf.getBytes(0, data);
|
|
} else {
|
|
buf.getBytes(1, data);
|
|
}
|
|
assertArrayEquals(data, channel.writtenBytes());
|
|
|
|
buf.release();
|
|
}
|
|
|
|
@Test
|
|
public void testGatheringWritesSingleHeap() throws Exception {
|
|
testGatheringWritesSingleBuf(buffer().order(order));
|
|
}
|
|
|
|
@Test
|
|
public void testGatheringWritesSingleDirect() throws Exception {
|
|
testGatheringWritesSingleBuf(directBuffer().order(order));
|
|
}
|
|
|
|
private static void testGatheringWritesSingleBuf(ByteBuf buf1) throws Exception {
|
|
CompositeByteBuf buf = compositeBuffer();
|
|
buf.addComponent(buf1.writeBytes(new byte[]{1, 2, 3, 4}));
|
|
buf.writerIndex(3);
|
|
buf.readerIndex(1);
|
|
|
|
TestGatheringByteChannel channel = new TestGatheringByteChannel();
|
|
buf.readBytes(channel, 2);
|
|
|
|
byte[] data = new byte[2];
|
|
buf.getBytes(1, data);
|
|
assertArrayEquals(data, channel.writtenBytes());
|
|
|
|
buf.release();
|
|
}
|
|
|
|
@Override
|
|
@Test
|
|
public void testInternalNioBuffer() {
|
|
CompositeByteBuf buf = compositeBuffer();
|
|
assertEquals(0, buf.internalNioBuffer(0, 0).remaining());
|
|
|
|
// If non-derived buffer is added, its internal buffer should be returned
|
|
ByteBuf concreteBuffer = directBuffer().writeByte(1);
|
|
buf.addComponent(concreteBuffer);
|
|
assertSame(concreteBuffer.internalNioBuffer(0, 1), buf.internalNioBuffer(0, 1));
|
|
buf.release();
|
|
|
|
// In derived cases, the original internal buffer must not be used
|
|
buf = compositeBuffer();
|
|
concreteBuffer = directBuffer().writeByte(1);
|
|
buf.addComponent(concreteBuffer.slice());
|
|
assertNotSame(concreteBuffer.internalNioBuffer(0, 1), buf.internalNioBuffer(0, 1));
|
|
buf.release();
|
|
|
|
buf = compositeBuffer();
|
|
concreteBuffer = directBuffer().writeByte(1);
|
|
buf.addComponent(concreteBuffer.duplicate());
|
|
assertNotSame(concreteBuffer.internalNioBuffer(0, 1), buf.internalNioBuffer(0, 1));
|
|
buf.release();
|
|
}
|
|
|
|
@Test
|
|
public void testisDirectMultipleBufs() {
|
|
CompositeByteBuf buf = compositeBuffer();
|
|
assertFalse(buf.isDirect());
|
|
|
|
buf.addComponent(directBuffer().writeByte(1));
|
|
|
|
assertTrue(buf.isDirect());
|
|
buf.addComponent(directBuffer().writeByte(1));
|
|
assertTrue(buf.isDirect());
|
|
|
|
buf.addComponent(buffer().writeByte(1));
|
|
assertFalse(buf.isDirect());
|
|
|
|
buf.release();
|
|
}
|
|
|
|
// See https://github.com/netty/netty/issues/1976
|
|
@Test
|
|
public void testDiscardSomeReadBytes() {
|
|
CompositeByteBuf cbuf = compositeBuffer();
|
|
int len = 8 * 4;
|
|
for (int i = 0; i < len; i += 4) {
|
|
ByteBuf buf = buffer().writeInt(i);
|
|
cbuf.capacity(cbuf.writerIndex()).addComponent(buf).writerIndex(i + 4);
|
|
}
|
|
cbuf.writeByte(1);
|
|
|
|
byte[] me = new byte[len];
|
|
cbuf.readBytes(me);
|
|
cbuf.readByte();
|
|
|
|
cbuf.discardSomeReadBytes();
|
|
|
|
cbuf.release();
|
|
}
|
|
|
|
@Test
|
|
public void testAddEmptyBufferRelease() {
|
|
CompositeByteBuf cbuf = compositeBuffer();
|
|
ByteBuf buf = buffer();
|
|
assertEquals(1, buf.refCnt());
|
|
cbuf.addComponent(buf);
|
|
assertEquals(1, buf.refCnt());
|
|
|
|
cbuf.release();
|
|
assertEquals(0, buf.refCnt());
|
|
}
|
|
|
|
@Test
|
|
public void testAddEmptyBuffersRelease() {
|
|
CompositeByteBuf cbuf = compositeBuffer();
|
|
ByteBuf buf = buffer();
|
|
ByteBuf buf2 = buffer().writeInt(1);
|
|
ByteBuf buf3 = buffer();
|
|
|
|
assertEquals(1, buf.refCnt());
|
|
assertEquals(1, buf2.refCnt());
|
|
assertEquals(1, buf3.refCnt());
|
|
|
|
cbuf.addComponents(buf, buf2, buf3);
|
|
assertEquals(1, buf.refCnt());
|
|
assertEquals(1, buf2.refCnt());
|
|
assertEquals(1, buf3.refCnt());
|
|
|
|
cbuf.release();
|
|
assertEquals(0, buf.refCnt());
|
|
assertEquals(0, buf2.refCnt());
|
|
assertEquals(0, buf3.refCnt());
|
|
}
|
|
|
|
@Test
|
|
public void testAddEmptyBufferInMiddle() {
|
|
CompositeByteBuf cbuf = compositeBuffer();
|
|
ByteBuf buf1 = buffer().writeByte((byte) 1);
|
|
cbuf.addComponent(true, buf1);
|
|
cbuf.addComponent(true, EMPTY_BUFFER);
|
|
ByteBuf buf3 = buffer().writeByte((byte) 2);
|
|
cbuf.addComponent(true, buf3);
|
|
|
|
assertEquals(2, cbuf.readableBytes());
|
|
assertEquals((byte) 1, cbuf.readByte());
|
|
assertEquals((byte) 2, cbuf.readByte());
|
|
|
|
assertSame(EMPTY_BUFFER, cbuf.internalComponent(1));
|
|
assertNotSame(EMPTY_BUFFER, cbuf.internalComponentAtOffset(1));
|
|
cbuf.release();
|
|
}
|
|
|
|
@Test
|
|
public void testInsertEmptyBufferInMiddle() {
|
|
CompositeByteBuf cbuf = compositeBuffer();
|
|
ByteBuf buf1 = buffer().writeByte((byte) 1);
|
|
cbuf.addComponent(true, buf1);
|
|
ByteBuf buf2 = buffer().writeByte((byte) 2);
|
|
cbuf.addComponent(true, buf2);
|
|
|
|
// insert empty one between the first two
|
|
cbuf.addComponent(true, 1, EMPTY_BUFFER);
|
|
|
|
assertEquals(2, cbuf.readableBytes());
|
|
assertEquals((byte) 1, cbuf.readByte());
|
|
assertEquals((byte) 2, cbuf.readByte());
|
|
|
|
assertEquals(2, cbuf.capacity());
|
|
assertEquals(3, cbuf.numComponents());
|
|
|
|
byte[] dest = new byte[2];
|
|
// should skip over the empty one, not throw a java.lang.Error :)
|
|
cbuf.getBytes(0, dest);
|
|
|
|
assertArrayEquals(new byte[] {1, 2}, dest);
|
|
|
|
cbuf.release();
|
|
}
|
|
|
|
@Test
|
|
public void testAddFlattenedComponents() {
|
|
testAddFlattenedComponents(false);
|
|
}
|
|
|
|
@Test
|
|
public void testAddFlattenedComponentsWithWrappedComposite() {
|
|
testAddFlattenedComponents(true);
|
|
}
|
|
|
|
private void testAddFlattenedComponents(boolean addWrapped) {
|
|
ByteBuf b1 = Unpooled.wrappedBuffer(new byte[] { 1, 2, 3 });
|
|
CompositeByteBuf newComposite = newCompositeBuffer()
|
|
.addComponent(true, b1)
|
|
.addFlattenedComponents(true, b1.retain())
|
|
.addFlattenedComponents(true, Unpooled.EMPTY_BUFFER);
|
|
|
|
assertEquals(2, newComposite.numComponents());
|
|
assertEquals(6, newComposite.capacity());
|
|
assertEquals(6, newComposite.writerIndex());
|
|
|
|
// It is important to use a pooled allocator here to ensure
|
|
// the slices returned by readRetainedSlice are of type
|
|
// PooledSlicedByteBuf, which maintains an independent refcount
|
|
// (so that we can be sure to cover this case)
|
|
ByteBuf buffer = PooledByteBufAllocator.DEFAULT.buffer()
|
|
.writeBytes(new byte[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10});
|
|
|
|
// use mixture of slice and retained slice
|
|
ByteBuf s1 = buffer.readRetainedSlice(2);
|
|
ByteBuf s2 = s1.retainedSlice(0, 2);
|
|
ByteBuf s3 = buffer.slice(0, 2).retain();
|
|
ByteBuf s4 = s2.retainedSlice(0, 2);
|
|
buffer.release();
|
|
|
|
CompositeByteBuf compositeToAdd = compositeBuffer()
|
|
.addComponent(s1)
|
|
.addComponent(Unpooled.EMPTY_BUFFER)
|
|
.addComponents(s2, s3, s4);
|
|
// set readable range to be from middle of first component
|
|
// to middle of penultimate component
|
|
compositeToAdd.setIndex(1, 5);
|
|
|
|
assertEquals(1, compositeToAdd.refCnt());
|
|
assertEquals(1, s4.refCnt());
|
|
|
|
ByteBuf compositeCopy = compositeToAdd.copy();
|
|
|
|
if (addWrapped) {
|
|
compositeToAdd = new WrappedCompositeByteBuf(compositeToAdd);
|
|
}
|
|
newComposite.addFlattenedComponents(true, compositeToAdd);
|
|
|
|
// verify that added range matches
|
|
ByteBufUtil.equals(compositeCopy, 0,
|
|
newComposite, 6, compositeCopy.readableBytes());
|
|
|
|
// should not include empty component or last component
|
|
// (latter outside of the readable range)
|
|
assertEquals(5, newComposite.numComponents());
|
|
assertEquals(10, newComposite.capacity());
|
|
assertEquals(10, newComposite.writerIndex());
|
|
|
|
assertEquals(0, compositeToAdd.refCnt());
|
|
// s4 wasn't in added range so should have been jettisoned
|
|
assertEquals(0, s4.refCnt());
|
|
assertEquals(1, newComposite.refCnt());
|
|
|
|
// releasing composite should release the remaining components
|
|
newComposite.release();
|
|
assertEquals(0, newComposite.refCnt());
|
|
assertEquals(0, s1.refCnt());
|
|
assertEquals(0, s2.refCnt());
|
|
assertEquals(0, s3.refCnt());
|
|
assertEquals(0, b1.refCnt());
|
|
}
|
|
|
|
@Test
|
|
public void testIterator() {
|
|
CompositeByteBuf cbuf = newCompositeBuffer();
|
|
cbuf.addComponent(EMPTY_BUFFER);
|
|
cbuf.addComponent(EMPTY_BUFFER);
|
|
|
|
Iterator<ByteBuf> it = cbuf.iterator();
|
|
assertTrue(it.hasNext());
|
|
assertSame(EMPTY_BUFFER, it.next());
|
|
assertTrue(it.hasNext());
|
|
assertSame(EMPTY_BUFFER, it.next());
|
|
assertFalse(it.hasNext());
|
|
|
|
try {
|
|
it.next();
|
|
fail();
|
|
} catch (NoSuchElementException e) {
|
|
//Expected
|
|
}
|
|
cbuf.release();
|
|
}
|
|
|
|
@Test
|
|
public void testEmptyIterator() {
|
|
CompositeByteBuf cbuf = newCompositeBuffer();
|
|
|
|
Iterator<ByteBuf> it = cbuf.iterator();
|
|
assertFalse(it.hasNext());
|
|
|
|
try {
|
|
it.next();
|
|
fail();
|
|
} catch (NoSuchElementException e) {
|
|
//Expected
|
|
}
|
|
cbuf.release();
|
|
}
|
|
|
|
@Test
|
|
public void testIteratorConcurrentModificationAdd() {
|
|
CompositeByteBuf cbuf = newCompositeBuffer();
|
|
cbuf.addComponent(EMPTY_BUFFER);
|
|
|
|
Iterator<ByteBuf> it = cbuf.iterator();
|
|
cbuf.addComponent(EMPTY_BUFFER);
|
|
|
|
assertTrue(it.hasNext());
|
|
try {
|
|
assertThrows(ConcurrentModificationException.class, it::next);
|
|
} finally {
|
|
cbuf.release();
|
|
}
|
|
}
|
|
|
|
@Test
|
|
public void testIteratorConcurrentModificationRemove() {
|
|
CompositeByteBuf cbuf = newCompositeBuffer();
|
|
cbuf.addComponent(EMPTY_BUFFER);
|
|
|
|
Iterator<ByteBuf> it = cbuf.iterator();
|
|
cbuf.removeComponent(0);
|
|
|
|
assertTrue(it.hasNext());
|
|
try {
|
|
assertThrows(ConcurrentModificationException.class, it::next);
|
|
} finally {
|
|
cbuf.release();
|
|
}
|
|
}
|
|
|
|
@Test
|
|
public void testReleasesItsComponents() {
|
|
ByteBuf buffer = PooledByteBufAllocator.DEFAULT.buffer(); // 1
|
|
|
|
buffer.writeBytes(new byte[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10});
|
|
|
|
ByteBuf s1 = buffer.readSlice(2).retain(); // 2
|
|
ByteBuf s2 = s1.readSlice(2).retain(); // 3
|
|
ByteBuf s3 = s2.readSlice(2).retain(); // 4
|
|
ByteBuf s4 = s3.readSlice(2).retain(); // 5
|
|
|
|
ByteBuf composite = PooledByteBufAllocator.DEFAULT.compositeBuffer()
|
|
.addComponent(s1)
|
|
.addComponents(s2, s3, s4)
|
|
.order(ByteOrder.LITTLE_ENDIAN);
|
|
|
|
assertEquals(1, composite.refCnt());
|
|
assertEquals(5, buffer.refCnt());
|
|
|
|
// releasing composite should release the 4 components
|
|
ReferenceCountUtil.release(composite);
|
|
assertEquals(0, composite.refCnt());
|
|
assertEquals(1, buffer.refCnt());
|
|
|
|
// last remaining ref to buffer
|
|
ReferenceCountUtil.release(buffer);
|
|
assertEquals(0, buffer.refCnt());
|
|
}
|
|
|
|
@Test
|
|
public void testReleasesItsComponents2() {
|
|
// It is important to use a pooled allocator here to ensure
|
|
// the slices returned by readRetainedSlice are of type
|
|
// PooledSlicedByteBuf, which maintains an independent refcount
|
|
// (so that we can be sure to cover this case)
|
|
ByteBuf buffer = PooledByteBufAllocator.DEFAULT.buffer(); // 1
|
|
|
|
buffer.writeBytes(new byte[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10});
|
|
|
|
// use readRetainedSlice this time - produces different kind of slices
|
|
ByteBuf s1 = buffer.readRetainedSlice(2); // 2
|
|
ByteBuf s2 = s1.readRetainedSlice(2); // 3
|
|
ByteBuf s3 = s2.readRetainedSlice(2); // 4
|
|
ByteBuf s4 = s3.readRetainedSlice(2); // 5
|
|
|
|
ByteBuf composite = newCompositeBuffer()
|
|
.addComponent(s1)
|
|
.addComponents(s2, s3, s4)
|
|
.order(ByteOrder.LITTLE_ENDIAN);
|
|
|
|
assertEquals(1, composite.refCnt());
|
|
assertEquals(2, buffer.refCnt());
|
|
|
|
// releasing composite should release the 4 components
|
|
composite.release();
|
|
assertEquals(0, composite.refCnt());
|
|
assertEquals(1, buffer.refCnt());
|
|
|
|
// last remaining ref to buffer
|
|
buffer.release();
|
|
assertEquals(0, buffer.refCnt());
|
|
}
|
|
|
|
@Test
|
|
public void testReleasesOnShrink() {
|
|
|
|
ByteBuf b1 = Unpooled.buffer(2).writeShort(1);
|
|
ByteBuf b2 = Unpooled.buffer(2).writeShort(2);
|
|
|
|
// composite takes ownership of s1 and s2
|
|
ByteBuf composite = newCompositeBuffer()
|
|
.addComponents(b1, b2);
|
|
|
|
assertEquals(4, composite.capacity());
|
|
|
|
// reduce capacity down to two, will drop the second component
|
|
composite.capacity(2);
|
|
assertEquals(2, composite.capacity());
|
|
|
|
// releasing composite should release the components
|
|
composite.release();
|
|
assertEquals(0, composite.refCnt());
|
|
assertEquals(0, b1.refCnt());
|
|
assertEquals(0, b2.refCnt());
|
|
}
|
|
|
|
@Test
|
|
public void testReleasesOnShrink2() {
|
|
// It is important to use a pooled allocator here to ensure
|
|
// the slices returned by readRetainedSlice are of type
|
|
// PooledSlicedByteBuf, which maintains an independent refcount
|
|
// (so that we can be sure to cover this case)
|
|
ByteBuf buffer = PooledByteBufAllocator.DEFAULT.buffer();
|
|
|
|
buffer.writeShort(1).writeShort(2);
|
|
|
|
ByteBuf b1 = buffer.readRetainedSlice(2);
|
|
ByteBuf b2 = b1.retainedSlice(b1.readerIndex(), 2);
|
|
|
|
// composite takes ownership of b1 and b2
|
|
ByteBuf composite = newCompositeBuffer()
|
|
.addComponents(b1, b2);
|
|
|
|
assertEquals(4, composite.capacity());
|
|
|
|
// reduce capacity down to two, will drop the second component
|
|
composite.capacity(2);
|
|
assertEquals(2, composite.capacity());
|
|
|
|
// releasing composite should release the components
|
|
composite.release();
|
|
assertEquals(0, composite.refCnt());
|
|
assertEquals(0, b1.refCnt());
|
|
assertEquals(0, b2.refCnt());
|
|
|
|
// release last remaining ref to buffer
|
|
buffer.release();
|
|
assertEquals(0, buffer.refCnt());
|
|
}
|
|
|
|
@Test
|
|
public void testAllocatorIsSameWhenCopy() {
|
|
testAllocatorIsSameWhenCopy(false);
|
|
}
|
|
|
|
@Test
|
|
public void testAllocatorIsSameWhenCopyUsingIndexAndLength() {
|
|
testAllocatorIsSameWhenCopy(true);
|
|
}
|
|
|
|
private void testAllocatorIsSameWhenCopy(boolean withIndexAndLength) {
|
|
ByteBuf buffer = newBuffer(8);
|
|
buffer.writeZero(4);
|
|
ByteBuf copy = withIndexAndLength ? buffer.copy(0, 4) : buffer.copy();
|
|
assertEquals(buffer, copy);
|
|
assertEquals(buffer.isDirect(), copy.isDirect());
|
|
assertSame(buffer.alloc(), copy.alloc());
|
|
buffer.release();
|
|
copy.release();
|
|
}
|
|
|
|
@Test
|
|
public void testDecomposeMultiple() {
|
|
testDecompose(150, 500, 3);
|
|
}
|
|
|
|
@Test
|
|
public void testDecomposeOne() {
|
|
testDecompose(310, 50, 1);
|
|
}
|
|
|
|
@Test
|
|
public void testDecomposeNone() {
|
|
testDecompose(310, 0, 0);
|
|
}
|
|
|
|
private void testDecompose(int offset, int length, int expectedListSize) {
|
|
byte[] bytes = new byte[1024];
|
|
ThreadLocalRandom.current().nextBytes(bytes);
|
|
ByteBuf buf = wrappedBuffer(bytes);
|
|
|
|
CompositeByteBuf composite = newCompositeBuffer();
|
|
composite.addComponents(true,
|
|
buf.retainedSlice(100, 200),
|
|
buf.retainedSlice(300, 400),
|
|
buf.retainedSlice(700, 100));
|
|
|
|
ByteBuf slice = composite.slice(offset, length);
|
|
List<ByteBuf> bufferList = composite.decompose(offset, length);
|
|
assertEquals(expectedListSize, bufferList.size());
|
|
ByteBuf wrapped = wrappedBuffer(bufferList.toArray(new ByteBuf[0]));
|
|
|
|
assertEquals(slice, wrapped);
|
|
composite.release();
|
|
buf.release();
|
|
|
|
for (ByteBuf buffer: bufferList) {
|
|
assertEquals(0, buffer.refCnt());
|
|
}
|
|
}
|
|
|
|
@Test
|
|
public void testComponentsLessThanLowerBound() {
|
|
try {
|
|
new CompositeByteBuf(ALLOC, true, 0);
|
|
fail();
|
|
} catch (IllegalArgumentException e) {
|
|
assertEquals("maxNumComponents: 0 (expected: >= 1)", e.getMessage());
|
|
}
|
|
}
|
|
|
|
@Test
|
|
public void testComponentsEqualToLowerBound() {
|
|
assertCompositeBufCreated(1);
|
|
}
|
|
|
|
@Test
|
|
public void testComponentsGreaterThanLowerBound() {
|
|
assertCompositeBufCreated(5);
|
|
}
|
|
|
|
/**
|
|
* Assert that a new {@linkplain CompositeByteBuf} was created successfully with the desired number of max
|
|
* components.
|
|
*/
|
|
private static void assertCompositeBufCreated(int expectedMaxComponents) {
|
|
CompositeByteBuf buf = new CompositeByteBuf(ALLOC, true, expectedMaxComponents);
|
|
|
|
assertEquals(expectedMaxComponents, buf.maxNumComponents());
|
|
assertTrue(buf.release());
|
|
}
|
|
|
|
@Test
|
|
public void testDiscardSomeReadBytesCorrectlyUpdatesLastAccessed() {
|
|
testDiscardCorrectlyUpdatesLastAccessed(true);
|
|
}
|
|
|
|
@Test
|
|
public void testDiscardReadBytesCorrectlyUpdatesLastAccessed() {
|
|
testDiscardCorrectlyUpdatesLastAccessed(false);
|
|
}
|
|
|
|
private void testDiscardCorrectlyUpdatesLastAccessed(boolean discardSome) {
|
|
CompositeByteBuf cbuf = newCompositeBuffer();
|
|
List<ByteBuf> buffers = new ArrayList<ByteBuf>(4);
|
|
for (int i = 0; i < 4; i++) {
|
|
ByteBuf buf = buffer().writeInt(i);
|
|
cbuf.addComponent(true, buf);
|
|
buffers.add(buf);
|
|
}
|
|
|
|
// Skip the first 2 bytes which means even if we call discard*ReadBytes() later we can no drop the first
|
|
// component as it is still used.
|
|
cbuf.skipBytes(2);
|
|
if (discardSome) {
|
|
cbuf.discardSomeReadBytes();
|
|
} else {
|
|
cbuf.discardReadBytes();
|
|
}
|
|
assertEquals(4, cbuf.numComponents());
|
|
|
|
// Now skip 3 bytes which means we should be able to drop the first component on the next discard*ReadBytes()
|
|
// call.
|
|
cbuf.skipBytes(3);
|
|
|
|
if (discardSome) {
|
|
cbuf.discardSomeReadBytes();
|
|
} else {
|
|
cbuf.discardReadBytes();
|
|
}
|
|
assertEquals(3, cbuf.numComponents());
|
|
// Now skip again 3 bytes which should bring our readerIndex == start of the 3 component.
|
|
cbuf.skipBytes(3);
|
|
|
|
// Read one int (4 bytes) which should bring our readerIndex == start of the 4 component.
|
|
assertEquals(2, cbuf.readInt());
|
|
if (discardSome) {
|
|
cbuf.discardSomeReadBytes();
|
|
} else {
|
|
cbuf.discardReadBytes();
|
|
}
|
|
|
|
// Now all except the last component should have been dropped / released.
|
|
assertEquals(1, cbuf.numComponents());
|
|
assertEquals(3, cbuf.readInt());
|
|
if (discardSome) {
|
|
cbuf.discardSomeReadBytes();
|
|
} else {
|
|
cbuf.discardReadBytes();
|
|
}
|
|
assertEquals(0, cbuf.numComponents());
|
|
|
|
// These should have been released already.
|
|
for (ByteBuf buffer: buffers) {
|
|
assertEquals(0, buffer.refCnt());
|
|
}
|
|
assertTrue(cbuf.release());
|
|
}
|
|
|
|
// See https://github.com/netty/netty/issues/11612
|
|
@Test
|
|
public void testAddComponentWithNullEntry() {
|
|
final ByteBuf buffer = Unpooled.buffer(8).writeZero(8);
|
|
final CompositeByteBuf compositeByteBuf = compositeBuffer(Integer.MAX_VALUE);
|
|
try {
|
|
compositeByteBuf.addComponents(true, new ByteBuf[] { buffer, null });
|
|
assertEquals(8, compositeByteBuf.readableBytes());
|
|
assertEquals(1, compositeByteBuf.numComponents());
|
|
} finally {
|
|
compositeByteBuf.release();
|
|
}
|
|
}
|
|
|
|
@Test
|
|
public void testOverflowWhileAddingComponent() {
|
|
int capacity = 1024 * 1024; // 1MB
|
|
ByteBuf buffer = Unpooled.buffer(capacity).writeZero(capacity);
|
|
CompositeByteBuf compositeByteBuf = compositeBuffer(Integer.MAX_VALUE);
|
|
|
|
try {
|
|
assertThrows(IllegalArgumentException.class, () -> {
|
|
for (int i = 0; i >= 0; i += buffer.readableBytes()) {
|
|
ByteBuf duplicate = buffer.duplicate();
|
|
compositeByteBuf.addComponent(duplicate);
|
|
duplicate.retain();
|
|
}
|
|
});
|
|
} finally {
|
|
compositeByteBuf.release();
|
|
}
|
|
}
|
|
|
|
@Test
|
|
public void testOverflowWhileAddingComponentsViaVarargs() {
|
|
int capacity = 1024 * 1024; // 1MB
|
|
ByteBuf buffer = Unpooled.buffer(capacity).writeZero(capacity);
|
|
CompositeByteBuf compositeByteBuf = compositeBuffer(Integer.MAX_VALUE);
|
|
|
|
try {
|
|
assertThrows(IllegalArgumentException.class, () -> {
|
|
for (int i = 0; i >= 0; i += buffer.readableBytes()) {
|
|
ByteBuf duplicate = buffer.duplicate();
|
|
compositeByteBuf.addComponents(duplicate);
|
|
duplicate.retain();
|
|
}
|
|
});
|
|
} finally {
|
|
compositeByteBuf.release();
|
|
}
|
|
}
|
|
|
|
@Test
|
|
public void testOverflowWhileAddingComponentsViaIterable() {
|
|
int capacity = 1024 * 1024; // 1MB
|
|
ByteBuf buffer = Unpooled.buffer(capacity).writeZero(capacity);
|
|
CompositeByteBuf compositeByteBuf = compositeBuffer(Integer.MAX_VALUE);
|
|
|
|
try {
|
|
assertThrows(IllegalArgumentException.class, () -> {
|
|
for (int i = 0; i >= 0; i += buffer.readableBytes()) {
|
|
ByteBuf duplicate = buffer.duplicate();
|
|
compositeByteBuf.addComponents(Collections.singletonList(duplicate));
|
|
duplicate.retain();
|
|
}
|
|
});
|
|
} finally {
|
|
compositeByteBuf.release();
|
|
}
|
|
}
|
|
|
|
@Test
|
|
public void testOverflowWhileUseConstructorWithOffset() {
|
|
int capacity = 1024 * 1024; // 1MB
|
|
final ByteBuf buffer = Unpooled.buffer(capacity).writeZero(capacity);
|
|
final List<ByteBuf> buffers = new ArrayList<ByteBuf>();
|
|
for (long i = 0; i <= Integer.MAX_VALUE; i += capacity) {
|
|
buffers.add(buffer.duplicate());
|
|
}
|
|
// Add one more
|
|
buffers.add(buffer.duplicate());
|
|
|
|
try {
|
|
assertThrows(IllegalArgumentException.class, () -> {
|
|
ByteBuf[] bufferArray = buffers.toArray(new ByteBuf[0]);
|
|
new CompositeByteBuf(ALLOC, false, Integer.MAX_VALUE, bufferArray, 0);
|
|
});
|
|
} finally {
|
|
buffer.release();
|
|
}
|
|
}
|
|
|
|
@Test
|
|
public void testNotOverflowWhileUseConstructorWithOffset() {
|
|
int capacity = 1024 * 1024; // 1MB
|
|
final ByteBuf buffer = Unpooled.buffer(capacity).writeZero(capacity);
|
|
final List<ByteBuf> buffers = new ArrayList<ByteBuf>();
|
|
for (long i = 0; i <= Integer.MAX_VALUE; i += capacity) {
|
|
buffers.add(buffer.duplicate());
|
|
}
|
|
// Add one more
|
|
buffers.add(buffer.duplicate());
|
|
|
|
ByteBuf[] bufferArray = buffers.toArray(new ByteBuf[0]);
|
|
CompositeByteBuf compositeByteBuf =
|
|
new CompositeByteBuf(ALLOC, false, Integer.MAX_VALUE, bufferArray, bufferArray.length - 1);
|
|
compositeByteBuf.release();
|
|
}
|
|
|
|
@Test
|
|
public void sliceOfCompositeBufferMustThrowISEAfterDiscardBytes() {
|
|
CompositeByteBuf composite = compositeBuffer();
|
|
composite.addComponent(true, buffer(8).writeZero(8));
|
|
|
|
ByteBuf slice = composite.retainedSlice();
|
|
composite.skipBytes(slice.readableBytes());
|
|
composite.discardSomeReadBytes();
|
|
|
|
try {
|
|
slice.readByte();
|
|
fail("Expected readByte of discarded slice to throw.");
|
|
} catch (IllegalStateException ignore) {
|
|
// Good.
|
|
} finally {
|
|
slice.release();
|
|
composite.release();
|
|
}
|
|
}
|
|
}
|