37 # include <valgrind/memcheck.h> 38 # include <sys/types.h> 81 static int vg_log_fd = -1;
84 #if HAVE_DECL_SIGSETJMP && HAVE_DECL_SIGLONGJMP 85 # define SIGSETJMP(ENV, SAVESIGS) sigsetjmp(ENV, SAVESIGS) 86 # define SIGLONGJMP(ENV, VAL) siglongjmp(ENV, VAL) 87 # define SIGJMP_BUF sigjmp_buf 89 # define SIGSETJMP(ENV, SAVESIGS) setjmp(ENV) 90 # define SIGLONGJMP(ENV, VAL) longjmp(ENV, VAL) 91 # define SIGJMP_BUF jmp_buf 120 const string & s =
tout.str();
130 char *p = getenv(
"srcdir");
131 if (p != NULL)
return string(p);
135 string::size_type i = srcdir.find_last_of(
DIR_SEPS);
137 if (i != string::npos) {
138 srcfile.assign(srcdir, i + 1, string::npos);
142 if (srcdir.substr(i + 1) ==
".libs") {
145 if (
startswith(srcfile,
"lt-")) srcfile.erase(0, 3);
156 if (
endswith(srcfile,
".exe")) srcfile.resize(srcfile.size() - 4);
159 if (!
file_exists(srcdir +
'/' + srcfile +
".cc")) {
161 <<
": srcdir is not in the environment and I can't guess it!\n" 162 "Run test programs using the runtest script - see HACKING " 170 : out(cout.rdbuf()),
tests(tests_)
182 #if defined HAVE_SIGACTION && defined SA_SIGINFO 183 XAPIAN_NORETURN(
static void handle_sig(
int signum_, siginfo_t *si,
void *));
184 static void handle_sig(
int signum_, siginfo_t *si,
void *)
189 sa.sa_handler = SIG_DFL;
190 sigemptyset(&sa.sa_mask);
194 if (signum_ != SIGSEGV) sigaction(SIGSEGV, &sa, NULL);
195 if (signum_ != SIGFPE) sigaction(SIGFPE, &sa, NULL);
196 if (signum_ != SIGILL) sigaction(SIGILL, &sa, NULL);
198 if (signum_ != SIGBUS) sigaction(SIGBUS, &sa, NULL);
201 if (signum_ != SIGSTKFLT) sigaction(SIGSTKFLT, &sa, NULL);
210 XAPIAN_NORETURN(
static void handle_sig(
int signum_));
215 signal(SIGSEGV, SIG_DFL);
216 signal(SIGFPE, SIG_DFL);
217 signal(SIGILL, SIG_DFL);
219 signal(SIGBUS, SIG_DFL);
222 signal(SIGSTKFLT, SIG_DFL);
241 #if defined HAVE_SIGACTION && defined SA_SIGINFO 244 sigemptyset(&sa.sa_mask);
245 sa.sa_flags = SA_RESETHAND|SA_SIGINFO;
246 sigaction(SIGSEGV, &sa, NULL);
247 sigaction(SIGFPE, &sa, NULL);
248 sigaction(SIGILL, &sa, NULL);
250 sigaction(SIGBUS, &sa, NULL);
253 sigaction(SIGSTKFLT, &sa, NULL);
269 #if defined HAVE_SIGACTION && defined SA_SIGINFO 271 sa.sa_handler = SIG_DFL;
272 sigemptyset(&sa.sa_mask);
274 sigaction(SIGSEGV, &sa, NULL);
275 sigaction(SIGFPE, &sa, NULL);
276 sigaction(SIGILL, &sa, NULL);
278 sigaction(SIGBUS, &sa, NULL);
281 sigaction(SIGSTKFLT, &sa, NULL);
284 signal(SIGSEGV, SIG_DFL);
285 signal(SIGFPE, SIG_DFL);
286 signal(SIGILL, SIG_DFL);
288 signal(SIGBUS, SIG_DFL);
291 signal(SIGSTKFLT, SIG_DFL);
309 volatile int runcount = 0;
318 static bool catch_signals =
319 (getenv(
"XAPIAN_TESTSUITE_SIG_DFL") == NULL);
326 long vg_leaks = 0, vg_dubious = 0, vg_reachable = 0;
327 if (vg_log_fd != -1) {
328 VALGRIND_DO_LEAK_CHECK;
329 vg_errs = VALGRIND_COUNT_ERRORS;
331 VALGRIND_COUNT_LEAKS(vg_leaks, vg_dubious, vg_reachable, dummy);
334 lseek(vg_log_fd, 0, SEEK_END);
345 if (vg_log_fd != -1) {
351 #define REPORT_FAIL_VG(M) do { \ 354 ssize_t c = read(vg_log_fd, buf, sizeof(buf)); \ 355 if (c == 0 || (c < 0 && errno != EINTR)) break; \ 356 if (c > 0) out << string(buf, c); \ 359 out << " " << col_red << M << col_reset; \ 363 off_t curpos = lseek(vg_log_fd, 0, SEEK_CUR);
366 ssize_t c = read(vg_log_fd, buf,
sizeof(buf));
367 if (c == 0 || (c < 0 && errno != EINTR)) {
378 spc =
static_cast<const char *
>(
379 memchr(buf + i,
' ', c - i));
389 (memcmp(buf + i,
"Warning:", 8) == 0 ||
390 memcmp(buf + i,
" ", 3) == 0)) {
394 nl =
static_cast<const char *
>(
395 memchr(buf + i,
'\n', c - i));
406 char *start = buf + i;
408 if (c > 128) c = 128;
412 p =
static_cast<const char*
>(
413 memchr(start,
'\n', c));
414 if (p != NULL) c = p - start;
417 memmove(buf, start, c);
422 lseek(vg_log_fd, curpos, SEEK_SET);
424 int vg_errs2 = VALGRIND_COUNT_ERRORS;
425 vg_errs = vg_errs2 - vg_errs;
426 VALGRIND_DO_LEAK_CHECK;
427 long vg_leaks2 = 0, vg_dubious2 = 0, vg_reachable2 = 0;
429 VALGRIND_COUNT_LEAKS(vg_leaks2, vg_dubious2, vg_reachable2,
432 vg_leaks = vg_leaks2 - vg_leaks;
433 vg_dubious = vg_dubious2 - vg_dubious;
434 vg_reachable = vg_reachable2 - vg_reachable;
436 string fail_msg(buf);
437 if (fail_msg.empty())
438 fail_msg =
"VALGRIND DETECTED A PROBLEM";
439 REPORT_FAIL_VG(fail_msg);
443 REPORT_FAIL_VG(
"LEAKED " << vg_leaks <<
" BYTES");
446 if (vg_dubious > 0) {
456 (void)fdtracker.
check();
459 REPORT_FAIL_VG(
"PROBABLY LEAKED " << vg_dubious <<
" BYTES");
462 if (vg_reachable > 0) {
480 (void)fdtracker.
check();
483 REPORT_FAIL_VG(
"FAILED TO RELEASE " << vg_reachable <<
" BYTES");
488 if (!fdtracker.
check()) {
519 if (errclass ==
"NetworkError" &&
541 }
catch (
const string & msg) {
552 }
catch (
const std::exception & e) {
561 out <<
"std::exception";
563 const char *
name =
typeid(e).
name();
564 # ifdef HAVE_CXXABI_H 568 char * realname = abi::__cxa_demangle(name, NULL, 0, &status);
582 }
catch (
const char * msg) {
591 out <<
"EXCEPTION char* " << msg;
593 out <<
"EXCEPTION (char*)NULL";
622 const char *signame =
"SIGNAL";
623 bool show_addr =
true;
625 case SIGSEGV: signame =
"SIGSEGV";
break;
626 case SIGFPE: signame =
"SIGFPE";
break;
627 case SIGILL: signame =
"SIGILL";
break;
629 case SIGBUS: signame =
"SIGBUS";
break;
633 signame =
"SIGSTKFLT";
641 sprintf(buf,
" at %p",
sigaddr);
652 vector<string>::const_iterator e)
660 const vector<string> blank;
666 vector<string>::const_iterator e)
669 bool check_name = !m.empty();
674 bool do_this_test = !check_name;
675 if (!do_this_test && m.find(test->name) != m.end())
680 string t = test->name;
682 i = t.find_last_not_of(
"0123456789") + 1;
683 if (i != string::npos) {
685 if (m.find(t) != m.end()) do_this_test =
true;
689 out <<
"Running test: " << test->name <<
"...";
713 throw "Test failed - aborting further tests";
720 throw "Test marked as XFAIL passed - aborting further tests";
737 cout <<
"Usage: " <<
argv0 <<
" [-v|--verbose] [-o|--abort-on-error] " 739 " " <<
argv0 <<
" [-h|--help]\n";
760 cout <<
argv0 <<
" " << desc <<
": ";
772 <<
" expected failures passed";
776 <<
" expected failures";
804 if (RUNNING_ON_VALGRIND) {
805 if (getenv(
"XAPIAN_TESTSUITE_VALGRIND") != NULL) {
808 sprintf(fname,
".valgrind.log.%lu",
809 static_cast<unsigned long>(getpid()));
811 if (vg_log_fd != -1) unlink(fname);
818 bool colourise =
true;
819 const char *p = getenv(
"XAPIAN_TESTSUITE_OUTPUT");
820 if (p == NULL || !*p || strcmp(p,
"auto") == 0) {
821 colourise = isatty(1);
822 }
else if (strcmp(p,
"plain") == 0) {
835 static const struct option long_opts[] = {
842 string short_opts_string =
"voh";
843 map<int, string *>::const_iterator i;
845 short_opts_string += char(i->first);
846 short_opts_string +=
':';
848 const char *
opts = short_opts_string.c_str();
862 i->second->assign(
optarg);
873 const char *p = getenv(
"VERBOSE");
903 if (a == b)
return true;
904 return (ceil(log10(max(fabs(a), fabs(b)))) - log10(fabs(a - b)) > DBL_DIG);
bool endswith(const std::string &s, char sfx)
Define the XAPIAN_NORETURN macro.
Run multiple tests for different backends.
Wrappers to allow GNU getopt to be used cleanly from C++ code.
result run_tests()
Run all the tests supplied and return the results.
unsigned int xfailed
Number of tests with result XFAIL.
static std::string col_yellow
Class which is thrown when a test case fails.
int gnu_getopt_long(int argc_, char *const *argv_, const char *shortopts_, const struct option *longopts_, int *optind_)
static void parse_command_line(int argc, char **argv)
Parse the command line arguments.
test_result runtest(const test_desc *test)
Runs the test function and returns its result.
static void report_totals(void)
unsigned int xpassed
Number of tests with result XFAIL.
Track leaked file descriptors.
static void report(const test_driver::result &r, const std::string &desc)
Print summary of tests passed, failed, and skipped.
static std::map< int, std::string * > short_opts
Convert errno value to std::string, thread-safe if possible.
a generic test suite engine
WritableDatabase open()
Construct a WritableDatabase object for a new, empty InMemory database.
result do_run_tests(std::vector< std::string >::const_iterator b, std::vector< std::string >::const_iterator e)
The implementation used by run_tests.
Utility functions for testing files.
const char * get_type() const
The type of this error (e.g. "DocNotFoundError".)
static std::string col_green
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 void add_command_line_option(const std::string &l, char s, std::string *arg)
Add a test-specific command line option.
Hierarchy of classes which Xapian can throw as exceptions.
Base class for backend handling in test harness.
static std::string col_reset
std::ostringstream tout
The debug printing stream.
void errno_to_string(int e, string &s)
unsigned int succeeded
The number of tests which succeeded.
const char * expected_failure
Set to a string explanation for testcases expected to fail.
unsigned int failed
The number of tests which failed.
BackendManager * backendmanager
backendmanager is global so that it can be accessed by individual tests.
bool startswith(const std::string &s, char pfx)
static const test_desc tests[]
The lists of tests to perform.
bool TEST_EQUAL_DOUBLE_(double a, double b)
Helper function for TEST_EQUAL_DOUBLE macro.
static std::string opt_help
static std::vector< std::string > test_names
virtual void clean_up()
Called after each test, to perform any necessary cleanup.
std::string get_description() const
Return a string describing this object.
#define SIGSETJMP(ENV, SAVESIGS)
static bool abort_on_error
const std::string & get_message() const
void write_and_clear_tout()
Write out anything in tout and clear it.
const char * get_error_string() const
Returns any system error string associated with this exception.
#define SIGLONGJMP(ENV, VAL)
All exceptions thrown by Xapian are subclasses of Xapian::Error.
void(* run)()
The function to run to perform the test.
static std::string col_red
Various handy helpers which std::string really should provide.
static int run(const test_desc *tests)
<unistd.h>, but with compat.
int verbose
The global verbose flag.
A structure used to report the summary of tests passed and failed.
const char * expected_exception
The exception type we were expecting in TEST_EXCEPTION.
Structure holding a description of a test.
The test driver. This class takes care of running the tests.
const char * name
The name of the test.
bool file_exists(const char *path)
Test if a file exists.
unsigned int skipped
The number of tests which were skipped.
include <fcntl.h>, but working around broken platforms.
Class which is thrown when a test case is to be skipped.
static void handle_sig(int signum_)