Fixed issue: NETTY-33 (CompositeChannelBuffer.copy() does not respect the byte order.)

* More test cases..
This commit is contained in:
Trustin Lee 2008-08-26 15:37:08 +00:00
parent 6f34eca0b6
commit a7c181072e
11 changed files with 294 additions and 10 deletions

View File

@ -296,6 +296,9 @@ public class ByteBufferBackedChannelBuffer extends AbstractChannelBuffer {
if (index == 0 && length == capacity()) { if (index == 0 && length == capacity()) {
return duplicate(); return duplicate();
} else { } else {
if (index >= 0 && length == 0) {
return ChannelBuffers.EMPTY_BUFFER;
}
return new ByteBufferBackedChannelBuffer( return new ByteBufferBackedChannelBuffer(
((ByteBuffer) buffer.duplicate().position(index).limit(index + length))); ((ByteBuffer) buffer.duplicate().position(index).limit(index + length)));
} }

View File

@ -620,10 +620,18 @@ public class ChannelBuffers {
int hashCode = 1; int hashCode = 1;
int arrayIndex = buffer.readerIndex(); int arrayIndex = buffer.readerIndex();
if (buffer.order() == BIG_ENDIAN) {
for (int i = intCount; i > 0; i --) { for (int i = intCount; i > 0; i --) {
hashCode = 31 * hashCode + buffer.getInt(arrayIndex); hashCode = 31 * hashCode + buffer.getInt(arrayIndex);
arrayIndex += 4; arrayIndex += 4;
} }
} else {
for (int i = intCount; i > 0; i --) {
hashCode = 31 * hashCode + swapInt(buffer.getInt(arrayIndex));
arrayIndex += 4;
}
}
for (int i = byteCount; i > 0; i --) { for (int i = byteCount; i > 0; i --) {
hashCode = 31 * hashCode + buffer.getByte(arrayIndex ++); hashCode = 31 * hashCode + buffer.getByte(arrayIndex ++);
} }
@ -631,6 +639,7 @@ public class ChannelBuffers {
if (hashCode == 0) { if (hashCode == 0) {
hashCode = 1; hashCode = 1;
} }
return hashCode; return hashCode;
} }

View File

@ -423,7 +423,7 @@ public class CompositeChannelBuffer extends AbstractChannelBuffer {
throw new IndexOutOfBoundsException(); throw new IndexOutOfBoundsException();
} }
ChannelBuffer dst = ChannelBuffers.buffer(length); ChannelBuffer dst = ChannelBuffers.buffer(order(), length);
int dstIndex = 0; int dstIndex = 0;
int i = sliceId; int i = sliceId;
@ -443,6 +443,9 @@ public class CompositeChannelBuffer extends AbstractChannelBuffer {
} }
public ChannelBuffer slice(int index, int length) { public ChannelBuffer slice(int index, int length) {
if (length == 0) {
return ChannelBuffers.EMPTY_BUFFER;
}
return new SlicedChannelBuffer(this, index, length); return new SlicedChannelBuffer(this, index, length);
} }

View File

@ -214,8 +214,10 @@ public class DynamicChannelBuffer extends AbstractChannelBuffer {
public ChannelBuffer copy(int index, int length) { public ChannelBuffer copy(int index, int length) {
DynamicChannelBuffer copiedBuffer = new DynamicChannelBuffer(endianness, Math.max(length, 64)); DynamicChannelBuffer copiedBuffer = new DynamicChannelBuffer(endianness, Math.max(length, 64));
copiedBuffer.buffer = buffer.copy(); if (readable()) {
if (copiedBuffer.buffer.capacity() == 0) { copiedBuffer.buffer = buffer.copy(readerIndex(), readableBytes());
copiedBuffer.setIndex(0, readableBytes());
} else {
copiedBuffer.buffer = ChannelBuffers.EMPTY_BUFFER; copiedBuffer.buffer = ChannelBuffers.EMPTY_BUFFER;
} }
return copiedBuffer; return copiedBuffer;
@ -223,8 +225,14 @@ public class DynamicChannelBuffer extends AbstractChannelBuffer {
public ChannelBuffer slice(int index, int length) { public ChannelBuffer slice(int index, int length) {
if (index == 0) { if (index == 0) {
if (length == 0) {
return ChannelBuffers.EMPTY_BUFFER;
}
return new TruncatedChannelBuffer(this, length); return new TruncatedChannelBuffer(this, length);
} else { } else {
if (length == 0) {
return ChannelBuffers.EMPTY_BUFFER;
}
return new SlicedChannelBuffer(this, index, length); return new SlicedChannelBuffer(this, index, length);
} }
} }

View File

@ -155,12 +155,18 @@ public abstract class HeapChannelBuffer extends AbstractChannelBuffer {
public ChannelBuffer slice(int index, int length) { public ChannelBuffer slice(int index, int length) {
if (index == 0) { if (index == 0) {
if (length == 0) {
return ChannelBuffers.EMPTY_BUFFER;
}
if (length == array.length) { if (length == array.length) {
return duplicate(); return duplicate();
} else { } else {
return new TruncatedChannelBuffer(this, length); return new TruncatedChannelBuffer(this, length);
} }
} else { } else {
if (length == 0) {
return ChannelBuffers.EMPTY_BUFFER;
}
return new SlicedChannelBuffer(this, index, length); return new SlicedChannelBuffer(this, index, length);
} }
} }

View File

@ -110,6 +110,9 @@ public class SlicedChannelBuffer extends AbstractChannelBuffer implements Wrappe
public ChannelBuffer slice(int index, int length) { public ChannelBuffer slice(int index, int length) {
checkIndex(index, length); checkIndex(index, length);
if (length == 0) {
return ChannelBuffers.EMPTY_BUFFER;
}
return new SlicedChannelBuffer(buffer, index + adjustment, length); return new SlicedChannelBuffer(buffer, index + adjustment, length);
} }

View File

@ -104,6 +104,9 @@ public class TruncatedChannelBuffer extends AbstractChannelBuffer implements Wra
public ChannelBuffer slice(int index, int length) { public ChannelBuffer slice(int index, int length) {
checkIndex(index, length); checkIndex(index, length);
if (length == 0) {
return ChannelBuffers.EMPTY_BUFFER;
}
return buffer.slice(index, length); return buffer.slice(index, length);
} }

View File

@ -30,7 +30,10 @@ import java.io.ByteArrayOutputStream;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.charset.UnsupportedCharsetException; import java.nio.charset.UnsupportedCharsetException;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashSet;
import java.util.NoSuchElementException;
import java.util.Random; import java.util.Random;
import java.util.Set;
import org.junit.After; import org.junit.After;
import org.junit.Before; import org.junit.Before;
@ -38,7 +41,7 @@ import org.junit.Test;
public abstract class AbstractChannelBufferTest { public abstract class AbstractChannelBufferTest {
private static final int CAPACITY = 4096; private static final int CAPACITY = 4096; // Must be even
private static final int BLOCK_SIZE = 128; private static final int BLOCK_SIZE = 128;
private long seed; private long seed;
@ -1071,7 +1074,7 @@ public abstract class AbstractChannelBufferTest {
} }
@Test @Test
public void testSequentialCopiedBufferTransfer() { public void testSequentialCopiedBufferTransfer1() {
buffer.writerIndex(0); buffer.writerIndex(0);
for (int i = 0; i < buffer.capacity() - BLOCK_SIZE + 1; i += BLOCK_SIZE) { for (int i = 0; i < buffer.capacity() - BLOCK_SIZE + 1; i += BLOCK_SIZE) {
byte[] value = new byte[BLOCK_SIZE]; byte[] value = new byte[BLOCK_SIZE];
@ -1097,7 +1100,31 @@ public abstract class AbstractChannelBufferTest {
} }
@Test @Test
public void testSequentialSlice() { public void testSequentialCopiedBufferTransfer2() {
buffer.clear();
buffer.writeZero(buffer.capacity());
try {
buffer.readBytes(ChannelBufferIndexFinder.CR);
fail();
} catch (NoSuchElementException e) {
// Expected
}
assertSame(EMPTY_BUFFER, buffer.readBytes(ChannelBufferIndexFinder.NUL));
buffer.clear();
buffer.writeBytes(new byte[] { 1, 2, 3, 4, 0 });
ChannelBuffer copy = buffer.readBytes(ChannelBufferIndexFinder.NUL);
assertEquals(wrappedBuffer(new byte[] { 1, 2, 3, 4 }), copy);
// Make sure if it's a copied buffer.
copy.setByte(0, (byte) (copy.getByte(0) + 1));
assertFalse(buffer.getByte(0) == copy.getByte(0));
}
@Test
public void testSequentialSlice1() {
buffer.writerIndex(0); buffer.writerIndex(0);
for (int i = 0; i < buffer.capacity() - BLOCK_SIZE + 1; i += BLOCK_SIZE) { for (int i = 0; i < buffer.capacity() - BLOCK_SIZE + 1; i += BLOCK_SIZE) {
byte[] value = new byte[BLOCK_SIZE]; byte[] value = new byte[BLOCK_SIZE];
@ -1122,8 +1149,39 @@ public abstract class AbstractChannelBufferTest {
} }
} }
@Test
public void testSequentialSlice2() {
buffer.clear();
buffer.writeZero(buffer.capacity());
try {
buffer.readSlice(ChannelBufferIndexFinder.CR);
fail();
} catch (NoSuchElementException e) {
// Expected
}
assertSame(EMPTY_BUFFER, buffer.readSlice(ChannelBufferIndexFinder.NUL));
buffer.clear();
buffer.writeBytes(new byte[] { 1, 2, 3, 4, 0 });
ChannelBuffer slice = buffer.readSlice(ChannelBufferIndexFinder.NUL);
assertEquals(wrappedBuffer(new byte[] { 1, 2, 3, 4 }), slice);
// Make sure if it's a sliced buffer.
slice.setByte(0, (byte) (slice.getByte(0) + 1));
assertTrue(buffer.getByte(0) == slice.getByte(0));
}
@Test @Test
public void testWriteZero() { public void testWriteZero() {
try {
buffer.writeZero(-1);
fail();
} catch (IllegalArgumentException e) {
// Expected
}
buffer.clear(); buffer.clear();
while (buffer.writable()) { while (buffer.writable()) {
buffer.writeByte((byte) 0xFF); buffer.writeByte((byte) 0xFF);
@ -1433,4 +1491,72 @@ public abstract class AbstractChannelBufferTest {
assertEquals(ByteBuffer.wrap(value, i, BLOCK_SIZE), nioBuffer); assertEquals(ByteBuffer.wrap(value, i, BLOCK_SIZE), nioBuffer);
} }
} }
@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 testSkipBytes2() {
buffer.clear();
buffer.writeZero(buffer.capacity());
try {
buffer.skipBytes(ChannelBufferIndexFinder.LF);
fail();
} catch (NoSuchElementException e) {
// Expected
}
buffer.skipBytes(ChannelBufferIndexFinder.NUL);
assertEquals(0, buffer.readerIndex());
buffer.clear();
buffer.writeBytes(new byte[] { 1, 2, 3, 4, 0 });
buffer.skipBytes(ChannelBufferIndexFinder.NUL);
assertEquals(4, buffer.readerIndex());
}
@Test
public void testHashCode() {
ChannelBuffer elemA = buffer(15);
ChannelBuffer 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<ChannelBuffer> set = new HashSet<ChannelBuffer>();
set.add(elemA);
set.add(elemB);
assertEquals(2, set.size());
assertTrue(set.contains(elemA.copy()));
assertTrue(set.contains(elemB.copy()));
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());
}
} }

View File

@ -30,7 +30,7 @@ import java.util.List;
public class CompositeChannelBufferTest extends AbstractChannelBufferTest { public class BigEndianCompositeChannelBufferTest extends AbstractChannelBufferTest {
private List<ChannelBuffer> buffers; private List<ChannelBuffer> buffers;
private ChannelBuffer buffer; private ChannelBuffer buffer;

View File

@ -0,0 +1,56 @@
/*
* JBoss, Home of Professional Open Source
*
* Copyright 2008, Red Hat Middleware LLC, and individual contributors
* by the @author tags. See the COPYRIGHT.txt in the distribution for a
* full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jboss.netty.buffer;
import static org.junit.Assert.*;
public class DynamicChannelBufferTest extends AbstractChannelBufferTest {
private ChannelBuffer buffer;
@Override
protected ChannelBuffer newBuffer(int length) {
buffer = ChannelBuffers.dynamicBuffer(length);
// A dynamic buffer does lazy initialization.
assertEquals(0, buffer.capacity());
// Initialize.
buffer.writeZero(1);
buffer.clear();
// And validate the initial capacity
assertEquals(0, buffer.writerIndex());
assertEquals(length, buffer.capacity());
return buffer;
}
@Override
protected ChannelBuffer[] components() {
return new ChannelBuffer[] { buffer };
}
}

View File

@ -0,0 +1,67 @@
/*
* JBoss, Home of Professional Open Source
*
* Copyright 2008, Red Hat Middleware LLC, and individual contributors
* by the @author tags. See the COPYRIGHT.txt in the distribution for a
* full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jboss.netty.buffer;
import static org.junit.Assert.*;
import java.util.ArrayList;
import java.util.List;
public class LittleEndianCompositeChannelBufferTest extends AbstractChannelBufferTest {
private List<ChannelBuffer> buffers;
private ChannelBuffer buffer;
@Override
protected ChannelBuffer newBuffer(int length) {
buffers = new ArrayList<ChannelBuffer>();
for (int i = 0; i < length; i += 10) {
buffers.add(ChannelBuffers.wrappedBuffer(ChannelBuffers.LITTLE_ENDIAN, new byte[1]));
buffers.add(ChannelBuffers.wrappedBuffer(ChannelBuffers.LITTLE_ENDIAN, new byte[2]));
buffers.add(ChannelBuffers.wrappedBuffer(ChannelBuffers.LITTLE_ENDIAN, new byte[3]));
buffers.add(ChannelBuffers.wrappedBuffer(ChannelBuffers.LITTLE_ENDIAN, new byte[4]));
buffers.add(ChannelBuffers.wrappedBuffer(ChannelBuffers.LITTLE_ENDIAN, new byte[5]));
buffers.add(ChannelBuffers.wrappedBuffer(ChannelBuffers.LITTLE_ENDIAN, new byte[6]));
buffers.add(ChannelBuffers.wrappedBuffer(ChannelBuffers.LITTLE_ENDIAN, new byte[7]));
buffers.add(ChannelBuffers.wrappedBuffer(ChannelBuffers.LITTLE_ENDIAN, new byte[8]));
buffers.add(ChannelBuffers.wrappedBuffer(ChannelBuffers.LITTLE_ENDIAN, new byte[9]));
}
buffer = ChannelBuffers.wrappedBuffer(buffers.toArray(new ChannelBuffer[buffers.size()]));
buffer.writerIndex(length);
buffer = ChannelBuffers.wrappedBuffer(buffer);
assertEquals(length, buffer.capacity());
assertEquals(length, buffer.readableBytes());
assertFalse(buffer.writable());
buffer.writerIndex(0);
return buffer;
}
@Override
protected ChannelBuffer[] components() {
return buffers.toArray(new ChannelBuffer[buffers.size()]);
}
}