diff options
author | Jon Bratseth <bratseth@yahoo-inc.com> | 2016-06-15 23:09:44 +0200 |
---|---|---|
committer | Jon Bratseth <bratseth@yahoo-inc.com> | 2016-06-15 23:09:44 +0200 |
commit | 72231250ed81e10d66bfe70701e64fa5fe50f712 (patch) | |
tree | 2728bba1131a6f6e5bdf95afec7d7ff9358dac50 /vespajlib/src/test/java/com/yahoo/io |
Publish
Diffstat (limited to 'vespajlib/src/test/java/com/yahoo/io')
11 files changed, 2004 insertions, 0 deletions
diff --git a/vespajlib/src/test/java/com/yahoo/io/BlobTestCase.java b/vespajlib/src/test/java/com/yahoo/io/BlobTestCase.java new file mode 100644 index 00000000000..9643d70ba5e --- /dev/null +++ b/vespajlib/src/test/java/com/yahoo/io/BlobTestCase.java @@ -0,0 +1,95 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.io; + +import java.nio.ByteBuffer; + +public class BlobTestCase extends junit.framework.TestCase { + + public void testEmpty() { + Blob empty = new Blob(); + assertTrue(empty.get() != null); + assertEquals(0, empty.get().length); + } + + public void testCopyArray() { + byte[] d = { 1, 2, 3 }; + Blob b = new Blob(d); + d[0] = 7; + d[1] = 8; + d[2] = 9; + assertEquals(3, b.get().length); + assertEquals(1, b.get()[0]); + assertEquals(2, b.get()[1]); + assertEquals(3, b.get()[2]); + } + + public void testCopyArraySubset() { + byte[] d = { 1, 2, 3 }; + Blob b = new Blob(d, 1, 1); + d[0] = 7; + d[1] = 8; + d[2] = 9; + assertEquals(1, b.get().length); + assertEquals(2, b.get()[0]); + } + + public void testCopyBlob() { + byte[] d = { 1, 2, 3 }; + Blob b = new Blob(d); + Blob x = new Blob(b); + b.get()[1] = 4; + assertEquals(3, x.get().length); + assertEquals(1, x.get()[0]); + assertEquals(4, b.get()[1]); + assertEquals(2, x.get()[1]); + assertEquals(3, x.get()[2]); + } + + public void testReadBuffer() { + ByteBuffer buf = ByteBuffer.allocate(100); + buf.put((byte)1); + buf.put((byte)2); + buf.put((byte)3); + buf.flip(); + assertEquals(3, buf.remaining()); + Blob b = new Blob(buf); + assertEquals(0, buf.remaining()); + assertEquals(3, b.get().length); + assertEquals(1, b.get()[0]); + assertEquals(2, b.get()[1]); + assertEquals(3, b.get()[2]); + } + + public void testReadPartialBuffer() { + ByteBuffer buf = ByteBuffer.allocate(100); + buf.put((byte)1); + buf.put((byte)2); + buf.put((byte)3); + buf.put((byte)4); + buf.put((byte)5); + buf.flip(); + assertEquals(5, buf.remaining()); + Blob b = new Blob(buf, 3); + assertEquals(2, buf.remaining()); + assertEquals(3, b.get().length); + assertEquals(1, b.get()[0]); + assertEquals(2, b.get()[1]); + assertEquals(3, b.get()[2]); + assertEquals(4, buf.get()); + assertEquals(5, buf.get()); + assertEquals(0, buf.remaining()); + } + + public void testWriteBuffer() { + byte[] d = { 1, 2, 3 }; + Blob b = new Blob(d); + ByteBuffer buf = ByteBuffer.allocate(100); + b.write(buf); + buf.flip(); + assertEquals(3, buf.remaining()); + assertEquals(1, buf.get()); + assertEquals(2, buf.get()); + assertEquals(3, buf.get()); + assertEquals(0, buf.remaining()); + } +} diff --git a/vespajlib/src/test/java/com/yahoo/io/ByteWriterTestCase.java b/vespajlib/src/test/java/com/yahoo/io/ByteWriterTestCase.java new file mode 100644 index 00000000000..d5025dd03aa --- /dev/null +++ b/vespajlib/src/test/java/com/yahoo/io/ByteWriterTestCase.java @@ -0,0 +1,444 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.io; + +import static org.junit.Assert.assertArrayEquals; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.nio.ByteBuffer; +import java.nio.charset.Charset; +import java.nio.charset.CharsetEncoder; +import java.util.Arrays; +import java.util.IdentityHashMap; + +import com.yahoo.text.Utf8; +import com.yahoo.text.Utf8Array; + +/** + * Test the ByteWriter class. ByteWriter is also implicitly tested in + * com.yahoo.prelude.templates.test.TemplateTestCase. + * + * @author <a href="mailt:steinar@yahoo-inc.com">Steinar Knutsen</a> + */ +public class ByteWriterTestCase extends junit.framework.TestCase { + private CharsetEncoder encoder; + private ByteArrayOutputStream stream; + + // TODO split BufferChain tests from ByteWriter tests + public ByteWriterTestCase (String name) { + super(name); + Charset cs = Charset.forName("UTF-8"); + encoder = cs.newEncoder(); + stream = new ByteArrayOutputStream(); + + } + + /** + * A stream which does nothing, but complains if it is called and asked to + * do nothing. + */ + private static class CurmudgeonlyStream extends OutputStream { + + static final String ZERO_LENGTH_WRITE = "Was asked to do zero length write."; + + @Override + public void write(int b) throws IOException { + // NOP + + } + + @Override + public void close() throws IOException { + // NOP + } + + @Override + public void flush() throws IOException { + // NOP + } + + @Override + public void write(byte[] b, int off, int len) throws IOException { + if (len == 0) { + throw new IOException(ZERO_LENGTH_WRITE); + } + } + + @Override + public void write(byte[] b) throws IOException { + if (b.length == 0) { + throw new IOException(ZERO_LENGTH_WRITE); + } + } + + } + + public void testMuchData() throws java.io.IOException { + final int SINGLE_BUFFER = 500; + final int APPENDS = 500; + assertTrue("Code has been changed making constants in this test meaningless, review test.", + BufferChain.BUFFERSIZE * BufferChain.MAXBUFFERS < SINGLE_BUFFER * APPENDS); + assertTrue("Code has been changed making constants in this test meaningless, review test.", + BufferChain.WATERMARK > SINGLE_BUFFER); + stream.reset(); + byte[] c = new byte[SINGLE_BUFFER]; + Arrays.fill(c, (byte) 'a'); + ByteWriter bw = new ByteWriter(stream, encoder); + for (int i = APPENDS; i > 0; --i) { + bw.append(c); + } + bw.close(); + byte[] res = stream.toByteArray(); + assertEquals("BufferChain has duplicated or lost a buffer.", SINGLE_BUFFER * APPENDS, res.length); + byte[] completeData = new byte[SINGLE_BUFFER * APPENDS]; + Arrays.fill(completeData, (byte) 'a'); + assertTrue("ByteWriter seems to have introduced data errors.", Arrays.equals(completeData, res)); + } + + public void testLongString() throws IOException { + final int length = BufferChain.BUFFERSIZE * BufferChain.MAXBUFFERS * 3; + StringBuilder b = new StringBuilder(length); + String s; + for (int i = length; i > 0; --i) { + b.append("\u00E5"); + } + s = b.toString(); + stream.reset(); + ByteWriter bw = new ByteWriter(stream, encoder); + bw.write(s); + bw.close(); + String res = stream.toString("UTF-8"); + assertEquals(s, res); + } + + public void testNoSpuriousWrite() throws IOException { + OutputStream grumpy = new CurmudgeonlyStream(); + ByteWriter bw = new ByteWriter(grumpy, encoder); + final int SINGLE_BUFFER = 500; + final int APPENDS = 500; + assertTrue("Code has been changed making constants in this test meaningless, review test.", + BufferChain.BUFFERSIZE * BufferChain.MAXBUFFERS < SINGLE_BUFFER * APPENDS); + assertTrue("Code has been changed making constants in this test meaningless, review test.", + BufferChain.WATERMARK > SINGLE_BUFFER); + stream.reset(); + byte[] c = new byte[SINGLE_BUFFER]; + for (int i = APPENDS; i > 0; --i) { + try { + bw.append(c); + } catch (IOException e) { + if (e.getMessage() == CurmudgeonlyStream.ZERO_LENGTH_WRITE) { + fail(CurmudgeonlyStream.ZERO_LENGTH_WRITE); + } else { + throw e; + } + } + } + try { + bw.close(); + } catch (IOException e) { + if (e.getMessage() == CurmudgeonlyStream.ZERO_LENGTH_WRITE) { + fail(CurmudgeonlyStream.ZERO_LENGTH_WRITE); + } else { + throw e; + } + } + } + + public void testDoubleFlush() throws IOException { + stream.reset(); + byte[] c = new byte[] { 97, 98, 99 }; + ByteWriter bw = new ByteWriter(stream, encoder); + bw.append(c); + bw.flush(); + bw.flush(); + bw.close(); + byte[] res = stream.toByteArray(); + assertTrue(Arrays.equals(new byte[] { 97, 98, 99 }, res)); + } + + public void testCharArrays() throws java.io.IOException { + stream.reset(); + char[] c = new char[] { 'a', 'b', 'c', '\u00F8' }; + ByteWriter bw = new ByteWriter(stream, encoder); + bw.write(c); + bw.close(); + byte[] res = stream.toByteArray(); + assertTrue(Arrays.equals(new byte[] { 97, 98, 99, (byte) 0xc3, (byte) 0xb8 }, res)); + } + + public void testByteBuffers() throws java.io.IOException { + stream.reset(); + ByteBuffer b = ByteBuffer.allocate(16); + b.put((byte) 97); + b.put((byte) 98); + b.put((byte) 99); + ByteWriter bw = new ByteWriter(stream, encoder); + b.flip(); + bw.append(b); + bw.close(); + byte[] res = stream.toByteArray(); + assertTrue(Arrays.equals(new byte[] { 97, 98, 99 }, res)); + } + + public void testByteArrays() throws java.io.IOException { + stream.reset(); + byte[] c = new byte[] { 97, 98, 99 }; + ByteWriter bw = new ByteWriter(stream, encoder); + bw.append(c); + bw.close(); + byte[] res = stream.toByteArray(); + assertTrue(Arrays.equals(new byte[] { 97, 98, 99 }, res)); + } + + public void testByteArrayWithOffset() throws java.io.IOException { + final int length = BufferChain.BUFFERSIZE * 3 / 2; + final int offset = 1; + final byte invalid = 3; + final byte valid = 2; + stream.reset(); + byte[] c = new byte[length]; + c[0] = invalid; + for (int i = offset; i < length; ++i) { + c[i] = valid; + } + ByteWriter bw = new ByteWriter(stream, encoder); + bw.append(c, offset, length - offset); + bw.close(); + byte[] res = stream.toByteArray(); + assertEquals(length - offset, res.length); + assertEquals(valid, res[0]); + } + + public void testStrings() throws java.io.IOException { + stream.reset(); + String c = "abc\u00F8"; + ByteWriter bw = new ByteWriter(stream, encoder); + bw.write(c); + bw.close(); + byte[] res = stream.toByteArray(); + assertTrue(Arrays.equals(new byte[] { 97, 98, 99, (byte) 0xc3, (byte) 0xb8 }, res)); + } + + public void testStringsAndByteArrays() throws java.io.IOException { + stream.reset(); + String c = "abc\u00F8"; + byte[] b = new byte[] { 97, 98, 99 }; + ByteWriter bw = new ByteWriter(stream, encoder); + bw.write(c); + bw.append(b); + bw.close(); + byte[] res = stream.toByteArray(); + assertTrue(Arrays.equals(new byte[] { 97, 98, 99, (byte) 0xc3, (byte) 0xb8, 97, 98, 99 }, res)); + } + + public void testByteBuffersAndByteArrays() throws java.io.IOException { + stream.reset(); + ByteBuffer b = ByteBuffer.allocate(16); + b.put((byte) 97); + b.put((byte) 98); + b.put((byte) 99); + b.flip(); + byte[] c = new byte[] { 100, 101, 102 }; + ByteWriter bw = new ByteWriter(stream, encoder); + bw.append(b); + bw.append(c); + bw.close(); + byte[] res = stream.toByteArray(); + assertTrue(Arrays.equals(new byte[] { 97, 98, 99, 100, 101, 102 }, res)); + } + + public void testOverFlow() throws java.io.IOException { + stream.reset(); + byte[] b = new byte[] { 97, 98, 99 }; + ByteWriter bw = new ByteWriter(stream, encoder); + int i = 0; + while (i < 5000) { + bw.append(b); + ++i; + } + bw.close(); + byte[] res = stream.toByteArray(); + assertEquals(15000, res.length); + i = 0; + int base = 0; + while (i < 5000) { + byte[] sub = new byte[3]; + System.arraycopy(res, base, sub, 0, 3); + assertTrue(Arrays.equals(new byte[] { 97, 98, 99 }, sub)); + base += 3; + ++i; + } + } + + public void testUnMappableCharacter() throws java.io.IOException { + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + ByteWriter writer = new ByteWriter(stream, Charset.forName("ascii").newEncoder()); + writer.write("yahoo\u9999bahoo"); + writer.close(); + assertTrue(stream.toString("ascii").contains("yahoo")); + assertTrue(stream.toString("ascii").contains("bahoo")); + } + + public void testNoRecycling() throws IOException { + final int SINGLE_BUFFER = 500; + final int APPENDS = 500; + assertTrue( + "Code has been changed making constants in this test meaningless, review test.", + BufferChain.BUFFERSIZE * BufferChain.MAXBUFFERS < SINGLE_BUFFER + * APPENDS); + assertTrue( + "Code has been changed making constants in this test meaningless, review test.", + BufferChain.WATERMARK > SINGLE_BUFFER); + byte[] c = new byte[SINGLE_BUFFER]; + Arrays.fill(c, (byte) 'a'); + OnlyUniqueBuffers b = new OnlyUniqueBuffers(); + try { + for (int i = APPENDS; i > 0; --i) { + b.insert(ByteBuffer.wrap(c)); + } + b.flush(); + } catch (IOException e) { + if (e.getMessage() == OnlyUniqueBuffers.RECYCLED_BYTE_BUFFER) { + fail(OnlyUniqueBuffers.RECYCLED_BYTE_BUFFER); + } else { + throw e; + } + } + } + + public void testGetEncoding() throws java.io.IOException { + stream.reset(); + ByteWriter b = new ByteWriter(stream, encoder); + assertEquals(Utf8.getCharset(), b.getEncoding()); + b.close(); + } + + public void testWriteLong() throws java.io.IOException { + stream.reset(); + ByteWriter b = new ByteWriter(stream, encoder); + b.write(1000L * 1000L * 1000L * 1000L); + b.close(); + assertArrayEquals(Utf8.toBytes("1000000000000"), stream.toByteArray()); + } + + public void testWriteInt() throws java.io.IOException { + stream.reset(); + ByteWriter b = new ByteWriter(stream, encoder); + b.write((int) 'z'); + b.close(); + assertArrayEquals(Utf8.toBytes("z"), stream.toByteArray()); + } + + public void testSurrogatePairs() throws java.io.IOException { + stream.reset(); + ByteWriter b = new ByteWriter(stream, encoder); + b.write(0xD800); + b.write(0xDFD0); + b.close(); + assertArrayEquals(Utf8.toBytes("\uD800\uDFD0"), stream.toByteArray()); + } + + public void testSurrogatePairsMixedWithSingleCharacters() throws java.io.IOException { + stream.reset(); + ByteWriter b = new ByteWriter(stream, encoder); + b.write(0x00F8); + b.write(0xD800); + b.write(0xDFD0); + b.write(0x00F8); + b.write(0xD800); + b.write((int) 'a'); + b.write(0xDFD0); + b.write((int) 'b'); + b.close(); + assertArrayEquals(Utf8.toBytes("\u00F8\uD800\uDFD0\u00F8ab"), stream.toByteArray()); + } + + + public void testWriteDouble() throws java.io.IOException { + stream.reset(); + ByteWriter b = new ByteWriter(stream, encoder); + b.write(12.0d); + b.close(); + assertArrayEquals(Utf8.toBytes("12.0"), stream.toByteArray()); + } + + public void testWriteFloat() throws java.io.IOException { + stream.reset(); + ByteWriter b = new ByteWriter(stream, encoder); + b.write(12.0f); + b.close(); + assertArrayEquals(Utf8.toBytes("12.0"), stream.toByteArray()); + } + + public void testWriteShort() throws java.io.IOException { + stream.reset(); + ByteWriter b = new ByteWriter(stream, encoder); + b.write((short) 12); + b.close(); + assertArrayEquals(Utf8.toBytes("12"), stream.toByteArray()); + } + + public void testWriteBoolean() throws java.io.IOException { + stream.reset(); + ByteWriter b = new ByteWriter(stream, encoder); + b.write(true); + b.close(); + assertArrayEquals(Utf8.toBytes("true"), stream.toByteArray()); + } + + public void testAppendSingleByte() throws java.io.IOException { + stream.reset(); + ByteWriter b = new ByteWriter(stream, encoder); + b.append((byte) 'a'); + b.close(); + assertArrayEquals(new byte[] { (byte) 'a' }, stream.toByteArray()); + } + + public void testAppended() throws IOException { + stream.reset(); + ByteWriter b = new ByteWriter(stream, encoder); + final String s = "nalle"; + b.write(s); + b.close(); + final byte[] bytes = Utf8.toBytes(s); + assertArrayEquals(bytes, stream.toByteArray()); + assertEquals(bytes.length, b.appended()); + } + + public void testWriteUtf8Array() throws IOException { + stream.reset(); + ByteWriter b = new ByteWriter(stream, encoder); + final byte[] bytes = Utf8.toBytes("nalle"); + b.write(new Utf8Array(bytes)); + b.close(); + assertArrayEquals(bytes, stream.toByteArray()); + } + + private static class OnlyUniqueBuffers implements WritableByteTransmitter { + static final String RECYCLED_BYTE_BUFFER = "Got a ByteBuffer instance twice."; + private final IdentityHashMap<ByteBuffer, ?> buffers = new IdentityHashMap<ByteBuffer, Object>(); + private final BufferChain datastore; + + public OnlyUniqueBuffers() { + datastore = new BufferChain(this); + } + + public void insert(ByteBuffer b) throws IOException { + datastore.append(b); + } + + @Override + public void send(ByteBuffer src) throws IOException { + if (buffers.containsKey(src)) { + throw new IOException(RECYCLED_BYTE_BUFFER); + } else { + buffers.put(src, null); + } + } + + public void flush() throws IOException { + datastore.flush(); + } + } +} diff --git a/vespajlib/src/test/java/com/yahoo/io/FatalErrorHandlerTestCase.java b/vespajlib/src/test/java/com/yahoo/io/FatalErrorHandlerTestCase.java new file mode 100644 index 00000000000..d4889c1fa96 --- /dev/null +++ b/vespajlib/src/test/java/com/yahoo/io/FatalErrorHandlerTestCase.java @@ -0,0 +1,55 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.io; + +import static org.junit.Assert.*; + +import java.security.Permission; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +/** + * Just to remove noise from the coverage report. + * + * @author <a href="mailto:steinar@yahoo-inc.com">Steinar Knutsen</a> + */ +public class FatalErrorHandlerTestCase { + private static final class AvoidExiting extends SecurityManager { + + @Override + public void checkPermission(Permission perm) { + } + + @Override + public void checkExit(int status) { + throw new SecurityException(); + } + + } + + private FatalErrorHandler h; + + @Before + public void setUp() throws Exception { + h = new FatalErrorHandler(); + System.setSecurityManager(new AvoidExiting()); + } + + @After + public void tearDown() throws Exception { + System.setSecurityManager(null); + } + + @Test + public final void testHandle() { + boolean caught = false; + try { + h.handle(new Throwable(), "abc"); + } catch (SecurityException e) { + caught = true; + } + assertTrue(caught); + } + +} diff --git a/vespajlib/src/test/java/com/yahoo/io/FileReadTestCase.java b/vespajlib/src/test/java/com/yahoo/io/FileReadTestCase.java new file mode 100644 index 00000000000..5ebdeeb797e --- /dev/null +++ b/vespajlib/src/test/java/com/yahoo/io/FileReadTestCase.java @@ -0,0 +1,39 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.io; + +import org.junit.Test; + +import java.io.File; +import java.io.IOException; +import java.io.StringReader; +import java.nio.charset.Charset; + + +public class FileReadTestCase extends junit.framework.TestCase { + + @Test + public void testReadByteArray() throws IOException { + byte[] thisFile = IOUtils.readFileBytes(new File("src/test/java/com/yahoo/io/FileReadTestCase.java")); + String str = new String(thisFile, Charset.forName("US-ASCII")); + assertTrue(str.startsWith("// Copyright 2016 Yahoo Inc.")); + assertTrue(str.endsWith("// Yeppers\n")); + } + + @Test + public void testReadString() throws IOException { + String str = IOUtils.readFile(new File("src/test/java/com/yahoo/io/FileReadTestCase.java")); + assertTrue(str.startsWith("// Copyright 2016 Yahoo Inc.")); + assertTrue(str.endsWith("// Yeppers\n")); + } + + @Test + public void testReadAllFromReader() throws IOException { + assertEquals(IOUtils.readAll(new StringReader("")), ""); + assertEquals(IOUtils.readAll(new StringReader("hei")), "hei"); + assertEquals(IOUtils.readAll(new StringReader("hei\nhaa")), "hei\nhaa"); + assertEquals(IOUtils.readAll(new StringReader("hei\nhaa\n")), "hei\nhaa\n"); + } + +} + +// Yeppers diff --git a/vespajlib/src/test/java/com/yahoo/io/GrowableBufferOutputStreamTestCase.java b/vespajlib/src/test/java/com/yahoo/io/GrowableBufferOutputStreamTestCase.java new file mode 100644 index 00000000000..71568a3cfbc --- /dev/null +++ b/vespajlib/src/test/java/com/yahoo/io/GrowableBufferOutputStreamTestCase.java @@ -0,0 +1,126 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.io; + +import java.nio.channels.WritableByteChannel; +import java.nio.ByteBuffer; +import java.io.IOException; +import com.yahoo.io.GrowableBufferOutputStream; + + +/** + * Tests the GrowableBufferOutputStream + * + * @author <a href="mailto:borud@yahoo-inc.com">Bjorn Borud</a> + */ +public class GrowableBufferOutputStreamTestCase extends junit.framework.TestCase { + private byte[] testData; + + static class DummyWritableByteChannel implements WritableByteChannel { + private ByteBuffer buffer; + + public DummyWritableByteChannel(ByteBuffer buffer) { + this.buffer = buffer; + } + + public int write(ByteBuffer src) throws IOException { + int written = Math.min(src.remaining(), buffer.remaining()); + + if (buffer.remaining() < src.remaining()) { + ByteBuffer tmp = src.slice(); + + tmp.limit(written); + src.position(src.position() + written); + } else { + buffer.put(src); + } + return written; + } + + public boolean isOpen() { + return true; + } + + public void close() throws IOException {} + } + + public GrowableBufferOutputStreamTestCase(String name) { + super(name); + } + + public void setUp() { + testData = new byte[100]; + for (int i = 0; i < 100; ++i) { + testData[i] = (byte) i; + } + } + + public void testSimple() throws IOException { + GrowableBufferOutputStream g = new GrowableBufferOutputStream(10, 5); + + g.write(testData, 0, 100); + g.flush(); + assertEquals(10, g.numWritableBuffers()); + assertEquals(100, g.writableSize()); + + ByteBuffer sink = ByteBuffer.allocate(60); + DummyWritableByteChannel channel = new DummyWritableByteChannel(sink); + int written = g.channelWrite(channel); + + assertEquals(60, written); + assertEquals(60, sink.position()); + assertEquals(40, g.writableSize()); + + // there should be 4 buffers left now + assertEquals(4, g.numWritableBuffers()); + + // ensure that we got what we expected + for (int i = 0; i < 60; ++i) { + if (((int) sink.get(i)) != i) { + fail(); + } + } + + // then we write more data + g.write(testData, 0, 100); + g.flush(); + assertEquals(140, g.writableSize()); + + // ...which implies that we should now have 14 writable buffers + assertEquals(14, g.numWritableBuffers()); + + // reset the sink so it can consume more data + sink.clear(); + + // then write more to the DummyWritableByteChannel + written = g.channelWrite(channel); + assertEquals(60, written); + assertEquals(60, sink.position()); + assertEquals(80, g.writableSize()); + + // now there should be 8 buffers + assertEquals(8, g.numWritableBuffers()); + + // ensure that we got what we expected + for (int i = 0; i < 60; ++i) { + int val = (int) sink.get(i); + int expected = (i + 60) % 100; + + if (val != expected) { + fail("Value was " + val + " and not " + i); + } + } + + // when we clear there should be no buffers + g.clear(); + assertEquals(0, g.numWritableBuffers()); + assertEquals(0, g.writableSize()); + + // ditto after flush after clear + g.flush(); + assertEquals(0, g.numWritableBuffers()); + + // flush the cache too + g.clearAll(); + assertEquals(0, g.numWritableBuffers()); + } +} diff --git a/vespajlib/src/test/java/com/yahoo/io/GrowableByteBufferTestCase.java b/vespajlib/src/test/java/com/yahoo/io/GrowableByteBufferTestCase.java new file mode 100644 index 00000000000..ffc3d6dfe64 --- /dev/null +++ b/vespajlib/src/test/java/com/yahoo/io/GrowableByteBufferTestCase.java @@ -0,0 +1,756 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.io; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.InvalidMarkException; +import java.nio.ReadOnlyBufferException; +import java.util.Arrays; + +import static org.junit.Assert.assertArrayEquals;; + +/** + * Tests GrowableByteBuffer. + * + * @author <a href="mailto:einarmr@yahoo-inc.com">Einar M R Rosenvinge</a> + */ +public class GrowableByteBufferTestCase extends junit.framework.TestCase { + public void testBuffer() { + GrowableByteBuffer buf = new GrowableByteBuffer(20, 1.5f); + + buf.putChar((char) 5); + assertEquals(2, buf.position()); + + buf.putDouble(983.982d); + assertEquals(10, buf.position()); + + buf.putFloat(94.322f); + assertEquals(14, buf.position()); + + buf.putInt(98); + assertEquals(18, buf.position()); + + assertEquals(20, buf.capacity()); + + buf.putLong(983L); + assertEquals(26, buf.position()); + + // Adding fudge factors and other fun to the growth rate, + // makes capacity() suboptimal to test, so this should perhaps + // be removed + // TODO: Better test of growth rate + assertEquals(130, buf.capacity()); + + buf.putShort((short) 4); + assertEquals(28, buf.position()); + + + buf.position(0); + assertEquals((char) 5, buf.getChar()); + assertEquals(2, buf.position()); + + assertEquals((int) (983.982d * 1000d), (int) (buf.getDouble() * 1000d)); + assertEquals(10, buf.position()); + + assertEquals((int) (94.322f * 1000f), (int) (buf.getFloat() * 1000f)); + assertEquals(14, buf.position()); + + assertEquals(98, buf.getInt()); + assertEquals(18, buf.position()); + + assertEquals(983L, buf.getLong()); + assertEquals(26, buf.position()); + + assertEquals((short) 4, buf.getShort()); + assertEquals(28, buf.position()); + + + byte[] twoBytes = new byte[2]; + buf.put(twoBytes); + assertEquals(30, buf.position()); + assertEquals(130, buf.capacity()); + + buf.put((byte) 1); + assertEquals(31, buf.position()); + assertEquals(130, buf.capacity()); + + ByteBuffer tmpBuf = ByteBuffer.allocate(15); + tmpBuf.putInt(56); + tmpBuf.position(0); + buf.put(tmpBuf); + assertEquals(46, buf.position()); + assertEquals(130, buf.capacity()); + } + + public void testGrowth() { + GrowableByteBuffer buf = new GrowableByteBuffer(256, 2.0f); + + //add bytes almost to the boundary + for (int i = 0; i < 255; i++) { + buf.put((byte) 0); + } + + //We are just before the boundary now. + assertEquals(255, buf.position()); + assertEquals(256, buf.capacity()); + assertEquals(256, buf.limit()); + + //Test adding one more byte. + buf.put((byte) 0); + //The buffer is full. + assertEquals(256, buf.position()); + assertEquals(256, buf.capacity()); + assertEquals(256, buf.limit()); + + //Adding one more byte should make it grow. + buf.put((byte) 0); + assertEquals(257, buf.position()); + assertEquals(612, buf.capacity()); + assertEquals(612, buf.limit()); + + //add a buffer exactly to the boundary + byte[] bytes = new byte[355]; + buf.put(bytes); + assertEquals(612, buf.position()); + assertEquals(612, buf.capacity()); + assertEquals(612, buf.limit()); + + //adding a one-byte buffer should make it grow again + byte[] oneByteBuf = new byte[1]; + buf.put(oneByteBuf); + assertEquals(613, buf.position()); + assertEquals(1324, buf.capacity()); + assertEquals(1324, buf.limit()); + + //add a large buffer that goes waaay past the boundary and makes it grow yet again, + //but that is not enough + byte[] largeBuf = new byte[3000]; + buf.put(largeBuf); + //the buffer should be doubled twice now + assertEquals(3613, buf.position()); + assertEquals(5596, buf.capacity()); + assertEquals(5596, buf.limit()); + + //let's try that again, and make the buffer double three times + byte[] veryLargeBuf = new byte[20000]; + buf.put(veryLargeBuf); + //the buffer should be doubled three times now + assertEquals(23613, buf.position()); + assertEquals(45468, buf.capacity()); + assertEquals(45468, buf.limit()); + } + + public void testBadGrowthFactors() { + try { + new GrowableByteBuffer(100, 1.0f); + assertTrue(false); + } catch (IllegalArgumentException iae) { + //we're OK + } + GrowableByteBuffer buf = new GrowableByteBuffer(16, 1.0000001f); + buf.putInt(1); + assertEquals(16, buf.capacity()); + buf.putInt(1); + assertEquals(16, buf.capacity()); + buf.putInt(1); + assertEquals(16, buf.capacity()); + buf.putInt(1); + assertEquals(16, buf.capacity()); + + buf.putInt(1); + assertEquals(116, buf.capacity()); + + } + + public void testPropertiesNonDirect() { + GrowableByteBuffer buf = new GrowableByteBuffer(10, 1.5f); + buf.order(ByteOrder.LITTLE_ENDIAN); + + assertEquals(0, buf.position()); + // GrowableByteBuffer never makes a buffer smaller than 16 bytes + assertEquals(16, buf.capacity()); + assertEquals(16, buf.limit()); + assertEquals(false, buf.isReadOnly()); + assertEquals(ByteOrder.LITTLE_ENDIAN, buf.order()); + assertEquals(false, buf.isDirect()); + + buf.put(new byte[17]); + + assertEquals(17, buf.position()); + assertEquals(124, buf.capacity()); + assertEquals(124, buf.limit()); + assertEquals(false, buf.isReadOnly()); + assertEquals(ByteOrder.LITTLE_ENDIAN, buf.order()); + assertEquals(false, buf.isDirect()); + } + + public void testPropertiesDirect() { + // allocate* are simply encapsulated, so don't add logic to them, + // therefore minimum size becomes what it says + GrowableByteBuffer buf = GrowableByteBuffer.allocateDirect(10, 1.5f); + buf.order(ByteOrder.LITTLE_ENDIAN); + + assertEquals(0, buf.position()); + assertEquals(10, buf.capacity()); + assertEquals(10, buf.limit()); + assertEquals(false, buf.isReadOnly()); + assertEquals(ByteOrder.LITTLE_ENDIAN, buf.order()); + assertEquals(true, buf.isDirect()); + + buf.put(new byte[11]); + + assertEquals(11, buf.position()); + assertEquals(115, buf.capacity()); + assertEquals(115, buf.limit()); + assertEquals(false, buf.isReadOnly()); + assertEquals(ByteOrder.LITTLE_ENDIAN, buf.order()); + assertEquals(true, buf.isDirect()); + } + + public void testNumberEncodings() { + GrowableByteBuffer buf = new GrowableByteBuffer(); + buf.putInt1_2_4Bytes(124); + buf.putInt2_4_8Bytes(124); + buf.putInt1_4Bytes(124); + + buf.putInt1_2_4Bytes(127); + buf.putInt2_4_8Bytes(127); + buf.putInt1_4Bytes(127); + + buf.putInt1_2_4Bytes(128); + buf.putInt2_4_8Bytes(128); + buf.putInt1_4Bytes(128); + + buf.putInt1_2_4Bytes(255); + buf.putInt2_4_8Bytes(255); + buf.putInt1_4Bytes(255); + + buf.putInt1_2_4Bytes(256); + buf.putInt2_4_8Bytes(256); + buf.putInt1_4Bytes(256); + + buf.putInt1_2_4Bytes(0); + buf.putInt2_4_8Bytes(0); + buf.putInt1_4Bytes(0); + + buf.putInt1_2_4Bytes(1); + buf.putInt2_4_8Bytes(1); + buf.putInt1_4Bytes(1); + + try { + buf.putInt1_2_4Bytes(Integer.MAX_VALUE); + fail("Should have gotten exception here..."); + } catch (Exception e) { } + buf.putInt2_4_8Bytes(Integer.MAX_VALUE); + buf.putInt1_4Bytes(Integer.MAX_VALUE); + + try { + buf.putInt2_4_8Bytes(Long.MAX_VALUE); + fail("Should have gotten exception here..."); + } catch (Exception e) { } + + buf.putInt1_2_4Bytes(Short.MAX_VALUE); + buf.putInt2_4_8Bytes(Short.MAX_VALUE); + buf.putInt1_4Bytes(Short.MAX_VALUE); + + buf.putInt1_2_4Bytes(Byte.MAX_VALUE); + buf.putInt2_4_8Bytes(Byte.MAX_VALUE); + buf.putInt1_4Bytes(Byte.MAX_VALUE); + + try { + buf.putInt1_2_4Bytes(-1); + fail("Should have gotten exception here..."); + } catch (Exception e) { } + try { + buf.putInt2_4_8Bytes(-1); + fail("Should have gotten exception here..."); + } catch (Exception e) { } + try { + buf.putInt1_4Bytes(-1); + fail("Should have gotten exception here..."); + } catch (Exception e) { } + + try { + buf.putInt1_2_4Bytes(Integer.MIN_VALUE); + fail("Should have gotten exception here..."); + } catch (Exception e) { } + try { + buf.putInt2_4_8Bytes(Integer.MIN_VALUE); + fail("Should have gotten exception here..."); + } catch (Exception e) { } + try { + buf.putInt1_4Bytes(Integer.MIN_VALUE); + fail("Should have gotten exception here..."); + } catch (Exception e) { } + + try { + buf.putInt2_4_8Bytes(Long.MIN_VALUE); + fail("Should have gotten exception here..."); + } catch (Exception e) { } + + int endWritePos = buf.position(); + buf.position(0); + + assertEquals(124, buf.getInt1_2_4Bytes()); + assertEquals(124, buf.getInt2_4_8Bytes()); + assertEquals(124, buf.getInt1_4Bytes()); + + assertEquals(127, buf.getInt1_2_4Bytes()); + assertEquals(127, buf.getInt2_4_8Bytes()); + assertEquals(127, buf.getInt1_4Bytes()); + + assertEquals(128, buf.getInt1_2_4Bytes()); + assertEquals(128, buf.getInt2_4_8Bytes()); + assertEquals(128, buf.getInt1_4Bytes()); + + assertEquals(255, buf.getInt1_2_4Bytes()); + assertEquals(255, buf.getInt2_4_8Bytes()); + assertEquals(255, buf.getInt1_4Bytes()); + + assertEquals(256, buf.getInt1_2_4Bytes()); + assertEquals(256, buf.getInt2_4_8Bytes()); + assertEquals(256, buf.getInt1_4Bytes()); + + assertEquals(0, buf.getInt1_2_4Bytes()); + assertEquals(0, buf.getInt2_4_8Bytes()); + assertEquals(0, buf.getInt1_4Bytes()); + + assertEquals(1, buf.getInt1_2_4Bytes()); + assertEquals(1, buf.getInt2_4_8Bytes()); + assertEquals(1, buf.getInt1_4Bytes()); + + assertEquals(Integer.MAX_VALUE, buf.getInt2_4_8Bytes()); + assertEquals(Integer.MAX_VALUE, buf.getInt1_4Bytes()); + + assertEquals(Short.MAX_VALUE, buf.getInt1_2_4Bytes()); + assertEquals(Short.MAX_VALUE, buf.getInt2_4_8Bytes()); + assertEquals(Short.MAX_VALUE, buf.getInt1_4Bytes()); + + assertEquals(Byte.MAX_VALUE, buf.getInt1_2_4Bytes()); + assertEquals(Byte.MAX_VALUE, buf.getInt2_4_8Bytes()); + assertEquals(Byte.MAX_VALUE, buf.getInt1_4Bytes()); + + int endReadPos = buf.position(); + + assertEquals(endWritePos, endReadPos); + } + public void testNumberLengths() { + assertEquals(1, GrowableByteBuffer.getSerializedSize1_4Bytes(0)); + assertEquals(1, GrowableByteBuffer.getSerializedSize1_4Bytes(1)); + assertEquals(1, GrowableByteBuffer.getSerializedSize1_4Bytes(4)); + assertEquals(1, GrowableByteBuffer.getSerializedSize1_4Bytes(31)); + assertEquals(1, GrowableByteBuffer.getSerializedSize1_4Bytes(126)); + assertEquals(1, GrowableByteBuffer.getSerializedSize1_4Bytes(127)); + assertEquals(4, GrowableByteBuffer.getSerializedSize1_4Bytes(128)); + assertEquals(4, GrowableByteBuffer.getSerializedSize1_4Bytes(129)); + assertEquals(4, GrowableByteBuffer.getSerializedSize1_4Bytes(255)); + assertEquals(4, GrowableByteBuffer.getSerializedSize1_4Bytes(256)); + assertEquals(4, GrowableByteBuffer.getSerializedSize1_4Bytes(0x7FFFFFFF)); + + assertEquals(2, GrowableByteBuffer.getSerializedSize2_4_8Bytes(0)); + assertEquals(2, GrowableByteBuffer.getSerializedSize2_4_8Bytes(1)); + assertEquals(2, GrowableByteBuffer.getSerializedSize2_4_8Bytes(4)); + assertEquals(2, GrowableByteBuffer.getSerializedSize2_4_8Bytes(31)); + assertEquals(2, GrowableByteBuffer.getSerializedSize2_4_8Bytes(126)); + assertEquals(2, GrowableByteBuffer.getSerializedSize2_4_8Bytes(127)); + assertEquals(2, GrowableByteBuffer.getSerializedSize2_4_8Bytes(128)); + assertEquals(2, GrowableByteBuffer.getSerializedSize2_4_8Bytes(32767)); + assertEquals(4, GrowableByteBuffer.getSerializedSize2_4_8Bytes(32768)); + assertEquals(4, GrowableByteBuffer.getSerializedSize2_4_8Bytes(32769)); + assertEquals(4, GrowableByteBuffer.getSerializedSize2_4_8Bytes(1030493)); + assertEquals(4, GrowableByteBuffer.getSerializedSize2_4_8Bytes(0x3FFFFFFF)); + assertEquals(8, GrowableByteBuffer.getSerializedSize2_4_8Bytes(0x40000000)); + assertEquals(8, GrowableByteBuffer.getSerializedSize2_4_8Bytes(0x40000001)); + + assertEquals(1, GrowableByteBuffer.getSerializedSize1_2_4Bytes(0)); + assertEquals(1, GrowableByteBuffer.getSerializedSize1_2_4Bytes(1)); + assertEquals(1, GrowableByteBuffer.getSerializedSize1_2_4Bytes(4)); + assertEquals(1, GrowableByteBuffer.getSerializedSize1_2_4Bytes(31)); + assertEquals(1, GrowableByteBuffer.getSerializedSize1_2_4Bytes(126)); + assertEquals(1, GrowableByteBuffer.getSerializedSize1_2_4Bytes(127)); + assertEquals(2, GrowableByteBuffer.getSerializedSize1_2_4Bytes(128)); + assertEquals(2, GrowableByteBuffer.getSerializedSize1_2_4Bytes(16383)); + assertEquals(4, GrowableByteBuffer.getSerializedSize1_2_4Bytes(16384)); + assertEquals(4, GrowableByteBuffer.getSerializedSize1_2_4Bytes(16385)); + } + + public void testSize0() { + GrowableByteBuffer buf = new GrowableByteBuffer(0, 2.0f); + buf.put((byte) 1); + buf.put((byte) 1); + } + + public void testExceptionSafety() { + GrowableByteBuffer g = new GrowableByteBuffer(32); + ByteBuffer b = ByteBuffer.allocate(232); + for (int i = 0; i < 232; ++i) { + b.put((byte) 32); + } + b.flip(); + g.put(b); + b.flip(); + g.put(b); + assertEquals(464, g.position()); + g.flip(); + for (int i = 0; i < 464; ++i) { + assertEquals(32, (int) g.get()); + } + } + + public void testGrowthFactorAccessor() { + GrowableByteBuffer g = new GrowableByteBuffer(32); + assertEquals(GrowableByteBuffer.DEFAULT_GROW_FACTOR, g.getGrowFactor()); + } + + public void testGrowthWithNonZeroMark() { + GrowableByteBuffer g = new GrowableByteBuffer(32); + final int mark = 16; + byte[] stuff = new byte[mark]; + Arrays.fill(stuff, (byte) 37); + g.put(stuff); + g.mark(); + stuff = new byte[637]; + Arrays.fill(stuff, (byte) 38); + g.put(stuff); + assertEquals(mark, g.getByteBuffer().reset().position()); + } + + public void testPutInt2_4_8BytesMore() { + GrowableByteBuffer g = new GrowableByteBuffer(32); + g.putInt2_4_8Bytes(0x9000); + assertEquals(4, g.position()); + } + + public void testPutInt2_4_8BytesAs4() { + GrowableByteBuffer g = new GrowableByteBuffer(32); + boolean caught = false; + try { + g.putInt2_4_8BytesAs4(-1); + } catch (IllegalArgumentException e) { + caught = true; + } + assertTrue(caught); + caught = false; + try { + g.putInt2_4_8BytesAs4(1L << 37); + } catch (IllegalArgumentException e) { + caught = true; + } + assertTrue(caught); + g.putInt2_4_8BytesAs4(37); + assertEquals(4, g.position()); + } + + public void testGetInt2_4_8Bytes() { + GrowableByteBuffer g = new GrowableByteBuffer(32); + final long expected3 = 37L; + g.putInt2_4_8Bytes(expected3); + final long expected2 = 0x9000L; + g.putInt2_4_8Bytes(expected2); + final long expected = 1L << 56; + g.putInt2_4_8Bytes(expected); + g.flip(); + assertEquals(expected3, g.getInt2_4_8Bytes()); + assertEquals(expected2, g.getInt2_4_8Bytes()); + assertEquals(expected, g.getInt2_4_8Bytes()); + } + + public void testSerializedSize2_4_8BytesIllegalValues() { + boolean caught = false; + try { + GrowableByteBuffer.getSerializedSize2_4_8Bytes(-1); + } catch (IllegalArgumentException e) { + caught = true; + } + assertTrue(caught); + caught = false; + try { + GrowableByteBuffer.getSerializedSize2_4_8Bytes((1L << 62) + 1L); + } catch (IllegalArgumentException e) { + caught = true; + } + assertTrue(caught); + } + + public void testPutInt1_2_4BytesAs4IllegalValues() { + GrowableByteBuffer g = new GrowableByteBuffer(32); + boolean caught = false; + try { + g.putInt1_2_4BytesAs4(-1); + } catch (IllegalArgumentException e) { + caught = true; + } + assertTrue(caught); + caught = false; + try { + g.putInt1_2_4BytesAs4((1 << 30) + 1); + } catch (IllegalArgumentException e) { + caught = true; + } + assertTrue(caught); + } + + public void testSerializedSize1_2_4BytesIllegalValues() { + boolean caught = false; + try { + GrowableByteBuffer.getSerializedSize1_2_4Bytes(-1); + } catch (IllegalArgumentException e) { + caught = true; + } + assertTrue(caught); + caught = false; + try { + GrowableByteBuffer.getSerializedSize1_2_4Bytes((1 << 30) + 1); + } catch (IllegalArgumentException e) { + caught = true; + } + assertTrue(caught); + } + + public void testPutInt1_4BytesAs4() { + GrowableByteBuffer g = new GrowableByteBuffer(32); + boolean caught = false; + try { + g.putInt1_4BytesAs4(-1); + } catch (IllegalArgumentException e) { + caught = true; + } + assertTrue(caught); + g.putInt1_4BytesAs4(37); + assertEquals(4, g.position()); + } + + public void testSerializedSize1_4BytesIllegalValues() { + boolean caught = false; + try { + GrowableByteBuffer.getSerializedSize1_4Bytes(-1); + } catch (IllegalArgumentException e) { + caught = true; + } + assertTrue(caught); + } + + public void testBuilders() { + GrowableByteBuffer g = GrowableByteBuffer.allocate(1063); + assertEquals(1063, g.capacity()); + g = GrowableByteBuffer.allocate(1063, 37.0f); + assertEquals(1063, g.capacity()); + assertEquals(37.0f, g.getGrowFactor()); + g = GrowableByteBuffer.allocateDirect(1063); + assertTrue(g.isDirect()); + } + + public void testForwarding() { + GrowableByteBuffer g = new GrowableByteBuffer(1063); + int first = g.arrayOffset(); + g.put(0, (byte) 37); + assertTrue(g.hasArray()); + assertEquals((byte) 37, g.array()[first]); + g.putChar(0, 'a'); + assertEquals('a', g.getChar(0)); + assertEquals('a', g.asCharBuffer().get(0)); + g.putDouble(0, 10.0d); + assertEquals(10.0d, g.getDouble(0)); + assertEquals(10.0d, g.asDoubleBuffer().get(0)); + g.putFloat(0, 10.0f); + assertEquals(10.0f, g.getFloat(0)); + assertEquals(10.0f, g.asFloatBuffer().get(0)); + g.putInt(0, 10); + assertEquals(10, g.getInt(0)); + assertEquals(10, g.asIntBuffer().get(0)); + g.putLong(0, 10L); + assertEquals(10L, g.getLong(0)); + assertEquals(10L, g.asLongBuffer().get(0)); + boolean caught = false; + try { + g.asReadOnlyBuffer().put((byte) 10); + } catch (ReadOnlyBufferException e) { + caught = true; + } + assertTrue(caught); + g.putShort(0, (short) 10); + assertEquals((short) 10, g.getShort(0)); + assertEquals((short) 10, g.asShortBuffer().get(0)); + g.position(0); + g.put((byte) 0); + g.put((byte) 10); + g.limit(2); + g.position(1); + g.compact(); + assertEquals((byte) 10, g.get(0)); + } + + public void testComparison() { + GrowableByteBuffer g0 = new GrowableByteBuffer(32); + GrowableByteBuffer g1 = new GrowableByteBuffer(32); + assertEquals(g0.hashCode(), g1.hashCode()); + assertFalse(g0.equals(Integer.valueOf(12))); + assertFalse(g0.hashCode() == new GrowableByteBuffer(1063).hashCode()); + assertTrue(g0.equals(g1)); + assertEquals(0, g0.compareTo(g1)); + g0.put((byte) 9); + assertFalse(g0.equals(g1)); + assertEquals(-1, g0.compareTo(g1)); + } + + public void testDuplicate() { + GrowableByteBuffer g0 = new GrowableByteBuffer(32); + GrowableByteBuffer g1 = g0.duplicate(); + g0.put((byte) 12); + assertEquals(12, g1.get()); + } + + public void testGetByteArrayOffsetLen() { + GrowableByteBuffer g = new GrowableByteBuffer(32); + byte[] expected = new byte[] { (byte) 1, (byte) 2, (byte) 3 }; + for (int i = 0; i < expected.length; ++i) { + g.put(expected[i]); + } + byte[] got = new byte[3]; + g.flip(); + g.get(got, 0, got.length); + assertArrayEquals(expected, got); + } + + public void testPutByteArrayOffsetLen() { + GrowableByteBuffer g = new GrowableByteBuffer(32); + byte[] expected = new byte[] { (byte) 1, (byte) 2, (byte) 3 }; + g.put(expected, 0, expected.length); + byte[] got = new byte[3]; + g.flip(); + g.get(got, 0, got.length); + assertArrayEquals(expected, got); + } + + public void testPutGrowableBuffer() { + GrowableByteBuffer g0 = new GrowableByteBuffer(32); + byte[] expected = new byte[] { (byte) 1, (byte) 2, (byte) 3 }; + GrowableByteBuffer g1 = new GrowableByteBuffer(32); + g0.put(expected, 0, expected.length); + byte[] got = new byte[3]; + g0.flip(); + g1.put(g0); + g1.flip(); + g1.get(got, 0, got.length); + assertArrayEquals(expected, got); + } + + private GrowableByteBuffer fullBuffer() { + GrowableByteBuffer g = new GrowableByteBuffer(32); + byte[] stuffer = new byte[g.remaining()]; + Arrays.fill(stuffer, (byte) 'a'); + g.put(stuffer); + return g; + } + + public void testPutWithGrow() { + GrowableByteBuffer g = fullBuffer(); + final int capacity = g.capacity(); + byte[] b = new byte[] { (byte) 'b' }; + g.put(b, 0, b.length); + assertTrue(capacity < g.capacity()); + + g = fullBuffer(); + GrowableByteBuffer toPut = fullBuffer(); + toPut.flip(); + g.put(toPut); + + assertTrue(capacity < g.capacity()); + g = fullBuffer(); + g.put(g.position(), (byte) 'b'); + assertTrue(capacity < g.capacity()); + + g = fullBuffer(); + g.putChar('b'); + assertTrue(capacity < g.capacity()); + g = fullBuffer(); + g.putChar(g.position(), 'b'); + assertTrue(capacity < g.capacity()); + + g = fullBuffer(); + g.putDouble(1.0d); + assertTrue(capacity < g.capacity()); + g = fullBuffer(); + g.putDouble(g.position(), 1.0d); + assertTrue(capacity < g.capacity()); + + g = fullBuffer(); + g.putFloat(1.0f); + assertTrue(capacity < g.capacity()); + g = fullBuffer(); + g.putFloat(g.position(), 1.0f); + assertTrue(capacity < g.capacity()); + + g = fullBuffer(); + g.putInt(g.position(), 1); + assertTrue(capacity < g.capacity()); + + g = fullBuffer(); + g.putLong(g.position(), 1L); + assertTrue(capacity < g.capacity()); + + g = fullBuffer(); + g.putShort((short) 1); + assertTrue(capacity < g.capacity()); + g = fullBuffer(); + g.putShort(g.position(), (short) 1); + assertTrue(capacity < g.capacity()); + } + + public void testSlice() { + GrowableByteBuffer g0 = new GrowableByteBuffer(32); + GrowableByteBuffer g1 = g0.slice(); + final int expected = 37; + g0.putInt(expected); + assertEquals(expected, g1.getInt()); + } + + public void testToString() { + assertEquals("GrowableByteBuffer[pos=32 lim=32 cap=32 grow=2.0]", + fullBuffer().toString()); + } + + public void testWrappers() { + final byte expected = (byte) 2; + byte[] data = new byte[] { (byte) 1, expected, (byte) 3 }; + final float grow = 9e5f; + GrowableByteBuffer g = GrowableByteBuffer.wrap(data, grow); + assertEquals(expected, g.get(1)); + assertEquals(grow, g.getGrowFactor()); + g = GrowableByteBuffer.wrap(data, 1, 1); + assertEquals(expected, g.get()); + assertEquals(2, g.limit()); + g = GrowableByteBuffer.wrap(data, 1, 1, grow); + assertEquals(expected, g.get()); + assertEquals(2, g.limit()); + assertEquals(grow, g.getGrowFactor()); + } + + public void testByteBufferMethods() { + GrowableByteBuffer g = fullBuffer(); + assertFalse(g.hasRemaining()); + g.clear(); + assertTrue(g.hasRemaining()); + g = fullBuffer(); + g.mark(); + g.limit(16); + boolean caught = false; + try { + g.reset(); + } catch (InvalidMarkException e) { + caught = true; + } + assertTrue(caught); + caught = false; + g = fullBuffer(); + g.mark(); + g.position(16); + try { + g.reset(); + } catch (InvalidMarkException e) { + caught = true; + } + assertTrue(caught); + } + +} diff --git a/vespajlib/src/test/java/com/yahoo/io/HexDumpTestCase.java b/vespajlib/src/test/java/com/yahoo/io/HexDumpTestCase.java new file mode 100644 index 00000000000..940f0150540 --- /dev/null +++ b/vespajlib/src/test/java/com/yahoo/io/HexDumpTestCase.java @@ -0,0 +1,40 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.io; + +import org.junit.Test; + +import com.yahoo.text.Utf8; + +import java.io.ByteArrayOutputStream; +import java.io.PrintStream; +import java.io.UnsupportedEncodingException; +import java.nio.ByteBuffer; +import java.nio.charset.Charset; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; + +/** + * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen Hult</a> + * @author <a href="mailto:steinar@yahoo-inc.com">Steinar Knutsen</a> + */ +public class HexDumpTestCase { + + private static final Charset UTF8 = Charset.forName("UTF-8"); + private static final Charset UTF16 = Charset.forName("UTF-16"); + + @Test + public void requireThatToHexStringAcceptsNull() { + assertNull(HexDump.toHexString(null)); + } + + @Test + public void requireThatToHexStringIsUnformatted() { + assertEquals("6162636465666768696A6B6C6D6E6F707172737475767778797A", + HexDump.toHexString("abcdefghijklmnopqrstuvwxyz".getBytes(UTF8))); + assertEquals("FEFF006100620063006400650066006700680069006A006B006C00" + + "6D006E006F0070007100720073007400750076007700780079007A", + HexDump.toHexString("abcdefghijklmnopqrstuvwxyz".getBytes(UTF16))); + } + +} diff --git a/vespajlib/src/test/java/com/yahoo/io/IOUtilsTestCase.java b/vespajlib/src/test/java/com/yahoo/io/IOUtilsTestCase.java new file mode 100644 index 00000000000..7f89cccc6c8 --- /dev/null +++ b/vespajlib/src/test/java/com/yahoo/io/IOUtilsTestCase.java @@ -0,0 +1,149 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.io; + +import java.io.*; +import java.util.Arrays; +import java.util.List; + +/** + * @author <a href="mailto:bratseth@yahoo-inc.com">Jon Bratseth</a> + */ +public class IOUtilsTestCase extends junit.framework.TestCase { + + public void testCloseNUllDoesNotFail() { + IOUtils.closeWriter(null); + IOUtils.closeReader(null); + IOUtils.closeInputStream(null); + IOUtils.closeOutputStream(null); + } + + public void testFileWriter() throws IOException { + IOUtils.writeFile("temp1.txt", "hello",false); + assertEquals("hello", IOUtils.readFile(new File("temp1.txt"))); + new File("temp1.txt").delete(); + } + + public void testFileWriterWithoutEncoding() throws IOException { + BufferedWriter writer=null; + try { + writer=IOUtils.createWriter(new File("temp2.txt"),false); + writer.write("hello"); + } + finally { + IOUtils.closeWriter(writer); + } + assertEquals("hello", IOUtils.readFile(new File("temp2.txt"))); + new File("temp2.txt").delete(); + } + + public void testFileWriterWithoutEncodingFromFileName() throws IOException { + BufferedWriter writer=null; + try { + writer=IOUtils.createWriter("temp3.txt",false); + writer.write("hello"); + } + finally { + IOUtils.closeWriter(writer); + } + assertEquals("hello",IOUtils.readFile(new File("temp3.txt"))); + new File("temp3.txt").delete(); + } + + public void testFileCounting() throws IOException { + IOUtils.writeFile("temp4.txt","hello\nworld",false); + assertEquals(2,IOUtils.countLines("temp4.txt")); + new File("temp4.txt").delete(); + } + + public void testFileCopy() throws IOException { + IOUtils.writeFile("temp5.txt","hello",false); + IOUtils.copy(new File("temp5.txt"), new File("temp5copy.txt")); + assertEquals("hello", IOUtils.readFile(new File("temp5copy.txt"))); + new File("temp5.txt").delete(); + new File("temp5copy.txt").delete(); + } + + public void testFileCopyWithLineCap() throws IOException { + IOUtils.writeFile("temp6.txt","hello\nyou\nworld",false); + IOUtils.copy("temp6.txt","temp6copy.txt",2); + assertEquals("hello\nyou\n", IOUtils.readFile(new File("temp6copy.txt"))); + new File("temp6.txt").delete(); + new File("temp6copy.txt").delete(); + } + + public void testGetLines() throws IOException { + IOUtils.writeFile("temp7.txt","hello\nworld",false); + List<String> lines=IOUtils.getLines("temp7.txt"); + assertEquals(2,lines.size()); + assertEquals("hello",lines.get(0)); + assertEquals("world",lines.get(1)); + new File("temp7.txt").delete(); + } + + public void testFileWriterAppend() throws IOException { + boolean append=true; + IOUtils.writeFile("temp8.txt", "hello",!append); + BufferedWriter writer=null; + try { + writer=IOUtils.createWriter(new File("temp8.txt"),append); + writer.write("\nworld"); + } + finally { + IOUtils.closeWriter(writer); + } + assertEquals("hello\nworld", IOUtils.readFile(new File("temp8.txt"))); + new File("temp8.txt").delete(); + } + + public void testCloseAllReaders() throws IOException { + StringReader reader1=new StringReader("hello"); + StringReader reader2=new StringReader("world"); + IOUtils.closeAll(Arrays.<Reader>asList(reader1, reader2)); + try { + reader1.ready(); + fail("Expected exception due to reader closed"); + } + catch (IOException e) { + // Expected + } + try { + reader2.ready(); + fail("Expected exception due to reader closed"); + } + catch (IOException e) { + // Expected + } + } + + public void testDirCopying() throws IOException { + IOUtils.writeFile("temp1/temp1.txt","hello",false); + IOUtils.writeFile("temp1/temp2.txt","world",false); + IOUtils.copyDirectory(new File("temp1"), new File("temp2")); + assertEquals("hello", IOUtils.readFile(new File("temp2/temp1.txt"))); + assertEquals("world", IOUtils.readFile(new File("temp2/temp2.txt"))); + IOUtils.recursiveDeleteDir(new File("temp1")); + IOUtils.recursiveDeleteDir(new File("temp2")); + assertTrue(!new File("temp1").exists()); + assertTrue(!new File("temp2").exists()); + } + + public void testDirCopyingWithFilter() throws IOException { + IOUtils.writeFile("temp1/temp1.txt","hello",false); + IOUtils.writeFile("temp1/temp2.txt","world",false); + IOUtils.writeFile("temp1/temp3.json", "world", false); + IOUtils.copyDirectory(new File("temp1"), new File("temp2"), -1, new FilenameFilter() { + @Override + public boolean accept(File dir, String name) { + return name.endsWith(".json"); + } + }); + assertEquals("world", IOUtils.readFile(new File("temp2/temp3.json"))); + assertFalse(new File("temp2/temp1.txt").exists()); + assertFalse(new File("temp2/temp2.txt").exists()); + IOUtils.recursiveDeleteDir(new File("temp1")); + IOUtils.recursiveDeleteDir(new File("temp2")); + assertTrue(!new File("temp1").exists()); + assertTrue(!new File("temp2").exists()); + } + +} diff --git a/vespajlib/src/test/java/com/yahoo/io/ListenerTestCase.java b/vespajlib/src/test/java/com/yahoo/io/ListenerTestCase.java new file mode 100644 index 00000000000..e2049017076 --- /dev/null +++ b/vespajlib/src/test/java/com/yahoo/io/ListenerTestCase.java @@ -0,0 +1,108 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.io; + +import static org.junit.Assert.*; + +import java.io.IOException; +import java.net.InetSocketAddress; +import java.net.Socket; +import java.nio.ByteBuffer; +import java.nio.channels.SelectionKey; +import java.nio.channels.SocketChannel; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import com.yahoo.collections.Tuple2; +import com.yahoo.concurrent.Receiver; +import com.yahoo.concurrent.Receiver.MessageState; + +/** + * Test a NIO based Reactor pattern implementation, com.yahoo.io.Listener. + * + * @author <a href="mailto:steinar@yahoo-inc.com">Steinar Knutsen</a> + */ +public class ListenerTestCase { + + @Before + public void setUp() throws Exception { + } + + @After + public void tearDown() throws Exception { + } + + Receiver<Byte> r = new Receiver<>(); + + private final class MockConnection implements Connection { + + private SocketChannel channel; + + MockConnection(SocketChannel channel, Listener listener) { + this.channel = channel; + } + + @Override + public void write() throws IOException { + } + + @Override + public void read() throws IOException { + ByteBuffer b = ByteBuffer.allocate(1); + channel.read(b); + b.flip(); + r.put(b.get()); + } + + @Override + public void close() throws IOException { + channel.close(); + + } + + @Override + public void connect() throws IOException { + } + + @Override + public int selectOps() { + return SelectionKey.OP_READ; + } + + @Override + public SocketChannel socketChannel() { + return channel; + } + } + + private final class GetConnection implements ConnectionFactory { + + @Override + public Connection newConnection(SocketChannel channel, Listener listener) { + return new MockConnection(channel, listener); + } + } + + @Test + public final void testRun() throws IOException, InterruptedException { + Listener l = new Listener("ListenerTestCase"); + l.listen(new GetConnection(), 0); + l.start(); + int port = ((InetSocketAddress) l.acceptors.get(0).socket.getLocalAddress()).getPort(); + Socket s = new Socket("127.0.0.1", port); + final byte expected = 42; + s.getOutputStream().write(expected); + s.getOutputStream().flush(); + s.close(); + Tuple2<MessageState, Byte> received = r.get(60 * 1000); + l.acceptors.get(0).interrupt(); + l.acceptors.get(0).socket.close(); + l.acceptors.get(0).join(); + l.interrupt(); + l.join(); + assertTrue("Test timed out.", received.first == MessageState.VALID); + assertEquals(expected, received.second.byteValue()); + } + +} diff --git a/vespajlib/src/test/java/com/yahoo/io/SlowInflateTestCase.java b/vespajlib/src/test/java/com/yahoo/io/SlowInflateTestCase.java new file mode 100644 index 00000000000..48d8e8cdffe --- /dev/null +++ b/vespajlib/src/test/java/com/yahoo/io/SlowInflateTestCase.java @@ -0,0 +1,61 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.io; + +import static org.junit.Assert.*; + +import java.util.Arrays; +import java.util.zip.Deflater; + +import org.junit.Before; +import org.junit.Test; + +import com.yahoo.text.Utf8; + +/** + * Check decompressor used among other things for packed summary fields. + * + * @author <a href="mailto:steinar@yahoo-inc.com">Steinar Knutsen</a> + */ +public class SlowInflateTestCase { + + private String value; + private byte[] raw; + private byte[] output; + private byte[] compressed; + private int compressedDataLength; + + @Before + public void setUp() throws Exception { + value = "000000000000000000000000000000000000000000000000000000000000000"; + raw = Utf8.toBytesStd(value); + output = new byte[raw.length * 2]; + Deflater compresser = new Deflater(); + compresser.setInput(raw); + compresser.finish(); + compressedDataLength = compresser.deflate(output); + compresser.end(); + compressed = Arrays.copyOf(output, compressedDataLength); + } + + @Test + public final void test() { + byte[] unpacked = new SlowInflate().unpack(compressed, raw.length); + assertArrayEquals(raw, unpacked); + } + + @Test + public final void testCorruptData() { + compressed[0] = (byte) (compressed[0] ^ compressed[1]); + compressed[1] = (byte) (compressed[1] ^ compressed[2]); + compressed[2] = (byte) (compressed[2] ^ compressed[3]); + compressed[3] = (byte) (compressed[3] ^ compressed[4]); + boolean caught = false; + try { + new SlowInflate().unpack(compressed, raw.length); + } catch (RuntimeException e) { + caught = true; + } + assertTrue(caught); + } + +} diff --git a/vespajlib/src/test/java/com/yahoo/io/reader/NamedReaderTestCase.java b/vespajlib/src/test/java/com/yahoo/io/reader/NamedReaderTestCase.java new file mode 100644 index 00000000000..280d0782bd2 --- /dev/null +++ b/vespajlib/src/test/java/com/yahoo/io/reader/NamedReaderTestCase.java @@ -0,0 +1,131 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.io.reader; + +import java.io.IOException; +import java.io.Reader; +import java.io.StringReader; +import java.nio.CharBuffer; +import java.util.Collections; + +import com.yahoo.io.reader.NamedReader; +import com.yahoo.protect.ClassValidator; + +/** + * Tests all method of NamedReader. + * + * @author <a href="mailto:bratseth@yahoo-inc.com">Jon Bratseth</a> + * @author <a href="mailto:steinar@yahoo-inc.com">Steinar Knutsen</a> + */ +public class NamedReaderTestCase extends junit.framework.TestCase { + + public void testIt() { + StringReader stringReader=new StringReader("hello world"); + NamedReader r=new NamedReader("test1",stringReader); + assertEquals("test1",r.getName()); + assertEquals("test1",r.toString()); + assertEquals(stringReader,r.getReader()); + NamedReader.closeAll(Collections.singletonList(r)); + NamedReader.closeAll(null); // noop, nor exception + } + + public void testMethodMasking() { + assertEquals(0, + ClassValidator.unmaskedMethodsFromSuperclass(NamedReader.class).size()); + } + + private static class MarkerReader extends Reader { + static final String READ_CHAR_BUFFER = "com.yahoo.io.reader.NamedReaderTestCase.MarkerReader.read(CharBuffer)"; + static final String READ = "com.yahoo.io.reader.NamedReaderTestCase.MarkerReader.read()"; + static final String READ_CHAR = "com.yahoo.io.reader.NamedReaderTestCase.MarkerReader.read(char[])"; + static final String READ_CHAR_INT_INT = "com.yahoo.io.reader.NamedReaderTestCase.MarkerReader.read(char[], int, int)"; + static final String SKIP_LONG = "com.yahoo.io.reader.NamedReaderTestCase.MarkerReader.skip(long)"; + static final String READY = "com.yahoo.io.reader.NamedReaderTestCase.MarkerReader.ready()"; + static final String MARK_SUPPORTED = "com.yahoo.io.reader.NamedReaderTestCase.MarkerReader.markSupported()"; + static final String MARK_INT = "com.yahoo.io.reader.NamedReaderTestCase.MarkerReader.mark(int)"; + static final String RESET = "com.yahoo.io.reader.NamedReaderTestCase.MarkerReader.reset()"; + static final String CLOSE = "com.yahoo.io.reader.NamedReaderTestCase.MarkerReader.close()"; + String lastMethodHit = null; + + @Override + public int read(CharBuffer target) throws IOException { + lastMethodHit = READ_CHAR_BUFFER; + return 0; + } + + @Override + public int read() throws IOException { + lastMethodHit = READ; + return -1; + } + + @Override + public int read(char[] cbuf) throws IOException { + lastMethodHit = READ_CHAR; + return 0; + } + + @Override + public int read(char[] cbuf, int off, int len) throws IOException { + lastMethodHit = READ_CHAR_INT_INT; + return 0; + } + + @Override + public long skip(long n) throws IOException { + lastMethodHit = SKIP_LONG; + return 0; + } + + @Override + public boolean ready() throws IOException { + lastMethodHit = READY; + return false; + } + + @Override + public boolean markSupported() { + lastMethodHit = MARK_SUPPORTED; + return false; + } + + @Override + public void mark(int readAheadLimit) throws IOException { + lastMethodHit = MARK_INT; + } + + @Override + public void reset() throws IOException { + lastMethodHit = RESET; + } + + @Override + public void close() throws IOException { + lastMethodHit = CLOSE; + } + } + + public void testAllDelegators() throws IOException { + MarkerReader m = new MarkerReader(); + NamedReader r = new NamedReader("nalle", m); + r.read(CharBuffer.allocate(5000)); + assertEquals(MarkerReader.READ_CHAR_BUFFER, m.lastMethodHit); + r.read(); + assertEquals(MarkerReader.READ, m.lastMethodHit); + r.read(new char[5]); + assertEquals(MarkerReader.READ_CHAR, m.lastMethodHit); + r.read(new char[5], 0, 5); + assertEquals(MarkerReader.READ_CHAR_INT_INT, m.lastMethodHit); + r.skip(5L); + assertEquals(MarkerReader.SKIP_LONG, m.lastMethodHit); + r.ready(); + assertEquals(MarkerReader.READY, m.lastMethodHit); + r.markSupported(); + assertEquals(MarkerReader.MARK_SUPPORTED, m.lastMethodHit); + r.mark(5); + assertEquals(MarkerReader.MARK_INT, m.lastMethodHit); + r.reset(); + assertEquals(MarkerReader.RESET, m.lastMethodHit); + r.close(); + assertEquals(MarkerReader.CLOSE, m.lastMethodHit); + } +} |