42 #include "../SOURCE_TOOLS/arb_main.h"
44 #define ut_assert(cond) arb_assert(cond)
46 #if defined(DEVEL_ELMAR)
47 #define COLORED_MESSAGES
51 # if defined(DEVEL_RALF)
55 # define TEST_VALID_LOCATION
60 #ifdef COLORED_MESSAGES
62 #define ESC_BOLD "\033[1m"
63 #define ESC_RED "\033[31m"
64 #define ESC_GREEN "\033[32m"
65 #define ESC_YELLOW "\033[33m"
66 #define ESC_RESET_COL "\033[39m"
67 #define ESC_RESET_ALL "\033[0m"
106 #define TRACE_PREFIX "UnitTester: "
114 #if defined(COLORED_MESSAGES)
115 fputs(ESC_BOLD, stderr);
121 #if defined(COLORED_MESSAGES)
122 fputs(ESC_RESET_ALL, stderr);
130 #ifdef COLORED_MESSAGES
132 ESC_GREEN
"OK" ESC_RESET_COL,
133 ESC_RED
"TRAPPED" ESC_RESET_COL,
134 ESC_RED
"VIOLATED" ESC_RESET_COL,
135 ESC_RED
"INTERRUPTED" ESC_RESET_COL,
136 ESC_RED
"THREW" ESC_RESET_COL,
137 ESC_RED
"INVALID" ESC_RESET_COL,
138 ESC_RED
"{unknown}" ESC_RESET_COL,
141 static const char *readable_result[] = {
167 const char *backtrace_cause =
NULp;
172 arb_test::GlobalTestData& test_data = arb_test::test_data();
173 if (!test_data.assertion_failed) {
174 backtrace_cause =
"Caught SIGSEGV not caused by assertion";
180 backtrace_cause =
"Caught SIGINT (deadlock in test function?)";
186 backtrace_cause =
"Caught SIGTERM, cause std::terminate() has been called in test-code (might be an invalid throw)";
189 backtrace_cause =
"Caught SIGTERM (deadlock in uninterruptable test function?)";
195 test_assert(0,
true);
202 const char *signame =
NULp;
204 case SIGSEGV: signame =
"SEGV";
break;
205 case SIGINT: signame =
"INT";
break;
206 case SIGTERM: signame =
"TERM";
break;
209 fputs(
"[UnitTester catched unexpected signal ", stderr);
210 if (signame)
fputs(signame, stderr);
else fprintf(stderr,
"%i", sig);
211 fputs(
"]\n", stderr);
216 #define SECOND 1000000
251 gettimeofday((timeval*)&t1,
NULp);
253 arb_test::test_data().assertion_failed =
false;
254 arb_test::test_data().running_test =
true;
271 gettimeofday(&t2,
NULp);
272 *duration_usec = (t2.tv_sec - t1.tv_sec) *
SECOND + (t2.tv_usec - t1.tv_usec);
280 terminate_handler handler = std::set_terminate(old_terminate);
282 fputs(
"Error: test-code has modified std::terminate (this is invalid)\n", stderr);
291 int result = kill(pid, sig);
293 fprintf(stderr,
"Failed to send %s to test (%s)\n", signame, strerror(errno));
303 Flag(
const string& flagname_) : flagname(flagname_) {}
305 bool is_up()
const {
struct stat stt;
return stat(flagname.c_str(), &stt) == 0 && S_ISREG(stt.st_mode); }
307 fprintf(stderr,
"Raising flag '%s'\n", flagname.c_str());
fflush(stderr);
309 FILE *fp = fopen(flagname.c_str(),
"w");
313 fprintf(stderr,
"Lowering flag '%s'\n", flagname.c_str());
fflush(stderr);
323 return Flag(localname);
337 result = flag.
is_up();
355 long seconds = ms/1000;
356 long rest_ms = ms - seconds*1000;
362 #if (DEADLOCKGUARD == 1)
363 __ATTR__NORETURN static void deadlockguard(
long max_allowed_duration_ms,
bool detect_environment_calls) {
365 sleepms(max_allowed_duration_ms);
368 fprintf(stderr,
"[test_environment has been called. Added %li ms tolerance]\n",
MAX_EXEC_MS_ENV);
376 fprintf(stderr,
"[external calls are running valgrinded. Added %li ms tolerance]\n", additional);
379 max_allowed_duration_ms += additional;
385 "[deadlockguard woke up after %li ms]\n"
386 "[interrupting possibly deadlocked test]\n",
387 max_allowed_duration_ms);
fflush(stderr);
391 fprintf(stderr,
"[test still running -> terminate]\n");
fflush(stderr);
395 fprintf(stderr,
"[still running -> kill]\n");
fflush(stderr);
398 fprintf(stderr,
"[still alive after suicide -> perplexed]\n");
fflush(stderr);
407 pid_t child_pid = fork();
411 if (kill(child_pid, SIGKILL) != 0) {
412 fprintf(stderr,
"Failed to kill deadlock-guard (%s)\n", strerror(errno));
fflush(stderr);
416 #if (DEADLOCKGUARD == 1)
417 deadlockguard(max_allowed_duration_ms, detect_environment_calls);
419 #warning DEADLOCKGUARD has been disabled (not default!)
420 detect_environment_calls = !!detect_environment_calls;
438 UnitTestResult run_postcond(
long *duration_usec,
long max_allowed_duration_ms,
bool print_errors);
446 for (count = 0; tests[count].
fun; ++count) {}
447 for (postcount = 0; postcond[postcount].
fun; ++postcount) {}
450 size_t perform_all();
460 trace(
"performing %zu simple tests..", count);
462 for (
size_t c = 0; c<count; ++c) {
471 UnitTestResult SimpleTester::run_postcond(
long *duration_usec_sum,
long abort_after_ms,
bool print_errors) {
473 *duration_usec_sum = 0;
474 for (
size_t pc = 0; pc<postcount && result ==
TEST_OK; ++pc) {
476 result =
execute_guarded(postcond[pc].fun, &duration_usec, abort_after_ms,
true);
477 *duration_usec_sum += duration_usec;
479 if (result !=
TEST_OK && print_errors) {
480 postcond[pc].print_error(stderr, result);
492 fprintf(out,
"%s: Error: %s failed (details above)\n", location, name);
496 fprintf(out,
"%s: Error: %s succeeded, but violates general postconditions (see above)\n", location, name);
500 fprintf(out,
"%s: Error: %s has been interrupted (details above)\n", location, name);
504 fprintf(out,
"%s: Error: %s has thrown an exception\n", location, name);
508 fprintf(out,
"%s: Error: %s is invalid (see above)\n", location, name);
517 bool SimpleTester::perform(
size_t which) {
525 bool marked_as_slow = strlen(test.
name) >= 10 && memcmp(test.
name,
"TEST_SLOW_", 10) == 0;
528 #if defined(TEST_VALID_LOCATION)
531 bool invalid =
false;
536 for (
unsigned tryCount = 1; tryCount<=tryMax && result !=
TEST_OK; ++tryCount) {
539 double duration_ms_this = invalid ? 0.0 : duration_usec/1000.0;
541 duration_ms += duration_ms_this;
543 long duration_usec_post = 0;
549 if (postcond_result !=
TEST_OK) {
554 trace(
"* %s = %s (%.1f ms)", test.
name, readable_result[result], duration_ms_this);
558 if (!marked_as_slow) {
561 fprintf(stderr,
"%s: Warning: Name of slow tests shall start with TEST_SLOW_ (it'll be run after other tests)\n",
572 tryMax = arb_test::test_data().allowed_retries();
574 fprintf(stderr,
"%s: Warning: test failed, but allows %u retries\n", test.
location, tryMax-1);
586 double duration_ms_postcond = duration_usec_post/1000.0;
587 duration_ms += duration_ms_postcond;
601 inline void appendValue(
string& report,
const char *tag,
const char *value) { report = report+
' '+tag+
'='+value; }
606 static const char *
generateReport(
const char *libname,
size_t tests,
size_t skipped,
size_t passed,
double duration_ms,
size_t warnings) {
609 static string report;
612 size_t tested = tests-skipped;
613 size_t failed = tested-passed;
618 if (skipped)
appendValue(report,
"skipped", skipped);
624 if (warnings)
appendValue(report,
"warnings", warnings);
626 return report.c_str()+1;
629 const size_t Mb = 1024*1024;
636 #if !defined(LEAKS_SANITIZED) && !defined(UNDEF_SANITIZED)
638 ModRLimit restrict_virtual_memory(RLIMIT_AS, 1 * Gb);
651 arb_test::GlobalTestData& global = arb_test::test_data();
654 global.show_warnings = (warn_level != 0);
656 double duration_ms = 0;
668 tests+skippedTests, skippedTests, passed,
669 duration_ms, global.warnings));
672 arb_test::GlobalTestData::erase_instance();
SimpleTester(const UnitTest_simple *tests_, const UnitTest_simple *postcond_)
void reset_test_local_flags()
void(* UnitTest_function)()
const char * as_text(size_t z)
AliDataPtr format(AliDataPtr data, const size_t wanted_len, GB_ERROR &error)
return string(buffer, length)
const long MAX_EXEC_MS_NORMAL
#define INSTALL_SIGHANDLER(sig, handler, context)
void demangle_backtrace(const class BackTraceInfo &trace, FILE *out, const char *message)
Flag(const string &flagname_)
#define RUNNING_ON_VALGRIND
static void terminate_called()
bool did_valgrinded_syscall()
static const char * readable_result[]
const long WARN_SLOW_ABOVE_MS
Flag getLocalFlag(const char *flagname)
void setup_test_precondition()
UnitTestResult execute_guarded(UnitTest_function fun, long *duration_usec, long max_allowed_duration_ms, bool detect_environment_calls)
static __ATTR__NORETURN void UNITTEST_sigsegv_handler(int sig)
static bool terminate_was_called
static UnitTestResult execute_guarded_ClientCode(UnitTest_function fun, long *duration_usec)
void print_error(FILE *out, UnitTestResult result) const
bool seen_valgrinded_call()
bool been_inside_environment()
#define TEST_EXPECT_ZERO_OR_SHOW_ERRNO(iocond)
vfprintf(stderr, format, parg)
void ARB_sleep(int amount, TimeUnit tu)
static bool flag_callback(arb_test::FlagAction action, const char *name)
const long MAX_EXEC_MS_SLOW
double overall_duration_ms() const
fputs(TRACE_PREFIX, stderr)
static char text_buffer[100]
const long MAX_EXEC_MS_ENV
static list< LineAttachedMessage > warnings
void setup_test_postcondition()
__ATTR__FORMAT(1) static void trace(const char *format
static const char * generateReport(const char *libname, size_t tests, size_t skipped, size_t passed, double duration_ms, size_t warnings)
size_t get_test_count() const
static void start_of_main()
#define UNINSTALL_SIGHANDLER(sig, handler, old_handler, context)
void appendValue(string &report, const char *tag, const char *value)
bool dump(FILE *out, const char *message) const
const long MAX_EXEC_MS_VGSYS
UnitTester(const char *libname, const UnitTest_simple *simple_tests, int warn_level, size_t skippedTests, const UnitTest_simple *postcond) __attribute__((noreturn))
static jmp_buf UNITTEST_return_after_segv
bool kill_verbose(pid_t pid, int sig, const char *signame)