diff --git a/src/ioc/db/test/Makefile b/src/ioc/db/test/Makefile index 2c374985b..f85f62f8c 100644 --- a/src/ioc/db/test/Makefile +++ b/src/ioc/db/test/Makefile @@ -12,13 +12,15 @@ include $(TOP)/configure/CONFIG TESTLIBRARY = dbTestIoc -dbTestIoc_SRCS = xRecord.c +dbTestIoc_SRCS += xRecord.c +dbTestIoc_SRCS += dbLinkdset.c dbTestIoc_LIBS = dbCore TARGETS += $(COMMON_DIR)/dbTestIoc.dbd dbTestIoc_DBD += menuGlobal.dbd dbTestIoc_DBD += menuConvert.dbd dbTestIoc_DBD += xRecord.dbd +dbTestIoc_DBD += dbLinkdset.dbd TESTFILES += $(COMMON_DIR)/dbTestIoc.dbd ../xRecord.db testHarness_SRCS += dbTestIoc_registerRecordDeviceDriver.cpp diff --git a/src/ioc/db/test/dbBadLink.db b/src/ioc/db/test/dbBadLink.db new file mode 100644 index 000000000..6c41e854b --- /dev/null +++ b/src/ioc/db/test/dbBadLink.db @@ -0,0 +1,16 @@ +# The records in this file have intentional +# syntax error in their input links + +record(x, "eVME_IO1") { + field(DTYP, "Unit Test VME_IO") + field(INP, "C100 S101 @parm VME_IO") +} +record(x, "eVME_IO2") { + field(DTYP, "Unit Test VME_IO") + field(INP, "#C200 201 @parm VME_IO") +} + +record(x, "eINST_IO") { + field(DTYP, "Unit Test INST_IO") + field(INP, "hello") +} diff --git a/src/ioc/db/test/dbLinkdset.c b/src/ioc/db/test/dbLinkdset.c new file mode 100644 index 000000000..dce258a3f --- /dev/null +++ b/src/ioc/db/test/dbLinkdset.c @@ -0,0 +1,40 @@ + +#include + +#include + +#include + +static +long link_test_extend(struct dbCommon *junk) +{ return 0; } + +static dsxt xrecextend = {&link_test_extend, &link_test_extend}; + +static +long link_test_init(int junk) +{ + devExtend(&xrecextend); + return 0; +} + +static +long link_test_noop(void *junk) +{ return 0; } + + + +#define DEFDSET(LTYPE) \ + static dset devxLTest ## LTYPE = {4, NULL, &link_test_init, &link_test_noop, &link_test_noop}; \ + epicsExportAddress(dset, devxLTest ## LTYPE); + +DEFDSET(Soft) +DEFDSET(VME_IO) +DEFDSET(CAMAC_IO) +DEFDSET(AB_IO) +DEFDSET(GPIB_IO) +DEFDSET(BITBUS_IO) +DEFDSET(INST_IO) +DEFDSET(BBGPIB_IO) +DEFDSET(RF_IO) +DEFDSET(VXI_IO) diff --git a/src/ioc/db/test/dbLinkdset.dbd b/src/ioc/db/test/dbLinkdset.dbd new file mode 100644 index 000000000..b1e070c66 --- /dev/null +++ b/src/ioc/db/test/dbLinkdset.dbd @@ -0,0 +1,11 @@ +device(x, CONSTANT,devxLTestSoft,"Soft Channel") + +device(x, VME_IO, devxLTestVME_IO, "Unit Test VME_IO") +device(x, CAMAC_IO, devxLTestCAMAC_IO, "Unit Test CAMAC_IO") +device(x, AB_IO, devxLTestAB_IO, "Unit Test AB_IO") +device(x, GPIB_IO, devxLTestGPIB_IO, "Unit Test GPIB_IO") +device(x, BITBUS_IO, devxLTestBITBUS_IO, "Unit Test BITBUS_IO") +device(x, INST_IO, devxLTestINST_IO, "Unit Test INST_IO") +device(x, BBGPIB_IO, devxLTestBBGPIB_IO, "Unit Test BBGPIB_IO") +device(x, RF_IO, devxLTestRF_IO, "Unit Test RF_IO") +device(x, VXI_IO, devxLTestVXI_IO, "Unit Test VXI_IO") diff --git a/src/ioc/db/test/dbPutLinkTest.c b/src/ioc/db/test/dbPutLinkTest.c index c6f6adb77..75e01b2d7 100644 --- a/src/ioc/db/test/dbPutLinkTest.c +++ b/src/ioc/db/test/dbPutLinkTest.c @@ -31,10 +31,10 @@ void dbTestIoc_registerRecordDeviceDriver(struct dbBase *); static const struct testDataT { - const char *linkstring; + const char * const linkstring; short linkType; unsigned int pvlMask; - const char *linkback; + const char * const linkback; } testSetData[] = { {"", CONSTANT, 0}, {"0", CONSTANT, 0}, @@ -56,11 +56,12 @@ static const struct testDataT { {NULL} }; -static void testSet(void) +static void testCADBSet(void) { const struct testDataT *td = testSetData; xRecord *prec; DBLINK *plink; + testDiag("DB/CA link retargeting"); testdbPrepare(); testdbReadDatabase("dbTestIoc.dbd", NULL, NULL); @@ -111,9 +112,286 @@ static void testSet(void) testdbCleanup(); } +typedef struct { + const char * const recname; + short ltype; + const char * const wval; + short vals[5]; + const char * const parm; +} testHWDataT; + +static const testHWDataT testHWData[] = { + {"rVME_IO", VME_IO, "#C100 S101 @parm VME_IO", {100, 101}, "parm VME_IO"}, + {"rCAMAC_IO", CAMAC_IO, "#B11 C12 N13 A14 F15 @parm CAMAC_IO", {11, 12, 13, 14, 15}, "parm CAMAC_IO"}, + {"rAB_IO", AB_IO, "#L21 A22 C23 S24 @parm AB_IO", {21, 22, 23, 24}, "parm AB_IO"}, + {"rGPIB_IO", GPIB_IO, "#L31 A32 @parm GPIB_IO", {31, 32}, "parm GPIB_IO"}, + {"rBITBUS_IO", BITBUS_IO, "#L41 N42 P43 S44 @parm BITBUS_IO", {41, 42, 43, 44}, "parm BITBUS_IO"}, + {"rINST_IO", INST_IO, "@parm INST_IO", {}, "parm INST_IO"}, + {"rBBGPIB_IO", BBGPIB_IO, "#L51 B52 G53 @parm BBGPIB_IO", {51, 52, 53}, "parm BBGPIB_IO"}, + {"rRF_IO", RF_IO, "#R61 M62 D63 E64", {61, 62, 63, 64}, NULL}, + {"rVXI_IO1", VXI_IO, "#V71 C72 S73 @parm1 VXI_IO", {71, 72, 73}, "parm1 VXI_IO"}, + {"rVXI_IO2", VXI_IO, "#V81 S82 @parm2 VXI_IO", {81, 82}, "parm2 VXI_IO"}, + {NULL} +}; + +static void testLink(DBLINK *plink, const testHWDataT *td) +{ + switch(td->ltype) { + case VME_IO: + testOk1(plink->value.vmeio.card==td->vals[0]); + testOk1(plink->value.vmeio.signal==td->vals[1]); + testOk1(strcmp(plink->value.vmeio.parm, td->parm)==0); + break; + case CAMAC_IO: + testOk1(plink->value.camacio.b==td->vals[0]); + testOk1(plink->value.camacio.c==td->vals[1]); + testOk1(plink->value.camacio.n==td->vals[2]); + testOk1(plink->value.camacio.a==td->vals[3]); + testOk1(plink->value.camacio.f==td->vals[4]); + testOk1(strcmp(plink->value.camacio.parm, td->parm)==0); + break; + case AB_IO: + testOk1(plink->value.abio.link==td->vals[0]); + testOk1(plink->value.abio.adapter==td->vals[1]); + testOk1(plink->value.abio.card==td->vals[2]); + testOk1(plink->value.abio.signal==td->vals[3]); + testOk1(strcmp(plink->value.abio.parm, td->parm)==0); + break; + case GPIB_IO: + testOk1(plink->value.gpibio.link==td->vals[0]); + testOk1(plink->value.gpibio.addr==td->vals[1]); + testOk1(strcmp(plink->value.gpibio.parm, td->parm)==0); + break; + case BITBUS_IO: + testOk1(plink->value.bitbusio.link==td->vals[0]); + testOk1(plink->value.bitbusio.node==td->vals[1]); + testOk1(plink->value.bitbusio.port==td->vals[2]); + testOk1(plink->value.bitbusio.signal==td->vals[3]); + testOk1(strcmp(plink->value.bitbusio.parm, td->parm)==0); + break; + case INST_IO: + testOk1(strcmp(plink->value.instio.string, td->parm)==0); + break; + case BBGPIB_IO: + testOk1(plink->value.bbgpibio.link==td->vals[0]); + testOk1(plink->value.bbgpibio.bbaddr==td->vals[1]); + testOk1(plink->value.bbgpibio.gpibaddr==td->vals[2]); + testOk1(strcmp(plink->value.bbgpibio.parm, td->parm)==0); + break; + case RF_IO: + testOk1(plink->value.rfio.cryo==td->vals[0]); + testOk1(plink->value.rfio.micro==td->vals[1]); + testOk1(plink->value.rfio.dataset==td->vals[2]); + testOk1(plink->value.rfio.element==td->vals[3]); + break; + case VXI_IO: + if(plink->value.vxiio.flag==VXIDYNAMIC) { + testOk1(plink->value.vxiio.frame==td->vals[0]); + testOk1(plink->value.vxiio.slot==td->vals[1]); + testOk1(plink->value.vxiio.signal==td->vals[2]); + } else { + testOk1(plink->value.vxiio.la==td->vals[0]); + testOk1(plink->value.vxiio.signal==td->vals[1]); + } + testOk1(strcmp(plink->value.vxiio.parm, td->parm)==0); + break; + } +} + +static void testHWInitSet(void) +{ + const testHWDataT *td = testHWData; + testDiag("HW link parsing during initialization"); + testdbPrepare(); + + testdbReadDatabase("dbTestIoc.dbd", NULL, NULL); + + dbTestIoc_registerRecordDeviceDriver(pdbbase); + + testdbReadDatabase("dbPutLinkTest.db", NULL, NULL); + + eltc(0); + testIocInitOk(); + eltc(1); + + for(;td->recname;td++) { + char buf[MAX_STRING_SIZE]; + xRecord *prec; + DBLINK *plink; + testDiag("%s == \"%s\"", td->recname, td->wval); + + prec = (xRecord*)testdbRecordPtr(td->recname); + plink = &prec->inp; + + strcpy(buf, td->recname); + strcat(buf, ".INP"); + + testdbGetFieldEqual(buf, DBR_STRING, td->wval); + + testOk(plink->type==td->ltype, "link type %d == %d", + plink->type, td->ltype); + if(plink->type==td->ltype) { + testLink(plink, td); + } + + } + + testIocShutdownOk(); + + testdbCleanup(); +} + +static const testHWDataT testHWData2[] = { + {"rVME_IO", VME_IO, "#C200 S201 @another VME_IO", {200, 201}, "another VME_IO"}, + {"rCAMAC_IO", CAMAC_IO, "#B111 C112 N113 A114 F115 @CAMAC_IO", {111, 112, 113, 114, 115}, "CAMAC_IO"}, + {"rAB_IO", AB_IO, "#L121 A122 C123 S124 @another AB_IO", {121, 122, 123, 124}, "another AB_IO"}, + {"rGPIB_IO", GPIB_IO, "#L131 A132 @another GPIB_IO", {131, 132}, "another GPIB_IO"}, + {"rBITBUS_IO", BITBUS_IO, "#L141 N142 P143 S144 @BITBUS_IO", {141, 142, 143, 144}, "BITBUS_IO"}, + {"rINST_IO", INST_IO, "@another INST_IO", {}, "another INST_IO"}, + {"rBBGPIB_IO", BBGPIB_IO, "#L151 B152 G153 @another BBGPIB_IO", {151, 152, 153}, "another BBGPIB_IO"}, + {"rRF_IO", RF_IO, "#R161 M162 D163 E164", {161, 162, 163, 164}, NULL}, + {"rVXI_IO1", VXI_IO, "#V171 C172 S173 @another1 VXI_IO", {171, 172, 173}, "another1 VXI_IO"}, + {"rVXI_IO2", VXI_IO, "#V181 S182 @another2 VXI_IO", {181, 182}, "another2 VXI_IO"}, + {NULL} +}; + +static void testHWMod(void) +{ + const testHWDataT *td = testHWData2; + testDiag("HW link parsing during retarget"); + testdbPrepare(); + + testdbReadDatabase("dbTestIoc.dbd", NULL, NULL); + + dbTestIoc_registerRecordDeviceDriver(pdbbase); + + testdbReadDatabase("dbPutLinkTest.db", NULL, NULL); + + eltc(0); + testIocInitOk(); + eltc(1); + + for(;td->recname;td++) { + char buf[MAX_STRING_SIZE]; + xRecord *prec; + DBLINK *plink; + testDiag("%s -> \"%s\"", td->recname, td->wval); + + prec = (xRecord*)testdbRecordPtr(td->recname); + plink = &prec->inp; + + strcpy(buf, td->recname); + strcat(buf, ".INP"); + + testdbPutFieldOk(buf, DBR_STRING, td->wval); + + testdbGetFieldEqual(buf, DBR_STRING, td->wval); + + testOk(plink->type==td->ltype, "link type %d == %d", + plink->type, td->ltype); + if(plink->type==td->ltype) { + testLink(plink, td); + } + + } + + testIocShutdownOk(); + + testdbCleanup(); +} + +static void testLinkInitFail(void) +{ + xRecord *prec; + DBLINK *plink; + testDiag("Link parsing failures during initialization"); + testdbPrepare(); + + testdbReadDatabase("dbTestIoc.dbd", NULL, NULL); + + dbTestIoc_registerRecordDeviceDriver(pdbbase); + + + /* this load will fail */ + eltc(0); + testOk1(dbReadDatabase(&pdbbase, "dbBadLink.db", "." OSI_PATH_LIST_SEPARATOR ".." OSI_PATH_LIST_SEPARATOR + "../O.Common" OSI_PATH_LIST_SEPARATOR "O.Common", NULL)!=0); + + testIocInitOk(); + eltc(1); + + testdbGetFieldEqual("eVME_IO1.INP", DBR_STRING, "#C0 S0 @"); + + prec = (xRecord*)testdbRecordPtr("eVME_IO1"); + plink = &prec->inp; + testOk1(plink->type==VME_IO); + testOk1(plink->value.vmeio.parm!=NULL); + + testdbGetFieldEqual("eVME_IO2.INP", DBR_STRING, "#C200 S0 @"); + + prec = (xRecord*)testdbRecordPtr("eVME_IO2"); + plink = &prec->inp; + testOk1(plink->type==VME_IO); + testOk1(plink->value.vmeio.parm!=NULL); + + testdbGetFieldEqual("eINST_IO.INP", DBR_STRING, "@"); + + prec = (xRecord*)testdbRecordPtr("eINST_IO"); + plink = &prec->inp; + testOk1(plink->type==INST_IO); + testOk1(plink->value.instio.string!=NULL); + + testIocShutdownOk(); + + testdbCleanup(); +} + +static void testLinkFail(void) +{ + testDiag("Link parsing failures"); + testdbPrepare(); + + testdbReadDatabase("dbTestIoc.dbd", NULL, NULL); + + dbTestIoc_registerRecordDeviceDriver(pdbbase); + + testdbReadDatabase("dbPutLinkTest.db", NULL, NULL); + + eltc(0); + testIocInitOk(); + eltc(1); + + /* INST_IO doesn't accept empty string */ + testdbPutFieldFail(S_dbLib_badField, "rINST_IO.INP", DBR_STRING, ""); + + /* INST_IO accepts invalid input as empty string */ + testdbPutFieldOk("rINST_IO.INP", DBR_STRING, "abc"); + testdbGetFieldEqual("rINST_IO.INP", DBR_STRING, "@"); + + /* syntax errors */ + testdbPutFieldFail(S_dbLib_badField, "rVME_IO.INP", DBR_STRING, "#S201 C200 @another VME_IO"); + testdbPutFieldFail(S_dbLib_badField, "rVME_IO.INP", DBR_STRING, "C200 #S201"); + + /* VME_IO doesn't accept empty string */ + testdbPutFieldFail(S_dbLib_badField, "rVME_IO.INP", DBR_STRING, ""); + + testdbPutFieldOk("rVME_IO.INP", DBR_STRING, "#C1 S2 @hello"); + + /* VME_IO fails invalid input */ + testdbPutFieldFail(S_dbLib_badField, "rVME_IO.INP", DBR_STRING, "abc"); + + testIocShutdownOk(); + + testdbCleanup(); +} + MAIN(dbPutLinkTest) { - testPlan(56); - testSet(); + testPlan(200); + testCADBSet(); + testHWInitSet(); + testHWMod(); + testLinkInitFail(); + testLinkFail(); return testDone(); } diff --git a/src/ioc/db/test/dbPutLinkTest.db b/src/ioc/db/test/dbPutLinkTest.db index 940ea2e7f..7753b5b08 100644 --- a/src/ioc/db/test/dbPutLinkTest.db +++ b/src/ioc/db/test/dbPutLinkTest.db @@ -2,3 +2,44 @@ record(x, "x1") {} record(x, "x2") {} record(x, "x3") {} record(x, "x4") {} + +record(x, "rVME_IO") { + field(DTYP, "Unit Test VME_IO") + field(INP, "#C100 S101 @parm VME_IO") +} +record(x, "rCAMAC_IO") { + field(DTYP, "Unit Test CAMAC_IO") + field(INP, "#B11 C12 N13 A14 F15 @parm CAMAC_IO") +} +record(x, "rAB_IO") { + field(DTYP, "Unit Test AB_IO") + field(INP, "#L21 A22 C23 S24 @parm AB_IO") +} +record(x, "rGPIB_IO") { + field(DTYP, "Unit Test GPIB_IO") + field(INP, "#L31 A32 @parm GPIB_IO") +} +record(x, "rBITBUS_IO") { + field(DTYP, "Unit Test BITBUS_IO") + field(INP, "#L41 N42 P43 S44 @parm BITBUS_IO") +} +record(x, "rINST_IO") { + field(DTYP, "Unit Test INST_IO") + field(INP, "@parm INST_IO") +} +record(x, "rBBGPIB_IO") { + field(DTYP, "Unit Test BBGPIB_IO") + field(INP, "#L51 B52 G53 @parm BBGPIB_IO") +} +record(x, "rRF_IO") { + field(DTYP, "Unit Test RF_IO") + field(INP, "#R61 M62 D63 E64") +} +record(x, "rVXI_IO1") { + field(DTYP, "Unit Test VXI_IO") + field(INP, "#V71 C72 S73 @parm1 VXI_IO") +} +record(x, "rVXI_IO2") { + field(DTYP, "Unit Test VXI_IO") + field(INP, "#V81 S82 @parm2 VXI_IO") +} diff --git a/src/ioc/db/test/xRecord.dbd b/src/ioc/db/test/xRecord.dbd index 8f4b2156c..fb230f563 100644 --- a/src/ioc/db/test/xRecord.dbd +++ b/src/ioc/db/test/xRecord.dbd @@ -8,4 +8,7 @@ recordtype(x) { field(LNK, DBF_INLINK) { prompt("Link") } + field(INP, DBF_INLINK) { + prompt("Input Link") + } }