blob: 83fab14938f08976ff38f8eb52801783c3814020 [file] [log] [blame]
/*
* 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.activemq.artemis.utils;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.ReadOnlyBufferException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.Map;
import io.netty.util.internal.PlatformDependent;
import org.jboss.logging.Logger;
import org.junit.Assert;
import org.junit.Assume;
import org.junit.Test;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
public class ByteUtilTest {
private static Logger log = Logger.getLogger(ByteUtilTest.class);
@Test
public void testBytesToString() {
byte[] byteArray = new byte[]{0, 1, 2, 3};
testEquals("0001 0203", ByteUtil.bytesToHex(byteArray, 2));
testEquals("00 01 02 03", ByteUtil.bytesToHex(byteArray, 1));
testEquals("000102 03", ByteUtil.bytesToHex(byteArray, 3));
}
@Test
public void testNonASCII() {
assertEquals("aA", ByteUtil.toSimpleString(new byte[]{97, 0, 65, 0}));
assertEquals(ByteUtil.NON_ASCII_STRING, ByteUtil.toSimpleString(new byte[]{0, 97, 0, 65}));
log.debug(ByteUtil.toSimpleString(new byte[]{0, 97, 0, 65}));
}
@Test
public void testMaxString() {
byte[] byteArray = new byte[20 * 1024];
log.debug(ByteUtil.maxString(ByteUtil.bytesToHex(byteArray, 2), 150));
}
void testEquals(String string1, String string2) {
if (!string1.equals(string2)) {
Assert.fail("String are not the same:=" + string1 + "!=" + string2);
}
}
@Test
public void testTextBytesToLongBytes() {
long[] factor = new long[] {1, 5, 10};
String[] type = new String[]{"", "b", "k", "m", "g"};
long[] size = new long[]{1, 1, 1024, 1024 * 1024, 1024 * 1024 * 1024};
for (int i = 0; i < 3; i++) {
for (int j = 0; j < type.length; j++) {
assertEquals(factor[i] * size[j], ByteUtil.convertTextBytes(factor[i] + type[j]));
assertEquals(factor[i] * size[j], ByteUtil.convertTextBytes(factor[i] + " " + type[j]));
assertEquals(factor[i] * size[j], ByteUtil.convertTextBytes(factor[i] + type[j].toUpperCase()));
assertEquals(factor[i] * size[j], ByteUtil.convertTextBytes(factor[i] + " " + type[j].toUpperCase()));
if (j >= 2) {
assertEquals(factor[i] * size[j], ByteUtil.convertTextBytes(factor[i] + type[j] + "b"));
assertEquals(factor[i] * size[j], ByteUtil.convertTextBytes(factor[i] + " " + type[j] + "b"));
assertEquals(factor[i] * size[j], ByteUtil.convertTextBytes(factor[i] + type[j].toUpperCase() + "B"));
assertEquals(factor[i] * size[j], ByteUtil.convertTextBytes(factor[i] + " " + type[j].toUpperCase() + "B"));
}
}
}
}
@Test
public void testUnsafeUnalignedByteArrayHashCode() {
Assume.assumeTrue(PlatformDependent.hasUnsafe());
Assume.assumeTrue(PlatformDependent.isUnaligned());
Map<byte[], Integer> map = new LinkedHashMap<>();
map.put(new byte[0], 1);
map.put(new byte[]{1}, 32);
map.put(new byte[]{2}, 33);
map.put(new byte[]{0, 1}, 962);
map.put(new byte[]{1, 2}, 994);
if (ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN) {
map.put(new byte[]{0, 1, 2, 3, 4, 5}, 63504931);
map.put(new byte[]{6, 7, 8, 9, 0, 1}, -1603953111);
map.put(new byte[]{-1, -1, -1, (byte) 0xE1}, 1);
} else {
map.put(new byte[]{0, 1, 2, 3, 4, 5}, 1250309600);
map.put(new byte[]{6, 7, 8, 9, 0, 1}, -417148442);
map.put(new byte[]{-1, -1, -1, (byte) 0xE1}, -503316450);
}
for (Map.Entry<byte[], Integer> e : map.entrySet()) {
assertEquals("input = " + Arrays.toString(e.getKey()), e.getValue().intValue(), ByteUtil.hashCode(e.getKey()));
}
}
@Test
public void testNoUnsafeAlignedByteArrayHashCode() {
Assume.assumeFalse(PlatformDependent.hasUnsafe());
Assume.assumeFalse(PlatformDependent.isUnaligned());
ArrayList<byte[]> inputs = new ArrayList<>();
inputs.add(new byte[0]);
inputs.add(new byte[]{1});
inputs.add(new byte[]{2});
inputs.add(new byte[]{0, 1});
inputs.add(new byte[]{1, 2});
inputs.add(new byte[]{0, 1, 2, 3, 4, 5});
inputs.add(new byte[]{6, 7, 8, 9, 0, 1});
inputs.add(new byte[]{-1, -1, -1, (byte) 0xE1});
inputs.forEach(input -> assertEquals("input = " + Arrays.toString(input), Arrays.hashCode(input), ByteUtil.hashCode(input)));
}
@Test
public void testTextBytesToLongBytesNegative() {
try {
ByteUtil.convertTextBytes("x");
fail();
} catch (Exception e) {
assertTrue(e instanceof IllegalArgumentException);
}
}
private static byte[] duplicateRemaining(ByteBuffer buffer, int offset, int bytes) {
final int end = offset + bytes;
final int expectedRemaining = buffer.capacity() - end;
//it is handling the case of <0 just to allow from to > capacity
if (expectedRemaining <= 0) {
return null;
}
final byte[] remaining = new byte[expectedRemaining];
final ByteBuffer duplicate = buffer.duplicate();
duplicate.clear().position(end);
duplicate.get(remaining, 0, expectedRemaining);
return remaining;
}
private static byte[] duplicateBefore(ByteBuffer buffer, int offset) {
if (offset <= 0) {
return null;
}
final int size = Math.min(buffer.capacity(), offset);
final byte[] remaining = new byte[size];
final ByteBuffer duplicate = buffer.duplicate();
duplicate.clear();
duplicate.get(remaining, 0, size);
return remaining;
}
private static void shouldZeroesByteBuffer(ByteBuffer buffer, int offset, int bytes) {
final byte[] originalBefore = duplicateBefore(buffer, offset);
final byte[] originalRemaining = duplicateRemaining(buffer, offset, bytes);
final int position = buffer.position();
final int limit = buffer.limit();
ByteUtil.zeros(buffer, offset, bytes);
Assert.assertEquals(position, buffer.position());
Assert.assertEquals(limit, buffer.limit());
final byte[] zeros = new byte[bytes];
final byte[] content = new byte[bytes];
final ByteBuffer duplicate = buffer.duplicate();
duplicate.clear().position(offset);
duplicate.get(content, 0, bytes);
Assert.assertArrayEquals(zeros, content);
if (originalRemaining != null) {
final byte[] remaining = new byte[duplicate.remaining()];
//duplicate position has been moved of bytes
duplicate.get(remaining);
Assert.assertArrayEquals(originalRemaining, remaining);
}
if (originalBefore != null) {
final byte[] before = new byte[offset];
//duplicate position has been moved of bytes: need to reset it
duplicate.position(0);
duplicate.get(before);
Assert.assertArrayEquals(originalBefore, before);
}
}
private ByteBuffer fill(ByteBuffer buffer, int offset, int length, byte value) {
for (int i = 0; i < length; i++) {
buffer.put(offset + i, value);
}
return buffer;
}
@Test
public void shouldZeroesDirectByteBuffer() {
final byte one = (byte) 1;
final int capacity = 64;
final int bytes = 32;
final int offset = 1;
final ByteBuffer buffer = ByteBuffer.allocateDirect(capacity);
try {
fill(buffer, 0, capacity, one);
shouldZeroesByteBuffer(buffer, offset, bytes);
} finally {
if (PlatformDependent.hasUnsafe()) {
PlatformDependent.freeDirectBuffer(buffer);
}
}
}
@Test
public void shouldZeroesLimitedDirectByteBuffer() {
final byte one = (byte) 1;
final int capacity = 64;
final int bytes = 32;
final int offset = 1;
final ByteBuffer buffer = ByteBuffer.allocateDirect(capacity);
try {
fill(buffer, 0, capacity, one);
buffer.limit(0);
shouldZeroesByteBuffer(buffer, offset, bytes);
} finally {
if (PlatformDependent.hasUnsafe()) {
PlatformDependent.freeDirectBuffer(buffer);
}
}
}
@Test
public void shouldZeroesHeapByteBuffer() {
final byte one = (byte) 1;
final int capacity = 64;
final int bytes = 32;
final int offset = 1;
final ByteBuffer buffer = ByteBuffer.allocate(capacity);
fill(buffer, 0, capacity, one);
shouldZeroesByteBuffer(buffer, offset, bytes);
}
@Test
public void shouldZeroesLimitedHeapByteBuffer() {
final byte one = (byte) 1;
final int capacity = 64;
final int bytes = 32;
final int offset = 1;
final ByteBuffer buffer = ByteBuffer.allocate(capacity);
fill(buffer, 0, capacity, one);
buffer.limit(0);
shouldZeroesByteBuffer(buffer, offset, bytes);
}
@Test(expected = ReadOnlyBufferException.class)
public void shouldFailWithReadOnlyHeapByteBuffer() {
final byte one = (byte) 1;
final int capacity = 64;
final int bytes = 32;
final int offset = 1;
ByteBuffer buffer = ByteBuffer.allocate(capacity);
fill(buffer, 0, capacity, one);
buffer = buffer.asReadOnlyBuffer();
shouldZeroesByteBuffer(buffer, offset, bytes);
}
@Test(expected = IndexOutOfBoundsException.class)
public void shouldFailIfOffsetIsGreaterOrEqualHeapByteBufferCapacity() {
final byte one = (byte) 1;
final int capacity = 64;
final int bytes = 0;
final int offset = 64;
ByteBuffer buffer = ByteBuffer.allocate(capacity);
fill(buffer, 0, capacity, one);
try {
shouldZeroesByteBuffer(buffer, offset, bytes);
} catch (IndexOutOfBoundsException expectedEx) {
//verify that the buffer hasn't changed
final byte[] originalContent = duplicateRemaining(buffer, 0, 0);
final byte[] expectedContent = new byte[capacity];
Arrays.fill(expectedContent, one);
Assert.assertArrayEquals(expectedContent, originalContent);
throw expectedEx;
}
}
@Test(expected = IllegalArgumentException.class)
public void shouldFailIfOffsetIsNegative() {
final byte one = (byte) 1;
final int capacity = 64;
final int bytes = 1;
final int offset = -1;
ByteBuffer buffer = ByteBuffer.allocate(capacity);
fill(buffer, 0, capacity, one);
try {
shouldZeroesByteBuffer(buffer, offset, bytes);
} catch (IndexOutOfBoundsException expectedEx) {
//verify that the buffer hasn't changed
final byte[] originalContent = duplicateRemaining(buffer, 0, 0);
final byte[] expectedContent = new byte[capacity];
Arrays.fill(expectedContent, one);
Assert.assertArrayEquals(expectedContent, originalContent);
throw expectedEx;
}
}
@Test(expected = IllegalArgumentException.class)
public void shouldFailIfBytesIsNegative() {
final byte one = (byte) 1;
final int capacity = 64;
final int bytes = -1;
final int offset = 0;
ByteBuffer buffer = ByteBuffer.allocate(capacity);
fill(buffer, 0, capacity, one);
try {
shouldZeroesByteBuffer(buffer, offset, bytes);
} catch (IndexOutOfBoundsException expectedEx) {
//verify that the buffer hasn't changed
final byte[] originalContent = duplicateRemaining(buffer, 0, 0);
final byte[] expectedContent = new byte[capacity];
Arrays.fill(expectedContent, one);
Assert.assertArrayEquals(expectedContent, originalContent);
throw expectedEx;
}
}
@Test(expected = IndexOutOfBoundsException.class)
public void shouldFailIfExceedingHeapByteBufferCapacity() {
final byte one = (byte) 1;
final int capacity = 64;
final int bytes = 65;
final int offset = 1;
ByteBuffer buffer = ByteBuffer.allocate(capacity);
fill(buffer, 0, capacity, one);
try {
shouldZeroesByteBuffer(buffer, offset, bytes);
} catch (IndexOutOfBoundsException expectedEx) {
//verify that the buffer hasn't changed
final byte[] originalContent = duplicateRemaining(buffer, 0, 0);
final byte[] expectedContent = new byte[capacity];
Arrays.fill(expectedContent, one);
Assert.assertArrayEquals(expectedContent, originalContent);
throw expectedEx;
}
}
@Test
public void testIntToBytes() {
internalIntToBytesTest(RandomUtil.randomInt(), null);
internalIntToBytesTest(0, new byte[]{0, 0, 0, 0});
internalIntToBytesTest(-1, new byte[] {(byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF});
internalIntToBytesTest(Integer.MIN_VALUE, new byte[] {(byte)0x80, (byte)0x00, (byte)0x00, (byte)0x00});
internalIntToBytesTest(Integer.MAX_VALUE, new byte[] {(byte)0x7F, (byte)0xFF, (byte)0xFF, (byte)0xFF});
}
private void internalIntToBytesTest(int intValue, byte[] manualExpect) {
byte[] expected = ByteBuffer.allocate(4).putInt(intValue).array();
byte[] actual = ByteUtil.intToBytes(intValue);
if (manualExpect != null) {
Assert.assertEquals(4, manualExpect.length);
assertArrayEquals(manualExpect, actual);
}
assertArrayEquals(expected, actual);
assertEquals(intValue, ByteUtil.bytesToInt(expected));
assertEquals(intValue, ByteUtil.bytesToInt(actual));
}
@Test
public void testLongToBytes() {
internalLongToBytesTest(RandomUtil.randomLong(), null);
internalLongToBytesTest(0, new byte[] {0, 0, 0, 0, 0, 0, 0, 0});
internalLongToBytesTest(-1, new byte[] {(byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF});
internalLongToBytesTest(Long.MIN_VALUE, new byte[] {(byte)0x80, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00});
internalLongToBytesTest(Long.MAX_VALUE, new byte[] {(byte)0x7F, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF});
}
private void internalLongToBytesTest(long longValue, byte[] manualExpected) {
byte[] expected = ByteBuffer.allocate(8).putLong(longValue).array();
byte[] actual = ByteUtil.longToBytes(longValue);
if (manualExpected != null) {
Assert.assertEquals(8, manualExpected.length);
assertArrayEquals(manualExpected, actual);
}
assertArrayEquals(expected, actual);
assertEquals(longValue, ByteUtil.bytesToLong(expected));
assertEquals(longValue, ByteUtil.bytesToLong(actual));
}
@Test
public void testDoubleLongToBytes() {
long randomLong1 = RandomUtil.randomLong();
long randomLong2 = RandomUtil.randomLong();
ByteBuffer buffer = ByteBuffer.allocate(16);
buffer.putLong(randomLong1);
buffer.putLong(randomLong2);
byte[] assertContent = buffer.array();
byte[] convertedContent = ByteUtil.doubleLongToBytes(randomLong1, randomLong2);
assertArrayEquals(assertContent, convertedContent);
}
}