diff options
Diffstat (limited to 'tests')
-rw-r--r-- | tests/backtrace/driver.cxx | 92 | ||||
-rw-r--r-- | tests/backtrace/testscript | 8 |
2 files changed, 83 insertions, 17 deletions
diff --git a/tests/backtrace/driver.cxx b/tests/backtrace/driver.cxx index 5fd9223..33967cd 100644 --- a/tests/backtrace/driver.cxx +++ b/tests/backtrace/driver.cxx @@ -24,9 +24,11 @@ import std.io; import std.core; #endif import butl.process; +import butl.fdstream; import butl.backtrace; #else #include <libbutl/process.mxx> +#include <libbutl/fdstream.mxx> #include <libbutl/backtrace.mxx> #endif @@ -46,31 +48,55 @@ namespace test static terminate_handler def_term_handler; -// Usage: argv[0] [-c] +// Usages: // -// Print the backtrace for an unhandled exception. +// argv[0] [-q] +// argv[0] -c [-b] +// +// In the first form run the child processes throwing unhandled exception, +// first of which sets up the backtrace-printing handler prior to throwing, +// and make sure that they terminate in the same way (abnormally or with the +// same exit status). Exit with the zero code if that's the case and the +// children terminated abnormally or with non-zero code and exit with the one +// code otherwise. Redirect stderr to /dev/null for the first child if +// requested (-q) and always for the second one. +// +// In the second form run as a child process that optionally sets up the +// backtrace-printing terminate handler (-b) and throws unhandled exception. // -// -c -// Run as a child process that sets up the backtrace-printing terminate -// handler and throws unhandled exception. int main (int argc, const char* argv[]) { - // Not to cause the testscript to fail due to the abnormal test driver - // termination, delegate the unhandled exception backtrace printing to the - // child process. - // bool child (false); + bool backtrace (false); + bool quiet (false); + for (int i (1); i != argc; ++i) { string o (argv[i]); if (o == "-c") + { child = true; + } + else if (o == "-b") + { + assert (child); + backtrace = true; + } + else if (o == "-q") + { + assert (!child); + quiet = true; + } else + { assert (false); + } } + // Run as a child. + // if (child) { // Disable dumping core file on POSIX. @@ -80,18 +106,50 @@ main (int argc, const char* argv[]) assert (setrlimit (RLIMIT_CORE, &rlim) == 0); #endif - def_term_handler = set_terminate ([]() - { - cerr << backtrace (); + if (backtrace) + { + def_term_handler = set_terminate ([]() + { + cerr << butl::backtrace (); - if (def_term_handler != nullptr) - def_term_handler (); - }); + if (def_term_handler != nullptr) + def_term_handler (); + }); + } return test::func (); } - // Report failure with non-zero code if child succeeds. + // Run as a parent. // - return process_run (0, 1, 2, argv[0], "-c") ? 1 : 0; + auto_fd null (fdnull ()); + process_exit pe1 (process_run (0 /* stdin */, + 1 /* stdout */, + quiet ? null.get () : 2 /* stderr */, + argv[0], "-c", "-b")); + + if (pe1) + { + cerr << "error: child exited with zero code" << endl; + return 1; + } + + // Always run quiet. + // + process_exit pe2 (process_run (0 /* stdin */, + 1 /* stdout */, + null /* stderr */, + argv[0], "-c")); + + if (!(pe1.normal () == pe2.normal () && + (!pe1.normal () || pe1.code () == pe2.code ()))) + { + cerr << "error: child processes terminated differently:" << endl << + " info: with backtrace: " << pe1 << endl << + " info: without backtrace: " << pe2 << endl; + + return 1; + } + + return 0; } diff --git a/tests/backtrace/testscript b/tests/backtrace/testscript index bdcd147..df1b7a1 100644 --- a/tests/backtrace/testscript +++ b/tests/backtrace/testscript @@ -18,3 +18,11 @@ if ($tclass == 'linux' || $tclass == 'macos' || $tsys == 'freebsd') %.* EOE } +else +{ + # On OSes where backtrace() is not supported we just check that setting the + # terminate handler doesn't change the way a process terminates on the + # unhandled exception (see driver.cxx for details). + # + $* -q +} |