Files
pvData/testApp/misc/testSerialization.cpp
2013-05-08 18:35:51 -04:00

473 lines
14 KiB
C++

/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* EPICS pvData is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
/*
* testSerialization.cpp
*
* Created on: Oct 25, 2010
* Author: Miha Vitorovic
*/
#include <iostream>
#include <fstream>
#include <epicsUnitTest.h>
#include <testMain.h>
#include <dbDefs.h> // for NELEMENTS
#include <epicsExit.h>
#include <pv/pvIntrospect.h>
#include <pv/pvData.h>
#include <pv/serialize.h>
#include <pv/noDefaultMethods.h>
#include <pv/byteBuffer.h>
#include <pv/convert.h>
#include <pv/standardField.h>
#include <limits>
#define BYTE_MAX_VALUE std::numeric_limits<int8>::max()
#define BYTE_MIN_VALUE std::numeric_limits<int8>::min()
#define UBYTE_MAX_VALUE std::numeric_limits<uint8>::max()
#define SHORT_MAX_VALUE std::numeric_limits<int16>::max()
#define SHORT_MIN_VALUE std::numeric_limits<int16>::min()
#define USHORT_MAX_VALUE std::numeric_limits<uint16>::max()
#define INT_MAX_VALUE std::numeric_limits<int32>::max()
#define INT_MIN_VALUE std::numeric_limits<int32>::min()
#define UINT_MAX_VALUE std::numeric_limits<uint32>::max()
#define LONG_MAX_VALUE std::numeric_limits<int64>::max()
#define LONG_MIN_VALUE std::numeric_limits<int64>::min()
#define ULONG_MAX_VALUE std::numeric_limits<uint64>::max()
#define FLOAT_MAX_VALUE std::numeric_limits<float>::max()
#define FLOAT_MIN_VALUE std::numeric_limits<float>::min()
#define DOUBLE_MAX_VALUE std::numeric_limits<double>::max()
#define DOUBLE_MIN_VALUE std::numeric_limits<double>::min()
using namespace epics::pvData;
namespace {
static SerializableControl* flusher;
static DeserializableControl* control;
static ByteBuffer* buffer;
class SerializableControlImpl : public SerializableControl,
public NoDefaultMethods {
public:
virtual void flushSerializeBuffer() {
}
virtual void ensureBuffer(std::size_t /*size*/) {
}
virtual void alignBuffer(std::size_t alignment) {
buffer->align(alignment);
}
virtual bool directSerialize(ByteBuffer */*existingBuffer*/, const char* /*toSerialize*/,
std::size_t /*elementCount*/, std::size_t /*elementSize*/)
{
return false;
}
virtual void cachedSerialize(std::tr1::shared_ptr<const Field> const & field, ByteBuffer* buffer)
{
field->serialize(buffer, this);
}
SerializableControlImpl() {
}
virtual ~SerializableControlImpl() {
}
};
class DeserializableControlImpl : public DeserializableControl,
public NoDefaultMethods {
public:
virtual void ensureData(size_t /*size*/) {
}
virtual void alignData(size_t alignment) {
buffer->align(alignment);
}
virtual bool directDeserialize(ByteBuffer */*existingBuffer*/, char* /*deserializeTo*/,
std::size_t /*elementCount*/, std::size_t /*elementSize*/)
{
return false;
}
virtual std::tr1::shared_ptr<const Field> cachedDeserialize(ByteBuffer* buffer)
{
return getFieldCreate()->deserialize(buffer, this);
}
DeserializableControlImpl() {
}
virtual ~DeserializableControlImpl() {
}
};
void serializationTest(PVFieldPtr const & field) {
buffer->clear();
// serialize
field->serialize(buffer, flusher);
buffer->flip();
// create new instance and deserialize
PVFieldPtr deserializedField = getPVDataCreate()->createPVField(field->getField());
deserializedField->deserialize(buffer, control);
// must equal
testOk1(*field==*deserializedField);
}
void testEquals() {
testDiag("Testing equals...");
PVDataCreatePtr factory = getPVDataCreate();
testOk1(factory.get()!=NULL);
// be sure all is covered
for (int i = pvBoolean; i < pvString; i++)
{
ScalarType scalarType = static_cast<ScalarType>(i);
PVScalarPtr scalar1 = factory->createPVScalar(scalarType);
PVScalarPtr scalar2 = factory->createPVScalar(scalarType);
testOk1((*scalar1)==(*scalar2));
PVScalarArrayPtr array1 = factory->createPVScalarArray(scalarType);
PVScalarArrayPtr array2 = factory->createPVScalarArray(scalarType);
testOk1((*array1)==(*array2));
}
// and a structure
PVStructurePtr structure1 = factory->createPVStructure(getStandardField()->timeStamp());
PVStructurePtr structure2 = factory->createPVStructure(getStandardField()->timeStamp());
testOk1((*structure1)==(*structure2));
// and a structure array
PVStructureArrayPtr structureArray1 = factory->createPVStructureArray(getFieldCreate()->createStructureArray(structure1->getStructure()));
PVStructureArrayPtr structureArray2 = factory->createPVStructureArray(getFieldCreate()->createStructureArray(structure2->getStructure()));
testOk1((*structureArray1)==(*structureArray2));
}
template<typename PVT>
void testScalarType()
{
typedef typename PVT::value_type value_type;
testDiag("type %s", ScalarTypeFunc::name(PVT::typeCode));
typename PVT::shared_pointer pv = std::tr1::static_pointer_cast<PVT>(getPVDataCreate()->createPVScalar(PVT::typeCode));
pv->put(0);
serializationTest(pv);
pv->put(42);
serializationTest(pv);
pv->put(std::numeric_limits<value_type>::max()-1);
serializationTest(pv);
pv->put(std::numeric_limits<value_type>::max());
serializationTest(pv);
if(std::numeric_limits<value_type>::min()!=0) {
pv->put(-42);
serializationTest(pv);
pv->put(std::numeric_limits<value_type>::min()+1);
serializationTest(pv);
pv->put(std::numeric_limits<value_type>::min());
serializationTest(pv);
}
if(std::numeric_limits<value_type>::has_infinity) {
pv->put(std::numeric_limits<value_type>::infinity());
serializationTest(pv);
}
}
void testScalar() {
testDiag("Testing scalars...");
PVDataCreatePtr factory = getPVDataCreate();
testOk1(factory.get()!=NULL);
testDiag("type %s", ScalarTypeFunc::name(pvBoolean));
PVBooleanPtr pvBoolean =
std::tr1::static_pointer_cast<PVBoolean>(factory->createPVScalar(epics::pvData::pvBoolean));
pvBoolean->put(false);
serializationTest(pvBoolean);
pvBoolean->put(true);
serializationTest(pvBoolean);
testScalarType<PVByte>();
testScalarType<PVUByte>();
testScalarType<PVShort>();
testScalarType<PVUShort>();
testScalarType<PVInt>();
testScalarType<PVUInt>();
testScalarType<PVLong>();
testScalarType<PVULong>();
testScalarType<PVFloat>();
testScalarType<PVDouble>();
testDiag("type %s", ScalarTypeFunc::name(pvString));
PVStringPtr pvString =
std::tr1::static_pointer_cast<PVString>(factory->createPVScalar(epics::pvData::pvString));
pvString->put("");
serializationTest(pvString);
pvString->put("s");
serializationTest(pvString);
pvString->put("string");
serializationTest(pvString);
pvString->put("string with spaces");
serializationTest(pvString);
pvString->put("string with spaces and special characters\f\n");
serializationTest(pvString);
// huge string test
pvString->put(String(10000, 'a'));
serializationTest(pvString);
}
template<typename PVT>
void testArrayType(const typename PVT::value_type* rdata, size_t len)
{
typedef typename PVT::value_type value_type;
typename PVT::svector empty(0), data(len);
std::copy(rdata, rdata+len, data.begin());
testDiag("type %s", ScalarTypeFunc::name(PVT::typeCode));
typename PVT::shared_pointer pv = std::tr1::static_pointer_cast<PVT>(getPVDataCreate()->createPVScalarArray(PVT::typeCode));
pv->replace(empty);
serializationTest(pv);
pv->replace(data);
serializationTest(pv);
}
static const boolean bdata[] = {0, 1, 0, 1, 1};
static const int8 i8data[] = { 0, 1, 2, -1, BYTE_MAX_VALUE, BYTE_MAX_VALUE-1,
BYTE_MIN_VALUE+1, BYTE_MIN_VALUE };
static const uint8 u8data[] = { 0, 1, 2, -1, UBYTE_MAX_VALUE, UBYTE_MAX_VALUE-1 };
static const int16 i16data[] = { 0, 1, 2, -1, SHORT_MAX_VALUE, SHORT_MAX_VALUE-1,
SHORT_MIN_VALUE+1, SHORT_MIN_VALUE };
static const uint16 u16data[] = { 0, 1, 2, -1, USHORT_MAX_VALUE, USHORT_MAX_VALUE-1 };
static const int32 i32data[] = { 0, 1, 2, -1, INT_MAX_VALUE, INT_MAX_VALUE-1,
INT_MIN_VALUE+1, INT_MIN_VALUE };
static const uint32 u32data[] = { 0, 1, 2, -1, UINT_MAX_VALUE, UINT_MAX_VALUE-1 };
static const int64 i64data[] = { 0, 1, 2, -1, LONG_MAX_VALUE, LONG_MAX_VALUE-1,
LONG_MIN_VALUE+1, LONG_MIN_VALUE };
static const uint64 u64data[] = { 0, 1, 2, -1, ULONG_MAX_VALUE, ULONG_MAX_VALUE-1 };
static const double ddata[] = { (double)0.0, (double)1.1, (double)2.3, (double)-1.4,
DOUBLE_MAX_VALUE, DOUBLE_MAX_VALUE-(double)123456.789,
DOUBLE_MIN_VALUE+(double)1.1, DOUBLE_MIN_VALUE };
static const float fdata[] = { (float)0.0, (float)1.1, (float)2.3, (float)-1.4,
FLOAT_MAX_VALUE, FLOAT_MAX_VALUE-(float)123456.789,
FLOAT_MIN_VALUE+(float)1.1, FLOAT_MIN_VALUE };
static const String sdata[] = {
"",
"a",
"a b",
" ",
"test",
"smile",
"this is a little longer string... maybe a little but longer... this makes test better",
String(10000, 'b')
};
void testArray() {
testDiag("Testing arrays...");
testArrayType<PVBooleanArray>(bdata, NELEMENTS(bdata));
testArrayType<PVByteArray>(i8data, NELEMENTS(i8data));
testArrayType<PVUByteArray>(u8data, NELEMENTS(u8data));
testArrayType<PVShortArray>(i16data, NELEMENTS(i16data));
testArrayType<PVUShortArray>(u16data, NELEMENTS(u16data));
testArrayType<PVIntArray>(i32data, NELEMENTS(i32data));
testArrayType<PVUIntArray>(u32data, NELEMENTS(u32data));
testArrayType<PVLongArray>(i64data, NELEMENTS(i64data));
testArrayType<PVULongArray>(u64data, NELEMENTS(u64data));
testArrayType<PVDoubleArray>(ddata, NELEMENTS(ddata));
testArrayType<PVFloatArray>(fdata, NELEMENTS(fdata));
testArrayType<PVStringArray>(sdata, NELEMENTS(sdata));
}
void testNonInitialized() {
testDiag("Testing non-initialized...");
PVDataCreatePtr factory = getPVDataCreate();
testOk1(factory.get()!=NULL);
// be sure all is covered
for (int i = pvBoolean; i < pvString; i++)
{
ScalarType scalarType = static_cast<ScalarType>(i);
PVScalarPtr scalar = factory->createPVScalar(scalarType);
serializationTest(scalar);
PVScalarArrayPtr array = factory->createPVScalarArray(scalarType);
serializationTest(array);
}
// and a structure
PVStructurePtr structure = factory->createPVStructure(getStandardField()->timeStamp());
serializationTest(structure);
// and a structure array
PVStructureArrayPtr structureArray = factory->createPVStructureArray(getFieldCreate()->createStructureArray(structure->getStructure()));
serializationTest(structureArray);
}
void testStructure() {
testDiag("Testing structure...");
PVDataCreatePtr factory = getPVDataCreate();
testOk1(factory.get()!=NULL);
testDiag("\tSimple structure serialization");
PVStructurePtr pvStructure = factory->createPVStructure(getStandardField()->timeStamp());
pvStructure->getLongField("secondsPastEpoch")->put(123);
pvStructure->getIntField("nanoSeconds")->put(456);
pvStructure->getIntField("userTag")->put(789);
serializationTest(pvStructure);
testDiag("\tComplex structure serialization");
pvStructure = factory->createPVStructure(
getStandardField()->structureArray(
getStandardField()->timeStamp(), "alarm,control,display,timeStamp")
);
// TODO fill with data
serializationTest(pvStructure);
}
void testStructureId() {
testDiag("Testing structureID...");
FieldCreatePtr fieldCreate = getFieldCreate();
StringArray fieldNames;
fieldNames.push_back("longField");
fieldNames.push_back("intField");
FieldConstPtrArray fields;
fields.push_back(fieldCreate->createScalar(pvLong));
fields.push_back(fieldCreate->createScalar(pvInt));
StructureConstPtr structureWithNoId = fieldCreate->createStructure(fieldNames, fields);
StructureConstPtr structure1 = fieldCreate->createStructure("id1", fieldNames, fields);
StructureConstPtr structure2 = fieldCreate->createStructure("id2", fieldNames, fields);
testOk1(structureWithNoId!=structure1);
testOk1(structure1!=structure2);
//serializationTest(structure1);
PVStructurePtr pvStructure = getPVDataCreate()->createPVStructure(structure1);
serializationTest(pvStructure);
}
void serializatioTest(FieldConstPtr const & field)
{
buffer->clear();
// serialize
field->serialize(buffer, flusher);
// deserialize
buffer->flip();
FieldConstPtr deserializedField = getFieldCreate()->deserialize(buffer, control);
// must equal
testOk1(*field == *deserializedField);
}
void testIntrospectionSerialization()
{
testDiag("Testing introspection serialization...");
FieldCreatePtr factory = getFieldCreate();
testOk1(factory.get()!=NULL);
// be sure all is covered
for (int i = pvBoolean; i < pvString; i++)
{
ScalarType scalarType = static_cast<ScalarType>(i);
ScalarConstPtr scalar = factory->createScalar(scalarType);
serializatioTest(scalar);
ScalarArrayConstPtr array = factory->createScalarArray(scalarType);
serializatioTest(array);
}
// and a structure
StructureConstPtr structure = getStandardField()->timeStamp();
serializatioTest(structure);
// and a structure array
StructureArrayConstPtr structureArray = factory->createStructureArray(structure);
serializatioTest(structureArray);
}
void testStringCopy() {
String s1 = "abc";
String s2 = s1;
if (s1.c_str() != s2.c_str())
testDiag("implementation of epics::pvData::String assignment operator does not share content");
}
} // end namespace
MAIN(testSerialization) {
testPlan(171);
flusher = new SerializableControlImpl();
control = new DeserializableControlImpl();
buffer = new ByteBuffer(1<<16);
testStringCopy();
testIntrospectionSerialization();
testEquals();
testNonInitialized();
testScalar();
testArray();
testStructure();
delete buffer;
delete control;
delete flusher;
epicsExitCallAtExits();
return testDone();
}