Skip to content

Instantly share code, notes, and snippets.

@ashjas
Created February 18, 2020 07:48
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ashjas/2f3d365c6edefff52589f1a7bbd83588 to your computer and use it in GitHub Desktop.
Save ashjas/2f3d365c6edefff52589f1a7bbd83588 to your computer and use it in GitHub Desktop.
implementing a BOOST_TEST test_runner for running multiple tests from different shared libraries containing testcases
#ifndef BOOST_TEST_DYN_LINK
#define BOOST_TEST_DYN_LINK
#endif
#include "boost/test/unit_test.hpp"
#include <boost/program_options.hpp>
#include <boost/variant.hpp>
#include <iostream>
#include <vector>
namespace dyn_lib {
#if defined(BOOST_WINDOWS) && !defined(BOOST_DISABLE_WIN32) // WIN32 API
#include <windows.h>
typedef HINSTANCE handle;
inline handle
open(std::string const& file_name)
{
return LoadLibrary(file_name.c_str());
}
template<typename TargType>
inline TargType
locate_symbol(handle h, std::string const& symbol)
{
return reinterpret_cast<TargType>(GetProcAddress(h, symbol.c_str()));
}
inline void close(handle h)
{
if (h)
FreeLibrary(h);
}
inline std::string error()
{
LPTSTR msg = NULL;
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
GetLastError(),
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR)&msg,
0, NULL);
std::string res(msg);
if (msg)
LocalFree(msg);
return res;
}
#elif defined(BOOST_HAS_UNISTD_H) // POSIX API
#include <dlfcn.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
typedef void* handle;
inline handle open(std::string const& file_name)
{
return dlopen(file_name.c_str(), RTLD_LOCAL | RTLD_LAZY);
}
template<typename TargType>
inline TargType
locate_symbol(handle h, std::string const& symbol)
{
return reinterpret_cast<TargType>(dlsym(h, symbol.c_str()));
}
inline void
close(handle h)
{
if (h)
dlclose(h);
}
inline std::string
error()
{
return dlerror();
}
#else
#error "Dynamic library API is unknown"
#endif
} // namespace dyn_lib
static std::string test_lib_name;
static std::string init_func_name("init_unit_test");
dyn_lib::handle test_lib_handle;
bool load_test_lib()
{
typedef bool(*init_func_ptr)();
init_func_ptr init_func;
test_lib_handle = dyn_lib::open(test_lib_name);//there is an undefined behaviour at this point, at 2nd iteration.
if (!test_lib_handle)
throw std::logic_error(std::string("Fail to load test library: ")
.append(dyn_lib::error()));
init_func = dyn_lib::locate_symbol<init_func_ptr>(test_lib_handle, init_func_name);
if (!init_func)
throw std::logic_error(std::string("Can't locate test initilization function ")
.append(init_func_name)
.append(": ")
.append(dyn_lib::error()));
return (*init_func)();
}
int main(int argc, char* argv[])
{
std::string desc_str;
std::vector<std::string> dllsToTest{"abc","def"};
try {
for (int i = 0; i < dllsToTest.size(); ++i)
{
test_lib_name = dllsToTest[i];
int res = ::boost::unit_test::unit_test_main(&load_test_lib, argc, argv);
::boost::unit_test::framework::clear();
dyn_lib::close(test_lib_handle);
test_lib_handle = NULL;
}
//return res;
}
catch (std::exception& ex){
std::cout << ex.what() << std::endl << desc_str;
return -1;
}
}
#ifndef BOOST_TEST_DYN_LINK
#define BOOST_TEST_DYN_LINK
#endif
#define BOOST_TEST_NO_MAIN
#define BOOST_TEST_ALTERNATIVE_INIT_API
#include <boost/test/unit_test.hpp>
extern "C" {
__declspec(dllexport) bool init_unit_test()
{
return true;
}
}
BOOST_AUTO_TEST_CASE(test1)
{
BOOST_TEST(false);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment