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);
136 string::size_type i = srcdir.find_last_of(
DIR_SEPS);
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);
160 if (!
file_exists(srcdir +
'/' + srcfile +
".cc")) {
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) {
862 static const struct option long_opts[] = {
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);
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.
Convert types to std::string.
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.
string str(int value)
Convert int to std::string.
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_)