| /** |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF 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.cassandra.utils; |
| |
| import java.io.ByteArrayInputStream; |
| import java.io.DataInputStream; |
| import java.io.IOException; |
| import java.nio.ByteBuffer; |
| import java.nio.charset.CharacterCodingException; |
| import java.util.Arrays; |
| import java.util.concurrent.ThreadLocalRandom; |
| |
| import org.junit.Assert; |
| import org.junit.Test; |
| |
| import org.apache.cassandra.io.util.DataOutputBuffer; |
| |
| import static org.junit.Assert.assertArrayEquals; |
| import static org.junit.Assert.assertEquals; |
| |
| public class ByteBufferUtilTest |
| { |
| private static final String s = "cassandra"; |
| |
| private ByteBuffer fromStringWithPosition(String s, int pos, boolean direct) |
| { |
| int l = s.length(); |
| ByteBuffer bb; |
| if (direct) |
| { |
| bb = ByteBuffer.allocateDirect(l + pos); |
| } |
| else |
| { |
| ByteBuffer tmp = ByteBuffer.allocate(l + pos + 3); |
| tmp.position(3); |
| bb = tmp.slice(); // make bb have a non null arrayOffset |
| } |
| bb.position(pos); |
| bb.mark(); |
| bb.put(s.getBytes()); |
| bb.reset(); |
| assert bb.position() == pos; |
| return bb; |
| } |
| |
| @Test |
| public void testString() throws Exception |
| { |
| assert s.equals(ByteBufferUtil.string(ByteBufferUtil.bytes(s))); |
| |
| int pos = 10; |
| ByteBuffer bb = fromStringWithPosition(s, 10, false); |
| assert s.equals(ByteBufferUtil.string(bb, 10, s.length())); |
| |
| bb = fromStringWithPosition(s, 10, true); |
| assert s.equals(ByteBufferUtil.string(bb, 10, s.length())); |
| } |
| |
| @Test |
| public void testGetArray() |
| { |
| byte[] t = s.getBytes(); |
| |
| ByteBuffer bb = ByteBufferUtil.bytes(s); |
| assertArrayEquals(t, ByteBufferUtil.getArray(bb)); |
| |
| bb = fromStringWithPosition(s, 10, false); |
| assertArrayEquals(t, ByteBufferUtil.getArray(bb)); |
| |
| bb = fromStringWithPosition(s, 10, true); |
| assertArrayEquals(t, ByteBufferUtil.getArray(bb)); |
| } |
| |
| @Test |
| public void testLastIndexOf() |
| { |
| ByteBuffer bb = ByteBufferUtil.bytes(s); |
| checkLastIndexOf(bb); |
| |
| bb = fromStringWithPosition(s, 10, false); |
| checkLastIndexOf(bb); |
| |
| bb = fromStringWithPosition(s, 10, true); |
| checkLastIndexOf(bb); |
| } |
| |
| private void checkLastIndexOf(ByteBuffer bb) |
| { |
| assert bb.position() + 8 == ByteBufferUtil.lastIndexOf(bb, (byte) 'a', bb.position() + 8); |
| assert bb.position() + 4 == ByteBufferUtil.lastIndexOf(bb, (byte) 'a', bb.position() + 7); |
| assert bb.position() + 3 == ByteBufferUtil.lastIndexOf(bb, (byte) 's', bb.position() + 8); |
| assert -1 == ByteBufferUtil.lastIndexOf(bb, (byte) 'o', bb.position() + 8); |
| assert -1 == ByteBufferUtil.lastIndexOf(bb, (byte) 'd', bb.position() + 5); |
| } |
| |
| @Test |
| public void testClone() |
| { |
| ByteBuffer bb = ByteBufferUtil.bytes(s); |
| ByteBuffer clone1 = ByteBufferUtil.clone(bb); |
| assert bb != clone1; |
| assert bb.equals(clone1); |
| assert bb.array() != clone1.array(); |
| |
| bb = fromStringWithPosition(s, 10, false); |
| ByteBuffer clone2 = ByteBufferUtil.clone(bb); |
| assert bb != clone2; |
| assert bb.equals(clone2); |
| assert clone1.equals(clone2); |
| assert bb.array() != clone2.array(); |
| |
| bb = fromStringWithPosition(s, 10, true); |
| ByteBuffer clone3 = ByteBufferUtil.clone(bb); |
| assert bb != clone3; |
| assert bb.equals(clone3); |
| assert clone1.equals(clone3); |
| } |
| |
| @Test |
| public void testArrayCopy() |
| { |
| ByteBuffer bb = ByteBufferUtil.bytes(s); |
| checkArrayCopy(bb); |
| |
| bb = fromStringWithPosition(s, 10, false); |
| checkArrayCopy(bb); |
| |
| bb = fromStringWithPosition(s, 10, true); |
| checkArrayCopy(bb); |
| } |
| |
| private void checkArrayCopy(ByteBuffer bb) |
| { |
| |
| byte[] bytes = new byte[s.length()]; |
| ByteBufferUtil.arrayCopy(bb, bb.position(), bytes, 0, s.length()); |
| assertArrayEquals(s.getBytes(), bytes); |
| |
| bytes = new byte[5]; |
| ByteBufferUtil.arrayCopy(bb, bb.position() + 3, bytes, 1, 4); |
| assertArrayEquals(Arrays.copyOfRange(s.getBytes(), 3, 7), Arrays.copyOfRange(bytes, 1, 5)); |
| } |
| |
| @Test |
| public void testReadWrite() throws IOException |
| { |
| ByteBuffer bb = ByteBufferUtil.bytes(s); |
| checkReadWrite(bb); |
| |
| bb = fromStringWithPosition(s, 10, false); |
| checkReadWrite(bb); |
| |
| bb = fromStringWithPosition(s, 10, true); |
| checkReadWrite(bb); |
| } |
| |
| private void checkReadWrite(ByteBuffer bb) throws IOException |
| { |
| DataOutputBuffer out = new DataOutputBuffer(); |
| ByteBufferUtil.writeWithLength(bb, out); |
| ByteBufferUtil.writeWithShortLength(bb, out); |
| |
| DataInputStream in = new DataInputStream(new ByteArrayInputStream(out.toByteArray())); |
| assert bb.equals(ByteBufferUtil.readWithLength(in)); |
| assert bb.equals(ByteBufferUtil.readWithShortLength(in)); |
| } |
| |
| @Test |
| public void testInputStream() throws IOException |
| { |
| ByteBuffer bb = ByteBuffer.allocate(13); |
| bb.putInt(255); |
| bb.put((byte) -3); |
| bb.putLong(42L); |
| bb.clear(); |
| |
| DataInputStream in = new DataInputStream(ByteBufferUtil.inputStream(bb)); |
| assert in.readInt() == 255; |
| assert in.readByte() == (byte)-3; |
| assert in.readLong() == 42L; |
| } |
| |
| @Test |
| public void testIntBytesConversions() |
| { |
| // positive, negative, 1 and 2 byte cases, including a few edges that would foul things up unless you're careful |
| // about masking away sign extension. |
| int[] ints = new int[] |
| { |
| -20, -127, -128, 0, 1, 127, 128, 65534, 65535, -65534, -65535 |
| }; |
| |
| for (int i : ints) { |
| ByteBuffer ba = ByteBufferUtil.bytes(i); |
| int actual = ByteBufferUtil.toInt(ba); |
| assertEquals(i, actual); |
| } |
| } |
| |
| @Test(expected=CharacterCodingException.class) |
| public void testDecode() throws IOException |
| { |
| ByteBuffer bytes = ByteBuffer.wrap(new byte[]{(byte)0xff, (byte)0xfe}); |
| ByteBufferUtil.string(bytes); |
| } |
| |
| @Test |
| public void testHexBytesConversion() |
| { |
| for (int i = Byte.MIN_VALUE; i <= Byte.MAX_VALUE; i++) |
| { |
| ByteBuffer bb = ByteBuffer.allocate(1); |
| bb.put((byte) i); |
| bb.clear(); |
| String s = ByteBufferUtil.bytesToHex(bb); |
| ByteBuffer bb2 = ByteBufferUtil.hexToBytes(s); |
| assertEquals(bb, bb2); |
| } |
| // check that non-zero buffer positions work, |
| // i.e. that conversion accounts for the buffer offset and limit correctly |
| ByteBuffer bb = ByteBuffer.allocate(4); |
| for (int i = 0; i < 4; i++) |
| { |
| bb.put((byte) i); |
| } |
| // use a chunk out of the middle of the buffer |
| bb.position(1); |
| bb.limit(3); |
| assertEquals(2, bb.remaining()); |
| String s = ByteBufferUtil.bytesToHex(bb); |
| ByteBuffer bb2 = ByteBufferUtil.hexToBytes(s); |
| assertEquals(bb, bb2); |
| assertEquals("0102", s); |
| } |
| |
| @Test |
| public void testStartsAndEndsWith() |
| { |
| byte[] bytes = new byte[512]; |
| ThreadLocalRandom random = ThreadLocalRandom.current(); |
| |
| random.nextBytes(bytes); |
| |
| ByteBuffer a = ByteBuffer.wrap(bytes); |
| ByteBuffer b = a.duplicate(); |
| |
| // let's take random slices of a and match |
| for (int i = 0; i < 512; i++) |
| { |
| // prefix from the original offset |
| b.position(0).limit(a.remaining() - random.nextInt(0, a.remaining() - 1)); |
| Assert.assertTrue(ByteBufferUtil.startsWith(a, b)); |
| Assert.assertTrue(ByteBufferUtil.startsWith(a, b.slice())); |
| |
| // prefix from random position inside of array |
| int pos = random.nextInt(1, a.remaining() - 5); |
| a.position(pos); |
| b.limit(bytes.length - 1).position(pos); |
| |
| Assert.assertTrue(ByteBufferUtil.startsWith(a, b)); |
| |
| a.position(0); |
| |
| // endsWith at random position |
| b.limit(a.remaining()).position(random.nextInt(0, a.remaining() - 1)); |
| Assert.assertTrue(ByteBufferUtil.endsWith(a, b)); |
| Assert.assertTrue(ByteBufferUtil.endsWith(a, b.slice())); |
| |
| } |
| |
| a.limit(bytes.length - 1).position(0); |
| b.limit(bytes.length - 1).position(1); |
| |
| Assert.assertFalse(ByteBufferUtil.startsWith(a, b)); |
| Assert.assertFalse(ByteBufferUtil.startsWith(a, b.slice())); |
| |
| Assert.assertTrue(ByteBufferUtil.endsWith(a, b)); |
| Assert.assertTrue(ByteBufferUtil.endsWith(a, b.slice())); |
| |
| |
| a.position(5); |
| |
| Assert.assertFalse(ByteBufferUtil.startsWith(a, b)); |
| Assert.assertFalse(ByteBufferUtil.endsWith(a, b)); |
| } |
| } |