add pvUnitTest.h
This commit is contained in:
3
Makefile
3
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
|
||||
|
@ -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
|
||||
|
14
examples/Makefile
Normal file
14
examples/Makefile
Normal file
@ -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
|
||||
|
||||
|
30
examples/unittest.cpp
Normal file
30
examples/unittest.cpp
Normal file
@ -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 <stdexcept>
|
||||
|
||||
#include <testMain.h>
|
||||
|
||||
#include <pv/pvUnitTest.h>
|
||||
#include <pv/epicsException.h>
|
||||
|
||||
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();
|
||||
}
|
@ -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
|
||||
|
141
src/misc/pv/pvUnitTest.h
Normal file
141
src/misc/pv/pvUnitTest.h
Normal file
@ -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 <sstream>
|
||||
#include <typeinfo>
|
||||
|
||||
#include <epicsUnitTest.h>
|
||||
|
||||
#include <pv/sharedPtr.h>
|
||||
#include <pv/epicsException.h>
|
||||
#include <pv/pvData.h>
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<class C, void (C::*M)()>
|
||||
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<typename T>
|
||||
inline testPassx& operator<<(T v) {
|
||||
strm<<v;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// move ctor masquerading as copy ctor
|
||||
testPassx(testPassx& o) :strm(o.strm.str()), pass(o.pass), alive(o.alive) { strm.seekp(0, std::ios_base::end); o.alive = false; }
|
||||
private:
|
||||
testPassx& operator=(const testPassx&);
|
||||
};
|
||||
|
||||
template<typename LHS, typename RHS>
|
||||
inline testPassx testEqualx(const char *nLHS, const char *nRHS, LHS l, RHS r)
|
||||
{
|
||||
return testPassx(l==r)<<nLHS<<" ("<<l<<") == "<<nRHS<<" ("<<r<<")";
|
||||
}
|
||||
|
||||
}//namespace detail
|
||||
|
||||
/** @defgroup testhelpers Unit testing helpers
|
||||
*
|
||||
* Helper functions for writing unit tests.
|
||||
*
|
||||
@include unittest.cpp
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** Run a class method as a test.
|
||||
*
|
||||
* Each invocation of TEST_METHOD() constructs a new instance of 'klass' on the stack.
|
||||
* Thus constructor and destructor can be used for common test setup and tear down.
|
||||
@code
|
||||
struct MyTest {
|
||||
MyTest() { } // setup
|
||||
~MyTest() { } // tear down
|
||||
void test1() {}
|
||||
void test2() {}
|
||||
};
|
||||
MAIN(somename) {
|
||||
testPlan(0);
|
||||
TEST_METHOD(MyTest, test1)
|
||||
TEST_METHOD(MyTest, test2)
|
||||
return testDone();
|
||||
}
|
||||
@endcode
|
||||
*/
|
||||
#define TEST_METHOD(klass, method) ::detail::test_method<klass, &klass::method>(#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<epics::pvData::PVInt>(x, "alarm.severity", 1);
|
||||
@endcode
|
||||
*/
|
||||
template<typename PVD>
|
||||
::detail::testPassx
|
||||
testFieldEqual(const std::tr1::shared_ptr<epics::pvData::PVStructure>& 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<PVD>(name));
|
||||
if(!fval) {
|
||||
return ::detail::testPassx(false)<<" field '"<<name<<"' with type "<<typeid(PVD).name()<<" does not exist";
|
||||
} else {
|
||||
typename PVD::value_type actual(fval->get());
|
||||
return ::detail::testPassx(actual==expect)<<name<<" ("<<actual<<") == "<<expect;
|
||||
}
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
||||
#endif // PVUNITTEST_H
|
@ -73,3 +73,7 @@ TESTPROD_HOST += testTypeCast
|
||||
testTypeCast_SRCS += testTypeCast.cpp
|
||||
testHarness_SRCS += testTypeCast.cpp
|
||||
TESTS += testTypeCast
|
||||
|
||||
TESTPROD_HOST += testUnitTest
|
||||
testUnitTest_SRCS += testUnitTest.cpp
|
||||
TESTS += testUnitTest
|
||||
|
51
testApp/misc/testUnitTest.cpp
Normal file
51
testApp/misc/testUnitTest.cpp
Normal file
@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright information and license terms for this software can be
|
||||
* found in the file LICENSE that is included with the distribution
|
||||
*/
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
#include <testMain.h>
|
||||
|
||||
#include <pv/pvUnitTest.h>
|
||||
#include <pv/valueBuilder.h>
|
||||
|
||||
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<pvd::pvInt>("severity", 1)
|
||||
.add<pvd::pvString>("message", "hello")
|
||||
.endNested()
|
||||
.buildPVStructure());
|
||||
|
||||
testFieldEqual<pvd::PVInt>(S, "alarm.severity", 1);
|
||||
testFieldEqual<pvd::PVString>(S, "alarm.message", "hello")<<" More";
|
||||
|
||||
}catch(std::exception& e){
|
||||
testAbort("Unhandled exception: %s", e.what());
|
||||
}
|
||||
return testDone();
|
||||
}
|
Reference in New Issue
Block a user