unittest: harden string comparison

std::string::compare((char*)nullptr) crashes circa gcc 4.8
in call to strlen(nullptr).
This commit is contained in:
Michael Davidsaver
2021-04-24 10:56:08 -07:00
parent d33672a859
commit a32f82ca35
3 changed files with 58 additions and 6 deletions
+23 -2
View File
@@ -146,8 +146,22 @@ testCase testNotEq(const char *sLHS, const LHS& lhs, const char *sRHS, const RHS
return ret;
}
template<typename T>
struct as_str {
static const char* op(const T& v) { return v; }
};
template<> struct as_str<std::string> {
static const char* op(const std::string& v) { return v.c_str(); }
};
template<> struct as_str<const std::string> {
static const char* op(const std::string& v) { return v.c_str(); }
};
template<typename T>
const char* asStr(const T& v) { return as_str<T>::op(v); }
PVXS_API
testCase _testStrEq(const char *sLHS, const std::string& lhs, const char *sRHS, const std::string& rhs);
testCase _testStrTest(unsigned op, const char *sLHS, const char* lhs, const char *sRHS, const char* rhs);
PVXS_API
testCase _testStrMatch(const char *spat, const std::string& pat, const char *sstr, const std::string& str);
@@ -263,7 +277,14 @@ testCase testThrowsMatch(const std::string& expr, FN fn)
//! Evaluates to a pvxs::testCase
//! Functionally equivalent to testEq() with two std::string instances.
//! Prints diff-like output which is friendlier to multi-line strings.
#define testStrEq(LHS, RHS) ::pvxs::detail::_testStrEq(#LHS, LHS, #RHS, RHS)
#define testStrEq(LHS, RHS) ::pvxs::detail::_testStrTest(1, #LHS, ::pvxs::detail::asStr(LHS), #RHS, ::pvxs::detail::asStr(RHS))
//! Macro which asserts inequality between LHS and RHS.
//! Evaluates to a pvxs::testCase
//! Functionally equivalent to testNotEq() with two std::string instances.
//! Prints diff-like output which is friendlier to multi-line strings.
//! @since UNRELEASED
#define testStrNotEq(LHS, RHS) ::pvxs::detail::_testStrTest(0, #LHS, ::pvxs::detail::asStr(LHS), #RHS, ::pvxs::detail::asStr(RHS))
//! Macro which asserts that STR matches the regular expression EXPR
//! Evaluates to a pvxs::testCase
+13 -3
View File
@@ -118,10 +118,20 @@ size_t findNextLine(const std::string& s, size_t pos=0u)
return next;
}
testCase _testStrEq(const char *sLHS, const std::string& lhs, const char *sRHS, const std::string& rhs)
testCase _testStrTest(unsigned op, const char *sLHS, const char* rlhs, const char *sRHS, const char* rrhs)
{
testCase ret(lhs==rhs);
ret<<sLHS<<" == "<<sRHS<<"\n";
bool eq;
if(rlhs==rrhs) // same string. handles NULL==NULL
eq = true;
else if(!rlhs ^ !rrhs) // one NULL
eq = false;
else
eq = strcmp(rlhs, rrhs)==0;
testCase ret(eq==op);
ret<<sLHS<<(op ? " == " : " != ")<<sRHS<<"\n";
std::string lhs(rlhs ? rlhs : "<null>");
std::string rhs(rrhs ? rrhs : "<null>");
size_t posL=0u, posR=0u;
+22 -1
View File
@@ -182,16 +182,37 @@ void testAccount()
}
}
void testTestEq()
{
testShow()<<__func__;
testStrNotEq((char*)nullptr, std::string());
testStrNotEq(std::string(), (char*)nullptr);
testStrEq((char*)nullptr, (char*)nullptr);
testStrEq(std::string(), std::string());
testStrEq("hello", "hello");
testStrEq("hello", std::string("hello"));
testStrEq(std::string("hello"), "hello");
testStrEq(std::string("hello"), std::string("hello"));
testStrNotEq("hello", "world");
testStrNotEq("hello", std::string("world"));
testStrNotEq(std::string("hello"), "world");
testStrNotEq(std::string("hello"), std::string("world"));
}
} // namespace
MAIN(testutil)
{
testPlan(12);
testPlan(24);
testTrue(version_abi_check())<<" 0x"<<std::hex<<PVXS_VERSION<<" ~= 0x"<<std::hex<<PVXS_ABI_VERSION;
testServerGUID();
testFill();
testSpam();
testSpamMany();
testAccount();
testTestEq();
return testDone();
}