package org.infinispan.commons.util; import java.io.IOException; import java.io.ObjectInput; import java.io.ObjectOutput; import java.util.Arrays; import java.util.LinkedList; import java.util.Queue; import java.util.Random; import java.util.UUID; import org.infinispan.commons.marshall.MarshallUtil; import org.junit.Assert; import org.junit.Test; /** * Unit tests for {@link org.infinispan.commons.marshall.MarshallUtil} * * @author Pedro Ruivo * @since 8.2 */ public class MarshallUtilTest { private static final int NR_RANDOM = 1000; private static void positiveRange(int min, int max, int bytesExpected, ObjectInputOutput io) throws IOException { for (int i = min; i > 0 && i < max; i <<= 1) { checkIntAndByteArray(i, bytesExpected, io); } } private static void checkIntAndByteArray(int i, int bytesExpected, ObjectInputOutput io) throws IOException { io.reset(); MarshallUtil.marshallSize(io, i); Assert.assertEquals("Error for i=" + i, bytesExpected, io.buffer.size()); Assert.assertEquals("Error for i=" + i, i, MarshallUtil.unmarshallSize(io)); Assert.assertEquals("Error for i=" + i, 0, io.buffer.size()); } private static void checkNegativeInt(int i, ObjectInputOutput io) throws IOException { io.reset(); MarshallUtil.marshallSize(io, i); Assert.assertEquals("Error for i=" + i, 1, io.buffer.size()); Assert.assertEquals("Error for i=" + i, -1, MarshallUtil.unmarshallSize(io)); Assert.assertEquals("Error for i=" + i, 0, io.buffer.size()); } @Test public void testPositiveRange() throws IOException { ObjectInputOutput io = new ObjectInputOutput(); checkIntAndByteArray(0, 1, io); //zero positiveRange(1, 1 << 6, 1, io); positiveRange(1 << 6, 1 << 13, 2, io); positiveRange(1 << 13, 1 << 20, 3, io); positiveRange(1 << 20, 1 << 27, 4, io); positiveRange(1 << 27, Integer.MAX_VALUE, 5, io); checkIntAndByteArray(Integer.MAX_VALUE, 5, io); } @Test public void testNegativeRange() throws IOException { ObjectInputOutput io = new ObjectInputOutput(); for (int i = 1; i < Integer.MAX_VALUE; i <<= 1) { int v = -i; if (v >= 0) { break; } checkNegativeInt(v, io); } checkNegativeInt(Integer.MIN_VALUE, io); } @Test public void testRandomPositiveInt() throws IOException { Random random = new Random(System.nanoTime()); ObjectInputOutput io = new ObjectInputOutput(); for (int i = 0; i < NR_RANDOM; ++i) { int v = random.nextInt(); if (v < 0) { v = -v; } io.reset(); MarshallUtil.marshallSize(io, v); Assert.assertEquals("Error for v=" + v, v, MarshallUtil.unmarshallSize(io)); } } @Test public void testRandomNegativeInt() throws IOException { Random random = new Random(System.nanoTime()); ObjectInputOutput io = new ObjectInputOutput(); for (int i = 0; i < NR_RANDOM; ++i) { int v = random.nextInt(); if (v > 0) { v = -v; } else if (v == 0) { i--; continue; } io.reset(); MarshallUtil.marshallSize(io, v); Assert.assertEquals("Error for v=" + v, -1, MarshallUtil.unmarshallSize(io)); } } @Test public void testEnum() throws IOException { ObjectInputOutput io = new ObjectInputOutput(); MarshallUtil.marshallEnum(null, io); Assert.assertNull(MarshallUtil.unmarshallEnum(io, ordinal -> TestEnum.values()[ordinal])); Assert.assertEquals(0, io.buffer.size()); for (TestEnum e : TestEnum.values()) { io.reset(); MarshallUtil.marshallEnum(e, io); Assert.assertEquals(e, MarshallUtil.unmarshallEnum(io, ordinal -> TestEnum.values()[ordinal])); Assert.assertEquals(0, io.buffer.size()); } } @Test public void testUUID() throws IOException { ObjectInputOutput io = new ObjectInputOutput(); MarshallUtil.marshallUUID(null, io, true); Assert.assertNull(MarshallUtil.unmarshallUUID(io, true)); Assert.assertEquals(0, io.buffer.size()); for (int i = 0; i < NR_RANDOM; ++i) { io.reset(); UUID uuid = UUID.randomUUID(); MarshallUtil.marshallUUID(uuid, io, false); Assert.assertEquals(uuid, MarshallUtil.unmarshallUUID(io, false)); Assert.assertEquals(0, io.buffer.size()); } for (int i = 0; i < NR_RANDOM; ++i) { io.reset(); UUID uuid = UUID.randomUUID(); MarshallUtil.marshallUUID(uuid, io, true); Assert.assertEquals(uuid, MarshallUtil.unmarshallUUID(io, true)); Assert.assertEquals(0, io.buffer.size()); } } @Test public void testArray() throws IOException, ClassNotFoundException { ObjectInputOutput io = new ObjectInputOutput(); MarshallUtil.marshallArray(null, io); Assert.assertNull(MarshallUtil.unmarshallArray(io, null)); Assert.assertEquals(0, io.buffer.size()); io.reset(); String[] array = new String[0]; MarshallUtil.marshallArray(array, io); Assert.assertTrue(Arrays.equals(array, MarshallUtil.unmarshallArray(io, String[]::new))); Assert.assertEquals(0, io.buffer.size()); io.reset(); array = new String[] {"a", "b", "c"}; MarshallUtil.marshallArray(array, io); Assert.assertTrue(Arrays.equals(array, MarshallUtil.unmarshallArray(io, String[]::new))); Assert.assertEquals(0, io.buffer.size()); io.reset(); } @Test public void testByteArray() throws IOException, ClassNotFoundException { ObjectInputOutput io = new ObjectInputOutput(); MarshallUtil.marshallByteArray(null, io); Assert.assertNull(MarshallUtil.unmarshallByteArray(io)); Assert.assertEquals(0, io.buffer.size()); io.reset(); byte[] array = new byte[0]; MarshallUtil.marshallByteArray(array, io); Assert.assertTrue(Arrays.equals(array, MarshallUtil.unmarshallByteArray(io))); Assert.assertEquals(0, io.buffer.size()); io.reset(); array = new byte[] {1, 2, 3}; MarshallUtil.marshallByteArray(array, io); Assert.assertTrue(Arrays.equals(array, MarshallUtil.unmarshallByteArray(io))); Assert.assertEquals(0, io.buffer.size()); io.reset(); } private enum TestEnum { ONE, TWO, THREE } private static class ObjectInputOutput implements ObjectOutput, ObjectInput { private final Queue<Object> buffer = new LinkedList<>(); @Override public void writeByte(int v) throws IOException { buffer.add((byte) v); } @Override public void writeShort(int v) throws IOException { throw new UnsupportedOperationException(); } @Override public void writeChar(int v) throws IOException { throw new UnsupportedOperationException(); } @Override public void writeInt(int v) throws IOException { throw new UnsupportedOperationException(); } @Override public void writeLong(long v) throws IOException { buffer.add(v); } @Override public void writeFloat(float v) throws IOException { throw new UnsupportedOperationException(); } @Override public void writeDouble(double v) throws IOException { throw new UnsupportedOperationException(); } @Override public void writeBytes(String s) throws IOException { throw new UnsupportedOperationException(); } @Override public void writeChars(String s) throws IOException { throw new UnsupportedOperationException(); } @Override public void writeUTF(String s) throws IOException { throw new UnsupportedOperationException(); } public void reset() { buffer.clear(); } @Override public Object readObject() throws ClassNotFoundException, IOException { return buffer.poll(); } @Override public int read() throws IOException { throw new UnsupportedOperationException(); } @Override public int read(byte[] b) throws IOException { throw new UnsupportedOperationException(); } @Override public int read(byte[] b, int off, int len) throws IOException { throw new UnsupportedOperationException(); } @Override public long skip(long n) throws IOException { throw new UnsupportedOperationException(); } @Override public int available() throws IOException { throw new UnsupportedOperationException(); } @Override public void readFully(byte[] b) throws IOException { byte[] array = (byte[]) buffer.poll(); Assert.assertEquals(array.length, b.length); System.arraycopy(array, 0, b, 0, b.length); } @Override public void readFully(byte[] b, int off, int len) throws IOException { throw new UnsupportedOperationException(); } @Override public int skipBytes(int n) throws IOException { throw new UnsupportedOperationException(); } @Override public boolean readBoolean() throws IOException { return (boolean) buffer.poll(); } @Override public byte readByte() throws IOException { return (byte) buffer.poll(); } @Override public int readUnsignedByte() throws IOException { throw new UnsupportedOperationException(); } @Override public short readShort() throws IOException { throw new UnsupportedOperationException(); } @Override public int readUnsignedShort() throws IOException { throw new UnsupportedOperationException(); } @Override public char readChar() throws IOException { throw new UnsupportedOperationException(); } @Override public int readInt() throws IOException { throw new UnsupportedOperationException(); } @Override public long readLong() throws IOException { return (long) buffer.poll(); } @Override public float readFloat() throws IOException { throw new UnsupportedOperationException(); } @Override public double readDouble() throws IOException { throw new UnsupportedOperationException(); } @Override public String readLine() throws IOException { throw new UnsupportedOperationException(); } @Override public String readUTF() throws IOException { throw new UnsupportedOperationException(); } @Override public void writeObject(Object obj) throws IOException { buffer.add(obj); } @Override public void write(int b) throws IOException { throw new UnsupportedOperationException(); } @Override public void write(byte[] b) throws IOException { buffer.add(b); } @Override public void write(byte[] b, int off, int len) throws IOException { throw new UnsupportedOperationException(); } @Override public void writeBoolean(boolean v) throws IOException { buffer.add(v); } @Override public void flush() throws IOException { throw new UnsupportedOperationException(); } @Override public void close() throws IOException { throw new UnsupportedOperationException(); } } }