* Copyright (c) 2019-2019 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved.
* BSD-style license. See OpenTrafficSim License.
*
* $LastChangedDate: 2015-07-24 02:58:59 +0200 (Fri, 24 Jul 2015) $, @version $Revision: 1147 $, by $Author: averbraeck $,
* initial version Jun 10, 2019
* @author Alexander Verbraeck
* @author Peter Knoppers
*/
public class Tests
{
/**
* Basic test encoding and decoding of the basic types.
* @throws SerializationException when that happens uncaught this test has failed
*/
@Test
public void simpleTests() throws SerializationException
{
int intValue = 123;
Integer integerValue = -456;
short shortValue = 234;
Short shortValue2 = -345;
long longValue = 98765L;
Long longValue2 = -98765L;
Byte byteValue = 12;
byte byteValue2 = -23;
float floatValue = 1.234f;
Float floatValue2 = -3.456f;
double doubleValue = 4.56789;
Double doubleValue2 = -4.56789;
boolean boolValue = true;
Boolean boolValue2 = false;
Character charValue = 'a';
char charValue2 = 'b';
String stringValue = "abcDEF123!@#ȦȧȨ\u0776\u0806\u080e";
Object[] objects = new Object[] { intValue, integerValue, shortValue, shortValue2, longValue, longValue2, byteValue,
byteValue2, floatValue, floatValue2, doubleValue, doubleValue2, boolValue, boolValue2, charValue, charValue2,
stringValue };
for (EndianUtil endianUtil : new EndianUtil[] { EndianUtil.BIG_ENDIAN, EndianUtil.LITTLE_ENDIAN })
{
for (boolean encodeUTF8 : new boolean[] { false, true })
{
// System.out.println("" + endianUtil + ", UTF8=" + encodeUTF8);
byte[] serialized = encodeUTF8 ? TypedMessage.encodeUTF8(endianUtil, objects)
: TypedMessage.encodeUTF16(endianUtil, objects);
System.out.print(HexDumper.hexDumper(serialized));
System.out.print(SerialDataDumper.serialDataDumper(endianUtil, serialized));
for (boolean primitive : new boolean[] { false, true })
{
Object[] decodedObjects = primitive ? TypedMessage.decodeToPrimitiveDataTypes(serialized, endianUtil)
: TypedMessage.decodeToObjectDataTypes(serialized, endianUtil);
assertEquals("Size of decoded matches", objects.length, decodedObjects.length);
for (int i = 0; i < objects.length; i++)
{
assertEquals(
"decoded object at index " + i + "(" + objects[i] + ") equals corresponding object in input",
objects[i], decodedObjects[i]);
}
}
}
}
}
/**
* Test encoding and decoding of Strings with more exotic characters for UTF-8 and UTF-16.
* @throws SerializationException when that happens uncaught this test has failed
* @throws UnsupportedEncodingException when UTF-8 en/decoding fails
*/
@Test
public void testStrings() throws SerializationException, UnsupportedEncodingException
{
String abc = "abc";
String copyright = "" + '\u00A9';
String xi = "" + '\u03BE';
String permille = "" + '\u2030';
String smiley = "\uD83D\uDE00";
String complex = smiley + copyright + xi + permille;
testString(3, 6, abc);
testString(2, 2, copyright);
testString(3, 2, permille);
testString(2, 2, xi);
testString(4, 4, smiley);
compare(TypedMessage.encodeUTF8(EndianUtil.BIG_ENDIAN, permille),
new byte[] { 9, 0, 0, 0, 3, (byte) 0xE2, (byte) 0x80, (byte) 0xB0 });
compare(TypedMessage.encodeUTF16(EndianUtil.BIG_ENDIAN, permille),
new byte[] { 10, 0, 0, 0, 1, (byte) 0x20, (byte) 0x30 });
compare(TypedMessage.encodeUTF8(EndianUtil.BIG_ENDIAN, smiley),
new byte[] { 9, 0, 0, 0, 4, (byte) 0xF0, (byte) 0x9F, (byte) 0x98, (byte) 0x80 });
compare(TypedMessage.encodeUTF16(EndianUtil.BIG_ENDIAN, smiley),
new byte[] { 10, 0, 0, 0, 2, (byte) 0xD8, (byte) 0x3D, (byte) 0xDE, (byte) 0x00 });
Object[] objects = new Object[] { copyright, xi, permille, smiley, abc, complex };
for (EndianUtil endianUtil : new EndianUtil[] { EndianUtil.BIG_ENDIAN, EndianUtil.LITTLE_ENDIAN })
{
for (boolean encodeUTF8 : new boolean[] { false, true })
{
byte[] serialized = encodeUTF8 ? TypedMessage.encodeUTF8(endianUtil, objects)
: TypedMessage.encodeUTF16(endianUtil, objects);
System.out.print(HexDumper.hexDumper(serialized));
System.out.print(SerialDataDumper.serialDataDumper(endianUtil, serialized));
Object[] decodedObjects = TypedMessage.decodeToObjectDataTypes(serialized, endianUtil);
assertEquals("Size of decoded matches", objects.length, decodedObjects.length);
for (int i = 0; i < objects.length; i++)
{
assertEquals("decoded object at index " + i + "(" + objects[i] + ") equals corresponding object in input",
objects[i], decodedObjects[i]);
}
}
}
}
/**
* Compare two byte arrays.
* @param actual the calculated byte array
* @param expected the expected byte array
*/
private void compare(final byte[] actual, final byte[] expected)
{
assertEquals(expected.length, actual.length);
for (int i = 0; i < expected.length; i++)
{
assertEquals("byte " + i + " expected: " + expected[i] + ", actual: " + actual[i], expected[i], actual[i]);
}
}
/**
* Test encoding and decoding of one String for UTF-8 and UTF-16.
* @param expected8 expected length of UTF-8 encoding
* @param expected16 expected length of UTF-16 encoding
* @param s the string to test
* @throws SerializationException when that happens uncaught this test has failed
* @throws UnsupportedEncodingException when UTF-8 en/decoding fails
*/
private void testString(final int expected8, final int expected16, final String s)
throws SerializationException, UnsupportedEncodingException
{
assertEquals(expected8, s.getBytes("UTF-8").length);
assertEquals(expected16, s.getBytes("UTF-16BE").length);
assertEquals(expected16, s.getBytes("UTF-16LE").length);
byte[] b8 = TypedMessage.encodeUTF8(EndianUtil.BIG_ENDIAN, s);
byte[] b16BE = TypedMessage.encodeUTF16(EndianUtil.BIG_ENDIAN, s);
byte[] b16LE = TypedMessage.encodeUTF16(EndianUtil.LITTLE_ENDIAN, s);
assertEquals(expected8, b8.length - 5);
assertEquals(expected16, b16BE.length - 5);
assertEquals(expected16, b16LE.length - 5);
// get the number from the byte arrays
assertEquals(9, b8[0]);
assertEquals(expected8, EndianUtil.BIG_ENDIAN.decodeInt(b8, 1));
assertEquals(10, b16BE[0]);
assertEquals(expected16 / 2, EndianUtil.BIG_ENDIAN.decodeInt(b16BE, 1));
// TODO: assertEquals(10, b16LE[0]); the code for UTF-16LE will be different from 10 in a next version of djutils
assertEquals(expected16 / 2, EndianUtil.LITTLE_ENDIAN.decodeInt(b16LE, 1));
}
/**
* Test encoding and decoding of arrays.
* @throws SerializationException when that happens uncaught this test has failed
*/
@Test
public void testArrays() throws SerializationException
{
int[] integer = new int[] { 1, 2, 3 };
Integer[] integerValues2 = new Integer[] { -1, -2, -3 };
short[] shortValues = new short[] { 10, 20, 30 };
Short[] shortValues2 = new Short[] { -10, -20, -30 };
long[] longValues = new long[] { 1000, 2000, 3000 };
Long[] longValues2 = new Long[] { -1000L, -2000L, -3000L };
byte[] byteValues = new byte[] { 12, 13, 14 };
Byte[] byteValues2 = new Byte[] { -12, -13, -14 };
boolean[] boolValues = new boolean[] { false, true, true };
Boolean[] boolValues2 = new Boolean[] { true, true, false };
float[] floatValues = new float[] { 12.3f, 23.4f, 34.5f };
Float[] floatValues2 = new Float[] { -12.3f, -23.4f, -34.5f };
double[] doubleValues = new double[] { 23.45, 34.56, 45.67 };
Double[] doubleValues2 = new Double[] { -23.45, -34.56, -45.67 };
Object[] objects = new Object[] { integer, integerValues2, shortValues, shortValues2, longValues, longValues2,
byteValues, byteValues2, floatValues, floatValues2, doubleValues, doubleValues2, boolValues, boolValues2 };
for (EndianUtil endianUtil : new EndianUtil[] { EndianUtil.BIG_ENDIAN, EndianUtil.LITTLE_ENDIAN })
{
for (boolean encodeUTF8 : new boolean[] { false, true })
{
byte[] serialized = encodeUTF8 ? TypedMessage.encodeUTF8(endianUtil, objects)
: TypedMessage.encodeUTF16(endianUtil, objects);
System.out.print(HexDumper.hexDumper(serialized));
System.out.print(SerialDataDumper.serialDataDumper(endianUtil, serialized));
for (boolean primitive : new boolean[] { false, true })
{
Object[] decodedObjects = primitive ? TypedMessage.decodeToPrimitiveDataTypes(serialized, endianUtil)
: TypedMessage.decodeToObjectDataTypes(serialized, endianUtil);
assertEquals("Size of decoded matches", objects.length, decodedObjects.length);
for (int i = 0; i < objects.length; i++)
{
assertTrue("decoded object at index " + i + "(" + objects[i] + ") equals corresponding object in input",
deepEquals0(makePrimitive(objects[i]), makePrimitive(decodedObjects[i])));
}
}
}
}
}
/**
* Test encoding and decoding of arrays.
* @throws SerializationException when that happens uncaught this test has failed
*/
@Test
public void testMatrices() throws SerializationException
{
int[][] integer = new int[][] { { 1, 2, 3 }, { 4, 5, 6 } };
Integer[][] integerValues2 = new Integer[][] { { -1, -2, -3 }, { -4, -5, -6 } };
short[][] shortValues = new short[][] { { 10, 20, 30 }, { 40, 50, 60 } };
Short[][] shortValues2 = new Short[][] { { -10, -20, -30 }, { -40, -50, -60 } };
long[][] longValues = new long[][] { { 1000, 2000, 3000 }, { 3000, 4000, 5000 } };
Long[][] longValues2 = new Long[][] { { -1000L, -2000L, -3000L }, { -3000L, -4000L, -5000L } };
byte[][] byteValues = new byte[][] { { 12, 13, 14 }, { 15, 16, 17 } };
Byte[][] byteValues2 = new Byte[][] { { -12, -13, -14 }, { -15, -16, -17 } };
boolean[][] boolValues = new boolean[][] { { false, true, true }, { false, false, false } };
Boolean[][] boolValues2 = new Boolean[][] { { true, true, false }, { true, true, true } };
float[][] floatValues = new float[][] { { 12.3f, 23.4f, 34.5f }, { 44.4f, 55.5f, 66.6f } };
Float[][] floatValues2 = new Float[][] { { -12.3f, -23.4f, -34.5f }, { -11.1f, -22.2f, -33.3f } };
double[][] doubleValues = new double[][] { { 23.45, 34.56, 45.67 }, { 55.5, 66.6, 77.7 } };
Double[][] doubleValues2 = new Double[][] { { -23.45, -34.56, -45.67 }, { -22.2, -33.3, -44.4 } };
Object[] objects = new Object[] { integer, integerValues2, shortValues, shortValues2, longValues, longValues2,
byteValues, byteValues2, floatValues, floatValues2, doubleValues, doubleValues2, boolValues, boolValues2 };
for (EndianUtil endianUtil : new EndianUtil[] { EndianUtil.BIG_ENDIAN, EndianUtil.LITTLE_ENDIAN })
{
for (boolean encodeUTF8 : new boolean[] { false, true })
{
byte[] serialized = encodeUTF8 ? TypedMessage.encodeUTF8(endianUtil, objects)
: TypedMessage.encodeUTF16(endianUtil, objects);
System.out.print(HexDumper.hexDumper(serialized));
System.out.print(SerialDataDumper.serialDataDumper(endianUtil, serialized));
for (boolean primitive : new boolean[] { false, true })
{
Object[] decodedObjects = primitive ? TypedMessage.decodeToPrimitiveDataTypes(serialized, endianUtil)
: TypedMessage.decodeToObjectDataTypes(serialized, endianUtil);
assertEquals("Size of decoded matches", objects.length, decodedObjects.length);
for (int i = 0; i < objects.length; i++)
{
assertTrue("decoded object at index " + i + "(" + objects[i] + ") equals corresponding object in input",
deepEquals0(makePrimitive(objects[i]), makePrimitive(decodedObjects[i])));
}
}
}
}
}
/**
* Test encoding and decoding of strongly typed quantities (DJUNITS).
* @throws SerializationException when that happens uncaught, this test has failed
* @throws ValueException when that happens uncaught, this test has failed
*/
@Test
public void testDJunits() throws SerializationException, ValueException
{
Length length = new Length(123.4, LengthUnit.FOOT);
Dimensionless value = new Dimensionless(345.6, DimensionlessUnit.SI);
Money money = new Money(456, MoneyUnit.EUR);
FloatMoney floatMoney = new FloatMoney(123.45f, MoneyUnit.AED);
MoneyPerArea mpa = new MoneyPerArea(0.33, MoneyPerAreaUnit.USD_PER_ACRE);
MoneyPerLength mpl = new MoneyPerLength(0.22, MoneyPerLengthUnit.USD_PER_MILE);
MoneyPerEnergy mpe = new MoneyPerEnergy(0.33, MoneyPerEnergyUnit.EUR_PER_KILOWATTHOUR);
MoneyPerMass mpm = new MoneyPerMass(0.33, MoneyPerMassUnit.USD_PER_POUND);
MoneyPerDuration mpt = new MoneyPerDuration(0.33, MoneyPerDurationUnit.EUR_PER_DAY);
MoneyPerVolume mpv = new MoneyPerVolume(0.44, MoneyPerVolumeUnit.USD_PER_OUNCE_US_FLUID);
FloatMoneyPerVolume mpvw = new FloatMoneyPerVolume(0.55, MoneyPerVolumeUnit.USD_PER_OUNCE_US_FLUID);
FloatArea area = new FloatArea(66.66f, AreaUnit.ACRE);
ElectricalCurrentVector currents = new ElectricalCurrentVector(new double[] { 1.2, 2.3, 3.4 },
ElectricalCurrentUnit.MILLIAMPERE, StorageType.DENSE);
FloatElectricalResistanceVector resistors = new FloatElectricalResistanceVector(new float[] { 1.2f, 4.7f, 6.8f },
ElectricalResistanceUnit.KILOOHM, StorageType.DENSE);
ElectricalCurrentMatrix currentMatrix = new ElectricalCurrentMatrix(
new double[][] { { 1.2, 2.3, 3.4 }, { 5.5, 6.6, 7.7 } }, ElectricalCurrentUnit.MILLIAMPERE, StorageType.DENSE);
FloatElectricalResistanceMatrix resistorMatrix =
new FloatElectricalResistanceMatrix(new float[][] { { 1.2f, 4.7f, 6.8f }, { 2.2f, 3.3f, 4.4f } },
ElectricalResistanceUnit.KILOOHM, StorageType.DENSE);
Object[] objects = new Object[] { length, value, money, floatMoney, mpa, mpl, mpe, mpm, mpt, mpv, mpvw, area, currents,
resistors, currentMatrix, resistorMatrix };
for (EndianUtil endianUtil : new EndianUtil[] { EndianUtil.BIG_ENDIAN, EndianUtil.LITTLE_ENDIAN })
{
byte[] serialized = TypedMessage.encodeUTF16(endianUtil, objects);
System.out.print(HexDumper.hexDumper(serialized));
System.out.print(SerialDataDumper.serialDataDumper(endianUtil, serialized));
for (boolean primitive : new boolean[] { false, true })
{
Object[] decodedObjects = primitive ? TypedMessage.decodeToPrimitiveDataTypes(serialized, endianUtil)
: TypedMessage.decodeToObjectDataTypes(serialized, endianUtil);
assertEquals("Size of decoded matches", objects.length, decodedObjects.length);
for (int i = 0; i < objects.length; i++)
{
assertTrue("decoded object at index " + i + "(" + objects[i] + ") equals corresponding object in input",
deepEquals0(makePrimitive(objects[i]), makePrimitive(decodedObjects[i])));
}
}
}
}
/** Class used to test serialization of classes that implement SerializableObject. */
static class Compound implements SerializableObject
{
/** Field 1. */
public Integer intValue;
/** Field 2. */
public Double doubleValue;
@Override
public int hashCode()
{
final int prime = 31;
int result = 1;
result = prime * result + ((this.doubleValue == null) ? 0 : this.doubleValue.hashCode());
result = prime * result + ((this.intValue == null) ? 0 : this.intValue.hashCode());
return result;
}
@SuppressWarnings("checkstyle:needbraces")
@Override
public boolean equals(final Object obj)
{
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Compound other = (Compound) obj;
if (this.doubleValue == null)
{
if (other.doubleValue != null)
return false;
}
else if (!this.doubleValue.equals(other.doubleValue))
return false;
if (this.intValue == null)
{
if (other.intValue != null)
return false;
}
else if (!this.intValue.equals(other.intValue))
return false;
return true;
}
@Override
public String toString()
{
return "Compound [intValue=" + this.intValue + ", doubleValue=" + this.doubleValue + "]";
}
/**
* Construct a new Compound object.
* @param intValue int; the value to assign to intValue
* @param doubleValue double; the value to assign to doubleValue
*/
Compound(final int intValue, final double doubleValue)
{
this.intValue = intValue;
this.doubleValue = doubleValue;
}
@Override
public List