Files
pvData/testApp/pv/testFieldBuilder.cpp
Michael Davidsaver 0406a2f614 Field de-duplication
add a global cache of Field instances to
allow O(0) comparison of types.
2018-07-06 12:01:14 -07:00

367 lines
14 KiB
C++

/*
* Copyright information and license terms for this software can be
* found in the file LICENSE that is included with the distribution
*/
#include <string>
#include <epicsUnitTest.h>
#include <testMain.h>
#include <pv/pvUnitTest.h>
#include <pv/pvData.h>
#include <pv/epicsException.h>
using namespace epics::pvData;
namespace {
void test_factory()
{
testDiag("Test test_factory()");
FieldCreatePtr fieldCreate = getFieldCreate();
FieldBuilderPtr fb = fieldCreate->createFieldBuilder();
testOk1(fb.get() != 0);
FieldBuilderPtr fb2 = fieldCreate->createFieldBuilder();
testOk1(fb.get() != fb2.get());
}
void test_structure()
{
testDiag("Test test_structure()");
FieldCreatePtr fieldCreate = getFieldCreate();
FieldBuilderPtr fb = fieldCreate->createFieldBuilder();
// test with simple (non-nested) structure
std::string ID = "testStructureID";
StructureConstPtr s = fb->setId(ID)->
add("double", pvDouble)->
addArray("intArray", pvInt)->
createStructure();
testOk1(s.get() != 0);
testOk1(ID == s->getID());
testOk1(2 == s->getFields().size());
FieldConstPtr f0 = s->getField(0);
testOk1(scalar == f0->getType());
testOk1("double" == s->getFieldName(0));
testOk(pvDouble == std::tr1::static_pointer_cast<const Scalar>(f0)->getScalarType(), "f0 scalar type == double");
FieldConstPtr f1 = s->getField(1);
testOk1(scalarArray == f1->getType());
testOk1("intArray" == s->getFieldName(1));
testOk(pvInt == std::tr1::static_pointer_cast<const ScalarArray>(f1)->getElementType(), "f1 element type == int");
// test reuse with empty structure
StructureConstPtr emptyStructure = fb->createStructure();
testOk1(emptyStructure.get() != 0);
testOk1(Structure::DEFAULT_ID == emptyStructure->getID());
testOk1(0 == emptyStructure->getFields().size());
// test add/addArray with Field
StructureConstPtr s2 = fb->add("s", s)->
addArray("sArray", s)->
createStructure();
testOk1(s2.get()!=0);
testOk1(Structure::DEFAULT_ID == s2->getID());
testOk1(2 == s2->getFields().size());
f0 = s2->getField(0);
testOk1(structure == f0->getType());
testOk1("s" == s2->getFieldName(0));
testOk1(s.get() == f0.get());
f1 = s2->getField(1);
testOk1(structureArray == f1->getType());
testOk1("sArray" == s2->getFieldName(1));
testOk(s.get() == std::tr1::static_pointer_cast<const StructureArray>(f1)->getStructure().get(), "array element is given structure");
}
void test_invalid()
{
testDiag("Test test_invalid()");
FieldCreatePtr fieldCreate = getFieldCreate();
try
{
fieldCreate->createFieldBuilder()->
add("f1", pvByte)->
endNested();
testFail("endNested() allowed in non-nested FieldBuilder");
}
catch (std::runtime_error& re) {
// ok
testPass("endNested() disallowed in non-nested FieldBuilder");
}
try
{
fieldCreate->createFieldBuilder()->
add("f1", pvByte)->
addNestedStructure("nested")->
add("n1", pvUInt)->
createStructure();
testFail("createStructure() allowed in nested FieldBuilder");
}
catch (std::runtime_error& re) {
// ok
testPass("createStructure() disallowed in nested FieldBuilder");
}
}
void test_arraySizeTypes()
{
testDiag("Test test_arraySizeTypes()");
FieldCreatePtr fieldCreate = getFieldCreate();
StructureConstPtr s = fieldCreate->createFieldBuilder()->
addArray("variableArray", pvDouble)->
addFixedArray("fixedArray", pvDouble, 10)->
addBoundedArray("boundedArray", pvDouble, 1024)->
createStructure();
testOk1(s.get() != 0);
testOk1(Structure::DEFAULT_ID == s->getID());
testOk1(3 == s->getFields().size());
}
void test_nestedStructure()
{
testDiag("Test test_nestedStructure()");
FieldCreatePtr fieldCreate = getFieldCreate();
std::string NESTED_ID = "nestedID";
StructureConstPtr s = fieldCreate->createFieldBuilder()->
add("double", pvDouble)->
addNestedStructure("nested")->
setId(NESTED_ID)->
add("short", pvShort)->
add("long", pvLong)->
endNested()->
addArray("intArray", pvInt)->
createStructure();
testOk1(s.get() != 0);
testOk1(Structure::DEFAULT_ID == s->getID());
testOk1(3 == s->getFields().size());
FieldConstPtr f0 = s->getField(0);
testOk1(scalar == f0->getType());
testOk1("double" == s->getFieldName(0));
testOk(pvDouble == std::tr1::static_pointer_cast<const Scalar>(f0)->getScalarType(), "f0 scalar type == double");
FieldConstPtr f1 = s->getField(1);
testOk1(structure == f1->getType());
testOk1("nested" == s->getFieldName(1));
{
StructureConstPtr s2 = std::tr1::static_pointer_cast<const Structure>(f1);
testOk1(s2.get() != 0);
testOk1(NESTED_ID == s2->getID());
testOk1(2 == s2->getFields().size());
FieldConstPtr f20 = s2->getField(0);
testOk1(scalar == f20->getType());
testOk1("short" == s2->getFieldName(0));
testOk(pvShort == std::tr1::static_pointer_cast<const Scalar>(f20)->getScalarType(), "f20 scalar type == short");
FieldConstPtr f21 = s2->getField(1);
testOk1(scalar == f21->getType());
testOk1("long" == s2->getFieldName(1));
testOk(pvLong == std::tr1::static_pointer_cast<const Scalar>(f21)->getScalarType(), "f21 element type == long");
}
FieldConstPtr f2 = s->getField(2);
testOk1(scalarArray == f2->getType());
testOk1("intArray" == s->getFieldName(2));
testOk(pvInt == std::tr1::static_pointer_cast<const ScalarArray>(f2)->getElementType(), "f2 element type == int");
}
void test_nestedStructureArray()
{
testDiag("Test test_nestedStructureArray()");
FieldCreatePtr fieldCreate = getFieldCreate();
std::string NESTED_ID = "nestedID";
StructureConstPtr s = fieldCreate->createFieldBuilder()->
add("double", pvDouble)->
addNestedStructureArray("nested")->
setId(NESTED_ID)->
add("short", pvShort)->
add("long", pvLong)->
endNested()->
addArray("intArray", pvInt)->
createStructure();
testOk1(s.get() != 0);
testOk1(Structure::DEFAULT_ID == s->getID());
testOk1(3 == s->getFields().size());
FieldConstPtr f0 = s->getField(0);
testOk1(scalar == f0->getType());
testOk1("double" == s->getFieldName(0));
testOk(pvDouble == std::tr1::static_pointer_cast<const Scalar>(f0)->getScalarType(), "f0 scalar type == double");
FieldConstPtr f1 = s->getField(1);
testOk1(structureArray == f1->getType());
testOk1("nested" == s->getFieldName(1));
{
StructureConstPtr s2 = std::tr1::static_pointer_cast<const StructureArray>(f1)->getStructure();
testOk1(s2.get() != 0);
testOk1(NESTED_ID == s2->getID());
testOk1(2 == s2->getFields().size());
FieldConstPtr f20 = s2->getField(0);
testOk1(scalar == f20->getType());
testOk1("short" == s2->getFieldName(0));
testOk(pvShort == std::tr1::static_pointer_cast<const Scalar>(f20)->getScalarType(), "f20 scalar type == short");
FieldConstPtr f21 = s2->getField(1);
testOk1(scalar == f21->getType());
testOk1("long" == s2->getFieldName(1));
testOk(pvLong == std::tr1::static_pointer_cast<const Scalar>(f21)->getScalarType(), "f21 element type == long");
}
FieldConstPtr f2 = s->getField(2);
testOk1(scalarArray == f2->getType());
testOk1("intArray" == s->getFieldName(2));
testOk(pvInt == std::tr1::static_pointer_cast<const ScalarArray>(f2)->getElementType(), "f2 element type == int");
}
void test_extendStructure()
{
testDiag("test_extendStructure()");
Structure::const_shared_pointer base(getFieldCreate()->createFieldBuilder()
->add("A", pvInt)
->addNestedStructure("nest")
->add("B", pvInt)
->addNestedStructure("one")
->add("XX", pvInt)
->endNested()
->endNested()
->addNestedUnion("U")
->add("B", pvInt)
->addNestedStructure("one")
->add("XX", pvInt)
->endNested()
->endNested()
->addNestedStructureArray("sarr")
->add("X", pvInt)
->addNestedStructure("one")
->add("XX", pvInt)
->endNested()
->endNested()
->createStructure());
Structure::const_shared_pointer amended(getFieldCreate()->createFieldBuilder(base)
->add("A2", pvInt)
->addNestedStructure("nest")
->add("B2", pvInt)
->addNestedStructure("one")
->add("XX", pvInt) // exact duplicate silently ignored
->add("YY", pvInt)
->endNested()
->endNested()
->addNestedUnion("U")
->add("B2", pvInt)
->addNestedStructure("one")
->add("YY", pvInt)
->endNested()
->endNested()
->addNestedStructureArray("sarr")
->add("Y", pvInt)
->addNestedStructure("one")
->add("YY", pvInt)
->endNested()
->endNested()
->createStructure());
Structure::const_shared_pointer expected(getFieldCreate()->createFieldBuilder()
->add("A", pvInt)
->addNestedStructure("nest")
->add("B", pvInt)
->addNestedStructure("one")
->add("XX", pvInt)
->add("YY", pvInt)
->endNested()
->add("B2", pvInt)
->endNested()
->addNestedUnion("U")
->add("B", pvInt)
->addNestedStructure("one")
->add("XX", pvInt)
->add("YY", pvInt)
->endNested()
->add("B2", pvInt)
->endNested()
->addNestedStructureArray("sarr")
->add("X", pvInt)
->addNestedStructure("one")
->add("XX", pvInt)
->add("YY", pvInt)
->endNested()
->add("Y", pvInt)
->endNested()
->add("A2", pvInt)
->createStructure());
testShow()<<"base: "<<base
<<"amended: "<<amended
<<"expected: "<<expected;
testEqual(static_cast<const void*>(amended.get()),
static_cast<const void*>(expected.get()));
testEqual(*amended, *expected);
testThrows(std::runtime_error,
getFieldCreate()->createFieldBuilder(amended)
->add("A2", pvDouble)
->createStructure());
testThrows(std::runtime_error,
getFieldCreate()->createFieldBuilder(amended)
->addNestedStructure("nest")
->add("B2", pvDouble)
->endNested()
->createStructure());
}
} // namespace
MAIN(testFieldBuilder)
{
testPlan(72);
try {
testDiag("Tests for FieldBuilder");
test_factory();
test_structure();
test_arraySizeTypes();
test_nestedStructure();
test_nestedStructureArray();
test_extendStructure();
test_invalid();
}catch(std::exception& e) {
PRINT_EXCEPTION(e);
testAbort("Unhandled exception: %s", e.what());
}
return testDone();
}