From e798417a9b6f52952c29d0394bc447e0150832e9 Mon Sep 17 00:00:00 2001
From: brinn <brinn>
Date: Mon, 26 Apr 2010 19:34:55 +0000
Subject: [PATCH] add: NativeArrayEncoding and unit tests add: AllTests class
 to run all tests in base and use it as main class for base-test-complete.jar

SVN: 15646
---
 base/build/build.xml                          |   2 +-
 .../base/convert/NativeArrayEncoding.java     | 172 +++++++++
 .../cisd/base/convert/NativeTaggedArray.java  | 344 ++++++++++++++++++
 .../java/ch/systemsx/cisd/base/AllTests.java  |  44 +++
 .../base/convert/NativeTaggedArrayTests.java  | 276 ++++++++++++++
 5 files changed, 837 insertions(+), 1 deletion(-)
 create mode 100644 base/source/java/ch/systemsx/cisd/base/convert/NativeArrayEncoding.java
 create mode 100644 base/source/java/ch/systemsx/cisd/base/convert/NativeTaggedArray.java
 create mode 100644 base/sourceTest/java/ch/systemsx/cisd/base/AllTests.java
 create mode 100644 base/sourceTest/java/ch/systemsx/cisd/base/convert/NativeTaggedArrayTests.java

diff --git a/base/build/build.xml b/base/build/build.xml
index 5c3d66618cb..2b95d8e7e58 100644
--- a/base/build/build.xml
+++ b/base/build/build.xml
@@ -135,7 +135,7 @@
 			<zipfileset src="${lib}/commons-lang/commons-lang.jar" />
 			<zipfileset src="${lib}/commons-io/commons-io.jar" />
 			<manifest>
-				<attribute name="Main-Class" value="ch.systemsx.cisd.base.unix.UnixTests" />
+				<attribute name="Main-Class" value="ch.systemsx.cisd.base.AllTests" />
 				<attribute name="Version" value="${version.number}" />
 				<attribute name="Build-Number"
 				           value="${version.number} (r${revision.number},${clean.flag})" />
diff --git a/base/source/java/ch/systemsx/cisd/base/convert/NativeArrayEncoding.java b/base/source/java/ch/systemsx/cisd/base/convert/NativeArrayEncoding.java
new file mode 100644
index 00000000000..26514c87fdc
--- /dev/null
+++ b/base/source/java/ch/systemsx/cisd/base/convert/NativeArrayEncoding.java
@@ -0,0 +1,172 @@
+/*
+ * Copyright 2010 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.systemsx.cisd.base.convert;
+
+import ch.systemsx.cisd.base.convert.NativeData.ByteOrder;
+
+/**
+ * An enum for encoding array of numbers (integer or float) in native (host) format.
+ * 
+ * @author Bernd Rinn
+ */
+enum NativeArrayEncoding
+{
+    INT8_NATIVE(false, (byte) 1, NativeData.ByteOrder.NATIVE),
+
+    INT16_LITTLE_ENDIAN(false, (byte) 2, NativeData.ByteOrder.LITTLE_ENDIAN),
+
+    INT32_LITTLE_ENDIAN(false, (byte) 4, NativeData.ByteOrder.LITTLE_ENDIAN),
+
+    INT64_LITTLE_ENDIAN(false, (byte) 8, NativeData.ByteOrder.LITTLE_ENDIAN),
+
+    INT16_BIG_ENDIAN(false, (byte) 2, NativeData.ByteOrder.BIG_ENDIAN),
+
+    INT32_BIG_ENDIAN(false, (byte) 4, NativeData.ByteOrder.BIG_ENDIAN),
+
+    INT64_BIG_ENDIAN(false, (byte) 8, NativeData.ByteOrder.BIG_ENDIAN),
+
+    FLOAT32_LITTLE_ENDIAN(true, (byte) 4, NativeData.ByteOrder.LITTLE_ENDIAN),
+
+    FLOAT64_LITTLE_ENDIAN(true, (byte) 8, NativeData.ByteOrder.LITTLE_ENDIAN),
+
+    FLOAT32_BIG_ENDIAN(true, (byte) 4, NativeData.ByteOrder.BIG_ENDIAN),
+
+    FLOAT64_BIG_ENDIAN(true, (byte) 8, NativeData.ByteOrder.BIG_ENDIAN),
+
+    ;
+
+    private static final int MIN_ENCODING_HEADER_SIZE = 8;
+
+    private static final int CHAR_N = 78;
+
+    private static final int CHAR_B = 66;
+
+    private static final int CHAR_L = 76;
+
+    private static final int CHAR_I = 73;
+
+    private static final int CHAR_F = 70;
+
+    NativeArrayEncoding(boolean floatingPoint, byte sizeInBytes, NativeData.ByteOrder byteOrder)
+    {
+        this.floatingPoint = floatingPoint;
+        this.byteOrder = byteOrder;
+        this.sizeInBytes = sizeInBytes;
+        this.magic =
+                new byte[]
+                    {
+                            (byte) (floatingPoint ? CHAR_F : CHAR_I),
+                            (byte) ((byteOrder == ByteOrder.LITTLE_ENDIAN) ? CHAR_L
+                                    : (byteOrder == ByteOrder.BIG_ENDIAN) ? CHAR_B : CHAR_N),
+                            sizeInBytes };
+    }
+
+    private boolean floatingPoint;
+
+    private ByteOrder byteOrder;
+
+    private byte sizeInBytes;
+
+    private byte[] magic;
+
+    boolean isFloatingPoint()
+    {
+        return floatingPoint;
+    }
+
+    boolean isInteger()
+    {
+        return floatingPoint == false;
+    }
+
+    NativeData.ByteOrder getByteOrder()
+    {
+        return byteOrder;
+    }
+
+    byte getSizeInBytes()
+    {
+        return sizeInBytes;
+    }
+
+    byte[] getMagic()
+    {
+        return magic;
+    }
+
+    static NativeArrayEncoding tryGetIntEncoding(ByteOrder byteOrder, byte sizeInBytes)
+    {
+        assert byteOrder != null;
+        if (sizeInBytes == 1 && byteOrder == ByteOrder.NATIVE)
+        {
+            return INT8_NATIVE;
+        } else if (sizeInBytes == 2)
+        {
+            return (byteOrder == ByteOrder.LITTLE_ENDIAN) ? INT16_LITTLE_ENDIAN : INT16_BIG_ENDIAN;
+        } else if (sizeInBytes == 4)
+        {
+            return (byteOrder == ByteOrder.LITTLE_ENDIAN) ? INT32_LITTLE_ENDIAN : INT32_BIG_ENDIAN;
+
+        } else if (sizeInBytes == 8)
+        {
+            return (byteOrder == ByteOrder.LITTLE_ENDIAN) ? INT64_LITTLE_ENDIAN : INT64_BIG_ENDIAN;
+        }
+        return null;
+    }
+
+    static NativeArrayEncoding tryGetFloatEncoding(ByteOrder byteOrder, byte sizeInBytes)
+    {
+        assert byteOrder != null;
+        if (sizeInBytes == 4)
+        {
+            return (byteOrder == ByteOrder.LITTLE_ENDIAN) ? FLOAT32_LITTLE_ENDIAN
+                    : FLOAT32_BIG_ENDIAN;
+        } else if (sizeInBytes == 8)
+        {
+            return (byteOrder == ByteOrder.LITTLE_ENDIAN) ? FLOAT64_LITTLE_ENDIAN
+                    : FLOAT64_BIG_ENDIAN;
+        }
+        return null;
+    }
+
+    /**
+     * Returns the encoding for the given <var>byteArr</var>, or <code>null</code>, if
+     * <var>byteArr</var> is not an encoded array.
+     */
+    public static NativeArrayEncoding tryGetEncoding(byte[] byteArr)
+    {
+        if (byteArr.length < MIN_ENCODING_HEADER_SIZE)
+        {
+            return null;
+        }
+        final ByteOrder byteOrder =
+                (byteArr[1] == CHAR_L) ? ByteOrder.LITTLE_ENDIAN
+                        : (byteArr[1] == CHAR_B) ? ByteOrder.BIG_ENDIAN : null;
+        if (byteOrder == null)
+        {
+            return null;
+        }
+        if (byteArr[0] == CHAR_F)
+        {
+            return tryGetFloatEncoding(byteOrder, byteArr[2]);
+        } else if (byteArr[0] == CHAR_I)
+        {
+            return tryGetIntEncoding(byteOrder, byteArr[2]);
+        }
+        return null;
+    }
+}
\ No newline at end of file
diff --git a/base/source/java/ch/systemsx/cisd/base/convert/NativeTaggedArray.java b/base/source/java/ch/systemsx/cisd/base/convert/NativeTaggedArray.java
new file mode 100644
index 00000000000..08b1100776b
--- /dev/null
+++ b/base/source/java/ch/systemsx/cisd/base/convert/NativeTaggedArray.java
@@ -0,0 +1,344 @@
+/*
+ * Copyright 2010 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.systemsx.cisd.base.convert;
+
+import static ch.systemsx.cisd.base.convert.NativeData.FLOAT_SIZE;
+import static ch.systemsx.cisd.base.convert.NativeData.DOUBLE_SIZE;
+import static ch.systemsx.cisd.base.convert.NativeData.INT_SIZE;
+import static ch.systemsx.cisd.base.convert.NativeData.LONG_SIZE;
+import static ch.systemsx.cisd.base.convert.NativeData.SHORT_SIZE;
+
+import ch.systemsx.cisd.base.convert.NativeData.ByteOrder;
+
+/**
+ * A utility class that supports encoding and decoding of arrays of primitive number types to byte
+ * arrays such that the characteristics of the number type (float or integer, byte order, element
+ * size) and the dimensions are known and can be checked for correctness when converted back to the
+ * number type.
+ * 
+ * @author Bernd Rinn
+ */
+public class NativeTaggedArray
+{
+
+    private final static NativeData.ByteOrder NATIVE_BYTE_ORDER = NativeData.getNativeByteOrder();
+
+    private static final int MAGIC_SIZE = 3;
+
+    private static final int RANK_SIZE = 1;
+
+    private static final int RANK_INDEX = 3;
+
+    private static final int LENGTH_SIZE = 4;
+
+    private static final int LENGTH_INDEX = 4;
+
+    private static final int RANK_1 = 1;
+
+    //
+    // Float
+    //
+
+    /**
+     * Converts <var>data</var> into a tagged array in native byte order.
+     */
+    public static byte[] toByteArray(float[] data)
+    {
+        return toByteArray(data, NATIVE_BYTE_ORDER);
+    }
+
+    /**
+     * Converts <var>data</var> into a tagged array in native byte order.
+     */
+    public static byte[] toByteArray(float[] data, ByteOrder byteOrder)
+    {
+        final byte[] magic =
+                NativeArrayEncoding.tryGetFloatEncoding(byteOrder, (byte) FLOAT_SIZE).getMagic();
+        assert magic.length == MAGIC_SIZE;
+        final int headerSize = MAGIC_SIZE + RANK_SIZE + 1 * LENGTH_SIZE;
+        final byte[] byteArr = new byte[headerSize + FLOAT_SIZE * data.length];
+        System.arraycopy(magic, 0, byteArr, 0, MAGIC_SIZE);
+        byteArr[RANK_INDEX] = RANK_1;
+        NativeData.copyIntToByte(new int[]
+            { data.length }, 0, byteArr, LENGTH_INDEX, 1, byteOrder);
+        NativeData.copyFloatToByte(data, 0, byteArr, headerSize, data.length, byteOrder);
+        return byteArr;
+    }
+
+    /**
+     * Returns the tagged array <var>data</var> as a float array or <code>null</code>, if
+     * <var>data</var> is not a tagged 1D float array.
+     */
+    public static float[] tryToFloatArray1D(byte[] data)
+    {
+        final NativeArrayEncoding encoding = NativeArrayEncoding.tryGetEncoding(data);
+        if (encoding == null || encoding.isInteger() || encoding.getSizeInBytes() != FLOAT_SIZE)
+        {
+            return null;
+        }
+        final int rank = data[RANK_INDEX];
+        if (rank != 1)
+        {
+            return null;
+        }
+        final int[] dimensions = new int[1];
+        NativeData.copyByteToInt(data, LENGTH_INDEX, dimensions, 0, 1, encoding.getByteOrder());
+        if (dimensions[0] * FLOAT_SIZE + LENGTH_INDEX + LENGTH_SIZE != data.length)
+        {
+            return null;
+        }
+        final float[] floatData = new float[dimensions[0]];
+        NativeData.copyByteToFloat(data, LENGTH_INDEX + LENGTH_SIZE, floatData, 0,
+                floatData.length, encoding.getByteOrder());
+        return floatData;
+    }
+
+    //
+    // Double
+    //
+
+    /**
+     * Converts <var>data</var> into a tagged array in native byte order.
+     */
+    public static byte[] toByteArray(double[] data)
+    {
+        return toByteArray(data, NATIVE_BYTE_ORDER);
+    }
+
+    /**
+     * Converts <var>data</var> into a tagged array in native byte order.
+     */
+    public static byte[] toByteArray(double[] data, ByteOrder byteOrder)
+    {
+        final byte[] magic =
+                NativeArrayEncoding.tryGetFloatEncoding(byteOrder, (byte) DOUBLE_SIZE).getMagic();
+        assert magic.length == MAGIC_SIZE;
+        final int headerSize = MAGIC_SIZE + RANK_SIZE + 1 * LENGTH_SIZE;
+        final byte[] byteArr = new byte[headerSize + DOUBLE_SIZE * data.length];
+        System.arraycopy(magic, 0, byteArr, 0, MAGIC_SIZE);
+        byteArr[RANK_INDEX] = RANK_1;
+        NativeData.copyIntToByte(new int[]
+            { data.length }, 0, byteArr, LENGTH_INDEX, 1, byteOrder);
+        NativeData.copyDoubleToByte(data, 0, byteArr, headerSize, data.length, byteOrder);
+        return byteArr;
+    }
+
+    /**
+     * Returns the tagged array <var>data</var> as a double array or <code>null</code>, if
+     * <var>data</var> is not a tagged 1D double array.
+     */
+    public static double[] tryToDoubleArray1D(byte[] data)
+    {
+        final NativeArrayEncoding encoding = NativeArrayEncoding.tryGetEncoding(data);
+        if (encoding == null || encoding.isInteger() || encoding.getSizeInBytes() != DOUBLE_SIZE)
+        {
+            return null;
+        }
+        final int rank = data[RANK_INDEX];
+        if (rank != 1)
+        {
+            return null;
+        }
+        final int[] dimensions = new int[1];
+        NativeData.copyByteToInt(data, LENGTH_INDEX, dimensions, 0, 1, encoding.getByteOrder());
+        if (dimensions[0] * DOUBLE_SIZE + LENGTH_INDEX + LENGTH_SIZE != data.length)
+        {
+            return null;
+        }
+        final double[] doubleData = new double[dimensions[0]];
+        NativeData.copyByteToDouble(data, LENGTH_INDEX + LENGTH_SIZE, doubleData, 0,
+                doubleData.length, encoding.getByteOrder());
+        return doubleData;
+    }
+
+    //
+    // Short
+    //
+
+    /**
+     * Converts <var>data</var> into a tagged array in native byte order.
+     */
+    public static byte[] toByteArray(short[] data)
+    {
+        return toByteArray(data, NATIVE_BYTE_ORDER);
+    }
+
+    /**
+     * Converts <var>data</var> into a tagged array in native byte order.
+     */
+    public static byte[] toByteArray(short[] data, ByteOrder byteOrder)
+    {
+        final byte[] magic =
+                NativeArrayEncoding.tryGetIntEncoding(byteOrder, (byte) SHORT_SIZE).getMagic();
+        assert magic.length == MAGIC_SIZE;
+        final int headerSize = MAGIC_SIZE + RANK_SIZE + 1 * LENGTH_SIZE;
+        final byte[] byteArr = new byte[headerSize + SHORT_SIZE * data.length];
+        System.arraycopy(magic, 0, byteArr, 0, MAGIC_SIZE);
+        byteArr[RANK_INDEX] = RANK_1;
+        NativeData.copyIntToByte(new int[]
+            { data.length }, 0, byteArr, LENGTH_INDEX, 1, byteOrder);
+        NativeData.copyShortToByte(data, 0, byteArr, headerSize, data.length, byteOrder);
+        return byteArr;
+    }
+
+    /**
+     * Returns the tagged array <var>data</var> as a short array or <code>null</code>, if
+     * <var>data</var> is not a tagged 1D short array.
+     */
+    public static short[] tryToShortArray1D(byte[] data)
+    {
+        final NativeArrayEncoding encoding = NativeArrayEncoding.tryGetEncoding(data);
+        if (encoding == null || encoding.isFloatingPoint()
+                || encoding.getSizeInBytes() != SHORT_SIZE)
+        {
+            return null;
+        }
+        final int rank = data[RANK_INDEX];
+        if (rank != 1)
+        {
+            return null;
+        }
+        final int[] dimensions = new int[1];
+        NativeData.copyByteToInt(data, LENGTH_INDEX, dimensions, 0, 1, encoding.getByteOrder());
+        if (dimensions[0] * SHORT_SIZE + LENGTH_INDEX + LENGTH_SIZE != data.length)
+        {
+            return null;
+        }
+        final short[] shortData = new short[dimensions[0]];
+        NativeData.copyByteToShort(data, LENGTH_INDEX + LENGTH_SIZE, shortData, 0,
+                shortData.length, encoding.getByteOrder());
+        return shortData;
+    }
+
+    //
+    // Int
+    //
+
+    /**
+     * Converts <var>data</var> into a tagged array in native byte order.
+     */
+    public static byte[] toByteArray(int[] data)
+    {
+        return toByteArray(data, NATIVE_BYTE_ORDER);
+    }
+
+    /**
+     * Converts <var>data</var> into a tagged array in native byte order.
+     */
+    public static byte[] toByteArray(int[] data, ByteOrder byteOrder)
+    {
+        final byte[] magic =
+                NativeArrayEncoding.tryGetIntEncoding(byteOrder, (byte) INT_SIZE).getMagic();
+        assert magic.length == MAGIC_SIZE;
+        final int headerSize = MAGIC_SIZE + RANK_SIZE + 1 * LENGTH_SIZE;
+        final byte[] byteArr = new byte[headerSize + INT_SIZE * data.length];
+        System.arraycopy(magic, 0, byteArr, 0, MAGIC_SIZE);
+        byteArr[RANK_INDEX] = RANK_1;
+        NativeData.copyIntToByte(new int[]
+            { data.length }, 0, byteArr, LENGTH_INDEX, 1, byteOrder);
+        NativeData.copyIntToByte(data, 0, byteArr, headerSize, data.length, byteOrder);
+        return byteArr;
+    }
+
+    /**
+     * Returns the tagged array <var>data</var> as an int array or <code>null</code>, if
+     * <var>data</var> is not a tagged 1D int array.
+     */
+    public static int[] tryToIntArray1D(byte[] data)
+    {
+        final NativeArrayEncoding encoding = NativeArrayEncoding.tryGetEncoding(data);
+        if (encoding == null || encoding.isFloatingPoint() || encoding.getSizeInBytes() != INT_SIZE)
+        {
+            return null;
+        }
+        final int rank = data[RANK_INDEX];
+        if (rank != 1)
+        {
+            return null;
+        }
+        final int[] dimensions = new int[1];
+        NativeData.copyByteToInt(data, LENGTH_INDEX, dimensions, 0, 1, encoding.getByteOrder());
+        if (dimensions[0] * INT_SIZE + LENGTH_INDEX + LENGTH_SIZE != data.length)
+        {
+            return null;
+        }
+        final int[] intData = new int[dimensions[0]];
+        NativeData.copyByteToInt(data, LENGTH_INDEX + LENGTH_SIZE, intData, 0, intData.length,
+                encoding.getByteOrder());
+        return intData;
+    }
+
+    //
+    // Long
+    //
+
+    /**
+     * Converts <var>data</var> into a tagged array in native byte order.
+     */
+    public static byte[] toByteArray(long[] data)
+    {
+        return toByteArray(data, NATIVE_BYTE_ORDER);
+    }
+
+    /**
+     * Converts <var>data</var> into a tagged array in native byte order.
+     */
+    public static byte[] toByteArray(long[] data, ByteOrder byteOrder)
+    {
+        final byte[] magic =
+                NativeArrayEncoding.tryGetIntEncoding(byteOrder, (byte) LONG_SIZE).getMagic();
+        assert magic.length == MAGIC_SIZE;
+        final int headerSize = MAGIC_SIZE + RANK_SIZE + 1 * LENGTH_SIZE;
+        final byte[] byteArr = new byte[headerSize + LONG_SIZE * data.length];
+        System.arraycopy(magic, 0, byteArr, 0, MAGIC_SIZE);
+        byteArr[RANK_INDEX] = RANK_1;
+        NativeData.copyIntToByte(new int[]
+            { data.length }, 0, byteArr, LENGTH_INDEX, 1, byteOrder);
+        NativeData.copyLongToByte(data, 0, byteArr, headerSize, data.length, byteOrder);
+        return byteArr;
+    }
+
+    /**
+     * Returns the tagged array <var>data</var> as a long array or <code>null</code>, if
+     * <var>data</var> is not a tagged 1D long array.
+     */
+    public static long[] tryToLongArray1D(byte[] data)
+    {
+        final NativeArrayEncoding encoding = NativeArrayEncoding.tryGetEncoding(data);
+        if (encoding == null || encoding.isFloatingPoint()
+                || encoding.getSizeInBytes() != LONG_SIZE)
+        {
+            return null;
+        }
+        final int rank = data[RANK_INDEX];
+        if (rank != 1)
+        {
+            return null;
+        }
+        final int[] dimensions = new int[1];
+        NativeData.copyByteToInt(data, LENGTH_INDEX, dimensions, 0, 1, encoding.getByteOrder());
+        if (dimensions[0] * LONG_SIZE + LENGTH_INDEX + LENGTH_SIZE != data.length)
+        {
+            return null;
+        }
+        final long[] intData = new long[dimensions[0]];
+        NativeData.copyByteToLong(data, LENGTH_INDEX + LENGTH_SIZE, intData, 0, intData.length,
+                encoding.getByteOrder());
+        return intData;
+    }
+
+}
diff --git a/base/sourceTest/java/ch/systemsx/cisd/base/AllTests.java b/base/sourceTest/java/ch/systemsx/cisd/base/AllTests.java
new file mode 100644
index 00000000000..f486b95131e
--- /dev/null
+++ b/base/sourceTest/java/ch/systemsx/cisd/base/AllTests.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2010 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.systemsx.cisd.base;
+
+import ch.systemsx.cisd.base.convert.NativeDataTests;
+import ch.systemsx.cisd.base.convert.NativeTaggedArrayTests;
+import ch.systemsx.cisd.base.unix.Unix;
+import ch.systemsx.cisd.base.unix.UnixTests;
+
+/**
+ * Run all unit tests.
+ *
+ * @author Bernd Rinn
+ */
+public class AllTests
+{
+
+    public static void main(String[] args) throws Throwable
+    {
+        if (Unix.isOperational())
+        {
+            UnixTests.main(args);
+        }
+        System.out.println();
+        NativeDataTests.main(args);
+        System.out.println();
+        NativeTaggedArrayTests.main(args);
+    }
+
+}
diff --git a/base/sourceTest/java/ch/systemsx/cisd/base/convert/NativeTaggedArrayTests.java b/base/sourceTest/java/ch/systemsx/cisd/base/convert/NativeTaggedArrayTests.java
new file mode 100644
index 00000000000..6020274d7f5
--- /dev/null
+++ b/base/sourceTest/java/ch/systemsx/cisd/base/convert/NativeTaggedArrayTests.java
@@ -0,0 +1,276 @@
+/*
+ * Copyright 2010 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.systemsx.cisd.base.convert;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.Arrays;
+
+import org.testng.annotations.Test;
+
+import ch.systemsx.cisd.base.BuildAndEnvironmentInfo;
+import ch.systemsx.cisd.base.convert.NativeData.ByteOrder;
+
+import static org.testng.AssertJUnit.*;
+
+/**
+ * Test cases for {@link NativeTaggedArray}.
+ * 
+ * @author Bernd Rinn
+ */
+public class NativeTaggedArrayTests
+{
+
+    @Test
+    public static void testFloat1DArrayNativeByteOrder()
+    {
+        final float[] floatArr = new float[]
+            { 1.1f, -3.2f, 1001.5f };
+        final byte[] taggedArr = NativeTaggedArray.toByteArray(floatArr);
+        assertEquals(3 * 4 + 4 + 4, taggedArr.length);
+        final float[] convertedFloatArr = NativeTaggedArray.tryToFloatArray1D(taggedArr);
+        final NativeArrayEncoding encoding = NativeArrayEncoding.tryGetEncoding(taggedArr);
+        assertNotNull(encoding);
+        assertEquals(NativeData.getNativeByteOrder(), encoding.getByteOrder());
+        assertEquals(4, encoding.getSizeInBytes());
+        assertTrue(encoding.isFloatingPoint());
+        assertFalse(encoding.isInteger());
+        assertTrue(Arrays.equals(floatArr, convertedFloatArr));
+    }
+
+    @Test
+    public static void testFloat1DArrayNonNativeByteOrder()
+    {
+        final float[] floatArr = new float[]
+            { 1.1f, -3.2f, 1001.5f };
+        final ByteOrder nonNativeByteOrder =
+                (NativeData.getNativeByteOrder() == ByteOrder.LITTLE_ENDIAN) ? ByteOrder.BIG_ENDIAN
+                        : ByteOrder.LITTLE_ENDIAN;
+        final byte[] taggedArr = NativeTaggedArray.toByteArray(floatArr, nonNativeByteOrder);
+        assertEquals(3 * 4 + 4 + 4, taggedArr.length);
+        final float[] convertedFloatArr = NativeTaggedArray.tryToFloatArray1D(taggedArr);
+        final NativeArrayEncoding encoding = NativeArrayEncoding.tryGetEncoding(taggedArr);
+        assertNotNull(encoding);
+        assertEquals(ByteOrder.BIG_ENDIAN, encoding.getByteOrder());
+        assertEquals(4, encoding.getSizeInBytes());
+        assertTrue(encoding.isFloatingPoint());
+        assertFalse(encoding.isInteger());
+        assertTrue(Arrays.equals(floatArr, convertedFloatArr));
+    }
+
+    @Test
+    public static void testDouble1DArrayNativeByteOrder()
+    {
+        final double[] doubleArr = new double[]
+            { 1.1, -3.2, 1001.5 };
+        final byte[] taggedArr = NativeTaggedArray.toByteArray(doubleArr);
+        assertEquals(3 * 8 + 4 + 4, taggedArr.length);
+        final double[] convertedDoubleArr = NativeTaggedArray.tryToDoubleArray1D(taggedArr);
+        final NativeArrayEncoding encoding = NativeArrayEncoding.tryGetEncoding(taggedArr);
+        assertNotNull(encoding);
+        assertEquals(NativeData.getNativeByteOrder(), encoding.getByteOrder());
+        assertEquals(8, encoding.getSizeInBytes());
+        assertTrue(encoding.isFloatingPoint());
+        assertFalse(encoding.isInteger());
+        assertTrue(Arrays.equals(doubleArr, convertedDoubleArr));
+    }
+
+    @Test
+    public static void testDouble1DArrayNonNativeByteOrder()
+    {
+        final double[] doubleArr = new double[]
+            { 1.1, -3.2, 1001.5 };
+        final ByteOrder nonNativeByteOrder =
+                (NativeData.getNativeByteOrder() == ByteOrder.LITTLE_ENDIAN) ? ByteOrder.BIG_ENDIAN
+                        : ByteOrder.LITTLE_ENDIAN;
+        final byte[] taggedArr = NativeTaggedArray.toByteArray(doubleArr, nonNativeByteOrder);
+        assertEquals(3 * 8 + 4 + 4, taggedArr.length);
+        final double[] convertedDoubleArr = NativeTaggedArray.tryToDoubleArray1D(taggedArr);
+        final NativeArrayEncoding encoding = NativeArrayEncoding.tryGetEncoding(taggedArr);
+        assertNotNull(encoding);
+        assertEquals(ByteOrder.BIG_ENDIAN, encoding.getByteOrder());
+        assertEquals(8, encoding.getSizeInBytes());
+        assertTrue(encoding.isFloatingPoint());
+        assertFalse(encoding.isInteger());
+        assertTrue(Arrays.equals(doubleArr, convertedDoubleArr));
+    }
+
+    @Test
+    public static void testShort1DArrayNativeByteOrder()
+    {
+        final short[] shortArr = new short[]
+            { 1, -3, 1001 };
+        final byte[] taggedArr = NativeTaggedArray.toByteArray(shortArr);
+        assertEquals(3 * 2 + 4 + 4, taggedArr.length);
+        final short[] convertedShortArr = NativeTaggedArray.tryToShortArray1D(taggedArr);
+        final NativeArrayEncoding encoding = NativeArrayEncoding.tryGetEncoding(taggedArr);
+        assertNotNull(encoding);
+        assertEquals(NativeData.getNativeByteOrder(), encoding.getByteOrder());
+        assertEquals(2, encoding.getSizeInBytes());
+        assertFalse(encoding.isFloatingPoint());
+        assertTrue(encoding.isInteger());
+        assertTrue(Arrays.equals(shortArr, convertedShortArr));
+    }
+
+    @Test
+    public static void testShort1DArrayNonNativeByteOrder()
+    {
+        final short[] shortArr = new short[]
+            { 1, -3, 1001 };
+        final ByteOrder nonNativeByteOrder =
+                (NativeData.getNativeByteOrder() == ByteOrder.LITTLE_ENDIAN) ? ByteOrder.BIG_ENDIAN
+                        : ByteOrder.LITTLE_ENDIAN;
+        final byte[] taggedArr = NativeTaggedArray.toByteArray(shortArr, nonNativeByteOrder);
+        assertEquals(3 * 2 + 4 + 4, taggedArr.length);
+        final short[] convertedShortArr = NativeTaggedArray.tryToShortArray1D(taggedArr);
+        final NativeArrayEncoding encoding = NativeArrayEncoding.tryGetEncoding(taggedArr);
+        assertNotNull(encoding);
+        assertEquals(ByteOrder.BIG_ENDIAN, encoding.getByteOrder());
+        assertEquals(2, encoding.getSizeInBytes());
+        assertFalse(encoding.isFloatingPoint());
+        assertTrue(encoding.isInteger());
+        assertTrue(Arrays.equals(shortArr, convertedShortArr));
+    }
+
+    @Test
+    public static void testInt1DArrayNativeByteOrder()
+    {
+        final int[] intArr = new int[]
+            { 1, -3, 1001 };
+        final byte[] taggedArr = NativeTaggedArray.toByteArray(intArr);
+        assertEquals(3 * 4 + 4 + 4, taggedArr.length);
+        final int[] convertedIntArr = NativeTaggedArray.tryToIntArray1D(taggedArr);
+        final NativeArrayEncoding encoding = NativeArrayEncoding.tryGetEncoding(taggedArr);
+        assertNotNull(encoding);
+        assertEquals(NativeData.getNativeByteOrder(), encoding.getByteOrder());
+        assertEquals(4, encoding.getSizeInBytes());
+        assertFalse(encoding.isFloatingPoint());
+        assertTrue(encoding.isInteger());
+        assertTrue(Arrays.equals(intArr, convertedIntArr));
+    }
+
+    @Test
+    public static void testInt1DArrayNonNativeByteOrder()
+    {
+        final int[] intArr = new int[]
+            { 1, -3, 1001 };
+        final ByteOrder nonNativeByteOrder =
+                (NativeData.getNativeByteOrder() == ByteOrder.LITTLE_ENDIAN) ? ByteOrder.BIG_ENDIAN
+                        : ByteOrder.LITTLE_ENDIAN;
+        final byte[] taggedArr = NativeTaggedArray.toByteArray(intArr, nonNativeByteOrder);
+        assertEquals(3 * 4 + 4 + 4, taggedArr.length);
+        final int[] convertedIntArr = NativeTaggedArray.tryToIntArray1D(taggedArr);
+        final NativeArrayEncoding encoding = NativeArrayEncoding.tryGetEncoding(taggedArr);
+        assertNotNull(encoding);
+        assertEquals(ByteOrder.BIG_ENDIAN, encoding.getByteOrder());
+        assertEquals(4, encoding.getSizeInBytes());
+        assertFalse(encoding.isFloatingPoint());
+        assertTrue(encoding.isInteger());
+        assertTrue(Arrays.equals(intArr, convertedIntArr));
+    }
+
+    @Test
+    public static void testLong1DArrayNativeByteOrder()
+    {
+        final long[] longArr = new long[]
+            { 1, -3, 1001 };
+        final byte[] taggedArr = NativeTaggedArray.toByteArray(longArr);
+        assertEquals(3 * 8 + 4 + 4, taggedArr.length);
+        final long[] convertedLongArr = NativeTaggedArray.tryToLongArray1D(taggedArr);
+        final NativeArrayEncoding encoding = NativeArrayEncoding.tryGetEncoding(taggedArr);
+        assertNotNull(encoding);
+        assertEquals(NativeData.getNativeByteOrder(), encoding.getByteOrder());
+        assertEquals(8, encoding.getSizeInBytes());
+        assertFalse(encoding.isFloatingPoint());
+        assertTrue(encoding.isInteger());
+        assertTrue(Arrays.equals(longArr, convertedLongArr));
+    }
+
+    @Test
+    public static void testLong1DArrayNonNativeByteOrder()
+    {
+        final long[] longArr = new long[]
+            { 1, -3, 1001 };
+        final ByteOrder nonNativeByteOrder =
+                (NativeData.getNativeByteOrder() == ByteOrder.LITTLE_ENDIAN) ? ByteOrder.BIG_ENDIAN
+                        : ByteOrder.LITTLE_ENDIAN;
+        final byte[] taggedArr = NativeTaggedArray.toByteArray(longArr, nonNativeByteOrder);
+        assertEquals(3 * 8 + 4 + 4, taggedArr.length);
+        final long[] convertedLongArr = NativeTaggedArray.tryToLongArray1D(taggedArr);
+        final NativeArrayEncoding encoding = NativeArrayEncoding.tryGetEncoding(taggedArr);
+        assertNotNull(encoding);
+        assertEquals(ByteOrder.BIG_ENDIAN, encoding.getByteOrder());
+        assertEquals(8, encoding.getSizeInBytes());
+        assertFalse(encoding.isFloatingPoint());
+        assertTrue(encoding.isInteger());
+        assertTrue(Arrays.equals(longArr, convertedLongArr));
+    }
+
+    private void afterClass()
+    {
+    }
+
+    private void setUp()
+    {
+    }
+
+    public static void main(String[] args) throws Throwable
+    {
+        System.out.println(BuildAndEnvironmentInfo.INSTANCE);
+        System.out.println();
+        NativeData.ensureNativeLibIsLoaded();
+        final NativeTaggedArrayTests test = new NativeTaggedArrayTests();
+        try
+        {
+            for (Method m : NativeTaggedArrayTests.class.getMethods())
+            {
+                final Test testAnnotation = m.getAnnotation(Test.class);
+                if (testAnnotation == null || m.getParameterTypes().length > 0)
+                {
+                    continue;
+                }
+                System.out.println("Running " + m.getName());
+                test.setUp();
+                try
+                {
+                    m.invoke(test);
+                } catch (InvocationTargetException wrapperThrowable)
+                {
+                    final Throwable th = wrapperThrowable.getCause();
+                    boolean exceptionFound = false;
+                    for (Class<?> expectedExClazz : testAnnotation.expectedExceptions())
+                    {
+                        if (expectedExClazz == th.getClass())
+                        {
+                            exceptionFound = true;
+                            break;
+                        }
+                    }
+                    if (exceptionFound == false)
+                    {
+                        throw th;
+                    }
+                }
+            }
+            System.out.println("Tests OK!");
+        } finally
+        {
+            test.afterClass();
+        }
+    }
+
+}
-- 
GitLab