aboutsummaryrefslogtreecommitdiff
path: root/tests/backtrace/driver.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'tests/backtrace/driver.cxx')
-rw-r--r--tests/backtrace/driver.cxx92
1 files changed, 75 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;
}