diff --git a/src/ioc/db/test/Makefile b/src/ioc/db/test/Makefile index c16016378..b844a0bd6 100644 --- a/src/ioc/db/test/Makefile +++ b/src/ioc/db/test/Makefile @@ -12,6 +12,7 @@ include $(TOP)/configure/CONFIG TESTLIBRARY = dbTestIoc +dbTestIoc_SRCS += arrRecord.c dbTestIoc_SRCS += xRecord.c dbTestIoc_SRCS += dbLinkdset.c dbTestIoc_LIBS = dbCore ca Com @@ -20,6 +21,7 @@ TARGETS += $(COMMON_DIR)/dbTestIoc.dbd dbTestIoc_DBD += menuGlobal.dbd dbTestIoc_DBD += menuConvert.dbd dbTestIoc_DBD += menuScan.dbd +#dbTestIoc_DBD += arrRecord.dbd dbTestIoc_DBD += xRecord.dbd dbTestIoc_DBD += dbLinkdset.dbd TESTFILES += $(COMMON_DIR)/dbTestIoc.dbd ../xRecord.db @@ -95,6 +97,16 @@ dbChannelTest_SRCS += dbTestIoc_registerRecordDeviceDriver.cpp testHarness_SRCS += dbChannelTest.c TESTS += dbChannelTest +TARGETS += $(COMMON_DIR)/dbChArrTest.dbd +dbChArrTest_DBD += arrRecord.dbd +TESTPROD_HOST += dbChArrTest +dbChArrTest_SRCS += dbChArrTest.cpp +dbChArrTest_SRCS += dbChArrTest_registerRecordDeviceDriver.cpp +testHarness_SRCS += dbChArrTest.cpp +testHarness_SRCS += dbChArrTest_registerRecordDeviceDriver.cpp +TESTFILES += $(COMMON_DIR)/dbChArrTest.dbd ../dbChArrTest.db +TESTS += dbChArrTest + TESTPROD_HOST += chfPluginTest chfPluginTest_SRCS += chfPluginTest.c chfPluginTest_SRCS += dbTestIoc_registerRecordDeviceDriver.cpp @@ -132,6 +144,7 @@ TESTSCRIPTS_HOST += $(TESTS:%=%.t) include $(TOP)/configure/RULES +arrRecord$(DEP): $(COMMON_DIR)/arrRecord.h xRecord$(DEP): $(COMMON_DIR)/xRecord.h dbPutLinkTest$(DEP): $(COMMON_DIR)/xRecord.h scanIoTest$(DEP): $(COMMON_DIR)/yRecord.h diff --git a/src/ioc/db/test/arrRecord.c b/src/ioc/db/test/arrRecord.c new file mode 100644 index 000000000..5e9b2f02c --- /dev/null +++ b/src/ioc/db/test/arrRecord.c @@ -0,0 +1,135 @@ +/*************************************************************************\ +* Copyright (c) 2010 Brookhaven National Laboratory. +* Copyright (c) 2010 Helmholtz-Zentrum Berlin +* fuer Materialien und Energie GmbH. +* Copyright (c) 2008 UChicago Argonne LLC, as Operator of Argonne +* National Laboratory. +* Copyright (c) 2002 The Regents of the University of California, as +* Operator of Los Alamos National Laboratory. +* EPICS BASE is distributed subject to a Software License Agreement found +* in file LICENSE that is included with this distribution. +\*************************************************************************/ + +/* arrRecord.c - minimal array record for test purposes: no processing */ + +/* + * Author: Ralph Lange + * + * vaguely implemented like parts of recWaveform.c by Bob Dalesio + * + */ + +#include + +#include "dbDefs.h" +#include "epicsPrint.h" +#include "dbAccess.h" +#include "dbEvent.h" +#include "dbFldTypes.h" +#include "recSup.h" +#include "recGbl.h" +#include "cantProceed.h" +#define GEN_SIZE_OFFSET +#include "arrRecord.h" +#undef GEN_SIZE_OFFSET +#include "epicsExport.h" + +/* Create RSET - Record Support Entry Table*/ +#define report NULL +#define initialize NULL +static long init_record(arrRecord *, int); +static long process(arrRecord *); +#define special NULL +#define get_value NULL +static long cvt_dbaddr(DBADDR *); +static long get_array_info(DBADDR *, long *, long *); +static long put_array_info(DBADDR *, long); +#define get_units NULL +#define get_precision NULL +#define get_enum_str NULL +#define get_enum_strs NULL +#define put_enum_str NULL +#define get_graphic_double NULL +#define get_control_double NULL +#define get_alarm_double NULL + +rset arrRSET = { + RSETNUMBER, + report, + initialize, + init_record, + process, + special, + get_value, + cvt_dbaddr, + get_array_info, + put_array_info, + get_units, + get_precision, + get_enum_str, + get_enum_strs, + put_enum_str, + get_graphic_double, + get_control_double, + get_alarm_double +}; +epicsExportAddress(rset, arrRSET); + +static long init_record(arrRecord *prec, int pass) +{ + if (pass == 0) { + if (prec->nelm <= 0) + prec->nelm = 1; + if (prec->ftvl > DBF_ENUM) + prec->ftvl = DBF_UCHAR; + prec->bptr = callocMustSucceed(prec->nelm, dbValueSize(prec->ftvl), + "arr calloc failed"); + + if (prec->nelm == 1) { + prec->nord = 1; + } else { + prec->nord = 0; + } + return 0; + } + return 0; +} + +static long process(arrRecord *prec) +{ + return 0; +} + +static long cvt_dbaddr(DBADDR *paddr) +{ + arrRecord *prec = (arrRecord *) paddr->precord; + + paddr->pfield = prec->bptr; + paddr->no_elements = prec->nelm; + paddr->field_type = prec->ftvl; + paddr->field_size = dbValueSize(prec->ftvl); + paddr->dbr_field_type = prec->ftvl; + + return 0; +} + +static long get_array_info(DBADDR *paddr, long *no_elements, long *offset) +{ + arrRecord *prec = (arrRecord *) paddr->precord; + + *no_elements = prec->nord; + *offset = prec->off; + + return 0; +} + +static long put_array_info(DBADDR *paddr, long nNew) +{ + arrRecord *prec = (arrRecord *) paddr->precord; + + prec->nord = nNew; + if (prec->nord > prec->nelm) + prec->nord = prec->nelm; + + return 0; +} diff --git a/src/ioc/db/test/arrRecord.dbd b/src/ioc/db/test/arrRecord.dbd new file mode 100644 index 000000000..2b115b500 --- /dev/null +++ b/src/ioc/db/test/arrRecord.dbd @@ -0,0 +1,34 @@ +include "menuGlobal.dbd" +include "menuConvert.dbd" +include "menuScan.dbd" +recordtype(arr) { + include "dbCommon.dbd" + field(VAL, DBF_NOACCESS) { + prompt("Value") + special(SPC_DBADDR) + pp(TRUE) + extra("void *val") + } + field(NELM, DBF_ULONG) { + prompt("Number of Elements") + special(SPC_NOMOD) + initial("1") + } + field(FTVL, DBF_MENU) { + prompt("Field Type of Value") + special(SPC_NOMOD) + menu(menuFtype) + } + field(NORD, DBF_ULONG) { + prompt("Number elements read") + special(SPC_NOMOD) + } + field(OFF, DBF_ULONG) { + prompt("Offset into array") + } + field(BPTR, DBF_NOACCESS) { + prompt("Buffer Pointer") + special(SPC_NOMOD) + extra("void *bptr") + } +} diff --git a/src/ioc/db/test/dbChArrTest.cpp b/src/ioc/db/test/dbChArrTest.cpp new file mode 100644 index 000000000..6116e3db5 --- /dev/null +++ b/src/ioc/db/test/dbChArrTest.cpp @@ -0,0 +1,242 @@ +/*************************************************************************\ +* Copyright (c) 2010 Brookhaven National Laboratory. +* Copyright (c) 2010 Helmholtz-Zentrum Berlin +* fuer Materialien und Energie GmbH. +* Copyright (c) 2016 UChicago Argonne LLC, as Operator of Argonne +* National Laboratory. +* Copyright (c) 2003 The Regents of the University of California, as +* Operator of Los Alamos National Laboratory. +* EPICS BASE is distributed subject to the Software License Agreement +* found in the file LICENSE that is included with this distribution. +\*************************************************************************/ + +/* + * Authors: Ralph Lange , + * Andrew Johnson + */ + +#include +#include +#include +#include +#include + +#include "registryFunction.h" +#include "epicsThread.h" +#include "epicsExit.h" +#include "epicsStdio.h" +#include "epicsString.h" +#include "envDefs.h" +#include "dbStaticLib.h" +#include "dbmf.h" +#include "registry.h" +#include "dbAddr.h" +#include "dbAccess.h" +#include "asDbLib.h" +#include "iocInit.h" +#include "iocsh.h" +#include "dbChannel.h" +#include "epicsUnitTest.h" +#include "testMain.h" +#include "osiFileName.h" + +extern "C" { + int dbChArrTest_registerRecordDeviceDriver(struct dbBase *pdbbase); +} + +#define CA_SERVER_PORT "65535" + +const char *server_port = CA_SERVER_PORT; + +static void createAndOpen(const char *name, dbChannel**pch) +{ + testOk(!!(*pch = dbChannelCreate(name)), "dbChannel %s created", name); + testOk(!(dbChannelOpen(*pch)), "dbChannel opened"); + testOk((ellCount(&(*pch)->pre_chain) == 0), "no filters in pre chain"); + testOk((ellCount(&(*pch)->post_chain) == 0), "no filters in post chain"); +} + +static void freeArray(db_field_log *pfl) { + if (pfl->type == dbfl_type_ref) { + free(pfl->u.r.field); + } +} + +static void testHead (const char *title, const char *typ = "") { + const char *line = "------------------------------------------------------------------------------"; + testDiag("%s", line); + testDiag(title, typ); + testDiag("%s", line); +} + +static void check(short dbr_type) { + dbChannel *pch; + db_field_log *pfl; + dbAddr valaddr; + dbAddr offaddr; + const char *offname = NULL, *valname = NULL, *typname = NULL; + epicsInt32 buf[26]; + long off, req; + int i; + + switch (dbr_type) { + case DBR_LONG: + offname = "i32.OFF"; + valname = "i32.VAL"; + typname = "long"; + break; + case DBR_DOUBLE: + offname = "f64.OFF"; + valname = "f64.VAL"; + typname = "double"; + break; + case DBR_STRING: + offname = "c40.OFF"; + valname = "c40.VAL"; + typname = "string"; + break; + default: + testDiag("Invalid data type %d", dbr_type); + } + + (void) dbNameToAddr(offname, &offaddr); + (void) dbNameToAddr(valname, &valaddr); + + testHead("Ten %s elements", typname); + + /* Fill the record's array field with data, 10..19 */ + + epicsInt32 ar[10] = {10,11,12,13,14,15,16,17,18,19}; + (void) dbPutField(&valaddr, DBR_LONG, ar, 10); + + /* Open a channel to it, make sure no filters present */ + + createAndOpen(valname, &pch); + testOk(pch->final_type == valaddr.field_type, + "final type unchanged (%d->%d)", valaddr.field_type, pch->final_type); + testOk(pch->final_no_elements == valaddr.no_elements, + "final no_elements unchanged (%ld->%ld)", valaddr.no_elements, pch->final_no_elements); + + /* TEST1 sets the record's OFF field, then requests 10 elements from the channel, + * passing in a transparent db_field_log and converting the data to LONG on the way in. + * It checks that it got back the expected data and the right number of elements. + */ + +#define TEST1(Size, Offset, Text, Expected) \ + testDiag("Reading from offset = %d (%s)", Offset, Text); \ + off = Offset; req = 10; \ + memset(buf, sizeof(buf), 0); \ + (void) dbPutField(&offaddr, DBR_LONG, &off, 1); \ + pfl = db_create_read_log(pch); \ + testOk(pfl && pfl->type == dbfl_type_rec, "Valid pfl, type = rec"); \ + testOk(!dbChannelGetField(pch, DBR_LONG, buf, NULL, &req, pfl), "Got Field value"); \ + testOk(req == Size, "Got %ld elements (expected %d)", req, Size); \ + if (!testOk(!memcmp(buf, Expected, sizeof(Expected)), "Data correct")) \ + for (i=0; ifinal_type == valaddr.field_type, + "final type unchanged (%d->%d)", valaddr.field_type, pch->final_type); + testOk(pch->final_no_elements == valaddr.no_elements, + "final no_elements unchanged (%ld->%ld)", valaddr.no_elements, pch->final_no_elements); + + const epicsInt32 res_5_0[] = {15,16,17,18,19}; + TEST1(5, 0, "no offset", res_5_0); + + const epicsInt32 res_5_3[] = {18,19,15,16,17}; + TEST1(5, 3, "wrapped", res_5_3); + + /* TEST2 sets the record's OFF field, then requests 15 elements from the channel + * but passes in a db_field_log with alternate data, converting that data to LONG. + * It checks that it got back the expected data and the right number of elements. + */ + +#define TEST2(Size, Offset, Text, Expected) \ + testDiag("Reading from offset = %d (%s)", Offset, Text); \ + off = Offset; req = 15; \ + memset(buf, sizeof(buf), 0); \ + (void) dbPutField(&offaddr, DBR_LONG, &off, 1); \ + pfl = db_create_read_log(pch); \ + pfl->type = dbfl_type_ref; \ + pfl->field_type = DBF_CHAR; \ + pfl->field_size = 1; \ + pfl->no_elements = 26; \ + pfl->u.r.dtor = freeArray; \ + pfl->u.r.field = epicsStrDup("abcdefghijklmnopqrsstuvwxyz"); \ + testOk(!dbChannelGetField(pch, DBR_LONG, buf, NULL, &req, pfl), "Got Field value"); \ + testOk(req == Size, "Got %ld elements (expected %d)", req, Size); \ + if (!testOk(!memcmp(buf, Expected, sizeof(Expected)), "Data correct")) \ + for (i=0; i