pvUnitTest.h multi-line prints

This commit is contained in:
Michael Davidsaver
2017-09-20 14:25:23 -05:00
parent 72fe0ca3e7
commit 7a71e758b1
3 changed files with 96 additions and 18 deletions
+1
View File
@@ -38,5 +38,6 @@ LIBSRCS += status.cpp
LIBSRCS += localStaticLock.cpp
LIBSRCS += typeCast.cpp
LIBSRCS += parseToPOD.cpp
LIBSRCS += pvUnitTest.cpp
LIBSRCS += debugPtr.cpp
LIBSRCS += reftrack.cpp
+42 -18
View File
@@ -29,24 +29,24 @@ void test_method(const char *kname, const char *mname)
}
}
class testPassx
class epicsShareClass testPassx
{
std::ostringstream strm;
bool pass, alive;
const bool dotest, pass;
bool alive;
public:
explicit testPassx(bool r) :pass(r), alive(true) {}
~testPassx() {
if(alive)
testOk(pass, "%s", strm.str().c_str());
}
testPassx() :dotest(false), pass(false), alive(true) {}
explicit testPassx(bool r) :dotest(true), pass(r), alive(true) {}
~testPassx();
template<typename T>
inline testPassx& operator<<(T v) {
strm<<v;
return *this;
}
// allow testPassx to be returned
// 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; }
testPassx(testPassx& o);
private:
testPassx& operator=(const testPassx&);
};
@@ -57,6 +57,12 @@ inline testPassx testEqualx(const char *nLHS, const char *nRHS, LHS l, RHS r)
return testPassx(l==r)<<nLHS<<" ("<<l<<") == "<<nRHS<<" ("<<r<<")";
}
template<typename LHS, typename RHS>
inline testPassx testNotEqualx(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
@@ -73,17 +79,19 @@ inline testPassx testEqualx(const char *nLHS, const char *nRHS, LHS l, RHS r)
* 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() {}
};
namespace { // anon
struct MyTest {
MyTest() { } // setup
~MyTest() { } // tear down
void test1() {}
void test2() {}
};
} // namespace anon
MAIN(somename) {
testPlan(0);
TEST_METHOD(MyTest, test1)
TEST_METHOD(MyTest, test2)
return testDone();
testPlan(0);
TEST_METHOD(MyTest, test1)
TEST_METHOD(MyTest, test2)
return testDone();
}
@endcode
*/
@@ -101,6 +109,8 @@ inline testPassx testEqualx(const char *nLHS, const char *nRHS, LHS l, RHS r)
*/
#define testEqual(LHS, RHS) ::detail::testEqualx(#LHS, #RHS, LHS, RHS)
#define testNotEqual(LHS, RHS) ::detail::testNotEqualx(#LHS, #RHS, LHS, RHS)
/** Pass/fail from boolean
*
@code
@@ -113,8 +123,22 @@ inline testPassx testEqualx(const char *nLHS, const char *nRHS, LHS l, RHS r)
*/
#define testTrue(B) ::detail::testPassx(!!(B))<<#B
/** Test that a given block throws an exception
*
@code
testThrows(std::runtime_error, somefunc(5))
@endcode
*/
#define testThrows(EXC, CODE) try{ CODE; testFail("unexpected success of " #CODE); }catch(EXC& e){testPass("catch expected exception: %s", e.what());}
/** Print test output w/o testing
*
@code
testShow()<<"Foo";
@endcode
*/
#define testShow() ::detail::testPassx()
/** Compare value of PVStructure field
*
@code
+53
View File
@@ -0,0 +1,53 @@
/*
* Copyright information and license terms for this software can be
* found in the file LICENSE that is included with the distribution
*/
#include <string>
#include <vector>
#include <epicsUnitTest.h>
#define epicsExportSharedSymbols
#include <pv/pvUnitTest.h>
namespace detail {
testPassx::~testPassx() {
if(!alive) return;
std::string msg(strm.str());
size_t nl = msg.find_first_of('\n');
if(nl==msg.npos) {
// single-line output
if(dotest)
testOk(pass, "%s", msg.c_str());
else
testDiag("%s", msg.c_str());
} else {
// multi-line output
std::istringstream lines(msg);
std::string line;
bool first = true;
while(std::getline(lines ,line)) {
if(dotest && first) {
first = false;
testOk(pass, "%s", line.c_str());
} else {
testDiag("%s", line.c_str());
}
}
}
}
testPassx::testPassx(testPassx& o)
:strm(o.strm.str())
,dotest(o.dotest)
,pass(o.pass)
,alive(o.alive)
{
strm.seekp(0, std::ios_base::end);
o.alive = false;
}
} // namespace detail