37 # include <valgrind/memcheck.h>
38 # 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
121 const string & s =
tout.str();
131 char *p = getenv(
"srcdir");
132 if (p != NULL)
return string(p);
138 if (i != string::npos) {
139 srcfile.assign(
srcdir, i + 1, string::npos);
143 if (
srcdir.substr(i + 1) ==
".libs") {
146 if (
startswith(srcfile,
"lt-")) srcfile.erase(0, 3);
157 if (
endswith(srcfile,
".exe")) srcfile.resize(srcfile.size() - 4);
162 <<
": srcdir is not in the environment and I can't guess it!\n"
163 "Run test programs using the runtest script - see HACKING "
171 : out(cout.rdbuf()),
tests(tests_)
183 #if defined HAVE_SIGACTION && defined SA_SIGINFO
184 XAPIAN_NORETURN(
static void handle_sig(
int signum_, siginfo_t *si,
void *));
185 static void handle_sig(
int signum_, siginfo_t *si,
void *)
190 sa.sa_handler = SIG_DFL;
191 sigemptyset(&sa.sa_mask);
195 if (signum_ != SIGSEGV) sigaction(SIGSEGV, &sa, NULL);
196 if (signum_ != SIGFPE) sigaction(SIGFPE, &sa, NULL);
197 if (signum_ != SIGILL) sigaction(SIGILL, &sa, NULL);
199 if (signum_ != SIGBUS) sigaction(SIGBUS, &sa, NULL);
202 if (signum_ != SIGPIPE) sigaction(SIGPIPE, &sa, NULL);
205 if (signum_ != SIGSTKFLT) sigaction(SIGSTKFLT, &sa, NULL);
214 XAPIAN_NORETURN(
static void handle_sig(
int signum_));
219 signal(SIGSEGV, SIG_DFL);
220 signal(SIGFPE, SIG_DFL);
221 signal(SIGILL, SIG_DFL);
223 signal(SIGBUS, SIG_DFL);
226 signal(SIGPIPE, SIG_DFL);
229 signal(SIGSTKFLT, SIG_DFL);
250 #if defined HAVE_SIGACTION && defined SA_SIGINFO
253 sigemptyset(&sa.sa_mask);
254 sa.sa_flags = SA_RESETHAND|SA_SIGINFO;
255 sigaction(SIGSEGV, &sa, NULL);
256 sigaction(SIGFPE, &sa, NULL);
257 sigaction(SIGILL, &sa, NULL);
259 sigaction(SIGBUS, &sa, NULL);
262 sigaction(SIGPIPE, &sa, NULL);
265 sigaction(SIGSTKFLT, &sa, NULL);
284 #if defined HAVE_SIGACTION && defined SA_SIGINFO
286 sa.sa_handler = SIG_DFL;
287 sigemptyset(&sa.sa_mask);
289 sigaction(SIGSEGV, &sa, NULL);
290 sigaction(SIGFPE, &sa, NULL);
291 sigaction(SIGILL, &sa, NULL);
293 sigaction(SIGBUS, &sa, NULL);
296 sigaction(SIGPIPE, &sa, NULL);
299 sigaction(SIGSTKFLT, &sa, NULL);
302 signal(SIGSEGV, SIG_DFL);
303 signal(SIGFPE, SIG_DFL);
304 signal(SIGILL, SIG_DFL);
306 signal(SIGBUS, SIG_DFL);
309 signal(SIGPIPE, SIG_DFL);
312 signal(SIGSTKFLT, SIG_DFL);
330 volatile int runcount = 0;
339 static bool catch_signals =
340 (getenv(
"XAPIAN_TESTSUITE_SIG_DFL") == NULL);
347 long vg_leaks = 0, vg_dubious = 0, vg_reachable = 0;
348 if (vg_log_fd != -1) {
349 VALGRIND_DO_LEAK_CHECK;
350 vg_errs = VALGRIND_COUNT_ERRORS;
352 VALGRIND_COUNT_LEAKS(vg_leaks, vg_dubious, vg_reachable,
dummy);
355 lseek(vg_log_fd, 0, SEEK_END);
366 if (vg_log_fd != -1) {
372 #define REPORT_FAIL_VG(M) do { \
375 ssize_t c = read(vg_log_fd, buf, sizeof(buf)); \
376 if (c == 0 || (c < 0 && errno != EINTR)) break; \
377 if (c > 0) out << string(buf, c); \
380 out << " " << col_red << M << col_reset; \
384 off_t curpos = lseek(vg_log_fd, 0, SEEK_CUR);
387 ssize_t c = read(vg_log_fd, buf,
sizeof(buf));
388 if (c == 0 || (c < 0 && errno != EINTR)) {
399 spc =
static_cast<const char *
>(
400 memchr(buf + i,
' ', c - i));
410 (memcmp(buf + i,
"Warning:", 8) == 0 ||
411 memcmp(buf + i,
" ", 3) == 0)) {
415 nl =
static_cast<const char *
>(
416 memchr(buf + i,
'\n', c - i));
427 char *start = buf + i;
429 if (c > 128) c = 128;
433 p =
static_cast<const char*
>(
434 memchr(start,
'\n', c));
435 if (p != NULL) c = p - start;
438 memmove(buf, start, c);
443 lseek(vg_log_fd, curpos, SEEK_SET);
445 int vg_errs2 = VALGRIND_COUNT_ERRORS;
446 vg_errs = vg_errs2 - vg_errs;
447 VALGRIND_DO_LEAK_CHECK;
448 long vg_leaks2 = 0, vg_dubious2 = 0, vg_reachable2 = 0;
450 VALGRIND_COUNT_LEAKS(vg_leaks2, vg_dubious2, vg_reachable2,
453 vg_leaks = vg_leaks2 - vg_leaks;
454 vg_dubious = vg_dubious2 - vg_dubious;
455 vg_reachable = vg_reachable2 - vg_reachable;
457 string fail_msg(buf);
458 if (fail_msg.empty())
459 fail_msg =
"VALGRIND DETECTED A PROBLEM";
460 REPORT_FAIL_VG(fail_msg);
464 REPORT_FAIL_VG(
"LEAKED " << vg_leaks <<
" BYTES");
467 if (vg_dubious > 0) {
474 runcount = runcount + 1;
477 (void)fdtracker.
check();
480 REPORT_FAIL_VG(
"PROBABLY LEAKED " << vg_dubious <<
" BYTES");
483 if (vg_reachable > 0) {
498 runcount = runcount + 1;
501 (void)fdtracker.
check();
504 REPORT_FAIL_VG(
"FAILED TO RELEASE " << vg_reachable <<
" BYTES");
509 if (!fdtracker.
check()) {
512 runcount = runcount + 1;
540 if (errclass ==
"NetworkError" &&
562 }
catch (
const string & msg) {
573 }
catch (
const std::exception & e) {
582 out <<
"std::exception";
584 const char *
name =
typeid(e).
name();
585 # ifdef HAVE_CXXABI_H
589 char * realname = abi::__cxa_demangle(
name, NULL, 0, &status);
603 }
catch (
const char * msg) {
612 out <<
"EXCEPTION char* " << msg;
614 out <<
"EXCEPTION (char*)NULL";
643 const char *signame =
"SIGNAL";
644 #if defined HAVE_SIGACTION && defined SA_SIGINFO
645 bool show_addr =
true;
647 bool show_addr =
false;
650 case SIGSEGV: signame =
"SIGSEGV";
break;
651 case SIGFPE: signame =
"SIGFPE";
break;
652 case SIGILL: signame =
"SIGILL";
break;
654 case SIGBUS: signame =
"SIGBUS";
break;
664 signame =
"SIGSTKFLT";
681 vector<string>::const_iterator e)
689 const vector<string> blank;
695 vector<string>::const_iterator e)
698 bool check_name = !m.empty();
703 bool do_this_test = !check_name;
704 if (!do_this_test && m.find(test->name) != m.end())
709 string t = test->name;
711 i = t.find_last_not_of(
"0123456789") + 1;
712 if (i != string::npos) {
714 if (m.find(t) != m.end()) do_this_test =
true;
718 out <<
"Running test: " << test->name <<
"...";
742 throw "Test failed - aborting further tests";
749 throw "Test marked as XFAIL passed - aborting further tests";
766 cout <<
"Usage: " <<
argv0 <<
" [-v|--verbose] [-o|--abort-on-error] "
768 " " <<
argv0 <<
" [-h|--help]\n";
789 cout <<
argv0 <<
" " << desc <<
": ";
801 <<
" expected failures passed";
805 <<
" expected failures";
833 if (RUNNING_ON_VALGRIND) {
834 if (getenv(
"XAPIAN_TESTSUITE_VALGRIND") != NULL) {
836 string fname =
".valgrind.log." +
str(getpid());
837 vg_log_fd =
open(fname.c_str(), O_RDONLY|O_NONBLOCK|
O_CLOEXEC);
838 if (vg_log_fd != -1) unlink(fname.c_str());
845 bool colourise =
true;
846 const char *p = getenv(
"XAPIAN_TESTSUITE_OUTPUT");
847 if (p == NULL || !*p || strcmp(p,
"auto") == 0) {
848 colourise = isatty(1);
849 }
else if (strcmp(p,
"plain") == 0) {
869 string short_opts_string =
"voh";
870 map<int, string *>::const_iterator i;
872 short_opts_string += char(i->first);
873 short_opts_string +=
':';
875 const char *
opts = short_opts_string.c_str();
889 i->second->assign(
optarg);
900 const char *p = getenv(
"VERBOSE");
930 if (a == b)
return true;
931 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_type() const
The type of this error (e.g. "DocNotFoundError".)
const char * get_error_string() const
Returns any system error string associated with this exception.
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.
WritableDatabase open()
Construct a WritableDatabase object for a new, empty InMemory database.
string str(int value)
Convert int to std::string.
Define the XAPIAN_NORETURN macro.
include <fcntl.h>, but working around broken platforms.
<unistd.h>, but with compat.
Convert types to std::string.
Various handy helpers which std::string really should provide.
bool endswith(const std::string &s, char sfx)
bool startswith(const std::string &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.
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_)
std::ostringstream tout
The debug printing stream.
#define SIGSETJMP(ENV, SAVESIGS)
a generic test suite engine
static const struct option long_opts[]