/* * Copyright 2014 NAVER Corp. * * Licensed 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 com.navercorp.pinpoint.common.util; import static org.junit.Assert.*; import java.nio.ByteBuffer; import java.util.Arrays; import com.navercorp.pinpoint.common.buffer.Buffer; import com.navercorp.pinpoint.common.buffer.FixedBuffer; import org.apache.thrift.TException; import org.apache.thrift.protocol.TCompactProtocol; import org.apache.thrift.transport.TMemoryBuffer; import org.junit.Assert; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.common.primitives.Ints; public class BytesUtilsTest { private final Logger logger = LoggerFactory.getLogger(this.getClass()); @Test public void testStringLongLongToBytes() { BytesUtils.stringLongLongToBytes("123", 3, 1, 2); try { BytesUtils.stringLongLongToBytes("123", 2, 1, 2); Assert.fail("fail"); } catch (IndexOutOfBoundsException ignore) { } } @Test public void testStringLongLongToBytes2() { byte[] bytes = BytesUtils.stringLongLongToBytes("123", 10, 1, 2); String s = BytesUtils.toStringAndRightTrim(bytes, 0, 10); Assert.assertEquals("123", s); long l = BytesUtils.bytesToLong(bytes, 10); Assert.assertEquals(l, 1); long l2 = BytesUtils.bytesToLong(bytes, 10 + BytesUtils.LONG_BYTE_LENGTH); Assert.assertEquals(l2, 2); } @Test public void testRightTrim() { String trim = BytesUtils.trimRight("test "); Assert.assertEquals("test", trim); String trim1 = BytesUtils.trimRight("test"); Assert.assertEquals("test", trim1); String trim2 = BytesUtils.trimRight(" test"); Assert.assertEquals(" test", trim2); } @Test public void testInt() { int i = Integer.MAX_VALUE - 5; checkInt(i); checkInt(23464); } private void checkInt(int i) { byte[] bytes = Ints.toByteArray(i); int i2 = BytesUtils.bytesToInt(bytes, 0); Assert.assertEquals(i, i2); int i3 = Ints.fromByteArray(bytes); Assert.assertEquals(i, i3); } @Test public void testAddStringLong() { byte[] testAgents = BytesUtils.add("testAgent", 11L); byte[] buf = ByteBuffer.allocate(17).put("testAgent".getBytes()).putLong(11L).array(); Assert.assertArrayEquals(testAgents, buf); } @Test public void testAddStringLong_NullError() { try { BytesUtils.add((String) null, 11L); Assert.fail(); } catch (NullPointerException ignore) { } } @Test public void testToFixedLengthBytes() { byte[] testValue = BytesUtils.toFixedLengthBytes("test", 10); Assert.assertEquals(testValue.length, 10); Assert.assertEquals(testValue[5], 0); try { BytesUtils.toFixedLengthBytes("test", 2); Assert.fail(); } catch (IndexOutOfBoundsException ignore) { } try { BytesUtils.toFixedLengthBytes("test", -1); Assert.fail(); } catch (IndexOutOfBoundsException ignore) { } byte[] testValue2 = BytesUtils.toFixedLengthBytes(null, 10); Assert.assertEquals(testValue2.length, 10); } @Test public void testMerge() { byte[] b1 = new byte[] { 1, 2 }; byte[] b2 = new byte[] { 3, 4 }; byte[] b3 = BytesUtils.merge(b1, b2); Assert.assertTrue(Arrays.equals(new byte[] { 1, 2, 3, 4 }, b3)); } @Test public void testZigZag() { testEncodingDecodingZigZag(0); testEncodingDecodingZigZag(1); testEncodingDecodingZigZag(2); testEncodingDecodingZigZag(3); } private void testEncodingDecodingZigZag(int value) { int encode = BytesUtils.intToZigZag(value); int decode = BytesUtils.zigzagToInt(encode); Assert.assertEquals(value, decode); } @Test public void compactProtocolVint() throws TException { TMemoryBuffer tMemoryBuffer = writeVInt32(BytesUtils.zigzagToInt(64)); logger.trace("length:{}", tMemoryBuffer.length()); TMemoryBuffer tMemoryBuffer2 = writeVInt32(64); logger.trace("length:{}", tMemoryBuffer2.length()); } private TMemoryBuffer writeVInt32(int i) throws TException { TMemoryBuffer tMemoryBuffer = new TMemoryBuffer(10); TCompactProtocol tCompactProtocol = new TCompactProtocol(tMemoryBuffer); tCompactProtocol.writeI32(i); return tMemoryBuffer; } @Test public void testWriteBytes1() { byte[] buffer = new byte[10]; byte[] write = new byte[] { 1, 2, 3, 4 }; Assert.assertEquals(BytesUtils.writeBytes(buffer, 0, write), write.length); Assert.assertArrayEquals(Arrays.copyOf(buffer, write.length), write); } @Test public void testWriteBytes2() { byte[] buffer = new byte[10]; byte[] write = new byte[] { 1, 2, 3, 4 }; int startOffset = 1; Assert.assertEquals(BytesUtils.writeBytes(buffer, startOffset, write), write.length + startOffset); Assert.assertArrayEquals(Arrays.copyOfRange(buffer, startOffset, write.length + startOffset), write); } @Test public void testAppropriateWriteBytes() { byte[] dst = new byte[10]; byte[] src = new byte[5]; src[0] = 1; src[1] = 2; src[2] = 3; src[3] = 4; src[4] = 5; // proper return? Assert.assertEquals(3, BytesUtils.writeBytes(dst, 1, src, 2, 2)); // successful write? Assert.assertEquals(3, dst[1]); Assert.assertEquals(4, dst[2]); } @Test public void testOverflowDestinationWriteBytes() { byte[] dst = new byte[5]; byte[] src = new byte[10]; for (int i = 0; i < 10; i++) { src[i] = (byte) (i + 1); } try { // overflow! BytesUtils.writeBytes(dst, 0, src); // if it does not catch any errors, it means memory leak! fail("invalid memory access"); } catch (Exception e) { // nice } } @Test public void testAppropriateBytesToLong() { byte[] such_long = new byte[12]; int i; for (i = 0; i < 12; i++) { such_long[i] = (byte) ((i << 4) + i); } Assert.assertEquals(0x33445566778899AAl, BytesUtils.bytesToLong(such_long, 3)); } @Test public void testOverflowBytesToLong() { byte[] such_long = new byte[12]; int i; for (i = 0; i < 12; i++) { such_long[i] = (byte) ((i << 4) + i); } try { // overflow! BytesUtils.bytesToLong(such_long, 9); // if it does not catch any errors, it means memory leak! fail("invalid memory access"); } catch (Exception e) { // nice } } @Test public void testWriteLong() { try { BytesUtils.writeLong(1234, null, 0); fail("null pointer accessed"); } catch (Exception ignore) { } byte[] such_long = new byte[13]; try { BytesUtils.writeLong(1234, such_long, -1); fail("negative offset did not catched"); } catch (Exception ignore) { } try { BytesUtils.writeLong(2222, such_long, 9); fail("index out of range exception did not catched"); } catch (Exception ignore) { } BytesUtils.writeLong(-1l, such_long, 2); for (int i = 2; i < 10; i++) { Assert.assertEquals((byte) 0xFF, such_long[i]); } } @Test public void testTrimRight() { // no space String testStr = "Shout-out! EE!"; Assert.assertEquals("Shout-out! EE!", BytesUtils.trimRight(testStr)); // right spaced testStr = "Shout-out! YeeYee! "; Assert.assertEquals("Shout-out! YeeYee!", BytesUtils.trimRight(testStr)); } @Test public void testByteTrimRight() { // no space String testStr = "Shout-out! EE!"; byte[] testByte1 = new byte[testStr.length()]; for (int i = 0; i < testByte1.length; i++) { testByte1[i] = (byte) testStr.charAt(i); } Assert.assertEquals("out-out!", BytesUtils.toStringAndRightTrim(testByte1, 2, 9)); // right spaced testStr = "Shout-out! YeeYee! "; byte[] testByte2 = new byte[testStr.length()]; for (int i = 0; i < testByte2.length; i++) { testByte2[i] = (byte) testStr.charAt(i); } Assert.assertEquals(" YeeYee!", BytesUtils.toStringAndRightTrim(testByte2, 10, 10)); } /** * bound 1->0 * bound 2->128 * bound 3->16384 * bound 4->2097152 * bound 5->268435456 */ // @Test public void testBoundaryValueVar32() { int boundSize = 0; for (int i =0; i< Integer.MAX_VALUE; i++) { final int size = BytesUtils.computeVar32Size(i); if (size> boundSize) { boundSize = size; logger.debug("bound {}->{}", boundSize, i); } } } /** * bound 1->0 * bound 2->128 * bound 3->16384 * bound 4->2097152 * bound 5->268435456 * bound 6->34359738368 * bound 7->? * bound 8->? * bound 9->? * bound 10->? */ // @Test public void testBoundaryValueVar64() { int boundSize = 0; for (long i =0; i< Long.MAX_VALUE; i++) { final int size = BytesUtils.computeVar64Size(i); if (size> boundSize) { boundSize = size; logger.debug("bound {}->{}", boundSize, i); } } } @Test public void testVar32() { assertVar32(127); assertVar32(128); assertVar32(16383); assertVar32(16384); assertVar32(2097151); assertVar32(2097152); assertVar32(268435455); assertVar32(268435456); assertVar32(Integer.MAX_VALUE-1); assertVar32(Integer.MAX_VALUE); assertVar32(Integer.MIN_VALUE); assertVar32(Integer.MIN_VALUE+1); assertVar32(-127); assertVar32(-128); assertVar32(-16383); assertVar32(-16384); assertVar32(-268435455); assertVar32(-268435456); } private void assertVar32(int value) { final int computeBufferSize = BytesUtils.computeVar32Size(value); final byte[] bytes = new byte[computeBufferSize]; BytesUtils.writeVar32(value, bytes, 0); final Buffer buffer = new FixedBuffer(bytes); final int varInt = buffer.readVInt(); Assert.assertEquals("check value", value, varInt); Assert.assertEquals("check buffer size", buffer.getOffset(), computeBufferSize); final int varInt_ByteUtils1 = BytesUtils.bytesToVar32(buffer.getBuffer(), 0); Assert.assertEquals("check value", value, varInt_ByteUtils1); final byte[] max_buffer = new byte[BytesUtils.VLONG_MAX_SIZE]; BytesUtils.writeVar32(value, max_buffer, 0); final int varInt_ByteUtils2 = BytesUtils.bytesToVar32(max_buffer, 0); Assert.assertEquals("check value", value, varInt_ByteUtils2); } @Test public void testVar64() { assertVar64(127); assertVar64(128); assertVar64(16383); assertVar64(16384); assertVar64(2097151); assertVar64(2097152); assertVar64(268435455); assertVar64(268435456); assertVar64(34359738367L); assertVar64(34359738368L); assertVar64(Long.MAX_VALUE-1); assertVar64(Long.MAX_VALUE); assertVar64(Long.MIN_VALUE); assertVar64(Long.MIN_VALUE+1); assertVar64(-127); assertVar64(-128); assertVar64(-2097151); assertVar64(-2097152); assertVar64(-34359738367L); assertVar64(-34359738368L); } private void assertVar64(long value) { final int computeBufferSize = BytesUtils.computeVar64Size(value); final byte[] bytes = new byte[computeBufferSize]; BytesUtils.writeVar64(value, bytes, 0); final Buffer buffer = new FixedBuffer(bytes); final long varLong = buffer.readVLong(); Assert.assertEquals("check value", value, varLong); Assert.assertEquals("check buffer size", buffer.getOffset(), computeBufferSize); final long varLong_ByteUtils1 = BytesUtils.bytesToVar64(buffer.getBuffer(), 0); Assert.assertEquals("check value", value, varLong_ByteUtils1); final byte[] max_buffer = new byte[BytesUtils.VLONG_MAX_SIZE]; BytesUtils.writeVar64(value, max_buffer, 0); final long varLong_ByteUtils2 = BytesUtils.bytesToVar64(max_buffer, 0); Assert.assertEquals("check value", value, varLong_ByteUtils2); } @Test public void testCheckBound() { final int bufferSize = 10; BytesUtils.checkBound(bufferSize, 0); BytesUtils.checkBound(bufferSize, 2); BytesUtils.checkBound(bufferSize, bufferSize - 1); try { BytesUtils.checkBound(bufferSize, bufferSize); Assert.fail("bound check fail"); } catch (Exception ignore) { } try { BytesUtils.checkBound(bufferSize, -1); Assert.fail("bound check fail"); } catch (Exception ignore) { } try { BytesUtils.bytesToSVar32(new byte[10], 10); Assert.fail("bound check fail"); } catch (Exception ignored) { } } @Test public void testShortToUnsignedShort() { Assert.assertEquals(BytesUtils.shortToUnsignedShort((short)0), 0); Assert.assertEquals(BytesUtils.shortToUnsignedShort(Short.MAX_VALUE), 32767); final short maxOver = (short) (Short.MAX_VALUE + 1); Assert.assertEquals(BytesUtils.shortToUnsignedShort(maxOver), 32768); Assert.assertEquals(BytesUtils.shortToUnsignedShort((short)-1), 65535); } }