Making tests less platform dependent.

Tests executables made several assumptions that are only valid on
some system/compiler:

* That the main function is found even in a shared library (not true
  on windows). To fix this, test_main is now an ojbect library
* That the extern test_registry in test.cpp will be initialized
  before any actual test uses it. This was either a lucky coincidence
  on linux, or being related to the variable being initialized in a
  shared library. The variable is now initialized by a function,
  guarantaaing initialization order.
* That test.hpp is only inluded once per binary, which was only true
  because it was once part of a DLL, once the executable, hiding ODR
  violations. As now it's linked twice within the same binary, some
  functions had to be made inline.
* not is not a valid C++ operator, replaced all occurences with !
This commit is contained in:
Zsolt Parragi 2019-08-24 07:49:39 +02:00
parent 4dfd5e6e24
commit ec14c48e3e
4 changed files with 17 additions and 13 deletions

View File

@ -94,13 +94,13 @@ target_include_directories(backward PUBLIC ${BACKWARD_INCLUDE_DIRS})
if(BACKWARD_TESTS)
enable_testing()
add_library(test_main SHARED test/_test_main.cpp)
add_library(test_main OBJECT test/_test_main.cpp)
macro(backward_add_test src)
get_filename_component(name ${src} NAME_WE)
set(test_name "test_${name}")
add_executable(${test_name} ${src} ${ARGN})
add_executable(${test_name} ${src} ${ARGN} $<TARGET_OBJECTS:test_main>)
target_link_libraries(${test_name} PRIVATE Backward::Backward test_main)

View File

@ -122,8 +122,8 @@ int main(int argc, const char *const argv[]) {
size_t success_cnt = 0;
size_t total_cnt = 0;
for (test_registry_t::iterator it = test_registry.begin();
it != test_registry.end(); ++it) {
for (test_registry_t::iterator it = test_registry().begin();
it != test_registry().end(); ++it) {
TestBase &test = **it;
bool consider_test = (argc <= 1);
@ -133,7 +133,7 @@ int main(int argc, const char *const argv[]) {
break;
}
}
if (not consider_test) {
if (!consider_test) {
continue;
}

View File

@ -30,7 +30,7 @@ using namespace backward;
typedef StackTrace stacktrace_t;
void end_of_our_journey(stacktrace_t &st) {
if (not st.size()) {
if (!st.size()) {
st.load_here();
}
}

View File

@ -41,7 +41,7 @@ struct AssertFailedError : std::exception {
: basename(_basename(filename)), line(_line), errmsg(_errmsg) {}
const char *what() const throw() {
if (not _what.size()) {
if (!_what.size()) {
std::ostringstream ss;
ss << "assertion failed (" << basename << ":" << line;
ss << ") " << errmsg;
@ -105,10 +105,14 @@ struct TestBase {
};
typedef std::vector<TestBase *> test_registry_t;
extern test_registry_t test_registry;
inline test_registry_t &test_registry() {
static test_registry_t reg;
return reg;
}
TestBase::TestBase(const char *n, TestStatus s) : name(n), expected_status(s) {
test_registry.push_back(this);
inline TestBase::TestBase(const char *n, TestStatus s)
: name(n), expected_status(s) {
test_registry().push_back(this);
}
} // namespace test
@ -135,9 +139,9 @@ TestBase::TestBase(const char *n, TestStatus s) : name(n), expected_status(s) {
: throw ::test::AssertFailedError(__FILE__, __LINE__, #expr)
#define _ASSERT_BINOP(a, b, cmp) \
(not(a cmp b)) ? static_cast<void>(0) \
: throw ::test::AssertFailedError( \
__FILE__, __LINE__, "because " #a " " #cmp " " #b)
(!(a cmp b)) ? static_cast<void>(0) \
: throw ::test::AssertFailedError( \
__FILE__, __LINE__, "because " #a " " #cmp " " #b)
#define ASSERT_EQ(a, b) _ASSERT_BINOP(a, b, !=)
#define ASSERT_NE(a, b) _ASSERT_BINOP(a, b, ==)