Structural changes to create database module

This commit is contained in:
Ralph Lange
2017-09-20 09:32:53 +02:00
parent c036fd056b
commit 7ad0210ef6
1424 changed files with 141 additions and 188700 deletions
+2 -3
View File
@@ -4,10 +4,10 @@
# 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.
# in file LICENSE that is included with this distribution.
#*************************************************************************
TOP=../..
TOP = ../..
include $(TOP)/configure/CONFIG
STDDIR=$(TOP)/src/std
@@ -27,4 +27,3 @@ include $(TOP)/configure/RULES
include $(STDDIR)/rec/RULES
include $(STDDIR)/softIoc/RULES
+1 -1
View File
@@ -2,7 +2,7 @@
# Copyright (c) 2011 UChicago Argonne LLC, as Operator of Argonne
# National Laboratory.
# EPICS BASE is distributed subject to a Software License Agreement found
# in file LICENSE that is included with this distribution.
# in file LICENSE that is included with this distribution.
#*************************************************************************
# This is a Makefile fragment, see src/std/Makefile.
-80
View File
@@ -1,80 +0,0 @@
#*************************************************************************
# Copyright (c) 2012 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 the file LICENSE that is included with this distribution.
#*************************************************************************
TOP=../../../..
include $(TOP)/configure/CONFIG
TESTLIBRARY = Recs
Recs_SRCS += xRecord.c
Recs_SRCS += arrRecord.c
Recs_LIBS += dbCore ca Com
PROD_LIBS = Recs dbRecStd dbCore ca Com
DBDDEPENDS_FILES += filterTest.dbd$(DEP)
TARGETS += $(COMMON_DIR)/filterTest.dbd
filterTest_DBD += menuGlobal.dbd
filterTest_DBD += menuConvert.dbd
filterTest_DBD += menuScan.dbd
filterTest_DBD += filters.dbd
filterTest_DBD += xRecord.dbd
filterTest_DBD += arrRecord.dbd
TESTFILES += $(COMMON_DIR)/filterTest.dbd
testHarness_SRCS += filterTest_registerRecordDeviceDriver.cpp
TESTPROD_HOST += tsTest
tsTest_SRCS += tsTest.c
tsTest_SRCS += filterTest_registerRecordDeviceDriver.cpp
testHarness_SRCS += tsTest.c
TESTFILES += ../xRecord.db
TESTS += tsTest
TESTPROD_HOST += dbndTest
dbndTest_SRCS += dbndTest.c
dbndTest_SRCS += filterTest_registerRecordDeviceDriver.cpp
testHarness_SRCS += dbndTest.c
TESTS += dbndTest
TESTPROD_HOST += arrTest
arrTest_SRCS += arrTest.cpp
arrTest_SRCS += filterTest_registerRecordDeviceDriver.cpp
testHarness_SRCS += arrTest.cpp
TESTFILES += ../arrTest.db
TESTS += arrTest
TESTPROD_HOST += syncTest
syncTest_SRCS += syncTest.c
syncTest_SRCS += filterTest_registerRecordDeviceDriver.cpp
testHarness_SRCS += syncTest.c
TESTS += syncTest
# epicsRunFilterTests runs all the test programs in a known working order.
testHarness_SRCS += epicsRunFilterTests.c
filterTestHarness_SRCS += $(testHarness_SRCS)
filterTestHarness_SRCS_RTEMS += rtemsTestHarness.c
PROD_vxWorks = filterTestHarness
PROD_RTEMS = filterTestHarness
TESTSPEC_vxWorks = filterTestHarness.munch; epicsRunFilterTests
TESTSPEC_RTEMS = filterTestHarness.boot; epicsRunFilterTests
TESTSCRIPTS_HOST += $(TESTS:%=%.t)
include $(TOP)/configure/RULES
xRecord$(DEP): $(COMMON_DIR)/xRecord.h
tsTest$(DEP): $(COMMON_DIR)/xRecord.h
dbndTest$(DEP): $(COMMON_DIR)/xRecord.h
syncTest$(DEP): $(COMMON_DIR)/xRecord.h
arrRecord$(DEP): $(COMMON_DIR)/arrRecord.h
arrTest$(DEP): $(COMMON_DIR)/arrRecord.h
-145
View File
@@ -1,145 +0,0 @@
/*************************************************************************\
* 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 <Ralph.Lange@bessy.de>
*
* vaguely implemented like parts of recWaveform.c by Bob Dalesio
*
*/
#include <stdio.h>
#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(struct dbCommon *, int);
static long process(struct dbCommon *);
#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(struct dbCommon *pcommon, int pass)
{
struct arrRecord *prec = (struct arrRecord *)pcommon;
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(struct dbCommon *pcommon)
{
struct arrRecord *prec = (struct arrRecord *)pcommon;
if(prec->clbk)
(*prec->clbk)(prec);
prec->pact = TRUE;
recGblGetTimeStamp(prec);
recGblFwdLink(prec);
prec->pact = FALSE;
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;
}
-42
View File
@@ -1,42 +0,0 @@
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")
}
field(INP, DBF_INLINK) {
prompt("Input Link")
}
field(CLBK, DBF_NOACCESS) {
prompt("Processing callback")
special(SPC_NOMOD)
extra("void (*clbk)(struct arrRecord*)")
}
}
-336
View File
@@ -1,336 +0,0 @@
/*************************************************************************\
* 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) 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.
\*************************************************************************/
/*
* Author: Ralph Lange <Ralph.Lange@bessy.de>
*/
/* using stuff from softIoc.cpp by Andrew Johnson */
#include <stddef.h>
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include <stdio.h>
#include "registryFunction.h"
#include "epicsThread.h"
#include "epicsExit.h"
#include "epicsStdio.h"
#include "envDefs.h"
#include "dbStaticLib.h"
#include "dbmf.h"
#include "errlog.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 "dbUnitTest.h"
#include "testMain.h"
#include "osiFileName.h"
#include "arrRecord.h"
extern "C" {
void filterTest_registerRecordDeviceDriver(struct dbBase *);
}
#define CA_SERVER_PORT "65535"
#define PATTERN 0x55
const char *server_port = CA_SERVER_PORT;
static int fl_equals_array(short type, const db_field_log *pfl1, void *p2) {
for (int i = 0; i < pfl1->no_elements; i++) {
switch (type) {
case DBR_DOUBLE:
if (((epicsFloat64*)pfl1->u.r.field)[i] != ((epicsInt32*)p2)[i]) {
testDiag("at index=%d: field log has %g, should be %d",
i, ((epicsFloat64*)pfl1->u.r.field)[i], ((epicsInt32*)p2)[i]);
return 0;
}
break;
case DBR_LONG:
if (((epicsInt32*)pfl1->u.r.field)[i] != ((epicsInt32*)p2)[i]) {
testDiag("at index=%d: field log has %d, should be %d",
i, ((epicsInt32*)pfl1->u.r.field)[i], ((epicsInt32*)p2)[i]);
return 0;
}
break;
case DBR_STRING:
if (strtol(&((const char*)pfl1->u.r.field)[i*MAX_STRING_SIZE], NULL, 0) != ((epicsInt32*)p2)[i]) {
testDiag("at index=%d: field log has '%s', should be '%d'",
i, &((const char*)pfl1->u.r.field)[i*MAX_STRING_SIZE], ((epicsInt32*)p2)[i]);
return 0;
}
break;
default:
return 0;
}
}
return 1;
}
static void createAndOpen(const char *chan, const char *json, const char *type, dbChannel**pch, short no) {
ELLNODE *node;
char name[80];
strncpy(name, chan, sizeof(name)-1);
strncat(name, json, sizeof(name)-strlen(name)-1);
testOk(!!(*pch = dbChannelCreate(name)), "dbChannel with plugin arr %s created", type);
testOk((ellCount(&(*pch)->filters) == no), "channel has %d filter(s) in filter list", no);
testOk(!(dbChannelOpen(*pch)), "dbChannel with plugin arr opened");
node = ellFirst(&(*pch)->pre_chain);
(void) CONTAINER(node, chFilter, pre_node);
testOk((ellCount(&(*pch)->pre_chain) == 0), "arr has no filter in pre chain");
node = ellFirst(&(*pch)->post_chain);
(void) CONTAINER(node, chFilter, post_node);
testOk((ellCount(&(*pch)->post_chain) == no),
"arr has %d filter(s) in post chain", no);
}
static void testHead (const char *title, const char *typ = "") {
const char *line = "------------------------------------------------------------------------------";
testDiag("%s", line);
testDiag(title, typ);
testDiag("%s", line);
}
#define TEST1(Size, Offset, Incr, Text) \
testDiag("Offset: %d (%s)", Offset, Text); \
off = Offset; \
(void) dbPutField(&offaddr, DBR_LONG, &off, 1); \
pfl = db_create_read_log(pch); \
testOk(pfl->type == dbfl_type_rec, "original field log has type rec"); \
pfl2 = dbChannelRunPostChain(pch, pfl); \
testOk(pfl2 == pfl, "call does not drop or replace field_log"); \
testOk(pfl->type == dbfl_type_ref, "filtered field log has type ref"); \
testOk(fl_equals_array(dbr_type, pfl2, ar##Size##_##Offset##_##Incr), "array data correct"); \
db_delete_field_log(pfl);
static void check(short dbr_type) {
dbChannel *pch;
db_field_log *pfl, *pfl2;
dbAddr valaddr;
dbAddr offaddr;
const char *offname = NULL, *valname = NULL, *typname = NULL;
epicsInt32 ar[10] = {10,11,12,13,14,15,16,17,18,19};
epicsInt32 *ar10_0_1 = ar;
epicsInt32 ar10_4_1[10] = {14,15,16,17,18,19,10,11,12,13};
epicsInt32 ar5_0_1[10] = {12,13,14,15,16};
epicsInt32 ar5_3_1[10] = {15,16,17,18,19};
epicsInt32 ar5_5_1[10] = {17,18,19,10,11};
epicsInt32 ar5_9_1[10] = {11,12,13,14,15};
epicsInt32 ar5_0_2[10] = {12,14,16};
epicsInt32 ar5_3_2[10] = {15,17,19};
epicsInt32 ar5_5_2[10] = {17,19,11};
epicsInt32 ar5_9_2[10] = {11,13,15};
epicsInt32 ar5_0_3[10] = {12,15};
epicsInt32 ar5_3_3[10] = {15,18};
epicsInt32 ar5_5_3[10] = {17,10};
epicsInt32 ar5_9_3[10] = {11,14};
epicsInt32 off = 0;
switch (dbr_type) {
case DBR_LONG:
offname = "x.OFF";
valname = "x.VAL";
typname = "long";
break;
case DBR_DOUBLE:
offname = "y.OFF";
valname = "y.VAL";
typname = "double";
break;
case DBR_STRING:
offname = "z.OFF";
valname = "z.VAL";
typname = "string";
break;
default:
testDiag("Invalid data type %d", dbr_type);
}
(void) dbNameToAddr(offname, &offaddr);
(void) dbNameToAddr(valname, &valaddr);
(void) dbPutField(&valaddr, DBR_LONG, ar, 10);
/* Default: should not change anything */
testHead("Ten %s elements from rec, increment 1, full size (default)", typname);
createAndOpen(valname, "{\"arr\":{}}", "(default)", &pch, 1);
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(10, 0, 1, "no offset");
TEST1(10, 4, 1, "wrapped");
dbChannelDelete(pch);
testHead("Ten %s elements from rec, increment 1, out-of-bound start parameter", typname);
createAndOpen(valname, "{\"arr\":{\"s\":-500}}", "out-of-bound start", &pch, 1);
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(10, 4, 1, "wrapped");
dbChannelDelete(pch);
testHead("Ten %s elements from rec, increment 1, out-of-bound end parameter", typname);
createAndOpen(valname, "{\"arr\":{\"e\":500}}", "out-of-bound end", &pch, 1);
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(10, 4, 1, "wrapped");
dbChannelDelete(pch);
testHead("Ten %s elements from rec, increment 1, zero increment parameter", typname);
createAndOpen(valname, "{\"arr\":{\"i\":0}}", "zero increment", &pch, 1);
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(10, 4, 1, "wrapped");
dbChannelDelete(pch);
testHead("Ten %s elements from rec, increment 1, invalid increment parameter", typname);
createAndOpen(valname, "{\"arr\":{\"i\":-30}}", "invalid increment", &pch, 1);
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(10, 4, 1, "wrapped");
dbChannelDelete(pch);
#define TEST5(Incr, Left, Right, Type) \
testHead("Five %s elements from rec, increment " #Incr ", " Type " addressing", typname); \
createAndOpen(valname, "{\"arr\":{\"s\":" #Left ",\"e\":" #Right ",\"i\":" #Incr "}}", \
"(" #Left ":" #Incr ":" #Right ")", &pch, 1); \
testOk(pch->final_type == valaddr.field_type, \
"final type unchanged (%d->%d)", valaddr.field_type, pch->final_type); \
testOk(pch->final_no_elements == 4 / Incr + 1, \
"final no_elements correct (%ld->%ld)", valaddr.no_elements, pch->final_no_elements); \
TEST1(5, 0, Incr, "no offset"); \
TEST1(5, 3, Incr, "from upper block"); \
TEST1(5, 5, Incr, "wrapped"); \
TEST1(5, 9, Incr, "from lower block"); \
dbChannelDelete(pch);
/* Contiguous block of 5 */
TEST5(1, 2, 6, "regular");
TEST5(1, -8, 6, "left side from-end");
TEST5(1, 2, -4, "right side from-end");
TEST5(1, -8, -4, "both sides from-end");
/* 5 elements with increment 2 */
TEST5(2, 2, 6, "regular");
TEST5(2, -8, 6, "left side from-end");
TEST5(2, 2, -4, "right side from-end");
TEST5(2, -8, -4, "both sides from-end");
/* 5 elements with increment 3 */
TEST5(3, 2, 6, "regular");
TEST5(3, -8, 6, "left side from-end");
TEST5(3, 2, -4, "right side from-end");
TEST5(3, -8, -4, "both sides from-end");
/* From buffer (plugin chain) */
#define TEST5B(Incr, Left, Right, Type) \
testHead("Five %s elements from buffer, increment " #Incr ", " Type " addressing", typname); \
createAndOpen(valname, "{\"arr\":{},\"arr\":{\"s\":" #Left ",\"e\":" #Right ",\"i\":" #Incr "}}", \
"(" #Left ":" #Incr ":" #Right ")", &pch, 2); \
testOk(pch->final_type == valaddr.field_type, \
"final type unchanged (%d->%d)", valaddr.field_type, pch->final_type); \
testOk(pch->final_no_elements == 4 / Incr + 1, \
"final no_elements correct (%ld->%ld)", valaddr.no_elements, pch->final_no_elements); \
TEST1(5, 0, Incr, "no offset"); \
dbChannelDelete(pch);
/* Contiguous block of 5 */
TEST5B(1, 2, 6, "regular");
TEST5B(1, -8, 6, "left side from-end");
TEST5B(1, 2, -4, "right side from-end");
TEST5B(1, -8, -4, "both sides from-end");
/* 5 elements with increment 2 */
TEST5B(2, 2, 6, "regular");
TEST5B(2, -8, 6, "left side from-end");
TEST5B(2, 2, -4, "right side from-end");
TEST5B(2, -8, -4, "both sides from-end");
/* 5 elements with increment 3 */
TEST5B(3, 2, 6, "regular");
TEST5B(3, -8, 6, "left side from-end");
TEST5B(3, 2, -4, "right side from-end");
TEST5B(3, -8, -4, "both sides from-end");
}
MAIN(arrTest)
{
dbEventCtx evtctx;
const chFilterPlugin *plug;
char arr[] = "arr";
testPlan(1402);
/* Prepare the IOC */
epicsEnvSet("EPICS_CA_SERVER_PORT", server_port);
testdbPrepare();
testdbReadDatabase("filterTest.dbd", NULL, NULL);
filterTest_registerRecordDeviceDriver(pdbbase);
testdbReadDatabase("arrTest.db", NULL, NULL);
eltc(0);
testIocInitOk();
eltc(1);
/* Start the IOC */
evtctx = db_init_events();
testOk(!!(plug = dbFindFilter(arr, strlen(arr))), "plugin arr registered correctly");
check(DBR_LONG);
check(DBR_DOUBLE);
check(DBR_STRING);
db_close_events(evtctx);
testIocShutdownOk();
testdbCleanup();
return testDone();
}
-15
View File
@@ -1,15 +0,0 @@
record(arr, "x") {
field(DESC, "test array record")
field(NELM, "10")
field(FTVL, "LONG")
}
record(arr, "y") {
field(DESC, "test array record")
field(NELM, "10")
field(FTVL, "DOUBLE")
}
record(arr, "z") {
field(DESC, "test array record")
field(NELM, "10")
field(FTVL, "STRING")
}
-285
View File
@@ -1,285 +0,0 @@
/*************************************************************************\
* Copyright (c) 2010 Brookhaven National Laboratory.
* Copyright (c) 2010 Helmholtz-Zentrum Berlin
* fuer Materialien und Energie GmbH.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/*
* Author: Ralph Lange <Ralph.Lange@bessy.de>
*/
#include <string.h>
#include "dbStaticLib.h"
#include "dbAccessDefs.h"
#include "db_field_log.h"
#include "dbCommon.h"
#include "registry.h"
#include "errlog.h"
#include "chfPlugin.h"
#include "epicsUnitTest.h"
#include "dbUnitTest.h"
#include "epicsTime.h"
#include "dbmf.h"
#include "testMain.h"
#include "osiFileName.h"
#define PATTERN 0x55
void filterTest_registerRecordDeviceDriver(struct dbBase *);
static db_field_log fl;
static int fl_equal(const db_field_log *pfl1, const db_field_log *pfl2) {
return !(memcmp(pfl1, pfl2, sizeof(db_field_log)));
}
static void fl_setup(dbChannel *chan, db_field_log *pfl) {
struct dbCommon *prec = dbChannelRecord(chan);
pfl->ctx = dbfl_context_read;
pfl->type = dbfl_type_val;
pfl->stat = prec->stat;
pfl->sevr = prec->sevr;
pfl->time = prec->time;
pfl->field_type = dbChannelFieldType(chan);
pfl->no_elements = dbChannelElements(chan);
/*
* use memcpy to avoid a bus error on
* union copy of char in the db at an odd
* address
*/
memcpy(&pfl->u.v.field,
dbChannelField(chan),
dbChannelFieldSize(chan));
}
static void changeValue(db_field_log *pfl2, long val) {
pfl2->u.v.field.dbf_long = val;
testDiag("new value: %ld", val);
}
static void mustPassOnce(dbChannel *pch, db_field_log *pfl2, char* m, double d, long val) {
db_field_log *pfl;
changeValue(pfl2, val);
testDiag("mode=%s delta=%g filter must pass once", m, d);
pfl = dbChannelRunPreChain(pch, pfl2);
testOk(pfl2 == pfl, "call 1 does not drop or replace field_log");
testOk(fl_equal(pfl, pfl2), "call 1 does not change field_log data");
pfl = dbChannelRunPreChain(pch, pfl2);
testOk(NULL == pfl, "call 2 drops field_log");
}
static void mustDrop(dbChannel *pch, db_field_log *pfl2, char* m, double d, long val) {
db_field_log *pfl;
changeValue(pfl2, val);
testDiag("mode=%s delta=%g filter must drop", m, d);
pfl = dbChannelRunPreChain(pch, pfl2);
testOk(NULL == pfl, "call 1 drops field_log");
}
static void mustPassTwice(dbChannel *pch, db_field_log *pfl2, char* m, double d, long val) {
db_field_log *pfl;
changeValue(pfl2, val);
testDiag("mode=%s delta=%g filter must pass twice", m, d);
pfl = dbChannelRunPreChain(pch, pfl2);
testOk(pfl2 == pfl, "call 1 does not drop or replace field_log");
testOk(fl_equal(pfl, pfl2), "call 1 does not change field_log data");
pfl = dbChannelRunPreChain(pch, pfl2);
testOk(pfl2 == pfl, "call 2 does not drop or replace field_log");
testOk(fl_equal(pfl, pfl2), "call 2 does not change field_log data");
}
static void testHead (char* title) {
testDiag("--------------------------------------------------------");
testDiag("%s", title);
testDiag("--------------------------------------------------------");
}
MAIN(dbndTest)
{
dbChannel *pch;
chFilter *filter;
const chFilterPlugin *plug;
char dbnd[] = "dbnd";
ELLNODE *node;
chPostEventFunc *cb_out = NULL;
void *arg_out = NULL;
db_field_log *pfl2;
db_field_log fl1;
dbEventCtx evtctx;
testPlan(59);
testdbPrepare();
testdbReadDatabase("filterTest.dbd", NULL, NULL);
filterTest_registerRecordDeviceDriver(pdbbase);
testdbReadDatabase("xRecord.db", NULL, NULL);
eltc(0);
testIocInitOk();
eltc(1);
evtctx = db_init_events();
testOk(!!(plug = dbFindFilter(dbnd, strlen(dbnd))), "plugin dbnd registered correctly");
testOk(!!(pch = dbChannelCreate("x.VAL{\"dbnd\":{}}")), "dbChannel with plugin dbnd (delta=0) created");
testOk((ellCount(&pch->filters) == 1), "channel has one plugin");
memset(&fl, PATTERN, sizeof(fl));
fl1 = fl;
node = ellFirst(&pch->filters);
filter = CONTAINER(node, chFilter, list_node);
plug->fif->channel_register_pre(filter, &cb_out, &arg_out, &fl1);
testOk(!!(cb_out) && !!(arg_out), "register_pre registers one filter with argument");
testOk(fl_equal(&fl1, &fl), "register_pre does not change field_log data type");
testOk(!(dbChannelOpen(pch)), "dbChannel with plugin dbnd opened");
node = ellFirst(&pch->pre_chain);
filter = CONTAINER(node, chFilter, pre_node);
testOk((ellCount(&pch->pre_chain) == 1 && filter->pre_arg != NULL),
"dbnd has one filter with argument in pre chain");
testOk((ellCount(&pch->post_chain) == 0), "dbnd has no filter in post chain");
/* Field logs of type ref and rec: pass any update */
testHead("Field logs of type ref and rec");
fl1.type = dbfl_type_rec;
mustPassTwice(pch, &fl1, "abs field_log=rec", 0., 0);
fl1.type = dbfl_type_ref;
mustPassTwice(pch, &fl1, "abs field_log=ref", 0., 0);
/* Delta = 0: pass any change */
testHead("Delta = 0: pass any change");
pfl2 = db_create_read_log(pch);
testDiag("new field_log from record");
fl_setup(pch, pfl2);
mustPassOnce(pch, pfl2, "abs", 0., 0);
pfl2 = db_create_read_log(pch);
testDiag("new field_log from record");
fl_setup(pch, pfl2);
mustPassOnce(pch, pfl2, "abs", 0., 1);
dbChannelDelete(pch);
/* Delta = -1: pass any update */
testHead("Delta = -1: pass any update");
testOk(!!(pch = dbChannelCreate("x.VAL{\"dbnd\":{\"d\":-1.0}}")), "dbChannel with plugin dbnd (delta=-1) created");
testOk(!(dbChannelOpen(pch)), "dbChannel with plugin dbnd opened");
pfl2 = db_create_read_log(pch);
testDiag("new field_log from record");
fl_setup(pch, pfl2);
mustPassTwice(pch, pfl2, "abs", -1., 0);
mustPassTwice(pch, pfl2, "abs", -1., 1);
db_delete_field_log(pfl2);
dbChannelDelete(pch);
/* Delta = absolute */
testHead("Delta = absolute");
testOk(!!(pch = dbChannelCreate("x.VAL{\"dbnd\":{\"d\":3}}")), "dbChannel with plugin dbnd (delta=3) created");
testOk(!(dbChannelOpen(pch)), "dbChannel with plugin dbnd opened");
pfl2 = db_create_read_log(pch);
testDiag("new field_log from record");
fl_setup(pch, pfl2);
mustPassOnce(pch, pfl2, "abs", 3., 1);
pfl2 = db_create_read_log(pch);
testDiag("new field_log from record");
fl_setup(pch, pfl2);
mustDrop(pch, pfl2, "abs", 3., 3);
pfl2 = db_create_read_log(pch);
testDiag("new field_log from record");
fl_setup(pch, pfl2);
mustDrop(pch, pfl2, "abs", 3., 4);
pfl2 = db_create_read_log(pch);
testDiag("new field_log from record");
fl_setup(pch, pfl2);
mustPassOnce(pch, pfl2, "abs", 3., 5);
dbChannelDelete(pch);
/* Delta = relative */
testHead("Delta = relative");
testOk(!!(pch = dbChannelCreate("x.VAL{\"dbnd\":{\"m\":\"rel\",\"d\":50}}")),
"dbChannel with plugin dbnd (mode=rel, delta=50) created");
testOk(!(dbChannelOpen(pch)), "dbChannel with plugin dbnd opened");
pfl2 = db_create_read_log(pch);
testDiag("new field_log from record");
fl_setup(pch, pfl2);
mustPassOnce(pch, pfl2, "rel", 50., 1);
pfl2 = db_create_read_log(pch);
testDiag("new field_log from record");
fl_setup(pch, pfl2);
mustPassOnce(pch, pfl2, "rel", 50., 2);
pfl2 = db_create_read_log(pch);
testDiag("new field_log from record");
fl_setup(pch, pfl2);
mustDrop(pch, pfl2, "rel", 50., 3);
pfl2 = db_create_read_log(pch);
testDiag("new field_log from record");
fl_setup(pch, pfl2);
mustPassOnce(pch, pfl2, "rel", 50., 4);
pfl2 = db_create_read_log(pch);
testDiag("new field_log from record");
fl_setup(pch, pfl2);
mustDrop(pch, pfl2, "rel", 50., 5);
pfl2 = db_create_read_log(pch);
testDiag("new field_log from record");
fl_setup(pch, pfl2);
mustDrop(pch, pfl2, "rel", 50., 6);
pfl2 = db_create_read_log(pch);
testDiag("new field_log from record");
fl_setup(pch, pfl2);
mustPassOnce(pch, pfl2, "rel", 50., 7);
dbChannelDelete(pch);
db_close_events(evtctx);
testIocShutdownOk();
testdbCleanup();
return testDone();
}
@@ -1,33 +0,0 @@
/*************************************************************************\
* Copyright (c) 2012 UChicago Argonne LLC, as Operator of Argonne
* National Laboratory.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/*
* Run filter tests as a batch.
*/
#include "epicsUnitTest.h"
#include "epicsExit.h"
#include "dbmf.h"
int tsTest(void);
int dbndTest(void);
int syncTest(void);
int arrTest(void);
void epicsRunFilterTests(void)
{
testHarness();
runTest(tsTest);
runTest(dbndTest);
runTest(syncTest);
runTest(arrTest);
dbmfFreeChunks();
epicsExit(0); /* Trigger test harness */
}
-14
View File
@@ -1,14 +0,0 @@
/*************************************************************************\
* Copyright (c) 2012 UChicago Argonne LLC, as Operator of Argonne
* National Laboratory.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
extern void epicsRunFilterTests(void);
int main(int argc, char **argv)
{
epicsRunFilterTests(); /* calls epicsExit(0) */
return 0;
}
-378
View File
@@ -1,378 +0,0 @@
/*************************************************************************\
* Copyright (c) 2010 Brookhaven National Laboratory.
* Copyright (c) 2010 Helmholtz-Zentrum Berlin
* fuer Materialien und Energie GmbH.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/*
* Author: Ralph Lange <Ralph.Lange@bessy.de>
*/
#include <string.h>
#include "dbStaticLib.h"
#include "dbAccessDefs.h"
#include "db_field_log.h"
#include "dbCommon.h"
#include "dbChannel.h"
#include "registry.h"
#include "chfPlugin.h"
#include "errlog.h"
#include "dbmf.h"
#include "epicsUnitTest.h"
#include "dbUnitTest.h"
#include "epicsTime.h"
#include "dbState.h"
#include "testMain.h"
#include "osiFileName.h"
#define PATTERN 0x55
void filterTest_registerRecordDeviceDriver(struct dbBase *);
static db_field_log fl;
static dbStateId red;
static int fl_equal(const db_field_log *pfl1, const db_field_log *pfl2) {
return !(memcmp(pfl1, pfl2, sizeof(db_field_log)));
}
static void fl_setup(dbChannel *chan, db_field_log *pfl, long val) {
struct dbCommon *prec = dbChannelRecord(chan);
pfl->ctx = dbfl_context_event;
pfl->type = dbfl_type_val;
pfl->stat = prec->stat;
pfl->sevr = prec->sevr;
pfl->time = prec->time;
pfl->field_type = DBF_LONG;
pfl->no_elements = 1;
/*
* use memcpy to avoid a bus error on
* union copy of char in the db at an odd
* address
*/
memcpy(&pfl->u.v.field,
dbChannelField(chan),
dbChannelFieldSize(chan));
pfl->u.v.field.dbf_long = val;
}
static void testHead (char* title) {
testDiag("--------------------------------------------------------");
testDiag("%s", title);
testDiag("--------------------------------------------------------");
}
static void mustDrop(dbChannel *pch, db_field_log *pfl2, char* m) {
db_field_log *pfl = dbChannelRunPreChain(pch, pfl2);
testOk(NULL == pfl, "filter drops field_log (%s)", m);
}
static void mustPassTwice(dbChannel *pch, db_field_log *pfl2, char* m) {
db_field_log *pfl;
testDiag("%s: filter must pass twice", m);
pfl = dbChannelRunPreChain(pch, pfl2);
testOk(pfl2 == pfl, "call 1 does not drop or replace field_log");
pfl = dbChannelRunPreChain(pch, pfl2);
testOk(pfl2 == pfl, "call 2 does not drop or replace field_log");
}
static void mustPassOld(dbChannel *pch, db_field_log *old, db_field_log *cur, char* m) {
db_field_log *pfl = dbChannelRunPreChain(pch, cur);
testOk(old == pfl, "filter passes previous field log (%s)", m);
}
static void mustPass(dbChannel *pch, db_field_log *cur, char* m) {
db_field_log *pfl = dbChannelRunPreChain(pch, cur);
testOk(cur == pfl, "filter passes field_log (%s)", m);
}
static void checkCtxRead(dbChannel *pch, dbStateId id) {
fl.ctx = dbfl_context_read;
dbStateClear(id);
mustPassTwice(pch, &fl, "ctx='read', state=FALSE");
dbStateSet(id);
mustPassTwice(pch, &fl, "ctx='read', state=TRUE");
dbStateClear(id);
mustPassTwice(pch, &fl, "ctx='read', state=FALSE");
fl.ctx = dbfl_context_event;
}
static void checkAndOpenChannel(dbChannel *pch, const chFilterPlugin *plug) {
ELLNODE *node;
chFilter *filter;
chPostEventFunc *cb_out = NULL;
void *arg_out = NULL;
db_field_log fl1;
testDiag("Test filter structure and open channel");
testOk((ellCount(&pch->filters) == 1), "channel has one plugin");
fl1 = fl;
node = ellFirst(&pch->filters);
filter = CONTAINER(node, chFilter, list_node);
plug->fif->channel_register_pre(filter, &cb_out, &arg_out, &fl1);
testOk(!!(cb_out) && !!(arg_out), "register_pre registers one filter with argument");
testOk(fl_equal(&fl1, &fl), "register_pre does not change field_log data type");
testOk(!(dbChannelOpen(pch)), "dbChannel with plugin sync opened");
node = ellFirst(&pch->pre_chain);
filter = CONTAINER(node, chFilter, pre_node);
testOk((ellCount(&pch->pre_chain) == 1 && filter->pre_arg != NULL),
"sync has one filter with argument in pre chain");
testOk((ellCount(&pch->post_chain) == 0), "sync has no filter in post chain");
checkCtxRead(pch, red);
}
MAIN(syncTest)
{
dbChannel *pch;
const chFilterPlugin *plug;
char myname[] = "sync";
db_field_log *pfl[10];
int i;
dbEventCtx evtctx;
testPlan(139);
testdbPrepare();
testdbReadDatabase("filterTest.dbd", NULL, NULL);
filterTest_registerRecordDeviceDriver(pdbbase);
testdbReadDatabase("xRecord.db", NULL, NULL);
eltc(0);
testIocInitOk();
eltc(1);
evtctx = db_init_events();
testOk(!!(plug = dbFindFilter(myname, strlen(myname))), "plugin %s registered correctly", myname);
testOk(!!(red = dbStateCreate("red")), "state 'red' created successfully");
/* nonexisting state */
testOk(!(pch = dbChannelCreate("x.VAL{\"sync\":{\"m\":\"while\",\"s\":\"blue\"}}")),
"dbChannel with sync (m='while' s='blue') (nonex state) failed");
/* missing state */
testOk(!(pch = dbChannelCreate("x.VAL{\"sync\":{\"m\":\"while\"}}")),
"dbChannel with sync (m='while') (no state) failed");
/* missing mode */
testOk(!(pch = dbChannelCreate("x.VAL{\"sync\":{\"s\":\"red\"}}")),
"dbChannel with sync (s='red') (no mode) failed");
/* mode WHILE */
testHead("Mode WHILE (m='while', s='red')");
testOk(!!(pch = dbChannelCreate("x.VAL{\"sync\":{\"m\":\"while\",\"s\":\"red\"}}")),
"dbChannel with plugin sync (m='while' s='red') created");
checkAndOpenChannel(pch, plug);
for (i = 0; i < 10; i++) {
pfl[i] = db_create_read_log(pch);
fl_setup(pch, pfl[i], 120 + i);
}
testDiag("Test event stream");
dbStateClear(red);
mustDrop(pch, pfl[0], "state=FALSE, log0");
mustDrop(pch, pfl[1], "state=FALSE, log1");
mustDrop(pch, pfl[2], "state=FALSE, log2");
dbStateSet(red);
mustPass(pch, pfl[3], "state=TRUE, log3");
mustPass(pch, pfl[4], "state=TRUE, log4");
mustPass(pch, pfl[5], "state=TRUE, log5");
dbStateClear(red);
mustDrop(pch, pfl[6], "state=FALSE, log6");
mustDrop(pch, pfl[7], "state=FALSE, log7");
mustDrop(pch, pfl[8], "state=FALSE, log8");
for (i = 0; i < 10; i++)
db_delete_field_log(pfl[i]);
dbChannelDelete(pch);
/* mode UNLESS */
testHead("Mode UNLESS (m='unless', s='red')");
testOk(!!(pch = dbChannelCreate("x.VAL{\"sync\":{\"m\":\"unless\",\"s\":\"red\"}}")),
"dbChannel with plugin sync (m='unless' s='red') created");
checkAndOpenChannel(pch, plug);
for (i = 0; i < 10; i++) {
pfl[i] = db_create_read_log(pch);
fl_setup(pch, pfl[i], 120 + i);
}
testDiag("Test event stream");
dbStateClear(red);
mustPass(pch, pfl[0], "state=FALSE, log0");
mustPass(pch, pfl[1], "state=FALSE, log1");
mustPass(pch, pfl[2], "state=FALSE, log2");
dbStateSet(red);
mustDrop(pch, pfl[3], "state=TRUE, log3");
mustDrop(pch, pfl[4], "state=TRUE, log4");
mustDrop(pch, pfl[5], "state=TRUE, log5");
dbStateClear(red);
mustPass(pch, pfl[6], "state=FALSE, log6");
mustPass(pch, pfl[7], "state=FALSE, log7");
mustPass(pch, pfl[8], "state=FALSE, log8");
for (i = 0; i < 10; i++)
db_delete_field_log(pfl[i]);
dbChannelDelete(pch);
/* mode BEFORE */
testHead("Mode BEFORE (m='before', s='red')");
testOk(!!(pch = dbChannelCreate("x.VAL{\"sync\":{\"m\":\"before\",\"s\":\"red\"}}")),
"dbChannel with plugin sync (m='before' s='red') created");
checkAndOpenChannel(pch, plug);
for (i = 0; i < 10; i++) {
pfl[i] = db_create_read_log(pch);
fl_setup(pch, pfl[i], 120 + i);
}
testDiag("Test event stream");
dbStateClear(red);
mustDrop(pch, pfl[0], "state=FALSE, log0");
mustDrop(pch, pfl[1], "state=FALSE, log1");
mustDrop(pch, pfl[2], "state=FALSE, log2");
dbStateSet(red);
mustPassOld(pch, pfl[2], pfl[3], "state=TRUE, log3, pass=log2");
mustDrop(pch, pfl[4], "state=TRUE, log4");
mustDrop(pch, pfl[5], "state=TRUE, log5");
mustDrop(pch, pfl[6], "state=TRUE, log6");
dbStateClear(red);
mustDrop(pch, pfl[7], "state=FALSE, log7");
mustDrop(pch, pfl[8], "state=FALSE, log8");
mustDrop(pch, pfl[9], "state=FALSE, log9");
db_delete_field_log(pfl[2]);
dbChannelDelete(pch);
/* mode FIRST */
testHead("Mode FIRST (m='first', s='red')");
testOk(!!(pch = dbChannelCreate("x.VAL{\"sync\":{\"m\":\"first\",\"s\":\"red\"}}")),
"dbChannel with plugin sync (m='first' s='red') created");
checkAndOpenChannel(pch, plug);
for (i = 0; i < 10; i++) {
pfl[i] = db_create_read_log(pch);
fl_setup(pch, pfl[i], 120 + i);
}
testDiag("Test event stream");
dbStateClear(red);
mustDrop(pch, pfl[0], "state=FALSE, log0");
mustDrop(pch, pfl[1], "state=FALSE, log1");
mustDrop(pch, pfl[2], "state=FALSE, log2");
dbStateSet(red);
mustPass(pch, pfl[3], "state=TRUE, log3");
mustDrop(pch, pfl[4], "state=TRUE, log4");
mustDrop(pch, pfl[5], "state=TRUE, log5");
dbStateClear(red);
mustDrop(pch, pfl[6], "state=FALSE, log6");
mustDrop(pch, pfl[7], "state=FALSE, log7");
mustDrop(pch, pfl[8], "state=FALSE, log8");
db_delete_field_log(pfl[3]);
db_delete_field_log(pfl[9]);
dbChannelDelete(pch);
/* mode LAST */
testHead("Mode LAST (m='last', s='red')");
testOk(!!(pch = dbChannelCreate("x.VAL{\"sync\":{\"m\":\"last\",\"s\":\"red\"}}")),
"dbChannel with plugin sync (m='last' s='red') created");
checkAndOpenChannel(pch, plug);
for (i = 0; i < 10; i++) {
pfl[i] = db_create_read_log(pch);
fl_setup(pch, pfl[i], 120 + i);
}
testDiag("Test event stream");
dbStateClear(red);
mustDrop(pch, pfl[0], "state=FALSE, log0");
mustDrop(pch, pfl[1], "state=FALSE, log1");
mustDrop(pch, pfl[2], "state=FALSE, log2");
dbStateSet(red);
mustDrop(pch, pfl[3], "state=TRUE, log3");
mustDrop(pch, pfl[4], "state=TRUE, log4");
mustDrop(pch, pfl[5], "state=TRUE, log5");
dbStateClear(red);
mustPassOld(pch, pfl[5], pfl[6], "state=TRUE, log6, pass=log5");
mustDrop(pch, pfl[7], "state=FALSE, log7");
mustDrop(pch, pfl[8], "state=FALSE, log8");
mustDrop(pch, pfl[9], "state=FALSE, log9");
db_delete_field_log(pfl[5]);
dbChannelDelete(pch);
/* mode AFTER */
testHead("Mode AFTER (m='after', s='red')");
testOk(!!(pch = dbChannelCreate("x.VAL{\"sync\":{\"m\":\"after\",\"s\":\"red\"}}")),
"dbChannel with plugin sync (m='after' s='red') created");
checkAndOpenChannel(pch, plug);
for (i = 0; i < 10; i++) {
pfl[i] = db_create_read_log(pch);
fl_setup(pch, pfl[i], 120 + i);
}
testDiag("Test event stream");
dbStateClear(red);
mustDrop(pch, pfl[0], "state=FALSE, log0");
mustDrop(pch, pfl[1], "state=FALSE, log1");
mustDrop(pch, pfl[2], "state=FALSE, log2");
dbStateSet(red);
mustDrop(pch, pfl[3], "state=TRUE, log3");
mustDrop(pch, pfl[4], "state=TRUE, log4");
mustDrop(pch, pfl[5], "state=TRUE, log5");
dbStateClear(red);
mustPass(pch, pfl[6], "state=FALSE, log6");
mustDrop(pch, pfl[7], "state=FALSE, log7");
mustDrop(pch, pfl[8], "state=FALSE, log8");
db_delete_field_log(pfl[6]);
db_delete_field_log(pfl[9]);
dbChannelDelete(pch);
db_close_events(evtctx);
testIocShutdownOk();
testdbCleanup();
return testDone();
}
-119
View File
@@ -1,119 +0,0 @@
/*************************************************************************\
* Copyright (c) 2010 Brookhaven National Laboratory.
* Copyright (c) 2010 Helmholtz-Zentrum Berlin
* fuer Materialien und Energie GmbH.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/*
* Author: Ralph Lange <Ralph.Lange@bessy.de>
*/
#include <string.h>
#include "dbStaticLib.h"
#include "dbAccessDefs.h"
#include "chfPlugin.h"
#include "errlog.h"
#include "epicsUnitTest.h"
#include "dbUnitTest.h"
#include "registry.h"
#include "dbmf.h"
#include "epicsTime.h"
#include "testMain.h"
#include "osiFileName.h"
#define PATTERN 0x55
void filterTest_registerRecordDeviceDriver(struct dbBase *);
static db_field_log fl;
static int fl_equal(const db_field_log *pfl1, const db_field_log *pfl2) {
return !(memcmp(pfl1, pfl2, sizeof(db_field_log)));
}
static int fl_equal_ex_ts(const db_field_log *pfl1, const db_field_log *pfl2) {
db_field_log fl1 = *pfl1;
fl1.time = pfl2->time;
return fl_equal(&fl1, pfl2);
}
MAIN(tsTest)
{
dbChannel *pch;
chFilter *filter;
const chFilterPlugin *plug;
char ts[] = "ts";
ELLNODE *node;
chPostEventFunc *cb_out = NULL;
void *arg_out = NULL;
db_field_log fl1;
db_field_log *pfl2;
epicsTimeStamp stamp, now;
dbEventCtx evtctx;
testPlan(12);
testdbPrepare();
testdbReadDatabase("filterTest.dbd", NULL, NULL);
filterTest_registerRecordDeviceDriver(pdbbase);
testdbReadDatabase("xRecord.db", NULL, NULL);
eltc(0);
testIocInitOk();
eltc(1);
evtctx = db_init_events();
testOk(!!(plug = dbFindFilter(ts, strlen(ts))), "plugin ts registered correctly");
testOk(!!(pch = dbChannelCreate("x.VAL{\"ts\":{}}")), "dbChannel with plugin ts created");
testOk((ellCount(&pch->filters) == 1), "channel has one plugin");
memset(&fl, PATTERN, sizeof(fl));
fl1 = fl;
node = ellFirst(&pch->filters);
filter = CONTAINER(node, chFilter, list_node);
plug->fif->channel_register_pre(filter, &cb_out, &arg_out, &fl1);
testOk(!!(cb_out) && !(arg_out), "register_pre registers one filter w/o argument");
testOk(fl_equal(&fl1, &fl), "register_pre does not change field_log data type");
testOk(!(dbChannelOpen(pch)), "dbChannel with plugin ts opened");
node = ellFirst(&pch->pre_chain);
filter = CONTAINER(node, chFilter, pre_node);
testOk((ellCount(&pch->pre_chain) == 1 && filter->pre_arg == NULL),
"ts has one filter w/o argument in pre chain");
testOk((ellCount(&pch->post_chain) == 0), "ts has no filter in post chain");
memset(&fl, PATTERN, sizeof(fl));
fl1 = fl;
pfl2 = dbChannelRunPreChain(pch, &fl1);
testOk(pfl2 == &fl1, "ts filter does not drop or replace field_log");
testOk(fl_equal_ex_ts(&fl1, pfl2), "ts filter does not change field_log data");
testOk(!!(pfl2 = db_create_read_log(pch)), "create field log from channel");
stamp = pfl2->time;
db_delete_field_log(pfl2);
pfl2 = dbChannelRunPreChain(pch, &fl1);
epicsTimeGetCurrent(&now);
testOk(epicsTimeDiffInSeconds(&pfl2->time, &stamp) >= 0 &&
epicsTimeDiffInSeconds(&now, &pfl2->time) >= 0,
"ts filter sets time stamp to \"now\"");
dbChannelDelete(pch);
db_close_events(evtctx);
testIocShutdownOk();
testdbCleanup();
return testDone();
}
-25
View File
@@ -1,25 +0,0 @@
/*************************************************************************\
* Copyright (c) 2010 UChicago Argonne LLC, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2010 Brookhaven National Laboratory.
* Copyright (c) 2010 Helmholtz-Zentrum Berlin
* fuer Materialien und Energie GmbH.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/*
* Author: Andrew Johnson <anj@aps.anl.gov>
* Ralph Lange <Ralph.Lange@bessy.de>
*/
#include "dbAccessDefs.h"
#include <recSup.h>
#define GEN_SIZE_OFFSET
#include "xRecord.h"
#include <epicsExport.h>
static rset xRSET;
epicsExportAddress(rset,xRSET);
-2
View File
@@ -1,2 +0,0 @@
record(x, x) {}
-8
View File
@@ -1,8 +0,0 @@
# This is a combined minimal DBD and DB file
recordtype(x) {
include "dbCommon.dbd"
field(VAL, DBF_LONG) {
prompt("Value")
}
}
+1 -1
View File
@@ -4,7 +4,7 @@
# 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.
# in file LICENSE that is included with this distribution.
#*************************************************************************
# This is a Makefile fragment, see src/std/Makefile.
-121
View File
@@ -1,121 +0,0 @@
#*************************************************************************
# Copyright (c) 2012 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 the file LICENSE that is included with this distribution.
#*************************************************************************
TOP=../../../..
include $(TOP)/configure/CONFIG
TESTLIBRARY = dbRecStdTest
dbRecStdTest_SRCS += asTestLib.c
dbRecStdTest_LIBS += dbRecStd dbCore ca Com
PROD_LIBS = dbRecStdTest dbRecStd dbCore ca Com
TARGETS += $(COMMON_DIR)/recTestIoc.dbd
DBDDEPENDS_FILES += recTestIoc.dbd$(DEP)
recTestIoc_DBD = base.dbd
TESTFILES += $(COMMON_DIR)/recTestIoc.dbd
testHarness_SRCS += recTestIoc_registerRecordDeviceDriver.cpp
testHarness_SRCS += asTestIoc_registerRecordDeviceDriver.cpp
TESTPROD_HOST += arrayOpTest
arrayOpTest_SRCS += arrayOpTest.c
arrayOpTest_SRCS += recTestIoc_registerRecordDeviceDriver.cpp
testHarness_SRCS += arrayOpTest.c
TESTFILES += ../arrayOpTest.db
TESTS += arrayOpTest
TESTPROD_HOST += recMiscTest
recMiscTest_SRCS += recMiscTest.c
recMiscTest_SRCS += recTestIoc_registerRecordDeviceDriver.cpp
testHarness_SRCS += recMiscTest.c
TESTFILES += ../recMiscTest.db
TESTS += recMiscTest
TESTPROD_HOST += linkRetargetLinkTest
linkRetargetLinkTest_SRCS += linkRetargetLinkTest.c
linkRetargetLinkTest_SRCS += recTestIoc_registerRecordDeviceDriver.cpp
testHarness_SRCS += linkRetargetLinkTest.c
TESTFILES += ../linkRetargetLink.db
TESTS += linkRetargetLinkTest
TESTPROD_HOST += linkInitTest
linkInitTest_SRCS += linkInitTest.c
linkInitTest_SRCS += recTestIoc_registerRecordDeviceDriver.cpp
testHarness_SRCS += linkInitTest.c
TESTFILES += ../linkInitTest.db
TESTS += linkInitTest
TESTPROD_HOST += compressTest
compressTest_SRCS += compressTest.c
compressTest_SRCS += recTestIoc_registerRecordDeviceDriver.cpp
testHarness_SRCS += compressTest.c
TESTFILES += ../compressTest.db
TESTS += compressTest
TESTPROD_HOST += asyncSoftTest
asyncSoftTest_SRCS += asyncSoftTest.c
asyncSoftTest_SRCS += recTestIoc_registerRecordDeviceDriver.cpp
testHarness_SRCS += asyncSoftTest.c
TESTFILES += ../asyncSoftTest.db
TESTS += asyncSoftTest
TESTPROD_HOST += softTest
softTest_SRCS += softTest.c
softTest_SRCS += recTestIoc_registerRecordDeviceDriver.cpp
testHarness_SRCS += softTest.c
TESTFILES += ../softTest.db
TESTS += softTest
TARGETS += $(COMMON_DIR)/asTestIoc.dbd
DBDDEPENDS_FILES += asTestIoc.dbd$(DEP)
asTestIoc_DBD += base.dbd
asTestIoc_DBD += asTest.dbd
TESTPROD_HOST += asTest
asTest_SRCS += asTest.c
asTest_SRCS += asTestIoc_registerRecordDeviceDriver.cpp
testHarness_SRCS += asTest.c
TESTFILES += $(COMMON_DIR)/asTestIoc.dbd ../asTest.db
TESTS += asTest
TARGETS += $(COMMON_DIR)/analogMonitorTest.dbd
DBDDEPENDS_FILES += analogMonitorTest.dbd$(DEP)
analogMonitorTest_DBD += base.dbd
TESTPROD_HOST += analogMonitorTest
analogMonitorTest_SRCS += analogMonitorTest.c
analogMonitorTest_SRCS += analogMonitorTest_registerRecordDeviceDriver.cpp
testHarness_SRCS += analogMonitorTest.c
testHarness_SRCS += analogMonitorTest_registerRecordDeviceDriver.cpp
TESTFILES += $(COMMON_DIR)/analogMonitorTest.dbd ../analogMonitorTest.db
TESTS += analogMonitorTest
TARGETS += $(COMMON_DIR)/regressTest.dbd
regressTest_DBD += base.dbd
TESTPROD_HOST += regressTest
regressTest_SRCS += regressTest.c
regressTest_SRCS += regressTest_registerRecordDeviceDriver.cpp
TESTFILES += $(COMMON_DIR)/regressTest.dbd ../regressArray1.db ../regressHex.db ../regressLinkMS.db
TESTS += regressTest
# epicsRunRecordTests runs all the test programs in a known working order.
testHarness_SRCS += epicsRunRecordTests.c
recordTestHarness_SRCS += $(testHarness_SRCS)
recordTestHarness_SRCS_RTEMS += rtemsTestHarness.c
PROD_vxWorks = recordTestHarness
PROD_RTEMS = recordTestHarness
TESTSPEC_vxWorks = recordTestHarness.munch; epicsRunRecordTests
TESTSPEC_RTEMS = recordTestHarness.boot; epicsRunRecordTests
TESTSCRIPTS_HOST += $(TESTS:%=%.t)
include $(TOP)/configure/RULES
-240
View File
@@ -1,240 +0,0 @@
/*************************************************************************\
* Copyright (c) 2014 ITER Organization.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/*
* Author: Ralph Lange <Ralph.Lange@gmx.de>
*/
#include <string.h>
#include "registryFunction.h"
#include "osiFileName.h"
#include "epicsThread.h"
#include "epicsMath.h"
#include "epicsUnitTest.h"
#include "dbAccessDefs.h"
#include "dbStaticLib.h"
#include "dbEvent.h"
#include "caeventmask.h"
#include "db_field_log.h"
#include "chfPlugin.h"
#include "iocInit.h"
#include "testMain.h"
#include "epicsExport.h"
/* Test parameters */
#define NO_OF_RECORD_TYPES 7
#define NO_OF_DEADBANDS 3
#define NO_OF_PATTERNS 16
#define NO_OF_VALUES_PER_SEQUENCE 2
void analogMonitorTest_registerRecordDeviceDriver(struct dbBase *);
/* Indices for record type, deadband type, deadband value, test number, val in sequence */
static int irec, ityp, idbnd, itest, iseq;
/* Records to test with */
static const char t_Record[NO_OF_RECORD_TYPES][10] = {
{"ai"}, {"ao"}, {"calc"}, {"calcout"}, {"dfanout"}, {"sel"}, {"sub"},
};
/* Deadband types to test */
static const char t_DbndType[2][6] = { {".MDEL"}, {".ADEL"} };
/* Different deadbands to test with */
static double t_Deadband[NO_OF_DEADBANDS] = { -1, 0, 1.5 };
/* Value sequences for each of the 16 tests */
static double t_SetValues[NO_OF_PATTERNS][NO_OF_VALUES_PER_SEQUENCE];
/* Expected updates (1=yes) for each sequence of each test of each deadband */
static int t_ExpectedUpdates[NO_OF_DEADBANDS][NO_OF_PATTERNS][NO_OF_VALUES_PER_SEQUENCE] = {
{ /* deadband = -1 */
{1, 1}, {1, 1}, {1, 1}, {1, 1},
{1, 1}, {1, 1}, {1, 1}, {1, 1},
{1, 1}, {1, 1}, {1, 1}, {1, 1},
{1, 1}, {1, 1}, {1, 1}, {1, 1},
},
{ /* deadband = 0 */
{1, 1}, {0, 1}, {0, 0}, {0, 0},
{1, 1}, {1, 0}, {1, 1}, {1, 1},
{1, 1}, {1, 1}, {1, 0}, {1, 1},
{1, 1}, {1, 1}, {1, 1}, {1, 0},
},
{ /* deadband = 1.5 */
{0, 1}, {0, 1}, {0, 0}, {0, 0},
{1, 1}, {1, 0}, {1, 1}, {1, 1},
{1, 1}, {1, 1}, {1, 0}, {1, 1},
{1, 1}, {1, 1}, {1, 1}, {1, 0},
},
};
static int t_ReceivedUpdates[NO_OF_PATTERNS][NO_OF_VALUES_PER_SEQUENCE];
/* Dummy subroutine needed for sub record */
static long myTestSub(void *p) {
return 0;
}
/* Minimal pre-chain plugin to divert all monitors back into the test (before they hit the queue) */
static db_field_log* filter(void* pvt, dbChannel *chan, db_field_log *pfl) {
double val = *((double*)chan->addr.pfield);
/* iseq == -1 is the value reset before the test pattern -> do not count */
if (iseq >= 0) {
t_ReceivedUpdates[itest][iseq] = 1;
testOk((val == t_SetValues[itest][iseq]) || (isnan(val) && isnan(t_SetValues[itest][iseq])),
"update %d pattern %2d with %s = %2.1f (expected %f, got %f)",
iseq, itest, (ityp==0?"MDEL":"ADEL"), t_Deadband[idbnd], t_SetValues[itest][iseq], val);
}
db_delete_field_log(pfl);
return NULL;
}
static void channelRegisterPre(dbChannel *chan, void *pvt,
chPostEventFunc **cb_out, void **arg_out, db_field_log *probe)
{
*cb_out = filter;
}
static chfPluginIf pif = {
NULL, /* allocPvt, */
NULL, /* freePvt, */
NULL, /* parse_error, */
NULL, /* parse_ok, */
NULL, /* channel_open, */
channelRegisterPre,
NULL, /* channelRegisterPost, */
NULL, /* channel_report, */
NULL /* channel_close */
};
MAIN(analogMonitorTest)
{
dbChannel *pch;
const chFilterPlugin *plug;
const char test[] = "test";
dbEventCtx evtctx;
dbEventSubscription subscr;
unsigned mask;
struct dbAddr vaddr, daddr;
double val;
char chan[50]; /* Channel name */
char cval[50]; /* Name for test values */
char cdel[50]; /* Name for deadband values */
/* Test patterns:
* 0: step less than deadband (of 1.5)
* 1: step larger than deadband (of 1.5)
* 2: no change
* 3: -0.0 -> +0.0
* ... all possible combinations of steps
* between: finite / NaN / -inf / +inf
*/
t_SetValues[ 0][0] = 1.0; t_SetValues[ 0][1] = 2.0;
t_SetValues[ 1][0] = 0.0; t_SetValues[ 1][1] = 2.0;
t_SetValues[ 2][0] = 0.0; t_SetValues[ 2][1] = 0.0;
t_SetValues[ 3][0] = -0.0; t_SetValues[ 3][1] = 0.0;
t_SetValues[ 4][0] = epicsNAN; t_SetValues[ 4][1] = 1.0;
t_SetValues[ 5][0] = epicsNAN; t_SetValues[ 5][1] = epicsNAN;
t_SetValues[ 6][0] = epicsNAN; t_SetValues[ 6][1] = epicsINF;
t_SetValues[ 7][0] = epicsNAN; t_SetValues[ 7][1] = -epicsINF;
t_SetValues[ 8][0] = epicsINF; t_SetValues[ 8][1] = 1.0;
t_SetValues[ 9][0] = epicsINF; t_SetValues[ 9][1] = epicsNAN;
t_SetValues[10][0] = epicsINF; t_SetValues[10][1] = epicsINF;
t_SetValues[11][0] = epicsINF; t_SetValues[11][1] = -epicsINF;
t_SetValues[12][0] = -epicsINF; t_SetValues[12][1] = 1.0;
t_SetValues[13][0] = -epicsINF; t_SetValues[13][1] = epicsNAN;
t_SetValues[14][0] = -epicsINF; t_SetValues[14][1] = epicsINF;
t_SetValues[15][0] = -epicsINF; t_SetValues[15][1] = -epicsINF;
registryFunctionAdd("myTestSub", (REGISTRYFUNCTION) myTestSub);
testPlan(1793);
if (dbReadDatabase(&pdbbase, "analogMonitorTest.dbd",
"." OSI_PATH_LIST_SEPARATOR ".." OSI_PATH_LIST_SEPARATOR
"../O.Common" OSI_PATH_LIST_SEPARATOR "O.Common", NULL))
testAbort("Error reading database description 'analogMonitorTest.dbd'");
analogMonitorTest_registerRecordDeviceDriver(pdbbase);
if (dbReadDatabase(&pdbbase, "analogMonitorTest.db",
"." OSI_PATH_LIST_SEPARATOR "..", NULL))
testAbort("Error reading test database 'analogMonitorTest.db'");
/* Start the core IOC (no CA) */
iocBuildIsolated();
evtctx = db_init_events();
chfPluginRegister(test, &pif, NULL);
plug = dbFindFilter(test, strlen(test));
testOk(!!plug, "interceptor plugin registered");
/* Loop over all analog record types (one instance each) */
for (irec = 0; irec < NO_OF_RECORD_TYPES; irec++) {
strcpy(cval, t_Record[irec]);
strcpy(chan, cval);
strcat(chan, ".VAL{\"test\":{}}");
if ((strcmp(t_Record[irec], "sel") == 0)
|| (strcmp(t_Record[irec], "calc") == 0)
|| (strcmp(t_Record[irec], "calcout") == 0)) {
strcat(cval, ".A");
} else {
strcat(cval, ".VAL");
}
testDiag("--------------------------------------------------------");
testDiag("Testing the %s record", t_Record[irec]);
testDiag("--------------------------------------------------------");
pch = dbChannelCreate(chan);
testOk(!!pch, "dbChannel with test plugin created");
testOk(!dbChannelOpen(pch), "dbChannel opened");
dbNameToAddr(cval, &vaddr);
/* Loop over both tested deadband types */
for (ityp = 0; ityp < 2; ityp++) {
strcpy(cdel, t_Record[irec]);
strcat(cdel, t_DbndType[ityp]);
dbNameToAddr(cdel, &daddr);
mask = (ityp==0?DBE_VALUE:DBE_ARCHIVE);
subscr = db_add_event(evtctx, pch, NULL, NULL, mask);
db_event_enable(subscr);
/* Loop over all tested deadband values */
for (idbnd = 0; idbnd < NO_OF_DEADBANDS; idbnd++) {
testDiag("Test %s%s = %g", t_Record[irec], t_DbndType[ityp], t_Deadband[idbnd]);
dbPutField(&daddr, DBR_DOUBLE, (void*) &t_Deadband[idbnd], 1);
memset(t_ReceivedUpdates, 0, sizeof(t_ReceivedUpdates));
/* Loop over all test patterns */
for (itest = 0; itest < NO_OF_PATTERNS; itest++) {
iseq = -1;
val = 0.0;
dbPutField(&vaddr, DBR_DOUBLE, (void*) &val, 1);
/* Loop over the test sequence */
for (iseq = 0; iseq < NO_OF_VALUES_PER_SEQUENCE; iseq++) {
dbPutField(&vaddr, DBR_DOUBLE, (void*) &t_SetValues[itest][iseq], 1);
}
/* Check expected vs. actual monitors */
testOk( (t_ExpectedUpdates[idbnd][itest][0] == t_ReceivedUpdates[itest][0]) &&
(t_ExpectedUpdates[idbnd][itest][1] == t_ReceivedUpdates[itest][1]),
"pattern %2d with %s = %2.1f (expected %d-%d, got %d-%d)",
itest, (ityp==0?"MDEL":"ADEL"), t_Deadband[idbnd],
t_ExpectedUpdates[idbnd][itest][0], t_ExpectedUpdates[idbnd][itest][1],
t_ReceivedUpdates[itest][0], t_ReceivedUpdates[itest][1]);
}
}
db_cancel_event(subscr);
}
}
iocShutdown();
return testDone();
}
-13
View File
@@ -1,13 +0,0 @@
record(ai, "ai") {}
record(ao, "ao") {}
record(calc, "calc") {
field(CALC, "A")
}
record(calcout, "calcout") {
field(CALC, "A")
}
record(dfanout, "dfanout") {}
record(sel, "sel") {}
record(sub, "sub") {
field(SNAM, "myTestSub")
}
-166
View File
@@ -1,166 +0,0 @@
/*************************************************************************\
* Copyright (c) 2014 Brookhaven Science Assoc. as operator of Brookhaven
* National Laboratory.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
#include <string.h>
#include "dbAccess.h"
#include "dbTest.h"
#include "dbUnitTest.h"
#include "errlog.h"
#include "waveformRecord.h"
#include "testMain.h"
void recTestIoc_registerRecordDeviceDriver(struct dbBase *);
static void testGetPutArray(void)
{
double data[4] = {11, 12, 13, 14};
DBADDR addr, save;
long nreq;
epicsInt32 *pbtr;
waveformRecord *prec;
testdbPrepare();
testdbReadDatabase("recTestIoc.dbd", NULL, NULL);
recTestIoc_registerRecordDeviceDriver(pdbbase);
testdbReadDatabase("arrayOpTest.db", NULL, NULL);
eltc(0);
testIocInitOk();
eltc(1);
testDiag("Test dbGet() and dbPut() from/to an array");
prec = (waveformRecord*)testdbRecordPtr("wfrec");
if(!prec || dbNameToAddr("wfrec", &addr))
testAbort("Failed to find record wfrec");
memcpy(&save, &addr, sizeof(save));
testDiag("Fetch initial value of %s", prec->name);
dbScanLock(addr.precord);
testOk(prec->nord==3, "prec->nord==3 (got %d)", prec->nord);
nreq = NELEMENTS(data);
if(dbGet(&addr, DBF_DOUBLE, &data, NULL, &nreq, NULL)) {
testFail("dbGet fails");
testSkip(1, "failed get");
} else {
testOk(nreq==3, "nreq==3 (got %ld)", nreq);
testOk1(data[0]==1.0 && data[1]==2.0 && data[2]==3.0);
}
dbScanUnlock(addr.precord);
testOk1(memcmp(&addr, &save, sizeof(save))==0);
addr=save;
testDiag("Write a new value");
data[0] = 4.0;
data[1] = 5.0;
data[2] = 6.0;
data[3] = 7.0;
dbScanLock(addr.precord);
testOk1(dbPut(&addr, DBF_DOUBLE, &data, NELEMENTS(data))==0);
pbtr = prec->bptr;
testOk(prec->nord==4, "prec->nord==4 (got %u)", prec->nord);
testOk1(pbtr[0]==4 && pbtr[1]==5 && pbtr[2]==6 && pbtr[3]==7);
dbScanUnlock(addr.precord);
testOk1(memcmp(&addr, &save, sizeof(save))==0);
addr=save;
memset(&data, 0, sizeof(data));
testDiag("Reread the value");
dbScanLock(addr.precord);
nreq = NELEMENTS(data);
if(dbGet(&addr, DBF_DOUBLE, &data, NULL, &nreq, NULL))
testFail("dbGet fails");
else {
testOk1(nreq==NELEMENTS(data));
testOk1(data[0]==4.0 && data[1]==5.0 && data[2]==6.0 && data[3]==7.0);
}
dbScanUnlock(addr.precord);
testOk1(memcmp(&addr, &save, sizeof(save))==0);
testDiag("Test dbGet() and dbPut() from/to an array of size 1");
prec = (waveformRecord*)testdbRecordPtr("wfrec1");
if(!prec || dbNameToAddr("wfrec1", &addr))
testAbort("Failed to find record wfrec1");
memcpy(&save, &addr, sizeof(save));
testDiag("Fetch initial value of %s", prec->name);
dbScanLock(addr.precord);
testOk(prec->nord==0, "prec->nord==0 (got %d)", prec->nord);
nreq = NELEMENTS(data);
if(dbGet(&addr, DBF_DOUBLE, &data, NULL, &nreq, NULL))
testFail("dbGet fails");
else {
testOk(nreq==0, "nreq==0 (got %ld)", nreq);
}
dbScanUnlock(addr.precord);
testOk1(memcmp(&addr, &save, sizeof(save))==0);
addr=save;
testDiag("Write a new value");
data[0] = 4.0;
data[1] = 5.0;
data[2] = 6.0;
data[3] = 7.0;
dbScanLock(addr.precord);
testOk1(dbPut(&addr, DBF_DOUBLE, &data, 1)==0);
pbtr = prec->bptr;
testOk(prec->nord==1, "prec->nord==1 (got %u)", prec->nord);
testOk1(pbtr[0]==4);
dbScanUnlock(addr.precord);
testOk1(memcmp(&addr, &save, sizeof(save))==0);
addr=save;
memset(&data, 0, sizeof(data));
testDiag("Reread the value");
dbScanLock(addr.precord);
nreq = NELEMENTS(data);
if(dbGet(&addr, DBF_DOUBLE, &data, NULL, &nreq, NULL))
testFail("dbGet fails");
else {
testOk1(nreq==1);
testOk1(data[0]==4.0);
}
dbScanUnlock(addr.precord);
testOk1(memcmp(&addr, &save, sizeof(save))==0);
testIocShutdownOk();
testdbCleanup();
}
MAIN(arrayOpTest)
{
testPlan(21);
testGetPutArray();
return testDone();
}
-9
View File
@@ -1,9 +0,0 @@
record(waveform, "wfrec") {
field(NELM, "10")
field(FTVL, "LONG")
field(INP, [1, 2, 3])
}
record(waveform, "wfrec1") {
field(NELM, "1")
field(FTVL, "LONG")
}
-48
View File
@@ -1,48 +0,0 @@
/*************************************************************************\
* Copyright (c) 2015 Brookhaven Science Assoc. as operator of Brookhaven
* National Laboratory.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/*
* Author: Michael Davidsaver <mdavidsaver@bnl.gov>
*
* Test the hooks that autosave uses during initialization
*/
#include "string.h"
#include "epicsString.h"
#include "dbUnitTest.h"
#include "epicsThread.h"
#include "iocInit.h"
#include "dbBase.h"
#include "link.h"
#include "recSup.h"
#include "dbAccess.h"
#include "dbConvert.h"
#include "dbStaticLib.h"
#include "registry.h"
#include "dbStaticLib.h"
#include "dbStaticPvt.h"
#include "osiFileName.h"
#include "initHooks.h"
#include "devSup.h"
#include "errlog.h"
#include "aoRecord.h"
#include "waveformRecord.h"
#include "testMain.h"
epicsShareFunc void testRestore(void);
#include "epicsExport.h"
MAIN(asTest)
{
testPlan(42);
testRestore();
return testDone();
}
-12
View File
@@ -1,12 +0,0 @@
record(ao, "rec0") {
field(DESC, "foobar")
field(DTYP, "asTest")
field(VAL, "1")
field(OUT, "rec0.DISV")
}
record(waveform, "rec1") {
field(DTYP, "asTest")
field(FTVL, "DOUBLE")
field(NELM, "5")
}
-2
View File
@@ -1,2 +0,0 @@
device(ao, CONSTANT, devAOasTest, "asTest")
device(waveform, CONSTANT, devWFasTest, "asTest")
-295
View File
@@ -1,295 +0,0 @@
/*************************************************************************\
* Copyright (c) 2015 Brookhaven Science Assoc. as operator of Brookhaven
* National Laboratory.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/*
* Author: Michael Davidsaver <mdavidsaver@bnl.gov>
*
* Test the hooks that autosave uses during initialization
*/
#include "string.h"
#include "epicsString.h"
#include "dbUnitTest.h"
#include "epicsThread.h"
#include "iocInit.h"
#include "dbBase.h"
#include "link.h"
#include "recSup.h"
#include "iocsh.h"
#include "dbAccess.h"
#include "dbConvert.h"
#include "dbStaticLib.h"
#include "registry.h"
#include "dbStaticLib.h"
#include "dbStaticPvt.h"
#include "osiFileName.h"
#include "initHooks.h"
#include "devSup.h"
#include "errlog.h"
#include "aoRecord.h"
#include "waveformRecord.h"
#include "epicsExport.h"
static unsigned iran;
static
int checkGetString(DBENTRY *pent, const char *expect)
{
dbCommon *prec = pent->precnode->precord;
const char *actual = dbGetString(pent);
int ret = strcmp(actual, expect);
testOk(ret==0, "dbGetString(\"%s.%s\") -> '%s' == '%s'", prec->name,
pent->pflddes->name, actual, expect);
return ret;
}
static void hookPass0(initHookState state)
{
DBENTRY entry;
if(state!=initHookAfterInitDevSup)
return;
testDiag("initHookAfterInitDevSup");
dbInitEntry(pdbbase, &entry);
testDiag("restore integer pass0");
/* rec0.VAL is initially 1, set it to 2 */
if(dbFindRecord(&entry, "rec0.VAL")==0) {
aoRecord *prec = entry.precnode->precord;
testOk(prec->val==1, "VAL %d==1 (initial value from .db)", (int)prec->val);
checkGetString(&entry, "1");
testOk1(dbPutString(&entry, "2")==0);
testOk(prec->val==2, "VAL %d==2", (int)prec->val);
checkGetString(&entry, "2");
} else {
testFail("Missing rec0");
testSkip(4, "missing record");
}
testDiag("restore string pass0");
if(dbFindRecord(&entry, "rec0.DESC")==0) {
aoRecord *prec = entry.precnode->precord;
testOk1(strcmp(prec->desc, "foobar")==0);
checkGetString(&entry, "foobar");
testOk1(dbPutString(&entry, "hello")==0);
testOk1(strcmp(prec->desc, "hello")==0);
checkGetString(&entry, "hello");
} else {
testFail("Missing rec0");
testSkip(4, "missing record");
}
if(dbFindRecord(&entry, "rec1.DESC")==0) {
aoRecord *prec = entry.precnode->precord;
testOk1(strcmp(prec->desc, "")==0);
checkGetString(&entry, "");
testOk1(dbPutString(&entry, "world")==0);
testOk1(strcmp(prec->desc, "world")==0);
checkGetString(&entry, "world");
} else {
testFail("Missing rec1");
testSkip(4, "missing record");
}
testDiag("restore link pass0");
/* rec0.OUT is initially "rec0.DISV", set it to "rec0.SEVR" */
if(dbFindRecord(&entry, "rec0.OUT")==0) {
aoRecord *prec = entry.precnode->precord;
if(prec->out.type==CONSTANT)
testOk(strcmp(prec->out.text,"rec0.DISV")==0,
"%s==rec0.DISV (initial value from .db)",
prec->out.text);
else
testFail("Wrong link type: %d", (int)prec->out.type);
/* note that dbGetString() reads an empty string before links are initialized
* should probably be considered a bug, but has been the case for so long
* we call it a 'feature'.
*/
checkGetString(&entry, "");
testOk1(dbPutString(&entry, "rec0.SEVR")==0);
} else{
testFail("Missing rec0");
testSkip(1, "missing record");
}
/* rec0.SDIS is initially NULL, set it to "rec0.STAT" */
if(dbFindRecord(&entry, "rec0.SDIS")==0) {
aoRecord *prec = entry.precnode->precord;
if(prec->sdis.type==CONSTANT)
testOk1(prec->sdis.value.constantStr==NULL);
else
testFail("Wrong link type: %d", (int)prec->sdis.type);
testOk1(dbPutString(&entry, "rec0.STAT")==0);
} else{
testFail("Missing rec0");
testSkip(1, "missing record");
}
/* can't restore array field in pass0 */
dbFinishEntry(&entry);
}
static long initRec0(aoRecord *prec)
{
DBLINK *plink = &prec->out;
testDiag("init_record(%s)", prec->name);
testOk(prec->val==2, "VAL %d==2 (pass0 value)", (int)prec->val);
prec->val = 3;
testOk(prec->val==3, "VAL %d==3", (int)prec->val);
testOk1(plink->type==DB_LINK);
if(plink->type==DB_LINK)
testOk(strcmp(plink->value.pv_link.pvname,"rec0.SEVR")==0,
"%s==rec0.SEVR (pass0 value)", plink->value.pv_link.pvname);
else
testFail("Wrong link type");
plink = &prec->sdis;
testOk1(plink->type==DB_LINK);
if(plink->type==DB_LINK)
testOk(strcmp(plink->value.pv_link.pvname,"rec0.STAT")==0,
"%s==rec0.STAT (pass0 value)", plink->value.pv_link.pvname);
else
testFail("Wrong link type");
iran |= 1;
return 2; /* we set .VAL, so don't use RVAL */
}
static long initRec1(waveformRecord *prec)
{
testDiag("init_record(%s)", prec->name);
testOk(prec->nord==0, "NORD %d==0", (int)prec->nord);
iran |= 2;
return 0;
}
static double values[] = {1,2,3,4,5};
static void hookPass1(initHookState state)
{
DBENTRY entry;
DBADDR addr;
if(state!=initHookAfterInitDatabase)
return;
testDiag("initHookAfterInitDatabase");
dbInitEntry(pdbbase, &entry);
if(dbFindRecord(&entry, "rec0.VAL")==0) {
aoRecord *prec = entry.precnode->precord;
testOk(prec->val==3, "VAL %d==3 (init_record value)", (int)prec->val);
testOk1(dbPutString(&entry, "4")==0);
testOk(prec->val==4, "VAL %d==4", (int)prec->val);
} else{
testFail("Missing rec0");
testSkip(1, "missing record");
}
/* Can't restore links in pass 1 */
if(dbNameToAddr("rec1.VAL", &addr)) {
testFail("missing rec1");
testSkip(3, "missing record");
} else {
rset *prset = dbGetRset(&addr);
dbfType ftype = addr.field_type;
long count=-1, offset=-1, maxcount = addr.no_elements;
testOk1(prset && prset->get_array_info && prset->put_array_info);
testOk1((*prset->get_array_info)(&addr, &count, &offset)==0);
/* count is ignored */
testOk1((*dbPutConvertRoutine[DBF_DOUBLE][ftype])(&addr, values, NELEMENTS(values), maxcount,offset)==0);
testOk1((*prset->put_array_info)(&addr, NELEMENTS(values))==0);
}
dbFinishEntry(&entry);
}
#if defined(__rtems__) || defined(vxWorks)
void asTestIoc_registerRecordDeviceDriver(struct dbBase *);
#endif
epicsShareFunc
void testRestore(void)
{
aoRecord *rec0;
waveformRecord *rec1;
testDiag("test Restore");
initHookRegister(hookPass0);
initHookRegister(hookPass1);
testdbPrepare();
testdbReadDatabase("asTestIoc.dbd", NULL, NULL);
/* since this test has device support it must appear in a
* DLL for windows dynamic builds.
* However, the rRDD function is in the executable,
* and not accessible here. So use iocsh.
* For rtems/vxworks the test harness clears
* iocsh registrations, so iocsh can't work here.
*/
#if defined(__rtems__) || defined(vxWorks)
asTestIoc_registerRecordDeviceDriver(pdbbase);
#else
iocshCmd("asTestIoc_registerRecordDeviceDriver(pdbbase)");
#endif
testdbReadDatabase("asTest.db", NULL, NULL);
rec0 = (aoRecord*)testdbRecordPtr("rec0");
rec1 = (waveformRecord*)testdbRecordPtr("rec1");
eltc(0);
testIocInitOk();
eltc(1);
testDiag("Post initialization");
testOk1(iran==3);
testOk1(rec0->val==4);
testOk1(rec1->nord==5);
{
double *buf = rec1->bptr;
testOk(buf[0]==1, "buf[0] %f==1", buf[0]);
testOk1(buf[1]==2);
testOk1(buf[2]==3);
testOk1(buf[3]==4);
testOk1(buf[4]==5);
}
testIocShutdownOk();
/* recSup doesn't cleanup after itself */
free(rec1->bptr);
testdbCleanup();
}
struct dset6 {
dset common;
DEVSUPFUN proc;
DEVSUPFUN linconv;
};
static long noop() {return 0;}
static struct dset6 devAOasTest = { {6, NULL, NULL, (DEVSUPFUN)initRec0, NULL}, (DEVSUPFUN)noop, NULL};
static struct dset6 devWFasTest = { {6, NULL, NULL, (DEVSUPFUN)initRec1, NULL}, (DEVSUPFUN)noop, NULL};
epicsExportAddress(dset, devAOasTest);
epicsExportAddress(dset, devWFasTest);
-189
View File
@@ -1,189 +0,0 @@
/*************************************************************************\
* Copyright (c) 2017 UChicago Argonne LLC, as operator of Argonne
* National Laboratory.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
#include <string.h>
#include "dbAccess.h"
#include "dbStaticLib.h"
#include "dbTest.h"
#include "dbUnitTest.h"
#include "epicsEvent.h"
#include "errlog.h"
#include "registryFunction.h"
#include "subRecord.h"
#include "testMain.h"
static int startCounter, doneCounter;
static epicsEventId asyncEvent, doneEvent;
static
long asyncSubr(subRecord *prec)
{
testDiag("Processing %s, pact=%d", prec->name, prec->pact);
if (!prec->pact) {
epicsEventTrigger(asyncEvent);
prec->pact = 1; /* Make asynchronous */
}
return 0;
}
static
long doneSubr(subRecord *prec)
{
epicsEventTrigger(doneEvent);
return 0;
}
static
void checkAsyncInput(const char *rec, int init, dbCommon *async)
{
char inp[16], proc[16];
testDiag("Checking record '%s'", rec);
strcpy(inp, rec);
strcat(inp, ".INP");
strcpy(proc, rec);
strcat(proc, ".PROC");
if (init) {
testdbGetFieldEqual(rec, DBF_LONG, init);
testdbPutFieldOk(inp, DBF_STRING, "async");
}
testdbPutFieldOk(proc, DBF_CHAR, 1);
epicsEventWait(asyncEvent);
testdbGetFieldEqual("startCounter", DBF_LONG, ++startCounter);
testdbGetFieldEqual("doneCounter", DBF_LONG, doneCounter);
dbScanLock(async);
async->rset->process(async);
dbScanUnlock(async);
epicsEventWait(doneEvent);
testdbGetFieldEqual("startCounter", DBF_LONG, startCounter);
testdbGetFieldEqual("doneCounter", DBF_LONG, ++doneCounter);
}
static
void testAsynInputs(dbCommon *async)
{
const char * records[] = {
"ai0", "bi0", "di0", "ii0", "li0", "mi0", "si0", NULL,
"bi1", /* bi1 must be first in this group */
"ai1", "di1", "ii1", "li1", "mi1", "si1", NULL,
};
const char ** rec = &records[0];
int init = 1; /* bi1 initializes to 1 */
testDiag("============ Starting %s ============", EPICS_FUNCTION);
startCounter = doneCounter = 0;
testdbPutFieldOk("startCounter", DBF_LONG, startCounter);
testdbPutFieldOk("doneCounter", DBF_LONG, doneCounter);
epicsEventTryWait(asyncEvent);
epicsEventTryWait(doneEvent);
while (*rec) { /* 1st group don't need initializing */
checkAsyncInput(*rec++, 0, async);
}
rec++;
while (*rec) {
checkAsyncInput(*rec++, init, async);
init = 9; /* remainder initialize to 9 */
}
testDiag("============= Ending %s =============", EPICS_FUNCTION);
}
static
void checkAsyncOutput(const char *rec, dbCommon *async)
{
char proc[16];
testDiag("Checking record '%s'", rec);
strcpy(proc, rec);
strcat(proc, ".PROC");
testdbPutFieldOk(proc, DBF_CHAR, 1);
epicsEventWait(asyncEvent);
testdbGetFieldEqual("startCounter", DBF_LONG, ++startCounter);
testdbGetFieldEqual("doneCounter", DBF_LONG, doneCounter);
dbScanLock(async);
async->rset->process(async);
dbScanUnlock(async);
epicsEventWait(doneEvent);
testdbGetFieldEqual("startCounter", DBF_LONG, startCounter);
testdbGetFieldEqual("doneCounter", DBF_LONG, ++doneCounter);
}
static
void testAsyncOutputs(dbCommon *async)
{
const char * records[] = {
"ao1", "bo1", "do1", "io1", "lo1", "lso1", "mo1", "so1", NULL,
};
const char ** rec = &records[0];
testDiag("============ Starting %s ============", EPICS_FUNCTION);
startCounter = doneCounter = 0;
testdbPutFieldOk("startCounter", DBF_LONG, startCounter);
testdbPutFieldOk("doneCounter", DBF_LONG, doneCounter);
epicsEventTryWait(asyncEvent);
epicsEventTryWait(doneEvent);
while (*rec) {
checkAsyncOutput(*rec++, async);
}
testDiag("============= Ending %s =============", EPICS_FUNCTION);
}
void recTestIoc_registerRecordDeviceDriver(struct dbBase *);
MAIN(asyncSoftTest)
{
dbCommon *async;
testPlan(128);
testdbPrepare();
testdbReadDatabase("recTestIoc.dbd", NULL, NULL);
recTestIoc_registerRecordDeviceDriver(pdbbase);
registryFunctionAdd("asyncSubr", (REGISTRYFUNCTION) asyncSubr);
registryFunctionAdd("doneSubr", (REGISTRYFUNCTION) doneSubr);
testdbReadDatabase("asyncSoftTest.db", NULL, NULL);
eltc(0);
testIocInitOk();
eltc(1);
async = testdbRecordPtr("async");
asyncEvent = epicsEventCreate(epicsEventEmpty);
doneEvent = epicsEventCreate(epicsEventEmpty);
testAsynInputs(async);
testAsyncOutputs(async);
testIocShutdownOk();
testdbCleanup();
return testDone();
}
-188
View File
@@ -1,188 +0,0 @@
record(ai, "ai0") {
field(DTYP, "Async Soft Channel")
field(INP, "async")
field(FLNK, "done")
}
record(bi, "bi0") {
field(DTYP, "Async Soft Channel")
field(INP, "async")
field(FLNK, "done")
field(ZNAM, "Zero")
field(ONAM, "One")
}
record(int64in, "ii0") {
field(DTYP, "Async Soft Channel")
field(INP, "async")
field(FLNK, "done")
}
record(longin, "li0") {
field(DTYP, "Async Soft Channel")
field(INP, "async")
field(FLNK, "done")
}
record(mbbiDirect, "di0") {
field(DTYP, "Async Soft Channel")
field(NOBT, 4)
field(INP, "async")
field(FLNK, "done")
}
record(mbbi, "mi0") {
field(DTYP, "Async Soft Channel")
field(NOBT, 4)
field(INP, "async")
field(FLNK, "done")
field(ZRST, "Zero")
field(ONST, "One")
field(TWST, "Two")
field(THST, "Three")
field(FRST, "Four")
field(FVST, "Five")
field(SXST, "Six")
field(SVST, "Seven")
field(EIST, "Eight")
field(NIST, "Nine")
field(TEST, "Ten")
field(ELST, "Eleven")
field(TWST, "Twelve")
field(TTST, "Thirteen")
field(FTST, "Fourteen")
field(FFST, "Fifteen")
}
record(stringin, "si0") {
field(DTYP, "Async Soft Channel")
field(INP, "async")
field(FLNK, "done")
}
record(ai, "ai1") {
field(DTYP, "Async Soft Channel")
field(INP, {const:9})
field(FLNK, "done")
}
record(bi, "bi1") {
field(DTYP, "Async Soft Channel")
field(INP, {const:1})
field(FLNK, "done")
field(ZNAM, "Zero")
field(ONAM, "One")
}
record(int64in, "ii1") {
field(DTYP, "Async Soft Channel")
field(INP, {const:9})
field(FLNK, "done")
}
record(longin, "li1") {
field(DTYP, "Async Soft Channel")
field(INP, {const:9})
field(FLNK, "done")
}
record(mbbiDirect, "di1") {
field(DTYP, "Async Soft Channel")
field(NOBT, 4)
field(INP, {const:9})
field(FLNK, "done")
}
record(mbbi, "mi1") {
field(DTYP, "Async Soft Channel")
field(NOBT, 4)
field(INP, {const:9})
field(FLNK, "done")
field(ZRST, "Zero")
field(ONST, "One")
field(TWST, "Two")
field(THST, "Three")
field(FRST, "Four")
field(FVST, "Five")
field(SXST, "Six")
field(SVST, "Seven")
field(EIST, "Eight")
field(NIST, "Nine")
field(TEST, "Ten")
field(ELST, "Eleven")
field(TWST, "Twelve")
field(TTST, "Thirteen")
field(FTST, "Fourteen")
field(FFST, "Fifteen")
}
record(stringin, "si1") {
field(DTYP, "Async Soft Channel")
field(INP, {const:"9"})
field(FLNK, "done")
}
record(sub, "async") {
field(INPA, "startCounter PP")
field(SNAM, "asyncSubr")
}
record(calc, "startCounter") {
field(CALC, "VAL+1")
}
record(sub, "done") {
field(INPA, "doneCounter PP")
field(SNAM, "doneSubr")
}
record(calc, "doneCounter") {
field(CALC, "VAL+1")
}
record(ao, "ao1") {
field(DTYP, "Async Soft Channel")
field(OUT, "async.PROC CA")
field(FLNK, "done")
}
record(bo, "bo1") {
field(DTYP, "Async Soft Channel")
field(OUT, "async.PROC CA")
field(FLNK, "done")
field(ZNAM, "Zero")
field(ONAM, "One")
}
record(int64out, "io1") {
field(DTYP, "Async Soft Channel")
field(OUT, "async.PROC CA")
field(FLNK, "done")
}
record(longout, "lo1") {
field(DTYP, "Async Soft Channel")
field(OUT, "async.PROC CA")
field(FLNK, "done")
}
record(mbboDirect, "do1") {
field(DTYP, "Async Soft Channel")
field(NOBT, 4)
field(OUT, "async.PROC CA")
field(FLNK, "done")
}
record(mbbo, "mo1") {
field(DTYP, "Async Soft Channel")
field(NOBT, 4)
field(OUT, "async.PROC CA")
field(FLNK, "done")
field(ZRST, "Zero")
field(ONST, "One")
field(TWST, "Two")
field(THST, "Three")
field(FRST, "Four")
field(FVST, "Five")
field(SXST, "Six")
field(SVST, "Seven")
field(EIST, "Eight")
field(NIST, "Nine")
field(TEST, "Ten")
field(ELST, "Eleven")
field(TWST, "Twelve")
field(TTST, "Thirteen")
field(FTST, "Fourteen")
field(FFST, "Fifteen")
}
record(lso, "lso1") {
field(DTYP, "Async Soft Channel")
field(OUT, "async.PROC CA")
field(FLNK, "done")
field(SIZV, 40)
}
record(stringout, "so1") {
field(DTYP, "Async Soft Channel")
field(OUT, "async.PROC CA")
field(FLNK, "done")
}
-354
View File
@@ -1,354 +0,0 @@
/*************************************************************************\
* Copyright (c) 2016 Michael Davidsaver
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
#include "dbUnitTest.h"
#include "testMain.h"
#include "dbLock.h"
#include "errlog.h"
#include "dbAccess.h"
#include "epicsMath.h"
#include "aiRecord.h"
#include "compressRecord.h"
#define testDEq(A,B,D) testOk(fabs((A)-(B))<(D), #A " (%f) ~= " #B " (%f)", A, B)
void recTestIoc_registerRecordDeviceDriver(struct dbBase *);
static
void checkArrD(const char *pv, long elen, double a, double b, double c, double d)
{
double buf[4];
double expect[4];
long nReq = NELEMENTS(buf), i;
unsigned match;
DBADDR addr;
expect[0] = a;
expect[1] = b;
expect[2] = c;
expect[3] = d;
if (dbNameToAddr(pv, &addr))
testAbort("Unknown PV '%s'", pv);
if (dbGet(&addr, DBR_DOUBLE, buf, NULL, &nReq, NULL))
testAbort("Failed to get '%s'", pv);
match = elen==nReq;
for (i=0; i<nReq && i<elen; i++) {
match &= fabs(buf[i]-expect[i])<0.01;
}
testOk(match, "dbGet(\"%s\") matches", pv);
if (elen!=nReq)
testDiag("lengths don't match %ld != %ld", elen, nReq);
for (i=0; i<nReq && i<elen; i++) {
if (fabs(buf[i]-expect[i])>=0.01)
testDiag("[%ld] -> %f != %f", i, expect[i], buf[i]);
}
}
static
void checkArrI(const char *pv, long elen, epicsInt32 a, epicsInt32 b, epicsInt32 c, epicsInt32 d)
{
epicsInt32 buf[4];
epicsInt32 expect[4];
long nReq = NELEMENTS(buf), i;
unsigned match;
DBADDR addr;
expect[0] = a;
expect[1] = b;
expect[2] = c;
expect[3] = d;
if (dbNameToAddr(pv, &addr))
testAbort("Unknown PV '%s'", pv);
if (dbGet(&addr, DBR_LONG, buf, NULL, &nReq, NULL))
testAbort("Failed to get '%s'", pv);
match = elen==nReq;
for (i=0; i<nReq && i<elen; i++) {
match &= buf[i]==expect[i];
}
testOk(match, "dbGet(\"%s\") matches", pv);
if (elen!=nReq)
testDiag("lengths don't match %ld != %ld", elen, nReq);
for (i=0; i<nReq && i<elen; i++) {
if(buf[i]!=expect[i])
testDiag("[%ld] -> %d != %d", i, (int)expect[i], (int)buf[i]);
}
}
static
void testFIFOCirc(void)
{
aiRecord *vrec;
compressRecord *crec;
double *cbuf;
testDiag("Test FIFO");
testdbPrepare();
testdbReadDatabase("recTestIoc.dbd", NULL, NULL);
recTestIoc_registerRecordDeviceDriver(pdbbase);
testdbReadDatabase("compressTest.db", NULL, "ALG=Circular Buffer,BALG=FIFO Buffer,NSAM=4");
vrec = (aiRecord*)testdbRecordPtr("val");
crec = (compressRecord*)testdbRecordPtr("comp");
eltc(0);
testIocInitOk();
eltc(1);
dbScanLock((dbCommon*)crec);
cbuf = crec->bptr;
testOk1(crec->off==0);
testOk1(crec->inx==0);
testOk1(crec->nuse==0);
testDiag("Push 1.1");
vrec->val = 1.1;
dbProcess((dbCommon*)crec);
/* In FIFO mode the valid elements are
* cbuf[(off-nuse-1) % size] through cbuf[(off-1) % size]
*/
testOk1(crec->off==1);
testOk1(crec->inx==0);
testOk1(crec->nuse==1);
testDEq(cbuf[0], 1.1, 0.1);
testDEq(cbuf[1], 0.0, 0.1);
testDEq(cbuf[2], 0.0, 0.1);
testDEq(cbuf[3], 0.0, 0.1);
checkArrD("comp", 1, 1.1, 0, 0, 0);
testDiag("Push 2.1");
vrec->val = 2.1;
dbProcess((dbCommon*)crec);
testOk1(crec->off==2);
testOk1(crec->inx==0);
testOk1(crec->nuse==2);
testDEq(cbuf[0], 1.1, 0.1);
testDEq(cbuf[1], 2.1, 0.1);
testDEq(cbuf[2], 0.0, 0.1);
testDEq(cbuf[3], 0.0, 0.1);
checkArrD("comp", 2, 1.1, 2.1, 0, 0);
testDiag("Push 3.1");
vrec->val = 3.1;
dbProcess((dbCommon*)crec);
testOk1(crec->off==3);
testOk1(crec->inx==0);
testOk1(crec->nuse==3);
testDEq(cbuf[0], 1.1, 0.1);
testDEq(cbuf[1], 2.1, 0.1);
testDEq(cbuf[2], 3.1, 0.1);
testDEq(cbuf[3], 0.0, 0.1);
checkArrD("comp", 3, 1.1, 2.1, 3.1, 0);
testDiag("Push 4.1");
vrec->val = 4.1;
dbProcess((dbCommon*)crec);
testOk1(crec->off==0);
testOk1(crec->inx==0);
testOk1(crec->nuse==4);
testDEq(cbuf[0], 1.1, 0.1);
testDEq(cbuf[1], 2.1, 0.1);
testDEq(cbuf[2], 3.1, 0.1);
testDEq(cbuf[3], 4.1, 0.1);
checkArrD("comp", 4, 1.1, 2.1, 3.1, 4.1);
testDiag("Push 5.1");
vrec->val = 5.1;
dbProcess((dbCommon*)crec);
testOk1(crec->off==1);
testOk1(crec->inx==0);
testOk1(crec->nuse==4);
testDEq(cbuf[0], 5.1, 0.1);
testDEq(cbuf[1], 2.1, 0.1);
testDEq(cbuf[2], 3.1, 0.1);
testDEq(cbuf[3], 4.1, 0.1);
checkArrD("comp", 4, 2.1, 3.1, 4.1, 5.1);
testDiag("Push 6.1");
vrec->val = 6.1;
dbProcess((dbCommon*)crec);
testOk1(crec->off==2);
testOk1(crec->inx==0);
testOk1(crec->nuse==4);
testDEq(cbuf[0], 5.1, 0.1);
testDEq(cbuf[1], 6.1, 0.1);
testDEq(cbuf[2], 3.1, 0.1);
testDEq(cbuf[3], 4.1, 0.1);
checkArrD("comp", 4, 3.1, 4.1, 5.1, 6.1);
dbScanUnlock((dbCommon*)crec);
testDiag("Reset");
testdbPutFieldOk("comp.RES", DBF_LONG, 0);
dbScanLock((dbCommon*)crec);
testOk1(crec->off==0);
testOk1(crec->inx==0);
testOk1(crec->nuse==0);
checkArrD("comp", 0, 0, 0, 0, 0);
dbScanUnlock((dbCommon*)crec);
testIocShutdownOk();
testdbCleanup();
}
static
void testLIFOCirc(void)
{
aiRecord *vrec;
compressRecord *crec;
double *cbuf;
testDiag("Test LIFO");
testdbPrepare();
testdbReadDatabase("recTestIoc.dbd", NULL, NULL);
recTestIoc_registerRecordDeviceDriver(pdbbase);
testdbReadDatabase("compressTest.db", NULL,
"ALG=Circular Buffer,BALG=LIFO Buffer,NSAM=4");
vrec = (aiRecord*)testdbRecordPtr("val");
crec = (compressRecord*)testdbRecordPtr("comp");
eltc(0);
testIocInitOk();
eltc(1);
dbScanLock((dbCommon*)crec);
cbuf = crec->bptr;
testOk1(crec->off==0);
testOk1(crec->inx==0);
testOk1(crec->nuse==0);
testDiag("Push 1.1");
vrec->val = 1.1;
dbProcess((dbCommon*)crec);
testDiag("off %u", crec->off);
testOk1(crec->off==3);
testOk1(crec->inx==0);
testOk1(crec->nuse==1);
testDEq(cbuf[0], 0.0, 0.1);
testDEq(cbuf[1], 0.0, 0.1);
testDEq(cbuf[2], 0.0, 0.1);
testDEq(cbuf[3], 1.1, 0.1);
checkArrD("comp", 1, 1.1, 0, 0, 0);
testDiag("Push 2.1");
vrec->val = 2.1;
dbProcess((dbCommon*)crec);
testOk1(crec->off==2);
testOk1(crec->inx==0);
testOk1(crec->nuse==2);
testDEq(cbuf[0], 0.0, 0.1);
testDEq(cbuf[1], 0.0, 0.1);
testDEq(cbuf[2], 2.1, 0.1);
testDEq(cbuf[3], 1.1, 0.1);
checkArrD("comp", 2, 2.1, 1.1, 0, 0);
checkArrI("comp", 2, 2, 1, 0, 0);
testDiag("Push 3.1");
vrec->val = 3.1;
dbProcess((dbCommon*)crec);
testOk1(crec->off==1);
testOk1(crec->inx==0);
testOk1(crec->nuse==3);
testDEq(cbuf[0], 0.0, 0.1);
testDEq(cbuf[1], 3.1, 0.1);
testDEq(cbuf[2], 2.1, 0.1);
testDEq(cbuf[3], 1.1, 0.1);
checkArrD("comp", 3, 3.1, 2.1, 1.1, 0);
checkArrI("comp", 3, 3, 2, 1, 0);
testDiag("Push 4.1");
vrec->val = 4.1;
dbProcess((dbCommon*)crec);
testOk1(crec->off==0);
testOk1(crec->inx==0);
testOk1(crec->nuse==4);
testDEq(cbuf[0], 4.1, 0.1);
testDEq(cbuf[1], 3.1, 0.1);
testDEq(cbuf[2], 2.1, 0.1);
testDEq(cbuf[3], 1.1, 0.1);
checkArrD("comp", 4, 4.1, 3.1, 2.1, 1.1);
checkArrI("comp", 4, 4, 3, 2, 1);
testDiag("Push 5.1");
vrec->val = 5.1;
dbProcess((dbCommon*)crec);
testOk1(crec->off==3);
testOk1(crec->inx==0);
testOk1(crec->nuse==4);
testDEq(cbuf[0], 4.1, 0.1);
testDEq(cbuf[1], 3.1, 0.1);
testDEq(cbuf[2], 2.1, 0.1);
testDEq(cbuf[3], 5.1, 0.1);
checkArrD("comp", 4, 5.1, 4.1, 3.1, 2.1);
checkArrI("comp", 4, 5, 4, 3, 2);
testDiag("Push 6.1");
vrec->val = 6.1;
dbProcess((dbCommon*)crec);
testOk1(crec->off==2);
testOk1(crec->inx==0);
testOk1(crec->nuse==4);
testDEq(cbuf[0], 4.1, 0.1);
testDEq(cbuf[1], 3.1, 0.1);
testDEq(cbuf[2], 6.1, 0.1);
testDEq(cbuf[3], 5.1, 0.1);
checkArrD("comp", 4, 6.1, 5.1, 4.1, 3.1);
dbScanUnlock((dbCommon*)crec);
testDiag("Reset");
testdbPutFieldOk("comp.RES", DBF_LONG, 0);
dbScanLock((dbCommon*)crec);
testOk1(crec->off==0);
testOk1(crec->inx==0);
testOk1(crec->nuse==0);
checkArrD("comp", 0, 0, 0, 0, 0);
dbScanUnlock((dbCommon*)crec);
testIocShutdownOk();
testdbCleanup();
}
MAIN(compressTest)
{
testPlan(116);
testFIFOCirc();
testLIFOCirc();
return testDone();
}
-7
View File
@@ -1,7 +0,0 @@
record(ai, "val") {}
record(compress, "comp") {
field(INP, "val NPP")
field(ALG, "$(ALG)")
field(BALG,"$(BALG)")
field(NSAM,"$(NSAM)")
}
-45
View File
@@ -1,45 +0,0 @@
/*************************************************************************\
* Copyright (c) 2012 UChicago Argonne LLC, as Operator of Argonne
* National Laboratory.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/*
* Run tests as a batch.
*/
#include "epicsUnitTest.h"
#include "epicsExit.h"
int analogMonitorTest(void);
int compressTest(void);
int recMiscTest(void);
int arrayOpTest(void);
int asTest(void);
int linkRetargetLinkTest(void);
int linkInitTest(void);
int asyncSoftTest(void);
void epicsRunRecordTests(void)
{
testHarness();
runTest(analogMonitorTest);
runTest(compressTest);
runTest(recMiscTest);
runTest(arrayOpTest);
runTest(asTest);
runTest(linkRetargetLinkTest);
runTest(linkInitTest);
runTest(asyncSoftTest);
epicsExit(0); /* Trigger test harness */
}
-225
View File
@@ -1,225 +0,0 @@
/*************************************************************************\
* Copyright (c) 2015 Michael Davidsaver
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
#include <string.h>
#include "dbAccess.h"
#include "alarm.h"
#include "dbUnitTest.h"
#include "errlog.h"
#include "epicsThread.h"
#include "testMain.h"
void recTestIoc_registerRecordDeviceDriver(struct dbBase *);
static void startTestIoc(const char *dbfile)
{
testdbPrepare();
testdbReadDatabase("recTestIoc.dbd", NULL, NULL);
recTestIoc_registerRecordDeviceDriver(pdbbase);
testdbReadDatabase(dbfile, NULL, NULL);
eltc(0);
testIocInitOk();
eltc(1);
}
static void testLongStringInit()
{
testDiag("testLongStringInit");
startTestIoc("linkInitTest.db");
{
const char buf[] = "!----------------------------------------------!";
testdbGetArrFieldEqual("longstr1.VAL$", DBF_CHAR, NELEMENTS(buf)+2, NELEMENTS(buf), buf);
testdbGetFieldEqual("longstr1.VAL", DBR_STRING, "!--------------------------------------");
}
{
const char buf[] = "!----------------------------------------------!";
testdbGetArrFieldEqual("longstr2.VAL$", DBF_CHAR, NELEMENTS(buf)+2, NELEMENTS(buf), buf);
testdbGetFieldEqual("longstr2.VAL", DBR_STRING, "!--------------------------------------");
}
{
const char buf[] = "!----------------------------------------------!";
testdbGetArrFieldEqual("longstr3.VAL$", DBF_CHAR, NELEMENTS(buf)+2, NELEMENTS(buf), buf);
testdbGetFieldEqual("longstr3.VAL", DBR_STRING, "!--------------------------------------");
}
testdbGetFieldEqual("longstr4.VAL", DBR_STRING, "One");
testIocShutdownOk();
testdbCleanup();
}
static void testCalcInit()
{
testDiag("testCalcInit");
startTestIoc("linkInitTest.db");
testdbGetFieldEqual("emptylink.VAL", DBR_DOUBLE, 0.0);
testdbGetFieldEqual("emptylink.SEVR", DBR_LONG, INVALID_ALARM);
testdbPutFieldOk("emptylink.PROC", DBF_LONG, 1);
testdbGetFieldEqual("emptylink.VAL", DBR_DOUBLE, 0.0);
testdbGetFieldEqual("emptylink.SEVR", DBR_LONG, 0);
testdbGetFieldEqual("emptylink1.VAL", DBR_DOUBLE, 0.0);
testdbGetFieldEqual("emptylink1.SEVR", DBR_LONG, INVALID_ALARM);
testdbPutFieldOk("emptylink1.PROC", DBF_LONG, 1);
testdbGetFieldEqual("emptylink1.VAL", DBR_DOUBLE, 1.0);
testdbGetFieldEqual("emptylink1.SEVR", DBR_LONG, 0);
testIocShutdownOk();
testdbCleanup();
}
static void testPrintfStrings()
{
testDiag("testPrintfStrings");
startTestIoc("linkInitTest.db");
{
const char buf1[] = "Test string, exactly 40 characters long";
const char buf2[] = "Longer test string, more that 40 characters long";
const char buf2t[] = "Longer test string, more that 40 charac";
/* The FMT field is pp(TRUE), so this put triggers processing */
testdbPutFieldOk("printf1.FMT", DBF_STRING, "%s");
testdbGetArrFieldEqual("printf1.VAL$", DBF_CHAR, NELEMENTS(buf1)+2,
NELEMENTS(buf1), buf1);
testdbGetFieldEqual("printf1.VAL", DBR_STRING, buf1);
testdbPutFieldOk("printf1.FMT", DBF_STRING, "%ls");
testdbGetArrFieldEqual("printf1.VAL$", DBF_CHAR, NELEMENTS(buf1)+2,
NELEMENTS(buf1), buf1);
testdbGetFieldEqual("printf1.VAL", DBR_STRING, buf1);
testdbPutFieldOk("printf2.FMT", DBF_STRING, "%s");
testdbGetArrFieldEqual("printf2.VAL$", DBF_CHAR, NELEMENTS(buf2)+2,
NELEMENTS(buf2t), buf2t);
testdbGetFieldEqual("printf2.VAL", DBR_STRING, buf2t);
testdbPutFieldOk("printf2.FMT", DBF_STRING, "%ls");
testdbGetArrFieldEqual("printf2.VAL$", DBF_CHAR, NELEMENTS(buf2)+2,
NELEMENTS(buf2), buf2);
testdbGetFieldEqual("printf2.VAL", DBR_STRING, buf2t);
testdbPutFieldOk("printf2.FMT", DBF_STRING, "%.39ls");
testdbGetArrFieldEqual("printf2.VAL$", DBF_CHAR, NELEMENTS(buf2)+2,
NELEMENTS(buf2t), buf2t);
}
testIocShutdownOk();
testdbCleanup();
}
static void testArrayInputs()
{
epicsInt32 oneToTwelve[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
testDiag("testArrayInputs");
startTestIoc("linkInitTest.db");
testdbGetFieldEqual("aai1.NORD", DBR_LONG, 10);
testdbGetFieldEqual("aai1.UDF", DBR_UCHAR, 0);
testdbGetFieldEqual("aai2.NORD", DBR_LONG, 10);
testdbGetFieldEqual("aai2.UDF", DBR_UCHAR, 0);
testdbGetFieldEqual("sa1.NORD", DBR_LONG, 10);
testdbGetFieldEqual("sa1.UDF", DBR_UCHAR, 0);
testdbGetFieldEqual("sa2.NORD", DBR_LONG, 0);
testdbGetFieldEqual("sa2.UDF", DBR_UCHAR, 1);
testdbGetFieldEqual("wf1.NORD", DBR_LONG, 10);
testdbGetFieldEqual("wf1.UDF", DBR_UCHAR, 0);
testdbGetFieldEqual("wf2.NORD", DBR_LONG, 10);
testdbGetFieldEqual("wf2.UDF", DBR_UCHAR, 0);
testdbGetArrFieldEqual("aai1.VAL", DBF_LONG, 12, 10, &oneToTwelve[0]);
testdbGetArrFieldEqual("aai2.VAL", DBF_LONG, 12, 10, &oneToTwelve[0]);
testdbGetArrFieldEqual("sa1.VAL", DBF_LONG, 12, 10, &oneToTwelve[2]);
testdbGetArrFieldEqual("sa2.VAL", DBF_LONG, 10, 0, NULL);
testdbGetArrFieldEqual("wf1.VAL", DBF_LONG, 12, 10, &oneToTwelve[0]);
testdbGetArrFieldEqual("wf2.VAL", DBF_LONG, 12, 10, &oneToTwelve[0]);
testdbPutFieldOk("sa1.INDX", DBF_LONG, 3);
testdbGetArrFieldEqual("sa1.VAL", DBF_LONG, 12, 9, &oneToTwelve[3]);
testdbPutFieldOk("sa1.NELM", DBF_LONG, 3);
testdbGetArrFieldEqual("sa1.VAL", DBF_LONG, 12, 3, &oneToTwelve[3]);
testdbPutFieldOk("sa2.VAL", DBF_LONG, 1);
testdbGetArrFieldEqual("sa2.VAL", DBF_LONG, 10, 1, &oneToTwelve[0]);
testDiag("testScalarInputs");
testdbGetFieldEqual("li1", DBR_LONG, 1);
testdbGetFieldEqual("i64i1", DBR_INT64, 1LL);
testdbGetFieldEqual("li2", DBR_LONG, 1);
testdbGetFieldEqual("i64i2", DBR_INT64, 1LL);
testIocShutdownOk();
testdbCleanup();
}
static void testEventRecord()
{
testMonitor *countmon;
testDiag("testEventRecord");
startTestIoc("linkInitTest.db");
countmon = testMonitorCreate("count1.VAL", DBR_LONG, 0);
testdbGetFieldEqual("ev1.VAL", DBR_STRING, "soft event 1");
testdbGetFieldEqual("ev1.UDF", DBR_UCHAR, 0);
testdbGetFieldEqual("ev2.VAL", DBR_STRING, "");
testdbGetFieldEqual("ev2.UDF", DBR_UCHAR, 1);
testdbGetFieldEqual("count1.VAL", DBR_LONG, 0);
testdbPutFieldOk("ev1.PROC", DBF_UCHAR, 1);
testMonitorWait(countmon);
testdbGetFieldEqual("count1.VAL", DBR_LONG, 1);
testdbPutFieldOk("ev2.PROC", DBF_UCHAR, 1);
testMonitorWait(countmon);
testdbGetFieldEqual("ev2.UDF", DBR_UCHAR, 0);
testdbGetFieldEqual("count1.VAL", DBR_LONG, 2);
testdbPutFieldOk("count1.EVNT", DBF_STRING, "Tock");
testdbPutFieldOk("ev2.PROC", DBF_UCHAR, 1);
testMonitorWait(countmon);
testdbGetFieldEqual("count1.VAL", DBR_LONG, 3);
testMonitorDestroy(countmon);
testIocShutdownOk();
testdbCleanup();
}
MAIN(linkInitTest)
{
testPlan(72);
testLongStringInit();
testCalcInit();
testPrintfStrings();
testArrayInputs();
testEventRecord();
return testDone();
}
-90
View File
@@ -1,90 +0,0 @@
record(lsi, "longstr1") {
field(SIZV, "100")
field(INP, ["!----------------------------------------------!"])
}
record(lsi, "longstr2") {
field(SIZV, "100")
field(INP, {const: ["!----------------------------------------------!"]})
}
record(lsi, "longstr3") {
field(SIZV, "100")
field(INP, {const: "!----------------------------------------------!"})
}
record(lsi, "longstr4") {
field(SIZV, "100")
field(INP, ["One","Two","Three","Four"])
}
record(ai, "emptylink" ) {
field(INP, {calc: {expr:"0"}})
}
record(ai, "emptylink1" ) {
field(INP, {calc: {expr:"1"}})
}
record(printf, "printf1") {
field(SIZV, "100")
field(INP0, ["Test string, exactly 40 characters long"])
}
record(printf, "printf2") {
field(SIZV, "100")
field(INP0, ["Longer test string, more that 40 characters long"])
}
record(aai, "aai1") {
field(NELM, 10)
field(FTVL, "LONG")
field(INP, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12])
}
record(aai, "aai2") {
field(NELM, 10)
field(FTVL, "LONG")
field(INP, {const:[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]})
}
record(subArray, "sa1") {
field(FTVL, "LONG")
field(MALM, 12)
field(INP, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12])
field(INDX, 2)
field(NELM, 10)
}
record(subArray, "sa2") {
field(FTVL, "LONG")
field(MALM, 10)
field(NELM, 1)
}
record(waveform, "wf1") {
field(NELM, 10)
field(FTVL, "LONG")
field(INP, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12])
}
record(waveform, "wf2") {
field(NELM, 10)
field(FTVL, "LONG")
field(INP, {const:[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]})
}
record(longin, "li1") {
field(INP, 1)
}
record(int64in, "i64i1") {
field(INP, 1)
}
record(longin, "li2") {
field(INP, {const:1})
}
record(int64in, "i64i2") {
field(INP, {const:1})
}
record(longin, "count1" ) {
field(INP, {calc: {expr:"VAL+1"}})
field(SCAN, "Event")
field(EVNT, "soft event 1")
}
record(event, "ev1") {
field(INP, ["soft event 1"])
}
record(event, "ev2") {
field(INP, "count1.EVNT")
}
-25
View File
@@ -1,25 +0,0 @@
record(ai, "rec:ai") {
field(INP, "0")
}
record(ai, "rec:src1") {
field(VAL, "1")
}
record(ai, "rec:src2") {
field(VAL, "2")
}
record(stringout, "rec:link1") {
field(VAL, "rec:src1")
field(OUT, "rec:ai.INP CA")
}
record(stringout, "rec:link2") {
field(VAL, "rec:src2 CP")
field(OUT, "rec:ai.INP CA")
}
record(ai, "rec:j1") {
field(INP, {calc:{
expr:"A+5",
args:5
}})
field(PINI, "YES")
}
-122
View File
@@ -1,122 +0,0 @@
/*************************************************************************\
* Copyright (c) 2015 Michael Davidsaver
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/*
* Author: Michael Davidsaver <mdavidsaver@gmail.com>
*
* Test using several stringout records to retarget the link of another record
*/
#define EPICS_DBCA_PRIVATE_API
#include <string.h>
#include "dbAccess.h"
#include "dbUnitTest.h"
#include "errlog.h"
#include "epicsThread.h"
#include "testMain.h"
void recTestIoc_registerRecordDeviceDriver(struct dbBase *);
static void testRetarget(void)
{
testMonitor *lnkmon, *valmon;
testDiag("In testRetarget");
lnkmon = testMonitorCreate("rec:ai.INP", DBE_VALUE, 0);
valmon = testMonitorCreate("rec:ai", DBE_VALUE, 0);
/* initially rec:ai.INP is CONSTANT */
testdbGetFieldEqual("rec:ai", DBR_DOUBLE, 0.0);
testdbGetFieldEqual("rec:ai.INP", DBR_STRING, "0");
/* rec:ai.INP becomes DB_LINK, but no processing is triggered */
testdbPutFieldOk("rec:link1.PROC", DBF_LONG, 0);
testMonitorWait(lnkmon);
testdbGetFieldEqual("rec:ai", DBR_DOUBLE, 0.0);
testdbGetFieldEqual("rec:ai.INP", DBR_STRING, "rec:src1 NPP NMS");
/* trigger a read from rec:ai.INP */
testdbPutFieldOk("rec:ai.PROC", DBF_LONG, 0);
testMonitorWait(valmon);
testdbGetFieldEqual("rec:ai", DBR_DOUBLE, 1.0);
/* rec:ai.INP becomes CA_LINK w/ CP, processing is triggered */
testdbPutFieldOk("rec:link2.PROC", DBF_LONG, 0);
testMonitorWait(lnkmon);
testMonitorWait(valmon);
testdbGetFieldEqual("rec:ai", DBR_DOUBLE, 2.0);
testdbGetFieldEqual("rec:ai.INP", DBR_STRING, "rec:src2 CP NMS");
testMonitorDestroy(lnkmon);
testMonitorDestroy(valmon);
}
#define testLongStrEq(PV, VAL) testdbGetArrFieldEqual(PV, DBF_CHAR, sizeof(VAL)+2, sizeof(VAL), VAL)
#define testPutLongStr(PV, VAL) testdbPutArrFieldOk(PV, DBF_CHAR, sizeof(VAL), VAL);
static void testRetargetJLink(void)
{
testDiag("In testRetargetJLink");
testdbGetFieldEqual("rec:j1", DBF_DOUBLE, 10.0);
/* minimal args */
testLongStrEq("rec:j1.INP$", "{\"calc\":{\"expr\":\"A+5\",\"args\":5}}");
/* with [] */
testPutLongStr("rec:j1.INP$", "{\"calc\":{\"expr\":\"A+5\",\"args\":[7]}}");
testdbPutFieldOk("rec:j1.PROC", DBF_LONG, 1);
/* with const */
testPutLongStr("rec:j1.INP$", "{\"calc\":{\"expr\":\"A+5\",\"args\":[{\"const\":7}]}}");
testdbPutFieldOk("rec:j1.PROC", DBF_LONG, 1);
testdbGetFieldEqual("rec:j1", DBF_DOUBLE, 12.0);
testLongStrEq("rec:j1.INP$", "{\"calc\":{\"expr\":\"A+5\",\"args\":[{\"const\":7}]}}");
}
MAIN(linkRetargetLinkTest)
{
testPlan(18);
testdbPrepare();
testdbReadDatabase("recTestIoc.dbd", NULL, NULL);
recTestIoc_registerRecordDeviceDriver(pdbbase);
testdbReadDatabase("linkRetargetLink.db", NULL, NULL);
eltc(0);
testIocInitOk();
eltc(1);
/* wait for local CA links to be connected or dbPutField() will fail */
/* wait for initial CA_CONNECT actions to be processed.
* Assume that local CA links deliver callbacks synchronously
* eg. that ca_create_channel() will invoke the connection callback
* before returning.
*/
dbCaSync();
testRetarget();
testRetargetJLink();
testIocShutdownOk();
testdbCleanup();
return testDone();
}
-88
View File
@@ -1,88 +0,0 @@
/*************************************************************************\
* Copyright (c) 2017 Michael Davidsaver
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
#include <string.h>
#include "dbAccess.h"
#include "errlog.h"
#include "dbStaticLib.h"
#include "dbUnitTest.h"
#include "testMain.h"
static
void testint64BeforeInit(void)
{
const char *S;
DBENTRY dbent;
/* check dbGet/PutString */
testDiag("In %s", EPICS_FUNCTION);
dbInitEntryFromRecord(testdbRecordPtr("out64"), &dbent);
if(dbFindField(&dbent, "VAL"))
testAbort("Failed to find out64.VAL");
S = dbGetString(&dbent);
testOk(S && strcmp(S, "0")==0, "initial value \"%s\"", S);
testOk1(dbPutString(&dbent, "0x12345678abcdef00")==0);
S = dbGetString(&dbent);
testOk(S && strcmp(S, "1311768467750121216")==0, "1311768467750121216 \"%s\"", S);
dbFinishEntry(&dbent);
}
static
void testint64AfterInit(void)
{
testDiag("In %s", EPICS_FUNCTION);
/* check dbGet/PutField and DB links */
testdbGetFieldEqual("in64", DBF_UINT64, 0ULL);
testdbGetFieldEqual("out64", DBF_UINT64, 0x12345678abcdef00ULL);
testdbPutFieldOk("out64.PROC", DBF_LONG, 1);
testdbGetFieldEqual("in64", DBF_UINT64, 0x12345678abcdef00ULL);
testdbPutFieldOk("out64.VAL", DBF_UINT64, 0x22345678abcdef00ULL);
testdbPutFieldOk("in64.PROC", DBF_LONG, 1);
testdbGetFieldEqual("in64", DBF_UINT64, 0x22345678abcdef00ULL);
}
void recTestIoc_registerRecordDeviceDriver(struct dbBase *);
MAIN(recMiscTest)
{
testPlan(10);
testdbPrepare();
testdbReadDatabase("recTestIoc.dbd", NULL, NULL);
recTestIoc_registerRecordDeviceDriver(pdbbase);
testdbReadDatabase("recMiscTest.db", NULL, NULL);
testint64BeforeInit();
eltc(0);
testIocInitOk();
eltc(1);
testint64AfterInit();
testIocShutdownOk();
testdbCleanup();
return testDone();
}
-10
View File
@@ -1,10 +0,0 @@
# check int64in/out
record(int64in, "in64") {
field(INP , "out64 NPP")
}
record(int64out, "out64") {
field(OUT , "in64 NPP")
}
-9
View File
@@ -1,9 +0,0 @@
record(waveform, "wf") {
field(FTVL, "DOUBLE")
field(NELM, "1")
field(FLNK, "co")
}
record(calcout, "co") {
field(CALC, "A")
field(INPA, "wf")
}
-28
View File
@@ -1,28 +0,0 @@
record(ai, "ai1") {
field(INP, 0x10)
}
record(longin, "li1") {
field(INP, 0x10)
}
record(mbbiDirect, "mi1") {
field(INP, 0x10)
field(NOBT, 8)
}
record(aSub, "as1") {
field(INPA, 0x10)
field(FTA, "CHAR")
field(INPB, 0x10)
field(FTB, "UCHAR")
field(INPC, 0x10)
field(FTC, "SHORT")
field(INPD, 0x10)
field(FTD, "USHORT")
field(INPE, 0x10)
field(FTE, "LONG")
field(INPF, 0x10)
field(FTF, "ULONG")
field(INPG, 0x10)
field(FTG, "FLOAT")
field(INPH, 0x10)
field(FTH, "DOUBLE")
}
-13
View File
@@ -1,13 +0,0 @@
record(ai, "alarm") {
field(HIGH, 1)
field(HSV, MINOR)
field(HIHI, 2)
field(HHSV, MAJOR)
field(FLNK, "latch")
}
record(calc, "latch") {
field(INPA, "alarm NPP MS")
field(INPB, "latch NPP MS")
field(CALC, "A")
}
-134
View File
@@ -1,134 +0,0 @@
/*************************************************************************\
* Copyright (c) 2016 Michael Davidsaver
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
#include <dbUnitTest.h>
#include <testMain.h>
#include <dbAccess.h>
#include <errlog.h>
#include <calcoutRecord.h>
#include <waveformRecord.h>
/*
* Tests for specific regressions
*/
void regressTest_registerRecordDeviceDriver(struct dbBase *);
static
void startRegressTestIoc(const char *dbfile)
{
testdbPrepare();
testdbReadDatabase("regressTest.dbd", NULL, NULL);
regressTest_registerRecordDeviceDriver(pdbbase);
testdbReadDatabase(dbfile, NULL, NULL);
eltc(0);
testIocInitOk();
eltc(1);
}
/*
* https://bugs.launchpad.net/epics-base/+bug/1577108
*/
static
void testArrayLength1(void)
{
waveformRecord *precwf;
calcoutRecord *precco;
double *pbuf;
startRegressTestIoc("regressArray1.db");
precwf = (waveformRecord*)testdbRecordPtr("wf");
precco = (calcoutRecord*)testdbRecordPtr("co");
dbScanLock((dbCommon*)precwf);
pbuf = (double*)precwf->bptr;
dbScanUnlock((dbCommon*)precwf);
testdbPutFieldOk("wf", DBF_DOUBLE, 2.0);
dbScanLock((dbCommon*)precwf);
testOk(precwf->nord==1, "wf.NORD = %u == 1", (unsigned)precwf->nord);
testOk(pbuf[0]==2.0, "wf.VAL[0] = %f == 2.0", pbuf[0]);
dbScanUnlock((dbCommon*)precwf);
dbScanLock((dbCommon*)precco);
testOk(precco->a==2.0, "co.A = %f == 2.0", precco->a);
dbScanUnlock((dbCommon*)precco);
testdbGetFieldEqual("co", DBF_DOUBLE, 2.0);
testIocShutdownOk();
testdbCleanup();
}
/*
* https://bugs.launchpad.net/epics-base/+bug/1699445
*/
static
void testHexConstantLinks(void)
{
startRegressTestIoc("regressHex.db");
testdbGetFieldEqual("ai1", DBR_LONG, 0x10);
testdbGetFieldEqual("li1", DBR_LONG, 0x10);
testdbGetFieldEqual("mi1", DBR_LONG, 0x10);
testTodoBegin("Needs JSON5 for hex arrays");
testdbGetFieldEqual("as1.A", DBR_LONG, 0x10);
testdbGetFieldEqual("as1.B", DBR_LONG, 0x10);
testdbGetFieldEqual("as1.C", DBR_LONG, 0x10);
testdbGetFieldEqual("as1.D", DBR_LONG, 0x10);
testdbGetFieldEqual("as1.E", DBR_LONG, 0x10);
testdbGetFieldEqual("as1.F", DBR_LONG, 0x10);
testdbGetFieldEqual("as1.G", DBR_LONG, 0x10);
testdbGetFieldEqual("as1.H", DBR_LONG, 0x10);
testTodoEnd();
testIocShutdownOk();
testdbCleanup();
}
static
void testLinkMS(void)
{
startRegressTestIoc("regressLinkMS.db");
testdbPutFieldOk("alarm", DBF_DOUBLE, 0.5);
testdbGetFieldEqual("latch", DBR_DOUBLE, 0.5);
testdbGetFieldEqual("latch.SEVR", DBR_LONG, 0);
testdbPutFieldOk("alarm", DBF_DOUBLE, 1.5);
testdbGetFieldEqual("latch", DBR_DOUBLE, 1.5);
testdbGetFieldEqual("latch.SEVR", DBR_LONG, 1);
testdbPutFieldOk("alarm", DBF_DOUBLE, 0.5);
testdbGetFieldEqual("latch", DBR_DOUBLE, 0.5);
testdbGetFieldEqual("latch.SEVR", DBR_LONG, 0);
testdbPutFieldOk("alarm", DBF_DOUBLE, 2.5);
testdbGetFieldEqual("latch", DBR_DOUBLE, 2.5);
testdbGetFieldEqual("latch.SEVR", DBR_LONG, 2);
testdbPutFieldOk("alarm", DBF_DOUBLE, 0.5);
testdbGetFieldEqual("latch", DBR_DOUBLE, 0.5);
testdbGetFieldEqual("latch.SEVR", DBR_LONG, 0);
testIocShutdownOk();
testdbCleanup();
}
MAIN(regressTest)
{
testPlan(31);
testArrayLength1();
testHexConstantLinks();
testLinkMS();
return testDone();
}
-14
View File
@@ -1,14 +0,0 @@
/*************************************************************************\
* Copyright (c) 2012 UChicago Argonne LLC, as Operator of Argonne
* National Laboratory.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
extern void epicsRunRecordTests(void);
int main(int argc, char **argv)
{
epicsRunRecordTests(); /* calls epicsExit(0) */
return 0;
}
-169
View File
@@ -1,169 +0,0 @@
/*************************************************************************\
* Copyright (c) 2017 UChicago Argonne LLC, as operator of Argonne
* National Laboratory.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
#include <string.h>
#include "dbAccess.h"
#include "dbStaticLib.h"
#include "dbTest.h"
#include "dbUnitTest.h"
#include "errlog.h"
#include "registryFunction.h"
#include "subRecord.h"
#include "testMain.h"
static
void checkDtyp(const char *rec)
{
char dtyp[16];
strcpy(dtyp, rec);
strcat(dtyp, ".DTYP");
testdbGetFieldEqual(dtyp, DBF_LONG, 0); /* Soft Channel = 0 */
}
static
void checkInput(const char *rec, int value)
{
char proc[16];
testDiag("Checking record '%s'", rec);
strcpy(proc, rec);
strcat(proc, ".PROC");
testdbPutFieldOk(proc, DBF_CHAR, 1);
testdbGetFieldEqual(rec, DBF_LONG, value);
}
static
void testGroup0(void)
{
const char ** rec;
const char * records[] = {
"ai0", "bi0", "di0", "ii0", "li0", "lsi0", "mi0", "si0", NULL
};
testDiag("============ Starting %s ============", EPICS_FUNCTION);
testdbPutFieldOk("source", DBF_LONG, 1);
for (rec = records; *rec; rec++) {
checkInput(*rec, 1);
checkDtyp(*rec);
}
testdbPutFieldOk("source", DBF_LONG, 0);
for (rec = records; *rec; rec++) {
checkInput(*rec, 0);
}
}
static
void testGroup1(void)
{
const char ** rec;
const char * records[] = {
"bi1",
"ai1", "di1", "ii1", "li1", "lsi1", "mi1", "si1", NULL
};
int init = 1; /* bi1 initializes to 1 */
testDiag("============ Starting %s ============", EPICS_FUNCTION);
for (rec = records; *rec; rec++) {
checkInput(*rec, init);
init = 9; /* remainder initialize to 9 */
}
}
int dest;
static
long destSubr(subRecord *prec)
{
dest = prec->val;
return 0;
}
static
void checkOutput(const char *rec, int value)
{
testDiag("Checking record '%s'", rec);
testdbPutFieldOk(rec, DBF_LONG, value);
testOk(dest == value, "value %d output -> %d", value, dest);
}
static
void testGroup2(void)
{
const char ** rec;
const char * records[] = {
"ao0", "bo0", "io0", "lo0", "lso0", "mo0", "so0", NULL,
};
testDiag("============ Starting %s ============", EPICS_FUNCTION);
for (rec = records; *rec; rec++) {
checkOutput(*rec, 1);
checkDtyp(*rec);
}
checkOutput("do0.B0", 1);
checkDtyp("do0");
for (rec = records; *rec; rec++) {
checkOutput(*rec, 0);
}
checkOutput("do0.B0", 0);
}
static
void testGroup3(void)
{
const char ** rec;
const char * records[] = {
"ao1", "bo1", "do1.B0", "io1", "lo1", "lso1", "mo1", "so1", NULL,
};
testDiag("============ Starting %s ============", EPICS_FUNCTION);
for (rec = records; *rec; rec++) {
checkOutput(*rec, 0);
}
}
void recTestIoc_registerRecordDeviceDriver(struct dbBase *);
MAIN(softTest)
{
testPlan(114);
testdbPrepare();
testdbReadDatabase("recTestIoc.dbd", NULL, NULL);
recTestIoc_registerRecordDeviceDriver(pdbbase);
registryFunctionAdd("destSubr", (REGISTRYFUNCTION) destSubr);
testdbReadDatabase("softTest.db", NULL, NULL);
eltc(0);
testIocInitOk();
eltc(1);
testGroup0();
testGroup1();
testGroup2();
testGroup3();
testIocShutdownOk();
testdbCleanup();
return testDone();
}
-227
View File
@@ -1,227 +0,0 @@
# Group 0 are input records with INP being a DB link to 'source'.
# Processing them reads that value.
record(longin, "source") {}
record(ai, "ai0") {
field(DTYP, "Soft Channel")
field(INP, "source")
}
record(bi, "bi0") {
field(DTYP, "Soft Channel")
field(INP, "source")
field(ZNAM, "Zero")
field(ONAM, "One")
}
record(int64in, "ii0") {
field(DTYP, "Soft Channel")
field(INP, "source")
}
record(longin, "li0") {
field(DTYP, "Soft Channel")
field(INP, "source")
}
record(mbbiDirect, "di0") {
field(DTYP, "Soft Channel")
field(NOBT, 4)
field(INP, "source")
}
record(mbbi, "mi0") {
field(DTYP, "Soft Channel")
field(NOBT, 4)
field(INP, "source")
field(ZRST, "Zero")
field(ONST, "One")
field(TWST, "Two")
field(THST, "Three")
field(FRST, "Four")
field(FVST, "Five")
field(SXST, "Six")
field(SVST, "Seven")
field(EIST, "Eight")
field(NIST, "Nine")
field(TEST, "Ten")
field(ELST, "Eleven")
field(TWST, "Twelve")
field(TTST, "Thirteen")
field(FTST, "Fourteen")
field(FFST, "Fifteen")
}
record(lsi, "lsi0") {
field(DTYP, "Soft Channel")
field(SIZV, 40)
field(INP, "source")
}
record(stringin, "si0") {
field(DTYP, "Soft Channel")
field(INP, "source")
}
# Group 1 are input records with INP being a non-zero constant.
# Processing them succeeds but does not change VAL.
record(ai, "ai1") {
field(DTYP, "Soft Channel")
field(INP, {const:9})
}
record(bi, "bi1") {
field(DTYP, "Soft Channel")
field(INP, {const:1})
field(ZNAM, "Zero")
field(ONAM, "One")
}
record(int64in, "ii1") {
field(DTYP, "Soft Channel")
field(INP, {const:9})
}
record(longin, "li1") {
field(DTYP, "Soft Channel")
field(INP, {const:9})
}
record(mbbiDirect, "di1") {
field(DTYP, "Soft Channel")
field(NOBT, 4)
field(INP, {const:9})
}
record(mbbi, "mi1") {
field(DTYP, "Soft Channel")
field(NOBT, 4)
field(INP, {const:9})
field(ZRST, "Zero")
field(ONST, "One")
field(TWST, "Two")
field(THST, "Three")
field(FRST, "Four")
field(FVST, "Five")
field(SXST, "Six")
field(SVST, "Seven")
field(EIST, "Eight")
field(NIST, "Nine")
field(TEST, "Ten")
field(ELST, "Eleven")
field(TWST, "Twelve")
field(TTST, "Thirteen")
field(FTST, "Fourteen")
field(FFST, "Fifteen")
}
record(lsi, "lsi1") {
field(DTYP, "Soft Channel")
field(SIZV, 40)
field(INP, {const:"9"})
}
record(stringin, "si1") {
field(DTYP, "Soft Channel")
field(INP, {const:"9"})
}
# Group 2 are output records with OUT being a DB link to 'dest' with PP.
# Putting a value to them writes that value to 'dest'.
record(sub, "dest") {
field(SNAM, "destSubr")
}
record(ao, "ao0") {
field(DTYP, "Soft Channel")
field(OUT, "dest PP")
}
record(bo, "bo0") {
field(DTYP, "Soft Channel")
field(OUT, "dest PP")
field(ZNAM, "Zero")
field(ONAM, "One")
}
record(int64out, "io0") {
field(DTYP, "Soft Channel")
field(OUT, "dest PP")
}
record(longout, "lo0") {
field(DTYP, "Soft Channel")
field(OUT, "dest PP")
}
record(mbboDirect, "do0") {
field(DTYP, "Soft Channel")
field(NOBT, 4)
field(OUT, "dest PP")
}
record(mbbo, "mo0") {
field(DTYP, "Soft Channel")
field(NOBT, 4)
field(OUT, "dest PP")
field(ZRST, "Zero")
field(ONST, "One")
field(TWST, "Two")
field(THST, "Three")
field(FRST, "Four")
field(FVST, "Five")
field(SXST, "Six")
field(SVST, "Seven")
field(EIST, "Eight")
field(NIST, "Nine")
field(TEST, "Ten")
field(ELST, "Eleven")
field(TWST, "Twelve")
field(TTST, "Thirteen")
field(FTST, "Fourteen")
field(FFST, "Fifteen")
}
record(lso, "lso0") {
field(DTYP, "Soft Channel")
field(OUT, "dest PP")
field(SIZV, 40)
}
record(stringout, "so0") {
field(DTYP, "Soft Channel")
field(OUT, "dest PP")
}
# Group 3 are output records with OUT being empty (a constant link).
# Putting a value to them must succeed.
record(ao, "ao1") {
field(DTYP, "Soft Channel")
}
record(bo, "bo1") {
field(DTYP, "Soft Channel")
field(ZNAM, "Zero")
field(ONAM, "One")
}
record(int64out, "io1") {
field(DTYP, "Soft Channel")
}
record(longout, "lo1") {
field(DTYP, "Soft Channel")
}
record(mbboDirect, "do1") {
field(DTYP, "Soft Channel")
field(NOBT, 4)
}
record(mbbo, "mo1") {
field(DTYP, "Soft Channel")
field(NOBT, 4)
field(ZRST, "Zero")
field(ONST, "One")
field(TWST, "Two")
field(THST, "Three")
field(FRST, "Four")
field(FVST, "Five")
field(SXST, "Six")
field(SVST, "Seven")
field(EIST, "Eight")
field(NIST, "Nine")
field(TEST, "Ten")
field(ELST, "Eleven")
field(TWST, "Twelve")
field(TTST, "Thirteen")
field(FTST, "Fourteen")
field(FFST, "Fifteen")
}
record(lso, "lso1") {
field(DTYP, "Soft Channel")
field(SIZV, 40)
}
record(stringout, "so1") {
field(DTYP, "Soft Channel")
}