| // |
| // ======================================================================== |
| // Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. |
| // ------------------------------------------------------------------------ |
| // All rights reserved. This program and the accompanying materials |
| // are made available under the terms of the Eclipse Public License v1.0 |
| // and Apache License v2.0 which accompanies this distribution. |
| // |
| // The Eclipse Public License is available at |
| // http://www.eclipse.org/legal/epl-v10.html |
| // |
| // The Apache License v2.0 is available at |
| // http://www.opensource.org/licenses/apache2.0.php |
| // |
| // You may elect to redistribute this code under either of these licenses. |
| // ======================================================================== |
| // |
| |
| package org.eclipse.jetty.util; |
| |
| |
| import static org.hamcrest.CoreMatchers.is; |
| import static org.junit.Assert.assertEquals; |
| import static org.junit.Assert.assertFalse; |
| import static org.junit.Assert.assertThat; |
| import static org.junit.Assert.assertTrue; |
| |
| import java.io.ByteArrayOutputStream; |
| import java.io.File; |
| import java.io.FileWriter; |
| import java.io.IOException; |
| import java.nio.BufferOverflowException; |
| import java.nio.ByteBuffer; |
| import java.nio.channels.FileChannel; |
| import java.nio.channels.FileChannel.MapMode; |
| import java.nio.charset.StandardCharsets; |
| import java.nio.file.OpenOption; |
| import java.util.Arrays; |
| import java.util.concurrent.ThreadLocalRandom; |
| |
| import org.eclipse.jetty.util.log.Log; |
| import org.eclipse.jetty.util.log.Logger; |
| import org.junit.Assert; |
| import org.junit.Ignore; |
| import org.junit.Test; |
| |
| public class BufferUtilTest |
| { |
| @Test |
| public void testToInt() throws Exception |
| { |
| ByteBuffer buf[] = |
| { |
| BufferUtil.toBuffer("0"), |
| BufferUtil.toBuffer(" 42 "), |
| BufferUtil.toBuffer(" 43abc"), |
| BufferUtil.toBuffer("-44"), |
| BufferUtil.toBuffer(" - 45;"), |
| BufferUtil.toBuffer("-2147483648"), |
| BufferUtil.toBuffer("2147483647"), |
| }; |
| |
| int val[] = |
| { |
| 0,42,43,-44,-45,-2147483648,2147483647 |
| }; |
| |
| for (int i=0;i<buf.length;i++) |
| assertEquals("t"+i, val[i], BufferUtil.toInt(buf[i])); |
| } |
| |
| @Test |
| public void testPutInt() throws Exception |
| { |
| int val[] = |
| { |
| 0,42,43,-44,-45,Integer.MIN_VALUE,Integer.MAX_VALUE |
| }; |
| |
| String str[] = |
| { |
| "0","42","43","-44","-45",""+Integer.MIN_VALUE,""+Integer.MAX_VALUE |
| }; |
| |
| ByteBuffer buffer = ByteBuffer.allocate(24); |
| |
| for (int i=0;i<val.length;i++) |
| { |
| BufferUtil.clearToFill(buffer); |
| BufferUtil.putDecInt(buffer,val[i]); |
| BufferUtil.flipToFlush(buffer,0); |
| assertEquals("t"+i,str[i],BufferUtil.toString(buffer)); |
| } |
| } |
| |
| @Test |
| public void testPutLong() throws Exception |
| { |
| long val[] = |
| { |
| 0L,42L,43L,-44L,-45L,Long.MIN_VALUE,Long.MAX_VALUE |
| }; |
| |
| String str[] = |
| { |
| "0","42","43","-44","-45",""+Long.MIN_VALUE,""+Long.MAX_VALUE |
| }; |
| |
| ByteBuffer buffer = ByteBuffer.allocate(50); |
| |
| for (int i=0;i<val.length;i++) |
| { |
| BufferUtil.clearToFill(buffer); |
| BufferUtil.putDecLong(buffer,val[i]); |
| BufferUtil.flipToFlush(buffer,0); |
| assertEquals("t"+i,str[i],BufferUtil.toString(buffer)); |
| } |
| } |
| |
| @Test |
| public void testPutHexInt() throws Exception |
| { |
| int val[] = |
| { |
| 0,42,43,-44,-45,-2147483648,2147483647 |
| }; |
| |
| String str[] = |
| { |
| "0","2A","2B","-2C","-2D","-80000000","7FFFFFFF" |
| }; |
| |
| ByteBuffer buffer = ByteBuffer.allocate(50); |
| |
| for (int i=0;i<val.length;i++) |
| { |
| BufferUtil.clearToFill(buffer); |
| BufferUtil.putHexInt(buffer,val[i]); |
| BufferUtil.flipToFlush(buffer,0); |
| assertEquals("t"+i,str[i],BufferUtil.toString(buffer)); |
| } |
| } |
| |
| @Test |
| public void testPut() throws Exception |
| { |
| ByteBuffer to = BufferUtil.allocate(10); |
| ByteBuffer from=BufferUtil.toBuffer("12345"); |
| |
| BufferUtil.clear(to); |
| assertEquals(5,BufferUtil.append(to,from)); |
| assertTrue(BufferUtil.isEmpty(from)); |
| assertEquals("12345",BufferUtil.toString(to)); |
| |
| from=BufferUtil.toBuffer("XX67890ZZ"); |
| from.position(2); |
| |
| assertEquals(5,BufferUtil.append(to,from)); |
| assertEquals(2,from.remaining()); |
| assertEquals("1234567890",BufferUtil.toString(to)); |
| } |
| |
| |
| |
| @Test |
| public void testAppend() throws Exception |
| { |
| ByteBuffer to = BufferUtil.allocate(8); |
| ByteBuffer from=BufferUtil.toBuffer("12345"); |
| |
| BufferUtil.append(to,from.array(),0,3); |
| assertEquals("123",BufferUtil.toString(to)); |
| BufferUtil.append(to,from.array(),3,2); |
| assertEquals("12345",BufferUtil.toString(to)); |
| |
| try |
| { |
| BufferUtil.append(to,from.array(),0,5); |
| Assert.fail(); |
| } |
| catch(BufferOverflowException e) |
| {} |
| } |
| |
| |
| @Test |
| public void testPutDirect() throws Exception |
| { |
| ByteBuffer to = BufferUtil.allocateDirect(10); |
| ByteBuffer from=BufferUtil.toBuffer("12345"); |
| |
| BufferUtil.clear(to); |
| assertEquals(5,BufferUtil.append(to,from)); |
| assertTrue(BufferUtil.isEmpty(from)); |
| assertEquals("12345",BufferUtil.toString(to)); |
| |
| from=BufferUtil.toBuffer("XX67890ZZ"); |
| from.position(2); |
| |
| assertEquals(5,BufferUtil.append(to,from)); |
| assertEquals(2,from.remaining()); |
| assertEquals("1234567890",BufferUtil.toString(to)); |
| } |
| |
| @Test |
| public void testToBuffer_Array() |
| { |
| byte arr[] = new byte[128]; |
| Arrays.fill(arr,(byte)0x44); |
| ByteBuffer buf = BufferUtil.toBuffer(arr); |
| |
| int count = 0; |
| while (buf.remaining() > 0) |
| { |
| byte b = buf.get(); |
| Assert.assertEquals(b,0x44); |
| count++; |
| } |
| |
| Assert.assertEquals("Count of bytes",arr.length,count); |
| } |
| |
| @Test |
| public void testToBuffer_ArrayOffsetLength() |
| { |
| byte arr[] = new byte[128]; |
| Arrays.fill(arr,(byte)0xFF); // fill whole thing with FF |
| int offset = 10; |
| int length = 100; |
| Arrays.fill(arr,offset,offset + length,(byte)0x77); // fill partial with 0x77 |
| ByteBuffer buf = BufferUtil.toBuffer(arr,offset,length); |
| |
| int count = 0; |
| while (buf.remaining() > 0) |
| { |
| byte b = buf.get(); |
| Assert.assertEquals(b,0x77); |
| count++; |
| } |
| |
| Assert.assertEquals("Count of bytes",length,count); |
| } |
| |
| private static final Logger LOG = Log.getLogger(BufferUtilTest.class); |
| |
| @Test |
| @Ignore("Very simple microbenchmark to compare different writeTo implementations. Only for development thus " + |
| "ignored.") |
| public void testWriteToMicrobenchmark() throws IOException |
| { |
| int capacity = 1024 * 128; |
| int iterations = 100; |
| int testRuns = 10; |
| byte[] bytes = new byte[capacity]; |
| ThreadLocalRandom.current().nextBytes(bytes); |
| ByteBuffer buffer = BufferUtil.allocate(capacity); |
| BufferUtil.append(buffer, bytes, 0, capacity); |
| long startTest = System.nanoTime(); |
| for (int i = 0; i < testRuns; i++) |
| { |
| long start = System.nanoTime(); |
| for (int j = 0; j < iterations; j++) |
| { |
| ByteArrayOutputStream out = new ByteArrayOutputStream(); |
| long startRun = System.nanoTime(); |
| BufferUtil.writeTo(buffer.asReadOnlyBuffer(), out); |
| long elapsedRun = System.nanoTime() - startRun; |
| // LOG.warn("run elapsed={}ms", elapsedRun / 1000); |
| assertThat("Bytes in out equal bytes in buffer", Arrays.equals(bytes, out.toByteArray()), is(true)); |
| } |
| long elapsed = System.nanoTime() - start; |
| LOG.warn("elapsed={}ms average={}ms", elapsed / 1000, elapsed/iterations/1000); |
| } |
| LOG.warn("overall average: {}ms", (System.nanoTime() - startTest) / testRuns / iterations / 1000); |
| } |
| |
| @Test |
| public void testWriteToWithBufferThatDoesNotExposeArrayAndSmallContent() throws IOException |
| { |
| int capacity = BufferUtil.TEMP_BUFFER_SIZE/4; |
| testWriteToWithBufferThatDoesNotExposeArray(capacity); |
| } |
| |
| @Test |
| public void testWriteToWithBufferThatDoesNotExposeArrayAndContentLengthMatchingTempBufferSize() throws IOException |
| { |
| int capacity = BufferUtil.TEMP_BUFFER_SIZE; |
| testWriteToWithBufferThatDoesNotExposeArray(capacity); |
| } |
| |
| @Test |
| public void testWriteToWithBufferThatDoesNotExposeArrayAndContentSlightlyBiggerThanTwoTimesTempBufferSize() |
| throws |
| IOException |
| { |
| int capacity = BufferUtil.TEMP_BUFFER_SIZE*2+1024; |
| testWriteToWithBufferThatDoesNotExposeArray(capacity); |
| } |
| |
| |
| @Test |
| public void testEnsureCapacity() throws Exception |
| { |
| ByteBuffer b = BufferUtil.toBuffer("Goodbye Cruel World"); |
| assertTrue(b==BufferUtil.ensureCapacity(b, 0)); |
| assertTrue(b==BufferUtil.ensureCapacity(b, 10)); |
| assertTrue(b==BufferUtil.ensureCapacity(b, b.capacity())); |
| |
| |
| ByteBuffer b1 = BufferUtil.ensureCapacity(b, 64); |
| assertTrue(b!=b1); |
| assertEquals(64, b1.capacity()); |
| assertEquals("Goodbye Cruel World", BufferUtil.toString(b1)); |
| |
| b1.position(8); |
| b1.limit(13); |
| assertEquals("Cruel", BufferUtil.toString(b1)); |
| ByteBuffer b2 = b1.slice(); |
| assertEquals("Cruel", BufferUtil.toString(b2)); |
| System.err.println(BufferUtil.toDetailString(b2)); |
| assertEquals(8, b2.arrayOffset()); |
| assertEquals(5, b2.capacity()); |
| |
| assertTrue(b2==BufferUtil.ensureCapacity(b2, 5)); |
| |
| ByteBuffer b3 = BufferUtil.ensureCapacity(b2, 64); |
| assertTrue(b2!=b3); |
| assertEquals(64, b3.capacity()); |
| assertEquals("Cruel", BufferUtil.toString(b3)); |
| assertEquals(0, b3.arrayOffset()); |
| |
| } |
| |
| |
| private void testWriteToWithBufferThatDoesNotExposeArray(int capacity) throws IOException |
| { |
| ByteArrayOutputStream out = new ByteArrayOutputStream(); |
| byte[] bytes = new byte[capacity]; |
| ThreadLocalRandom.current().nextBytes(bytes); |
| ByteBuffer buffer = BufferUtil.allocate(capacity); |
| BufferUtil.append(buffer, bytes, 0, capacity); |
| BufferUtil.writeTo(buffer.asReadOnlyBuffer(), out); |
| assertThat("Bytes in out equal bytes in buffer", Arrays.equals(bytes, out.toByteArray()), is(true)); |
| } |
| |
| @Test |
| public void testMappedFile() throws Exception |
| { |
| String data="Now is the time for all good men to come to the aid of the party"; |
| File file = File.createTempFile("test",".txt"); |
| file.deleteOnExit(); |
| try(FileWriter out = new FileWriter(file);) |
| { |
| out.write(data); |
| } |
| |
| ByteBuffer mapped = BufferUtil.toMappedBuffer(file); |
| assertEquals(data,BufferUtil.toString(mapped)); |
| assertTrue(BufferUtil.isMappedBuffer(mapped)); |
| |
| ByteBuffer direct = BufferUtil.allocateDirect(data.length()); |
| direct.clear(); |
| direct.put(data.getBytes(StandardCharsets.ISO_8859_1)); |
| direct.flip(); |
| assertEquals(data,BufferUtil.toString(direct)); |
| assertFalse(BufferUtil.isMappedBuffer(direct)); |
| |
| ByteBuffer slice = direct.slice(); |
| assertEquals(data,BufferUtil.toString(slice)); |
| assertFalse(BufferUtil.isMappedBuffer(slice)); |
| |
| ByteBuffer duplicate = direct.duplicate(); |
| assertEquals(data,BufferUtil.toString(duplicate)); |
| assertFalse(BufferUtil.isMappedBuffer(duplicate)); |
| |
| ByteBuffer readonly = direct.asReadOnlyBuffer(); |
| assertEquals(data,BufferUtil.toString(readonly)); |
| assertFalse(BufferUtil.isMappedBuffer(readonly)); |
| } |
| } |