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);
243 #if defined HAVE_SIGACTION && defined SA_SIGINFO 246 sigemptyset(&sa.sa_mask);
247 sa.sa_flags = SA_RESETHAND|SA_SIGINFO;
248 sigaction(SIGSEGV, &sa, NULL);
249 sigaction(SIGFPE, &sa, NULL);
250 sigaction(SIGILL, &sa, NULL);
252 sigaction(SIGBUS, &sa, NULL);
255 sigaction(SIGSTKFLT, &sa, NULL);
271 #if defined HAVE_SIGACTION && defined SA_SIGINFO 273 sa.sa_handler = SIG_DFL;
274 sigemptyset(&sa.sa_mask);
276 sigaction(SIGSEGV, &sa, NULL);
277 sigaction(SIGFPE, &sa, NULL);
278 sigaction(SIGILL, &sa, NULL);
280 sigaction(SIGBUS, &sa, NULL);
283 sigaction(SIGSTKFLT, &sa, NULL);
286 signal(SIGSEGV, SIG_DFL);
287 signal(SIGFPE, SIG_DFL);
288 signal(SIGILL, SIG_DFL);
290 signal(SIGBUS, SIG_DFL);
293 signal(SIGSTKFLT, SIG_DFL);
311 volatile int runcount = 0;
320 static bool catch_signals =
321 (getenv(
"XAPIAN_TESTSUITE_SIG_DFL") == NULL);
328 long vg_leaks = 0, vg_dubious = 0, vg_reachable = 0;
329 if (vg_log_fd != -1) {
330 VALGRIND_DO_LEAK_CHECK;
331 vg_errs = VALGRIND_COUNT_ERRORS;
333 VALGRIND_COUNT_LEAKS(vg_leaks, vg_dubious, vg_reachable, dummy);
336 lseek(vg_log_fd, 0, SEEK_END);
347 if (vg_log_fd != -1) {
353 #define REPORT_FAIL_VG(M) do { \ 356 ssize_t c = read(vg_log_fd, buf, sizeof(buf)); \ 357 if (c == 0 || (c < 0 && errno != EINTR)) break; \ 358 if (c > 0) out << string(buf, c); \ 361 out << " " << col_red << M << col_reset; \ 365 off_t curpos = lseek(vg_log_fd, 0, SEEK_CUR);
368 ssize_t c = read(vg_log_fd, buf,
sizeof(buf));
369 if (c == 0 || (c < 0 && errno != EINTR)) {
380 spc =
static_cast<const char *
>(
381 memchr(buf + i,
' ', c - i));
391 (memcmp(buf + i,
"Warning:", 8) == 0 ||
392 memcmp(buf + i,
" ", 3) == 0)) {
396 nl =
static_cast<const char *
>(
397 memchr(buf + i,
'\n', c - i));
408 char *start = buf + i;
410 if (c > 128) c = 128;
414 p =
static_cast<const char*
>(
415 memchr(start,
'\n', c));
416 if (p != NULL) c = p - start;
419 memmove(buf, start, c);
424 lseek(vg_log_fd, curpos, SEEK_SET);
426 int vg_errs2 = VALGRIND_COUNT_ERRORS;
427 vg_errs = vg_errs2 - vg_errs;
428 VALGRIND_DO_LEAK_CHECK;
429 long vg_leaks2 = 0, vg_dubious2 = 0, vg_reachable2 = 0;
431 VALGRIND_COUNT_LEAKS(vg_leaks2, vg_dubious2, vg_reachable2,
434 vg_leaks = vg_leaks2 - vg_leaks;
435 vg_dubious = vg_dubious2 - vg_dubious;
436 vg_reachable = vg_reachable2 - vg_reachable;
438 string fail_msg(buf);
439 if (fail_msg.empty())
440 fail_msg =
"VALGRIND DETECTED A PROBLEM";
441 REPORT_FAIL_VG(fail_msg);
445 REPORT_FAIL_VG(
"LEAKED " << vg_leaks <<
" BYTES");
448 if (vg_dubious > 0) {
458 (void)fdtracker.
check();
461 REPORT_FAIL_VG(
"PROBABLY LEAKED " << vg_dubious <<
" BYTES");
464 if (vg_reachable > 0) {
482 (void)fdtracker.
check();
485 REPORT_FAIL_VG(
"FAILED TO RELEASE " << vg_reachable <<
" BYTES");
490 if (!fdtracker.
check()) {
521 if (errclass ==
"NetworkError" &&
543 }
catch (
const string & msg) {
554 }
catch (
const std::exception & e) {
563 out <<
"std::exception";
565 const char *
name =
typeid(e).
name();
566 # ifdef HAVE_CXXABI_H 570 char * realname = abi::__cxa_demangle(name, NULL, 0, &status);
584 }
catch (
const char * msg) {
593 out <<
"EXCEPTION char* " << msg;
595 out <<
"EXCEPTION (char*)NULL";
624 const char *signame =
"SIGNAL";
625 #if defined HAVE_SIGACTION && defined SA_SIGINFO 626 bool show_addr =
true;
628 bool show_addr =
false;
631 case SIGSEGV: signame =
"SIGSEGV";
break;
632 case SIGFPE: signame =
"SIGFPE";
break;
633 case SIGILL: signame =
"SIGILL";
break;
635 case SIGBUS: signame =
"SIGBUS";
break;
639 signame =
"SIGSTKFLT";
647 sprintf(buf,
" at %p",
sigaddr);
658 vector<string>::const_iterator e)
666 const vector<string> blank;
672 vector<string>::const_iterator e)
675 bool check_name = !m.empty();
680 bool do_this_test = !check_name;
681 if (!do_this_test && m.find(test->name) != m.end())
686 string t = test->name;
688 i = t.find_last_not_of(
"0123456789") + 1;
689 if (i != string::npos) {
691 if (m.find(t) != m.end()) do_this_test =
true;
695 out <<
"Running test: " << test->name <<
"...";
719 throw "Test failed - aborting further tests";
726 throw "Test marked as XFAIL passed - aborting further tests";
743 cout <<
"Usage: " <<
argv0 <<
" [-v|--verbose] [-o|--abort-on-error] " 745 " " <<
argv0 <<
" [-h|--help]\n";
766 cout <<
argv0 <<
" " << desc <<
": ";
778 <<
" expected failures passed";
782 <<
" expected failures";
810 if (RUNNING_ON_VALGRIND) {
811 if (getenv(
"XAPIAN_TESTSUITE_VALGRIND") != NULL) {
814 sprintf(fname,
".valgrind.log.%lu",
815 static_cast<unsigned long>(getpid()));
817 if (vg_log_fd != -1) unlink(fname);
824 bool colourise =
true;
825 const char *p = getenv(
"XAPIAN_TESTSUITE_OUTPUT");
826 if (p == NULL || !*p || strcmp(p,
"auto") == 0) {
827 colourise = isatty(1);
828 }
else if (strcmp(p,
"plain") == 0) {
841 static const struct option long_opts[] = {
848 string short_opts_string =
"voh";
849 map<int, string *>::const_iterator i;
851 short_opts_string += char(i->first);
852 short_opts_string +=
':';
854 const char *
opts = short_opts_string.c_str();
868 i->second->assign(
optarg);
879 const char *p = getenv(
"VERBOSE");
909 if (a == b)
return true;
910 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_)