diff --git a/Makefile b/Makefile index 8b74cc0..c0ccd89 100644 --- a/Makefile +++ b/Makefile @@ -11,4 +11,7 @@ src_DEPEND_DIRS = configure DIRS += testApp testApp_DEPEND_DIRS = src +DIRS += examples +examples_DEPEND_DIRS = src + include $(TOP)/configure/RULES_TOP diff --git a/documentation/Doxyfile b/documentation/Doxyfile index 11d8b51..5931ef9 100644 --- a/documentation/Doxyfile +++ b/documentation/Doxyfile @@ -835,14 +835,14 @@ EXCLUDE_SYMBOLS = # that contain example code fragments that are included (see the \include # command). -EXAMPLE_PATH = +EXAMPLE_PATH = ../examples # If the value of the EXAMPLE_PATH tag contains directories, you can use the # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and # *.h) to filter out the source-files in the directories. If left blank all # files are included. -EXAMPLE_PATTERNS = * +EXAMPLE_PATTERNS = *.cpp # If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be # searched for input files to be used with the \include or \dontinclude commands diff --git a/examples/Makefile b/examples/Makefile new file mode 100644 index 0000000..ab92b31 --- /dev/null +++ b/examples/Makefile @@ -0,0 +1,14 @@ +# Makefile for the examples +# make sure they compile + +TOP = .. +include $(TOP)/configure/CONFIG + +PROD_LIBS += pvData Com + +TESTPROD_HOST += unittest +unittest_SRCS += unittest.cpp + +include $(TOP)/configure/RULES + + diff --git a/examples/unittest.cpp b/examples/unittest.cpp new file mode 100644 index 0000000..8e77bb9 --- /dev/null +++ b/examples/unittest.cpp @@ -0,0 +1,30 @@ +/* + * Copyright information and license terms for this software can be + * found in the file LICENSE that is included with the distribution + */ +/* c++ unittest skeleton */ + +#include + +#include + +#include +#include + +namespace { +void testCase1() { + testEqual(1+1, 2); +} +} // namespace + +MAIN(testUnitTest) +{ + testPlan(1); + try { + testCase1(); + }catch(std::exception& e){ + PRINT_EXCEPTION(e); // print stack trace if thrown with THROW_EXCEPTION() + testAbort("Unhandled exception: %s", e.what()); + } + return testDone(); +} diff --git a/src/misc/Makefile b/src/misc/Makefile index 5e3a60c..be873af 100644 --- a/src/misc/Makefile +++ b/src/misc/Makefile @@ -25,6 +25,7 @@ INC += pv/typeCast.h INC += pv/sharedVector.h INC += pv/templateMeta.h INC += pv/current_function.h +INC += pv/pvUnitTest.h LIBSRCS += byteBuffer.cpp LIBSRCS += bitSet.cpp diff --git a/src/misc/pv/pvUnitTest.h b/src/misc/pv/pvUnitTest.h new file mode 100644 index 0000000..2dbf52c --- /dev/null +++ b/src/misc/pv/pvUnitTest.h @@ -0,0 +1,141 @@ +/* + * Copyright information and license terms for this software can be + * found in the file LICENSE that is included with the distribution + */ +#ifndef PVUNITTEST_H +#define PVUNITTEST_H + +#include +#include + +#include + +#include +#include +#include + +namespace detail { + +template +void test_method(const char *kname, const char *mname) +{ + try { + testDiag("------- %s::%s --------", kname, mname); + C inst; + (inst.*M)(); + } catch(std::exception& e) { + PRINT_EXCEPTION(e); + testAbort("unexpected exception: %s", e.what()); + } +} + +class testPassx +{ + std::ostringstream strm; + bool pass, alive; +public: + explicit testPassx(bool r) :pass(r), alive(true) {} + ~testPassx() { + if(alive) + testOk(pass, "%s", strm.str().c_str()); + } + template + inline testPassx& operator<<(T v) { + strm< +inline testPassx testEqualx(const char *nLHS, const char *nRHS, LHS l, RHS r) +{ + return testPassx(l==r)<(#klass, #method) + +/** Compare equality. print left and right hand values and expression strings + * + @code + int x=5; + testEqual(x, 5); + // prints "ok 1 - x (5) == 5 (5)\n" + testEqual(x, 6)<<" oops"; + // prints "not ok 1 - x (5) == 6 (6) oops\n" + @endcode + */ +#define testEqual(LHS, RHS) ::detail::testEqualx(#LHS, #RHS, LHS, RHS) + +/** Pass/fail from boolean + * + @code + bool y=true; + testTrue(y); + // prints "ok 1 - y\n" + testTrue(!y)<<" oops"; + // prints "not ok 1 - !y oops\n" + @endcode + */ +#define testTrue(B) ::detail::testPassx(!!(B))<<#B + +/** Compare value of PVStructure field + * + @code + PVStructurePtr x(.....); + testFieldEqual(x, "alarm.severity", 1); + @endcode + */ +template +::detail::testPassx +testFieldEqual(const std::tr1::shared_ptr& val, const char *name, typename PVD::value_type expect) +{ + if(!val) { + return ::detail::testPassx(false)<<" null structure pointer"; + } + typename PVD::shared_pointer fval(val->getSubField(name)); + if(!fval) { + return ::detail::testPassx(false)<<" field '"<get()); + return ::detail::testPassx(actual==expect)< + +#include + +#include +#include + +namespace pvd = epics::pvData; + +namespace { +struct MyTest { + MyTest() { testPass("MyTest::MyTest"); } + ~MyTest() { testPass("MyTest::~MyTest"); } + void test1() { testPass("test1"); } + void test2() { testPass("test2"); } +}; +}//namespace + +MAIN(testUnitTest) +{ + testPlan(0); + try { + TEST_METHOD(MyTest, test1); + TEST_METHOD(MyTest, test2); + + { + std::string x("hello"); + testEqual(x, "hello"); + testEqual(x, "hello")<<" Extra"; + } + + pvd::PVStructurePtr S(pvd::ValueBuilder() + .addNested("alarm") + .add("severity", 1) + .add("message", "hello") + .endNested() + .buildPVStructure()); + + testFieldEqual(S, "alarm.severity", 1); + testFieldEqual(S, "alarm.message", "hello")<<" More"; + + }catch(std::exception& e){ + testAbort("Unhandled exception: %s", e.what()); + } + return testDone(); +}