* Copyright (c) 2019-2021 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved.
* BSD-style license. See OpenTrafficSim License.
*
* @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 ValueRuntimeException when that happens uncaught, this test has failed
*/
@Test
public void testDJunits() throws SerializationException, ValueRuntimeException
{
Length length = new Length(123.4, LengthUnit.FOOT);
Dimensionless value = new Dimensionless(345.6, DimensionlessUnit.SI);
FloatArea area = new FloatArea(66.66f, AreaUnit.ACRE);
ElectricalCurrentVector currents =
DoubleVector.instantiate(new double[] {1.2, 2.3, 3.4}, ElectricalCurrentUnit.MILLIAMPERE, StorageType.DENSE);
FloatElectricalResistanceVector resistors =
FloatVector.instantiate(new float[] {1.2f, 4.7f, 6.8f}, ElectricalResistanceUnit.KILOOHM, StorageType.DENSE);
ElectricalCurrentMatrix currentMatrix = DoubleMatrix.instantiate(new double[][] {{1.2, 2.3, 3.4}, {5.5, 6.6, 7.7}},
ElectricalCurrentUnit.MILLIAMPERE, StorageType.DENSE);
FloatElectricalResistanceMatrix resistorMatrix = FloatMatrix.instantiate(
new float[][] {{1.2f, 4.7f, 6.8f}, {2.2f, 3.3f, 4.4f}}, ElectricalResistanceUnit.KILOOHM, StorageType.DENSE);
Object[] objects = new Object[] {length, value, 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])));
}
}
}
}
/**
* Test stored information about djunits SerializationUnits.
* @throws SerializationException when that happens uncaught, this test has failed
* @throws ValueRuntimeException when that happens uncaught, this test has failed
*/
@Test
public void testSerializationUnits() throws SerializationException, ValueRuntimeException
{
SerializationUnits areaSerUnit = SerializationUnits.AREA;
assertEquals("Area", areaSerUnit.getName());
assertEquals("Area (m2)", areaSerUnit.getDescription());
assertEquals(5, areaSerUnit.getCode());
assertEquals(AreaUnit.class, areaSerUnit.getDjunitsType());
assertEquals("[m^2]", areaSerUnit.getSiUnit());
assertEquals(LengthUnit.class, SerializationUnits.getUnitClass((byte) 16));
assertEquals(16, SerializationUnits.getUnitCode(LengthUnit.INCH));
assertEquals(areaSerUnit, SerializationUnits.getUnitType((byte) 5));
assertEquals(areaSerUnit, SerializationUnits.getUnitType(AreaUnit.ARE));
assertNotEquals(SerializationUnits.RADIOACTIVITY, areaSerUnit);
assertNotEquals(new Object(), areaSerUnit);
assertNotEquals(SerializationUnits.RADIOACTIVITY.hashCode(), areaSerUnit.hashCode());
assertNotEquals(new Object().hashCode(), areaSerUnit.hashCode());
}
/**
* Test stored information about djunits display types.
* @throws SerializationException when that happens uncaught, this test has failed
* @throws ValueRuntimeException when that happens uncaught, this test has failed
*/
@Test
public void testDJunitDisplayTypes() throws SerializationException, ValueRuntimeException
{
SerializationUnits areaSerUnit = SerializationUnits.AREA;
DisplayType aream2 = DisplayType.AREA_SQUARE_METER;
DisplayType areaacre = DisplayType.AREA_ACRE;
DisplayType masskg = DisplayType.MASS_KILOGRAM;
assertEquals("m2", aream2.getAbbreviation());
assertEquals(0, aream2.getByteCode());
assertEquals(18, areaacre.getByteCode());
assertEquals(AreaUnit.SQUARE_METER, aream2.getDjunitsType());
assertEquals(AreaUnit.ACRE, areaacre.getDjunitsType());
assertEquals(0, aream2.getIntCode());
assertEquals(18, areaacre.getIntCode());
assertEquals("SQUARE_METER", aream2.getName());
assertEquals("ACRE", areaacre.getName());
assertEquals(areaSerUnit, aream2.getUnitType());
assertEquals(areaacre.getUnitType(), aream2.getUnitType());
assertEquals(8, DisplayType.getByteCode(ElectricalResistanceUnit.STATOHM));
assertEquals(areaacre, DisplayType.getDisplayType(AreaUnit.ACRE));
assertEquals(DisplayType.ENERGY_CALORIE, DisplayType.getDisplayType((byte) 11, 30));
assertEquals(areaacre, DisplayType.getDisplayType(areaSerUnit, 18));
assertEquals(30, DisplayType.getIntCode(EnergyUnit.CALORIE));
assertEquals(EnergyUnit.CALORIE, DisplayType.getUnit((byte) 11, 30));
assertEquals(AreaUnit.ACRE, DisplayType.getUnit(areaSerUnit, 18));
assertNotEquals(aream2, areaacre);
assertNotEquals(masskg, areaacre);
assertNotEquals(new Object(), areaacre);
assertNotEquals(aream2.hashCode(), areaacre.hashCode());
assertNotEquals(masskg.hashCode(), areaacre.hashCode());
assertNotEquals(new Object().hashCode(), areaacre.hashCode());
}
/** Class used to test serialization of classes that implement SerializableObject. */
static class Compound implements SerializableObject
{
/** Field 1. */
@SuppressWarnings("checkstyle:visibilitymodifier")
public Integer intValue;
/** Field 2. */
@SuppressWarnings("checkstyle:visibilitymodifier")
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