36 # include <valgrind/memcheck.h>
37 # include <sys/types.h>
82 static int vg_log_fd = -1;
85 #if HAVE_DECL_SIGSETJMP && HAVE_DECL_SIGLONGJMP
86 # define SIGSETJMP(ENV, SAVESIGS) sigsetjmp(ENV, SAVESIGS)
87 # define SIGLONGJMP(ENV, VAL) siglongjmp(ENV, VAL)
88 # define SIGJMP_BUF sigjmp_buf
90 # define SIGSETJMP(ENV, SAVESIGS) setjmp(ENV)
91 # define SIGLONGJMP(ENV, VAL) longjmp(ENV, VAL)
92 # define SIGJMP_BUF jmp_buf
127 const string & s =
tout.str();
137 char *
p = getenv(
"srcdir");
138 if (
p != NULL)
return string(
p);
144 if (i != string::npos) {
145 srcfile.assign(
srcdir, i + 1, string::npos);
149 if (
srcdir.substr(i + 1) ==
".libs") {
152 if (
startswith(srcfile,
"lt-")) srcfile.erase(0, 3);
163 if (
endswith(srcfile,
".exe")) srcfile.resize(srcfile.size() - 4);
168 <<
": srcdir is not in the environment and I can't guess it!\n"
169 "Run test programs using the runtest script - see HACKING "
177 : out(cout.rdbuf()),
tests(tests_)
189 #if defined HAVE_SIGACTION && defined SA_SIGINFO
191 static void handle_sig(
int signum_, siginfo_t *si,
void *)
196 sa.sa_handler = SIG_DFL;
197 sigemptyset(&sa.sa_mask);
201 if (signum_ != SIGSEGV) sigaction(SIGSEGV, &sa, NULL);
202 if (signum_ != SIGFPE) sigaction(SIGFPE, &sa, NULL);
203 if (signum_ != SIGILL) sigaction(SIGILL, &sa, NULL);
205 if (signum_ != SIGBUS) sigaction(SIGBUS, &sa, NULL);
208 if (signum_ != SIGPIPE) sigaction(SIGPIPE, &sa, NULL);
211 if (signum_ != SIGSTKFLT) sigaction(SIGSTKFLT, &sa, NULL);
225 signal(SIGSEGV, SIG_DFL);
226 signal(SIGFPE, SIG_DFL);
227 signal(SIGILL, SIG_DFL);
229 signal(SIGBUS, SIG_DFL);
232 signal(SIGPIPE, SIG_DFL);
235 signal(SIGSTKFLT, SIG_DFL);
256 #if defined HAVE_SIGACTION && defined SA_SIGINFO
259 sigemptyset(&sa.sa_mask);
260 sa.sa_flags = SA_RESETHAND|SA_SIGINFO;
261 sigaction(SIGSEGV, &sa, NULL);
262 sigaction(SIGFPE, &sa, NULL);
263 sigaction(SIGILL, &sa, NULL);
265 sigaction(SIGBUS, &sa, NULL);
268 sigaction(SIGPIPE, &sa, NULL);
271 sigaction(SIGSTKFLT, &sa, NULL);
290 #if defined HAVE_SIGACTION && defined SA_SIGINFO
292 sa.sa_handler = SIG_DFL;
293 sigemptyset(&sa.sa_mask);
295 sigaction(SIGSEGV, &sa, NULL);
296 sigaction(SIGFPE, &sa, NULL);
297 sigaction(SIGILL, &sa, NULL);
299 sigaction(SIGBUS, &sa, NULL);
302 sigaction(SIGPIPE, &sa, NULL);
305 sigaction(SIGSTKFLT, &sa, NULL);
308 signal(SIGSEGV, SIG_DFL);
309 signal(SIGFPE, SIG_DFL);
310 signal(SIGILL, SIG_DFL);
312 signal(SIGBUS, SIG_DFL);
315 signal(SIGPIPE, SIG_DFL);
318 signal(SIGSTKFLT, SIG_DFL);
336 volatile int runcount = 0;
348 # pragma warning(push)
349 # pragma warning(disable:4611)
353 # pragma warning(pop)
356 static bool catch_signals =
357 (getenv(
"XAPIAN_TESTSUITE_SIG_DFL") == NULL);
364 long vg_leaks = 0, vg_dubious = 0, vg_reachable = 0;
365 if (vg_log_fd != -1) {
366 VALGRIND_DO_LEAK_CHECK;
367 vg_errs = VALGRIND_COUNT_ERRORS;
369 VALGRIND_COUNT_LEAKS(vg_leaks, vg_dubious, vg_reachable,
dummy);
372 lseek(vg_log_fd, 0, SEEK_END);
383 if (vg_log_fd != -1) {
389 #define REPORT_FAIL_VG(M) do { \
392 ssize_t c = read(vg_log_fd, buf, sizeof(buf)); \
393 if (c == 0 || (c < 0 && errno != EINTR)) break; \
394 if (c > 0) out << string(buf, c); \
397 out << " " << col_red << M << col_reset; \
401 off_t curpos = lseek(vg_log_fd, 0, SEEK_CUR);
404 ssize_t c = read(vg_log_fd, buf,
sizeof(buf));
405 if (c == 0 || (c < 0 && errno != EINTR)) {
416 spc =
static_cast<const char *
>(
417 memchr(buf + i,
' ', c - i));
427 (memcmp(buf + i,
"Warning:", 8) == 0 ||
428 memcmp(buf + i,
" ", 3) == 0)) {
432 nl =
static_cast<const char *
>(
433 memchr(buf + i,
'\n', c - i));
444 char *start = buf + i;
446 if (c > 128) c = 128;
450 p =
static_cast<const char*
>(
451 memchr(start,
'\n', c));
452 if (
p != NULL) c =
p - start;
455 memmove(buf, start, c);
460 lseek(vg_log_fd, curpos, SEEK_SET);
462 int vg_errs2 = VALGRIND_COUNT_ERRORS;
463 vg_errs = vg_errs2 - vg_errs;
464 VALGRIND_DO_LEAK_CHECK;
465 long vg_leaks2 = 0, vg_dubious2 = 0, vg_reachable2 = 0;
467 VALGRIND_COUNT_LEAKS(vg_leaks2, vg_dubious2, vg_reachable2,
470 vg_leaks = vg_leaks2 - vg_leaks;
471 vg_dubious = vg_dubious2 - vg_dubious;
472 vg_reachable = vg_reachable2 - vg_reachable;
474 string fail_msg(buf);
475 if (fail_msg.empty())
476 fail_msg =
"VALGRIND DETECTED A PROBLEM";
477 REPORT_FAIL_VG(fail_msg);
481 REPORT_FAIL_VG(
"LEAKED " << vg_leaks <<
" BYTES");
484 if (vg_dubious > 0) {
491 runcount = runcount + 1;
494 (void)fdtracker.
check();
497 REPORT_FAIL_VG(
"PROBABLY LEAKED " << vg_dubious <<
" BYTES");
500 if (vg_reachable > 0) {
515 runcount = runcount + 1;
518 (void)fdtracker.
check();
521 REPORT_FAIL_VG(
"FAILED TO RELEASE " << vg_reachable <<
" BYTES");
526 if (!fdtracker.
check()) {
529 runcount = runcount + 1;
557 if (errclass ==
"NetworkError" &&
579 }
catch (
const string & msg) {
590 }
catch (
const std::exception & e) {
599 out <<
"std::exception";
601 const char *
name =
typeid(e).
name();
602 # ifdef HAVE_CXXABI_H
606 char * realname = abi::__cxa_demangle(
name, NULL, 0, &status);
620 }
catch (
const char * msg) {
629 out <<
"EXCEPTION char* " << msg;
631 out <<
"EXCEPTION (char*)NULL";
660 const char *signame =
"SIGNAL";
661 #if defined HAVE_SIGACTION && defined SA_SIGINFO
662 bool show_addr =
true;
664 bool show_addr =
false;
667 case SIGSEGV: signame =
"SIGSEGV";
break;
668 case SIGFPE: signame =
"SIGFPE";
break;
669 case SIGILL: signame =
"SIGILL";
break;
671 case SIGBUS: signame =
"SIGBUS";
break;
681 signame =
"SIGSTKFLT";
698 vector<string>::const_iterator e)
706 const vector<string> blank;
712 vector<string>::const_iterator e)
715 bool check_name = !m.empty();
720 bool do_this_test = !check_name;
721 if (!do_this_test && m.find(test->name) != m.end())
726 string t = test->name;
728 i = t.find_last_not_of(
"0123456789") + 1;
729 if (i != string::npos) {
731 if (m.find(t) != m.end()) do_this_test =
true;
735 out <<
"Running test: " << test->name <<
"...";
740 auto test_duration = chrono::duration_cast<chrono::duration<double>>
741 (endtime - starttime);
752 test_duration.count());
770 throw "Test failed - aborting further tests";
777 throw "Test marked as XFAIL passed - aborting further tests";
794 cout <<
"Usage: " <<
argv0 <<
" [-v|--verbose] [-o|--abort-on-error] "
796 " " <<
argv0 <<
" [-h|--help]\n";
817 cout <<
argv0 <<
" " << desc <<
": ";
829 <<
" expected failures passed";
833 <<
" expected failures";
843 const char* sep =
"Slow tests: ";
845 cout << sep << test.first <<
" (" << test.second <<
" s)";
871 if (RUNNING_ON_VALGRIND) {
872 if (getenv(
"XAPIAN_TESTSUITE_VALGRIND") != NULL) {
874 string fname =
".valgrind.log." +
str(getpid());
875 vg_log_fd =
open(fname.c_str(), O_RDONLY|O_NONBLOCK|
O_CLOEXEC);
876 if (vg_log_fd != -1) unlink(fname.c_str());
883 bool colourise =
true;
884 const char *
p = getenv(
"XAPIAN_TESTSUITE_OUTPUT");
885 if (
p == NULL || !*
p || strcmp(
p,
"auto") == 0) {
886 colourise = isatty(1);
887 }
else if (strcmp(
p,
"plain") == 0) {
907 string short_opts_string =
"voh";
908 map<int, string *>::const_iterator i;
910 short_opts_string += char(i->first);
911 short_opts_string +=
':';
913 const char *
opts = short_opts_string.c_str();
927 i->second->assign(
optarg);
938 const char *
p = getenv(
"VERBOSE");
942 throw "VERBOSE must be a non-negative integer";
972 if (a == b)
return true;
973 return (ceil(log10(max(fabs(a), fabs(b)))) - log10(fabs(a - b)) > DBL_DIG);
Base class for backend handling in test harness.
virtual void clean_up()
Called after each test, to perform any necessary cleanup.
const std::string & get_message() const
Class which is thrown when a test case fails.
Class which is thrown when a test case is to be skipped.
All exceptions thrown by Xapian are subclasses of Xapian::Error.
const char * get_error_string() const
Returns any system error string associated with this exception.
const char * get_type() const noexcept
The type of this error (e.g. "DocNotFoundError".)
std::string get_description() const
Return a string describing this object.
The test driver. This class takes care of running the tests.
static std::string col_yellow
static bool abort_on_error
static void report(const test_driver::result &r, const std::string &desc)
Print summary of tests passed, failed, and skipped.
static std::string col_green
static std::vector< std::string > test_names
test_result runtest(const test_desc *test)
Runs the test function and returns its result.
static std::string col_red
static std::string col_reset
static std::string opt_help
result run_tests()
Run all the tests supplied and return the results.
static void parse_command_line(int argc, char **argv)
Parse the command line arguments.
static std::string get_srcdir()
Read srcdir from environment and if not present, make a valiant attempt to guess a value.
test_driver(const test_desc *tests_)
The constructor, which sets up the test driver.
static int run(const test_desc *tests)
static void add_command_line_option(const std::string &l, char s, std::string *arg)
Add a test-specific command line option.
result do_run_tests(std::vector< std::string >::const_iterator b, std::vector< std::string >::const_iterator e)
The implementation used by run_tests.
static std::map< int, std::string * > short_opts
void write_and_clear_tout()
Write out anything in tout and clear it.
void errno_to_string(int e, string &s)
Convert errno value to std::string, thread-safe if possible.
Hierarchy of classes which Xapian can throw as exceptions.
Track leaked file descriptors.
Utility functions for testing files.
bool file_exists(const char *path)
Test if a file exists.
Wrappers to allow GNU getopt to be used cleanly from C++ code.
int gnu_getopt_long(int argc_, char *const *argv_, const char *shortopts_, const struct option *longopts_, int *optind_)
static const test_desc tests[]
The lists of tests to perform.
double now()
Return the current time.
string str(int value)
Convert int to std::string.
Database open(std::string_view host, unsigned int port, unsigned timeout=10000, unsigned connect_timeout=10000)
Construct a Database object for read-only access to a remote database accessed via a TCP connection.
Parse signed and unsigned type from string and check for trailing characters.
bool parse_unsigned(const char *p, T &res)
include <fcntl.h>, but working around broken platforms.
<unistd.h>, but with compat.
Convert types to std::string.
Various handy string-related helpers.
bool endswith(std::string_view s, char sfx)
bool startswith(std::string_view s, char pfx)
Structure holding a description of a test.
const char * name
The name of the test.
void(* run)()
The function to run to perform the test.
A structure used to report the summary of tests passed and failed.
unsigned int failed
The number of tests which failed.
unsigned int skipped
The number of tests which were skipped.
unsigned int xfailed
Number of tests with result XFAIL.
unsigned int xpassed
Number of tests with result XFAIL.
unsigned int succeeded
The number of tests which succeeded.
BackendManager * backendmanager
backendmanager is global so that it can be accessed by individual tests.
Run multiple tests for different backends.
static void report_totals(void)
int verbose
The global verbose flag.
const char * expected_failure
Set to a string explanation for testcases expected to fail.
static const double SLOW_TEST_THRESHOLD
const char * expected_exception
The exception type we were expecting in TEST_EXCEPTION.
#define SIGLONGJMP(ENV, VAL)
bool TEST_EQUAL_DOUBLE_(double a, double b)
Helper function for TEST_EQUAL_DOUBLE macro.
static void handle_sig(int signum_)
static vector< pair< const char *, double > > slow_tests
std::ostringstream tout
The debug printing stream.
#define SIGSETJMP(ENV, SAVESIGS)
a generic test suite engine
static const struct option long_opts[]