You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@qpid.apache.org by ro...@apache.org on 2019/05/29 18:52:15 UTC

[qpid-proton-j] 02/02: PROTON-2057: fix small/array8 array encodings over 128 bytes

This is an automated email from the ASF dual-hosted git repository.

robbie pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/qpid-proton-j.git

commit 3294a4019af6ab4ec0f89fff11bd53a83d8e9788
Author: Ang Iongchun <an...@gmail.com>
AuthorDate: Wed May 29 14:31:03 2019 +0800

    PROTON-2057: fix small/array8 array encodings over 128 bytes
    
    Changes split out from #34 by Ang Iongchun, plus tests from me (Robbie).
    See also b666d6a165af7835bde12e0e41de2ca6109126d9.
    This closes #34.
---
 .../org/apache/qpid/proton/codec/ArrayType.java    |  48 +-
 .../qpid/proton/codec/ArrayTypeCodecTest.java      | 726 ++++++++++++++++++++-
 2 files changed, 748 insertions(+), 26 deletions(-)

diff --git a/proton-j/src/main/java/org/apache/qpid/proton/codec/ArrayType.java b/proton-j/src/main/java/org/apache/qpid/proton/codec/ArrayType.java
index 418a251..7d4de49 100644
--- a/proton-j/src/main/java/org/apache/qpid/proton/codec/ArrayType.java
+++ b/proton-j/src/main/java/org/apache/qpid/proton/codec/ArrayType.java
@@ -697,10 +697,10 @@ public class ArrayType implements PrimitiveType<Object[]>
         public void writeValue(final boolean[] a)
         {
             BooleanType.BooleanEncoding underlyingEncoder = getUnderlyingEncoding(a);
-            byte encodedValueSize = (byte)(1 + underlyingEncoder.getConstructorSize() +
-                                    a.length * underlyingEncoder.getValueSize(null));
+            int encodedValueSize = 1 + underlyingEncoder.getConstructorSize() +
+                                    a.length * underlyingEncoder.getValueSize(null);
             getEncoder().getBuffer().ensureRemaining(encodedValueSize);
-            getEncoder().writeRaw(encodedValueSize);
+            getEncoder().writeRaw((byte)encodedValueSize);
             getEncoder().writeRaw((byte)a.length);
             underlyingEncoder.writeConstructor();
             for(boolean b : a)
@@ -713,10 +713,10 @@ public class ArrayType implements PrimitiveType<Object[]>
         public void writeValue(final byte[] a)
         {
             ByteType.ByteEncoding underlyingEncoder = getUnderlyingEncoding(a);
-            byte encodedValueSize = (byte)(1 + underlyingEncoder.getConstructorSize() +
-                                    a.length * underlyingEncoder.getValueSize(null));
+            int encodedValueSize = 1 + underlyingEncoder.getConstructorSize() +
+                                    a.length * underlyingEncoder.getValueSize(null);
             getEncoder().getBuffer().ensureRemaining(encodedValueSize);
-            getEncoder().writeRaw(encodedValueSize);
+            getEncoder().writeRaw((byte)encodedValueSize);
             getEncoder().writeRaw((byte)a.length);
             underlyingEncoder.writeConstructor();
             for(byte b : a)
@@ -729,10 +729,10 @@ public class ArrayType implements PrimitiveType<Object[]>
         public void writeValue(final short[] a)
         {
             ShortType.ShortEncoding underlyingEncoder = getUnderlyingEncoding(a);
-            byte encodedValueSize = (byte)(1 + underlyingEncoder.getConstructorSize() +
-                                    a.length * underlyingEncoder.getValueSize(null));
+            int encodedValueSize = 1 + underlyingEncoder.getConstructorSize() +
+                                    a.length * underlyingEncoder.getValueSize(null);
             getEncoder().getBuffer().ensureRemaining(encodedValueSize);
-            getEncoder().writeRaw(encodedValueSize);
+            getEncoder().writeRaw((byte)encodedValueSize);
             getEncoder().writeRaw((byte)a.length);
             underlyingEncoder.writeConstructor();
             for(short b : a)
@@ -745,10 +745,10 @@ public class ArrayType implements PrimitiveType<Object[]>
         public void writeValue(final int[] a)
         {
             IntegerType.IntegerEncoding underlyingEncoder = getUnderlyingEncoding(a);
-            byte encodedValueSize = (byte)(1 + underlyingEncoder.getConstructorSize() +
-                                    a.length * underlyingEncoder.getValueSize(null));
+            int encodedValueSize = 1 + underlyingEncoder.getConstructorSize() +
+                                    a.length * underlyingEncoder.getValueSize(null);
             getEncoder().getBuffer().ensureRemaining(encodedValueSize);
-            getEncoder().writeRaw(encodedValueSize);
+            getEncoder().writeRaw((byte)encodedValueSize);
             getEncoder().writeRaw((byte)a.length);
             underlyingEncoder.writeConstructor();
             for(int b : a)
@@ -761,10 +761,10 @@ public class ArrayType implements PrimitiveType<Object[]>
         public void writeValue(final long[] a)
         {
             LongType.LongEncoding underlyingEncoder = getUnderlyingEncoding(a);
-            byte encodedValueSize = (byte)(1 + underlyingEncoder.getConstructorSize() +
-                                    a.length * underlyingEncoder.getValueSize(null));
+            int encodedValueSize = 1 + underlyingEncoder.getConstructorSize() +
+                                    a.length * underlyingEncoder.getValueSize(null);
             getEncoder().getBuffer().ensureRemaining(encodedValueSize);
-            getEncoder().writeRaw(encodedValueSize);
+            getEncoder().writeRaw((byte)encodedValueSize);
             getEncoder().writeRaw((byte)a.length);
             underlyingEncoder.writeConstructor();
             for(long b : a)
@@ -777,10 +777,10 @@ public class ArrayType implements PrimitiveType<Object[]>
         public void writeValue(final float[] a)
         {
             FloatType.FloatEncoding underlyingEncoder = getUnderlyingEncoding(a);
-            byte encodedValueSize = (byte)(1 + underlyingEncoder.getConstructorSize() +
-                                    a.length * underlyingEncoder.getValueSize(null));
+            int encodedValueSize = 1 + underlyingEncoder.getConstructorSize() +
+                                    a.length * underlyingEncoder.getValueSize(null);
             getEncoder().getBuffer().ensureRemaining(encodedValueSize);
-            getEncoder().writeRaw(encodedValueSize);
+            getEncoder().writeRaw((byte)encodedValueSize);
             getEncoder().writeRaw((byte)a.length);
             underlyingEncoder.writeConstructor();
             for(float b : a)
@@ -793,10 +793,10 @@ public class ArrayType implements PrimitiveType<Object[]>
         public void writeValue(final double[] a)
         {
             DoubleType.DoubleEncoding underlyingEncoder = getUnderlyingEncoding(a);
-            byte encodedValueSize = (byte)(1 + underlyingEncoder.getConstructorSize() +
-                                    a.length * underlyingEncoder.getValueSize(null));
+            int encodedValueSize = 1 + underlyingEncoder.getConstructorSize() +
+                                    a.length * underlyingEncoder.getValueSize(null);
             getEncoder().getBuffer().ensureRemaining(encodedValueSize);
-            getEncoder().writeRaw(encodedValueSize);
+            getEncoder().writeRaw((byte)encodedValueSize);
             getEncoder().writeRaw((byte)a.length);
             underlyingEncoder.writeConstructor();
             for(double b : a)
@@ -809,10 +809,10 @@ public class ArrayType implements PrimitiveType<Object[]>
         public void writeValue(final char[] a)
         {
             CharacterType.CharacterEncoding underlyingEncoder = getUnderlyingEncoding(a);
-            byte encodedValueSize = (byte)(1 + underlyingEncoder.getConstructorSize() +
-                                    a.length * underlyingEncoder.getValueSize(null));
+            int encodedValueSize = 1 + underlyingEncoder.getConstructorSize() +
+                                    a.length * underlyingEncoder.getValueSize(null);
             getEncoder().getBuffer().ensureRemaining(encodedValueSize);
-            getEncoder().writeRaw(encodedValueSize);
+            getEncoder().writeRaw((byte)encodedValueSize);
             getEncoder().writeRaw((byte)a.length);
             underlyingEncoder.writeConstructor();
             for(char b : a)
diff --git a/proton-j/src/test/java/org/apache/qpid/proton/codec/ArrayTypeCodecTest.java b/proton-j/src/test/java/org/apache/qpid/proton/codec/ArrayTypeCodecTest.java
index 024534f..2b50723 100644
--- a/proton-j/src/test/java/org/apache/qpid/proton/codec/ArrayTypeCodecTest.java
+++ b/proton-j/src/test/java/org/apache/qpid/proton/codec/ArrayTypeCodecTest.java
@@ -308,8 +308,24 @@ public class ArrayTypeCodecTest extends CodecTestSupport {
     }
 
     @Test
-    public void testEncodeDecodeByteArray() throws IOException {
-        int count = 100;
+    public void testEncodeDecodeByteArray100() throws Throwable {
+        // byte array8 less than 128 bytes
+        doEncodeDecodeByteArrayTestImpl(100);
+    }
+
+    @Test
+    public void testEncodeDecodeByteArray192() throws Throwable {
+        // byte array8 greater than 128 bytes
+        doEncodeDecodeByteArrayTestImpl(192);
+    }
+
+    @Test
+    public void testEncodeDecodeByteArray384() throws Throwable {
+        // byte array32
+        doEncodeDecodeByteArrayTestImpl(384);
+    }
+
+    private void doEncodeDecodeByteArrayTestImpl(int count) throws Throwable {
         byte[] source = createPayloadArrayBytes(count);
 
         try {
@@ -380,4 +396,710 @@ public class ArrayTypeCodecTest extends CodecTestSupport {
 
         return payload;
     }
+
+    @Test
+    public void testEncodeDecodeBooleanArray100() throws Throwable {
+        // boolean array8 less than 128 bytes
+        doEncodeDecodeBooleanArrayTestImpl(100);
+    }
+
+    @Test
+    public void testEncodeDecodeBooleanArray192() throws Throwable {
+        // boolean array8 greater than 128 bytes
+        doEncodeDecodeBooleanArrayTestImpl(192);
+    }
+
+    @Test
+    public void testEncodeDecodeBooleanArray384() throws Throwable {
+        // boolean array32
+        doEncodeDecodeBooleanArrayTestImpl(384);
+    }
+
+    private void doEncodeDecodeBooleanArrayTestImpl(int count) throws Throwable {
+        boolean[] source = createPayloadArrayBooleans(count);
+
+        try {
+            assertEquals("Unexpected source array length", count, source.length);
+
+            int encodingWidth = count < 254 ? 1 : 4; // less than 254 and not 256, since we also need 1 byte for element count, and (in this case) 1 byte for primitive element type constructor.
+            int arrayPayloadSize =  encodingWidth + 1 + count; // variable width for element count + byte type descriptor + number of elements
+            int expectedEncodedArraySize = 1 + encodingWidth + arrayPayloadSize; // array type code +  variable width for array size + other encoded payload
+            byte[] expectedEncoding = new byte[expectedEncodedArraySize];
+            ByteBuffer expectedEncodingWrapper = ByteBuffer.wrap(expectedEncoding);
+
+            // Write the array encoding code, array size, and element count
+            if(count < 254) {
+                expectedEncodingWrapper.put((byte) 0xE0); // 'array8' type descriptor code
+                expectedEncodingWrapper.put((byte) arrayPayloadSize);
+                expectedEncodingWrapper.put((byte) count);
+            } else {
+                expectedEncodingWrapper.put((byte) 0xF0); // 'array32' type descriptor code
+                expectedEncodingWrapper.putInt(arrayPayloadSize);
+                expectedEncodingWrapper.putInt(count);
+            }
+
+            // Write the type descriptor
+            expectedEncodingWrapper.put((byte) 0x56); // 'boolean' type descriptor code
+
+            // Write the elements
+            for (int i = 0; i < count; i++) {
+                byte booleanCode = (byte) (source[i] ? 0x01 : 0x00); //  0x01 true, 0x00 false.
+                expectedEncodingWrapper.put(booleanCode);
+            }
+
+            assertFalse("Should have filled expected encoding array", expectedEncodingWrapper.hasRemaining());
+
+            // Now verify against the actual encoding of the array
+            assertEquals("Unexpected buffer position", 0, buffer.position());
+            encoder.writeArray(source);
+            assertEquals("Unexpected encoded payload length", expectedEncodedArraySize, buffer.position());
+
+            byte[] actualEncoding = new byte[expectedEncodedArraySize];
+            buffer.flip();
+            buffer.get(actualEncoding);
+            assertFalse("Should have drained the encoder buffer contents", buffer.hasRemaining());
+
+            assertArrayEquals("Unexpected actual array encoding", expectedEncoding, actualEncoding);
+
+            // Now verify against the decoding
+            buffer.flip();
+            Object decoded = decoder.readObject();
+            assertNotNull(decoded);
+            assertTrue(decoded.getClass().isArray());
+            assertTrue(decoded.getClass().getComponentType().isPrimitive());
+            assertEquals(boolean.class, decoded.getClass().getComponentType());
+
+            assertArrayEquals("Unexpected decoding", source, (boolean[]) decoded);
+        }
+        catch (Throwable t) {
+            System.err.println("Error during test, source array: " + Arrays.toString(source));
+            throw t;
+        }
+    }
+
+    private static boolean[] createPayloadArrayBooleans(int length) {
+        Random rand = new Random(System.currentTimeMillis());
+
+        boolean[] payload = new boolean[length];
+        for (int i = 0; i < length; i++) {
+            payload[i] = rand.nextBoolean();
+        }
+
+        return payload;
+    }
+
+    @Test
+    public void testEncodeDecodeShortArray50() throws Throwable {
+        // short array8 less than 128 bytes
+        doEncodeDecodeShortArrayTestImpl(50);
+    }
+
+    @Test
+    public void testEncodeDecodeShortArray100() throws Throwable {
+        // short array8 greater than 128 bytes
+        doEncodeDecodeShortArrayTestImpl(100);
+    }
+
+    @Test
+    public void testEncodeDecodeShortArray384() throws Throwable {
+        // short array32
+        doEncodeDecodeShortArrayTestImpl(384);
+    }
+
+    private void doEncodeDecodeShortArrayTestImpl(int count) throws Throwable {
+        short[] source = createPayloadArrayShorts(count);
+
+        try {
+            assertEquals("Unexpected source array length", count, source.length);
+
+            int encodingWidth = count < 127 ? 1 : 4; // less than 127, since each element is 2 bytes, but we also need 1 byte for element count, and (in this case) 1 byte for primitive element type constructor.
+            int arrayPayloadSize =  encodingWidth + 1 + (count * 2); // variable width for element count + byte type descriptor + (number of elements * size)
+            int expectedEncodedArraySize = 1 + encodingWidth + arrayPayloadSize; // array type code +  variable width for array size + other encoded payload
+            byte[] expectedEncoding = new byte[expectedEncodedArraySize];
+            ByteBuffer expectedEncodingWrapper = ByteBuffer.wrap(expectedEncoding);
+
+            // Write the array encoding code, array size, and element count
+            if(count < 254) {
+                expectedEncodingWrapper.put((byte) 0xE0); // 'array8' type descriptor code
+                expectedEncodingWrapper.put((byte) arrayPayloadSize);
+                expectedEncodingWrapper.put((byte) count);
+            } else {
+                expectedEncodingWrapper.put((byte) 0xF0); // 'array32' type descriptor code
+                expectedEncodingWrapper.putInt(arrayPayloadSize);
+                expectedEncodingWrapper.putInt(count);
+            }
+
+            // Write the type descriptor
+            expectedEncodingWrapper.put((byte) 0x61); // 'short' type descriptor code
+
+            // Write the elements
+            for (int i = 0; i < count; i++) {
+                expectedEncodingWrapper.putShort(source[i]);
+            }
+
+            assertFalse("Should have filled expected encoding array", expectedEncodingWrapper.hasRemaining());
+
+            // Now verify against the actual encoding of the array
+            assertEquals("Unexpected buffer position", 0, buffer.position());
+            encoder.writeArray(source);
+            assertEquals("Unexpected encoded payload length", expectedEncodedArraySize, buffer.position());
+
+            byte[] actualEncoding = new byte[expectedEncodedArraySize];
+            buffer.flip();
+            buffer.get(actualEncoding);
+            assertFalse("Should have drained the encoder buffer contents", buffer.hasRemaining());
+
+            assertArrayEquals("Unexpected actual array encoding", expectedEncoding, actualEncoding);
+
+            // Now verify against the decoding
+            buffer.flip();
+            Object decoded = decoder.readObject();
+            assertNotNull(decoded);
+            assertTrue(decoded.getClass().isArray());
+            assertTrue(decoded.getClass().getComponentType().isPrimitive());
+            assertEquals(short.class, decoded.getClass().getComponentType());
+
+            assertArrayEquals("Unexpected decoding", source, (short[]) decoded);
+        }
+        catch (Throwable t) {
+            System.err.println("Error during test, source array: " + Arrays.toString(source));
+            throw t;
+        }
+    }
+
+    private static short[] createPayloadArrayShorts(int length) {
+        Random rand = new Random(System.currentTimeMillis());
+
+        short[] payload = new short[length];
+        for (int i = 0; i < length; i++) {
+            payload[i] = (short) (64 + 1 + rand.nextInt(9));
+        }
+
+        return payload;
+    }
+
+    @Test
+    public void testEncodeDecodeIntArray10() throws Throwable {
+        // int array8 less than 128 bytes
+        doEncodeDecodeIntArrayTestImpl(10, false);
+    }
+
+    @Test
+    public void testEncodeDecodeIntArray50() throws Throwable {
+        // int array8 greater than 128 bytes
+        doEncodeDecodeIntArrayTestImpl(50, false);
+    }
+
+    @Test
+    public void testEncodeDecodeIntArray384() throws Throwable {
+        // int array32
+        doEncodeDecodeIntArrayTestImpl(384, false);
+    }
+
+    @Test
+    public void testEncodeDecodeSmallIntArray100() throws Throwable {
+        // small-int array8 less than 128 bytes
+        doEncodeDecodeIntArrayTestImpl(100, true);
+    }
+
+    @Test
+    public void testEncodeDecodeSmallIntArray192() throws Throwable {
+        // small-int array8 greater than 128 bytes
+        doEncodeDecodeIntArrayTestImpl(192, true);
+    }
+
+    @Test
+    public void testEncodeDecodeSmallIntArray384() throws Throwable {
+        // small-int array32
+        doEncodeDecodeIntArrayTestImpl(384, true);
+    }
+
+    private void doEncodeDecodeIntArrayTestImpl(int count, boolean smallInt) throws Throwable {
+        int[] source = createPayloadArrayInts(count, smallInt);
+
+        try {
+            assertEquals("Unexpected source array length", count, source.length);
+
+            int encodingWidth;
+            int elementWidth;
+            if(smallInt) {
+                elementWidth = 1;
+                encodingWidth = count < 254 ? 1 : 4; // less than 254 and not 256, since each element is 1 byte, but we also need 1 byte for element count, and (in this case) 1 byte for primitive element type constructor.
+            } else {
+                elementWidth = 4;
+                encodingWidth = count < 63 ? 1 : 4; // less than 63, since each element is 4 bytes, but we also need 1 byte for element count, and (in this case) 1 byte for primitive element type constructor.
+            }
+
+            int arrayPayloadSize =  encodingWidth + 1 + (count * elementWidth); // variable width for element count + byte type descriptor + (number of elements * size)
+            int expectedEncodedArraySize = 1 + encodingWidth + arrayPayloadSize; // array type code +  variable width for array size + other encoded payload
+            byte[] expectedEncoding = new byte[expectedEncodedArraySize];
+            ByteBuffer expectedEncodingWrapper = ByteBuffer.wrap(expectedEncoding);
+
+            // Write the array encoding code, array size, and element count
+            if(count < 254) {
+                expectedEncodingWrapper.put((byte) 0xE0); // 'array8' type descriptor code
+                expectedEncodingWrapper.put((byte) arrayPayloadSize);
+                expectedEncodingWrapper.put((byte) count);
+            } else {
+                expectedEncodingWrapper.put((byte) 0xF0); // 'array32' type descriptor code
+                expectedEncodingWrapper.putInt(arrayPayloadSize);
+                expectedEncodingWrapper.putInt(count);
+            }
+
+            // Write the type descriptor
+            if(smallInt) {
+                expectedEncodingWrapper.put((byte) 0x54); // 'small int' type descriptor code
+            } else {
+                expectedEncodingWrapper.put((byte) 0x71); // 'int' type descriptor code
+            }
+
+            // Write the elements
+            for (int i = 0; i < count; i++) {
+                int j = source[i];
+                if(smallInt) {
+                    // Using put as small int is 1 byte
+                    assertTrue("Unexpected value: + j", j <= 127 && j >=-128);
+                    expectedEncodingWrapper.put((byte) j);
+                } else {
+                    expectedEncodingWrapper.putInt(j);
+                }
+            }
+
+            assertFalse("Should have filled expected encoding array", expectedEncodingWrapper.hasRemaining());
+
+            // Now verify against the actual encoding of the array
+            assertEquals("Unexpected buffer position", 0, buffer.position());
+            encoder.writeArray(source);
+            assertEquals("Unexpected encoded payload length", expectedEncodedArraySize, buffer.position());
+
+            byte[] actualEncoding = new byte[expectedEncodedArraySize];
+            buffer.flip();
+            buffer.get(actualEncoding);
+            assertFalse("Should have drained the encoder buffer contents", buffer.hasRemaining());
+
+            assertArrayEquals("Unexpected actual array encoding", expectedEncoding, actualEncoding);
+
+            // Now verify against the decoding
+            buffer.flip();
+            Object decoded = decoder.readObject();
+            assertNotNull(decoded);
+            assertTrue(decoded.getClass().isArray());
+            assertTrue(decoded.getClass().getComponentType().isPrimitive());
+            assertEquals(int.class, decoded.getClass().getComponentType());
+
+            assertArrayEquals("Unexpected decoding", source, (int[]) decoded);
+        }
+        catch (Throwable t) {
+            System.err.println("Error during test, source array: " + Arrays.toString(source));
+            throw t;
+        }
+    }
+
+    private static int[] createPayloadArrayInts(int length, boolean smallInt) {
+        Random rand = new Random(System.currentTimeMillis());
+
+        int[] payload = new int[length];
+        for (int i = 0; i < length; i++) {
+            if(smallInt) {
+                payload[i] = 64 + 1 + rand.nextInt(9);
+            } else {
+                payload[i] = 128 + 1 + rand.nextInt(9);
+            }
+        }
+
+        return payload;
+    }
+
+    @Test
+    public void testEncodeDecodeLongArray10() throws Throwable {
+        // long array8 less than 128 bytes
+        doEncodeDecodeLongArrayTestImpl(10, false);
+    }
+
+    @Test
+    public void testEncodeDecodeLongArray25() throws Throwable {
+        // long array8 greater than 128 bytes
+        doEncodeDecodeLongArrayTestImpl(25, false);
+    }
+
+    @Test
+    public void testEncodeDecodeLongArray384() throws Throwable {
+        // long array32
+        doEncodeDecodeLongArrayTestImpl(384, false);
+    }
+
+    @Test
+    public void testEncodeDecodeSmallLongArray100() throws Throwable {
+        // small-long array8 less than 128 bytes
+        doEncodeDecodeLongArrayTestImpl(100, true);
+    }
+
+    @Test
+    public void testEncodeDecodeSmallLongArray192() throws Throwable {
+        // small-long array8 greater than 128 bytes
+        doEncodeDecodeLongArrayTestImpl(192, true);
+    }
+
+    @Test
+    public void testEncodeDecodeSmallLongArray384() throws Throwable {
+        // small-long array32
+        doEncodeDecodeLongArrayTestImpl(384, true);
+    }
+
+    private void doEncodeDecodeLongArrayTestImpl(int count, boolean smallLong) throws Throwable {
+        long[] source = createPayloadArrayLongs(count, smallLong);
+
+        try {
+            assertEquals("Unexpected source array length", count, source.length);
+
+            int encodingWidth;
+            int elementWidth;
+            if(smallLong) {
+                elementWidth = 1;
+                encodingWidth = count < 254 ? 1 : 4; // less than 254 and not 256, since each element is 1 byte, but we also need 1 byte for element count, and (in this case) 1 byte for primitive element type constructor.
+            } else {
+                elementWidth = 8;
+                encodingWidth = count < 31 ? 1 : 4; // less than 31, since each element is 8 bytes, but we also need 1 byte for element count, and (in this case) 1 byte for primitive element type constructor.
+            }
+
+            int arrayPayloadSize =  encodingWidth + 1 + (count * elementWidth); // variable width for element count + byte type descriptor + (number of elements * size)
+            int expectedEncodedArraySize = 1 + encodingWidth + arrayPayloadSize; // array type code +  variable width for array size + other encoded payload
+            byte[] expectedEncoding = new byte[expectedEncodedArraySize];
+            ByteBuffer expectedEncodingWrapper = ByteBuffer.wrap(expectedEncoding);
+
+            // Write the array encoding code, array size, and element count
+            if(count < 254) {
+                expectedEncodingWrapper.put((byte) 0xE0); // 'array8' type descriptor code
+                expectedEncodingWrapper.put((byte) arrayPayloadSize);
+                expectedEncodingWrapper.put((byte) count);
+            } else {
+                expectedEncodingWrapper.put((byte) 0xF0); // 'array32' type descriptor code
+                expectedEncodingWrapper.putInt(arrayPayloadSize);
+                expectedEncodingWrapper.putInt(count);
+            }
+
+            // Write the type descriptor
+            if(smallLong) {
+                expectedEncodingWrapper.put((byte) 0x55); // 'small long' type descriptor code
+            } else {
+                expectedEncodingWrapper.put((byte) 0x81); // 'long' type descriptor code
+            }
+
+            // Write the elements
+            for (int i = 0; i < count; i++) {
+                long j = source[i];
+                if(smallLong) {
+                    // Using put as small long is 1 byte
+                    assertTrue("Unexpected value: + j", j <= 127 && j >=-128);
+                    expectedEncodingWrapper.put((byte) j);
+                } else {
+                    expectedEncodingWrapper.putLong(j);
+                }
+            }
+
+            assertFalse("Should have filled expected encoding array", expectedEncodingWrapper.hasRemaining());
+
+            // Now verify against the actual encoding of the array
+            assertEquals("Unexpected buffer position", 0, buffer.position());
+            encoder.writeArray(source);
+            assertEquals("Unexpected encoded payload length", expectedEncodedArraySize, buffer.position());
+
+            byte[] actualEncoding = new byte[expectedEncodedArraySize];
+            buffer.flip();
+            buffer.get(actualEncoding);
+            assertFalse("Should have drained the encoder buffer contents", buffer.hasRemaining());
+
+            assertArrayEquals("Unexpected actual array encoding", expectedEncoding, actualEncoding);
+
+            // Now verify against the decoding
+            buffer.flip();
+            Object decoded = decoder.readObject();
+            assertNotNull(decoded);
+            assertTrue(decoded.getClass().isArray());
+            assertTrue(decoded.getClass().getComponentType().isPrimitive());
+            assertEquals(long.class, decoded.getClass().getComponentType());
+
+            assertArrayEquals("Unexpected decoding", source, (long[]) decoded);
+        }
+        catch (Throwable t) {
+            System.err.println("Error during test, source array: " + Arrays.toString(source));
+            throw t;
+        }
+    }
+
+    private static long[] createPayloadArrayLongs(int length, boolean smallLong) {
+        Random rand = new Random(System.currentTimeMillis());
+
+        long[] payload = new long[length];
+        for (int i = 0; i < length; i++) {
+            if(smallLong) {
+                payload[i] = 64 + 1 + rand.nextInt(9);
+            } else {
+                payload[i] = 128 + 1 + rand.nextInt(9);
+            }
+        }
+
+        return payload;
+    }
+
+    @Test
+    public void testEncodeDecodeFloatArray25() throws Throwable {
+        // float array8 less than 128 bytes
+        doEncodeDecodeFloatArrayTestImpl(25);
+    }
+
+    @Test
+    public void testEncodeDecodeFloatArray50() throws Throwable {
+        // float array8 greater than 128 bytes
+        doEncodeDecodeFloatArrayTestImpl(50);
+    }
+
+    @Test
+    public void testEncodeDecodeFloatArray384() throws Throwable {
+        // float array32
+        doEncodeDecodeFloatArrayTestImpl(384);
+    }
+
+    private void doEncodeDecodeFloatArrayTestImpl(int count) throws Throwable {
+        float[] source = createPayloadArrayFloats(count);
+
+        try {
+            assertEquals("Unexpected source array length", count, source.length);
+
+            int encodingWidth = count < 63 ? 1 : 4; // less than 63, since each element is 4 bytes, but we also need 1 byte for element count, and (in this case) 1 byte for primitive element type constructor.
+            int arrayPayloadSize =  encodingWidth + 1 + (count * 4); // variable width for element count + byte type descriptor + (number of elements * size)
+            int expectedEncodedArraySize = 1 + encodingWidth + arrayPayloadSize; // array type code +  variable width for array size + other encoded payload
+            byte[] expectedEncoding = new byte[expectedEncodedArraySize];
+            ByteBuffer expectedEncodingWrapper = ByteBuffer.wrap(expectedEncoding);
+
+            // Write the array encoding code, array size, and element count
+            if(count < 254) {
+                expectedEncodingWrapper.put((byte) 0xE0); // 'array8' type descriptor code
+                expectedEncodingWrapper.put((byte) arrayPayloadSize);
+                expectedEncodingWrapper.put((byte) count);
+            } else {
+                expectedEncodingWrapper.put((byte) 0xF0); // 'array32' type descriptor code
+                expectedEncodingWrapper.putInt(arrayPayloadSize);
+                expectedEncodingWrapper.putInt(count);
+            }
+
+            // Write the type descriptor
+            expectedEncodingWrapper.put((byte) 0x72); // 'float' type descriptor code
+
+            // Write the elements
+            for (int i = 0; i < count; i++) {
+                expectedEncodingWrapper.putFloat(source[i]);
+            }
+
+            assertFalse("Should have filled expected encoding array", expectedEncodingWrapper.hasRemaining());
+
+            // Now verify against the actual encoding of the array
+            assertEquals("Unexpected buffer position", 0, buffer.position());
+            encoder.writeArray(source);
+            assertEquals("Unexpected encoded payload length", expectedEncodedArraySize, buffer.position());
+
+            byte[] actualEncoding = new byte[expectedEncodedArraySize];
+            buffer.flip();
+            buffer.get(actualEncoding);
+            assertFalse("Should have drained the encoder buffer contents", buffer.hasRemaining());
+
+            assertArrayEquals("Unexpected actual array encoding", expectedEncoding, actualEncoding);
+
+            // Now verify against the decoding
+            buffer.flip();
+            Object decoded = decoder.readObject();
+            assertNotNull(decoded);
+            assertTrue(decoded.getClass().isArray());
+            assertTrue(decoded.getClass().getComponentType().isPrimitive());
+            assertEquals(float.class, decoded.getClass().getComponentType());
+
+            assertArrayEquals("Unexpected decoding", source, (float[]) decoded, 0.0F);
+        }
+        catch (Throwable t) {
+            System.err.println("Error during test, source array: " + Arrays.toString(source));
+            throw t;
+        }
+    }
+
+    private static float[] createPayloadArrayFloats(int length) {
+        Random rand = new Random(System.currentTimeMillis());
+
+        float[] payload = new float[length];
+        for (int i = 0; i < length; i++) {
+            payload[i] = 64 + 1 + rand.nextInt(9);
+        }
+
+        return payload;
+    }
+
+    @Test
+    public void testEncodeDecodeDoubleArray10() throws Throwable {
+        // double array8 less than 128 bytes
+        doEncodeDecodeDoubleArrayTestImpl(10);
+    }
+
+    @Test
+    public void testEncodeDecodeDoubleArray25() throws Throwable {
+        // double array8 greater than 128 bytes
+        doEncodeDecodeDoubleArrayTestImpl(25);
+    }
+
+    @Test
+    public void testEncodeDecodeDoubleArray384() throws Throwable {
+        // double array32
+        doEncodeDecodeDoubleArrayTestImpl(384);
+    }
+
+    private void doEncodeDecodeDoubleArrayTestImpl(int count) throws Throwable {
+        double[] source = createPayloadArrayDoubles(count);
+
+        try {
+            assertEquals("Unexpected source array length", count, source.length);
+
+            int encodingWidth = count < 31 ? 1 : 4; // less than 31, since each element is 8 bytes, but we also need 1 byte for element count, and (in this case) 1 byte for primitive element type constructor.
+            int arrayPayloadSize =  encodingWidth + 1 + (count * 8); // variable width for element count + byte type descriptor + (number of elements * size)
+            int expectedEncodedArraySize = 1 + encodingWidth + arrayPayloadSize; // array type code +  variable width for array size + other encoded payload
+            byte[] expectedEncoding = new byte[expectedEncodedArraySize];
+            ByteBuffer expectedEncodingWrapper = ByteBuffer.wrap(expectedEncoding);
+
+            // Write the array encoding code, array size, and element count
+            if(count < 254) {
+                expectedEncodingWrapper.put((byte) 0xE0); // 'array8' type descriptor code
+                expectedEncodingWrapper.put((byte) arrayPayloadSize);
+                expectedEncodingWrapper.put((byte) count);
+            } else {
+                expectedEncodingWrapper.put((byte) 0xF0); // 'array32' type descriptor code
+                expectedEncodingWrapper.putInt(arrayPayloadSize);
+                expectedEncodingWrapper.putInt(count);
+            }
+
+            // Write the type descriptor
+            expectedEncodingWrapper.put((byte) 0x82); // 'double' type descriptor code
+
+            // Write the elements
+            for (int i = 0; i < count; i++) {
+                expectedEncodingWrapper.putDouble(source[i]);
+            }
+
+            assertFalse("Should have filled expected encoding array", expectedEncodingWrapper.hasRemaining());
+
+            // Now verify against the actual encoding of the array
+            assertEquals("Unexpected buffer position", 0, buffer.position());
+            encoder.writeArray(source);
+            assertEquals("Unexpected encoded payload length", expectedEncodedArraySize, buffer.position());
+
+            byte[] actualEncoding = new byte[expectedEncodedArraySize];
+            buffer.flip();
+            buffer.get(actualEncoding);
+            assertFalse("Should have drained the encoder buffer contents", buffer.hasRemaining());
+
+            assertArrayEquals("Unexpected actual array encoding", expectedEncoding, actualEncoding);
+
+            // Now verify against the decoding
+            buffer.flip();
+            Object decoded = decoder.readObject();
+            assertNotNull(decoded);
+            assertTrue(decoded.getClass().isArray());
+            assertTrue(decoded.getClass().getComponentType().isPrimitive());
+            assertEquals(double.class, decoded.getClass().getComponentType());
+
+            assertArrayEquals("Unexpected decoding", source, (double[]) decoded, 0.0F);
+        }
+        catch (Throwable t) {
+            System.err.println("Error during test, source array: " + Arrays.toString(source));
+            throw t;
+        }
+    }
+
+    private static double[] createPayloadArrayDoubles(int length) {
+        Random rand = new Random(System.currentTimeMillis());
+
+        double[] payload = new double[length];
+        for (int i = 0; i < length; i++) {
+            payload[i] = 64 + 1 + rand.nextInt(9);
+        }
+
+        return payload;
+    }
+
+    @Test
+    public void testEncodeCharArray25() throws Throwable {
+        // char array8 less than 128 bytes
+        doEncodeCharArrayTestImpl(25);
+    }
+
+    @Test
+    public void testEncodeCharArray50() throws Throwable {
+        // char array8 greater than 128 bytes
+        doEncodeCharArrayTestImpl(50);
+    }
+
+    @Test
+    public void testEncodeCharArray384() throws Throwable {
+        // char array32
+        doEncodeCharArrayTestImpl(384);
+    }
+
+    private void doEncodeCharArrayTestImpl(int count) throws Throwable {
+        char[] source = createPayloadArrayChars(count);
+
+        try {
+            assertEquals("Unexpected source array length", count, source.length);
+
+            int encodingWidth = count < 63 ? 1 : 4; // less than 63, since each element is 4 bytes, but we also need 1 byte for element count, and (in this case) 1 byte for primitive element type constructor.
+            int arrayPayloadSize =  encodingWidth + 1 + (count * 4); // variable width for element count + byte type descriptor + (number of elements * size)
+            int expectedEncodedArraySize = 1 + encodingWidth + arrayPayloadSize; // array type code +  variable width for array size + other encoded payload
+            byte[] expectedEncoding = new byte[expectedEncodedArraySize];
+            ByteBuffer expectedEncodingWrapper = ByteBuffer.wrap(expectedEncoding);
+
+            // Write the array encoding code, array size, and element count
+            if(count < 254) {
+                expectedEncodingWrapper.put((byte) 0xE0); // 'array8' type descriptor code
+                expectedEncodingWrapper.put((byte) arrayPayloadSize);
+                expectedEncodingWrapper.put((byte) count);
+            } else {
+                expectedEncodingWrapper.put((byte) 0xF0); // 'array32' type descriptor code
+                expectedEncodingWrapper.putInt(arrayPayloadSize);
+                expectedEncodingWrapper.putInt(count);
+            }
+
+            // Write the type descriptor
+            expectedEncodingWrapper.put((byte) 0x73); // 'char' type descriptor code
+
+            // Write the elements
+            for (int i = 0; i < count; i++) {
+                expectedEncodingWrapper.putInt(source[i]); //4 byte encoding
+            }
+
+            assertFalse("Should have filled expected encoding array", expectedEncodingWrapper.hasRemaining());
+
+            // Now verify against the actual encoding of the array
+            assertEquals("Unexpected buffer position", 0, buffer.position());
+            encoder.writeArray(source);
+            assertEquals("Unexpected encoded payload length", expectedEncodedArraySize, buffer.position());
+
+            byte[] actualEncoding = new byte[expectedEncodedArraySize];
+            buffer.flip();
+            buffer.get(actualEncoding);
+            assertFalse("Should have drained the encoder buffer contents", buffer.hasRemaining());
+
+            assertArrayEquals("Unexpected actual array encoding", expectedEncoding, actualEncoding);
+        }
+        catch (Throwable t) {
+            System.err.println("Error during test, source array: " + Arrays.toString(source));
+            throw t;
+        }
+    }
+
+    private static char[] createPayloadArrayChars(int length) {
+        Random rand = new Random(System.currentTimeMillis());
+
+        char[] payload = new char[length];
+        for (int i = 0; i < length; i++) {
+            payload[i] = (char) (64 + 1 + rand.nextInt(9));
+        }
+
+        return payload;
+    }
+
 }
\ No newline at end of file


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org