unit-tests: Implement testing framework without "check"

This commit is contained in:
Martin Willi
2013-11-06 10:30:59 +01:00
parent 56866ecf3d
commit 35e8eb93a0
5 changed files with 959 additions and 116 deletions
+240
View File
@@ -0,0 +1,240 @@
/*
* Copyright (C) 2013 Martin Willi
* Copyright (C) 2013 revosec AG
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include "test_suite.h"
#include <signal.h>
#include <unistd.h>
/**
* Failure message buf
*/
static char failure_buf[512];
/**
* Source file failure occured
*/
static const char *failure_file;
/**
* Line of source file failure occured
*/
static int failure_line;
/**
* Backtrace of failure, if any
*/
static backtrace_t *failure_backtrace;
/**
* Longjump restore point when failing
*/
sigjmp_buf test_restore_point_env;
/**
* See header.
*/
test_suite_t* test_suite_create(const char *name)
{
test_suite_t *suite;
INIT(suite,
.name = name,
.tcases = array_create(0, 0),
);
return suite;
}
/**
* See header.
*/
test_case_t* test_case_create(const char *name)
{
test_case_t *tcase;
INIT(tcase,
.name = name,
.functions = array_create(sizeof(test_function_t), 0),
.fixtures = array_create(sizeof(test_fixture_t), 0),
.timeout = TEST_FUNCTION_DEFAULT_TIMEOUT,
);
return tcase;
}
/**
* See header.
*/
void test_case_add_checked_fixture(test_case_t *tcase, test_fixture_cb_t setup,
test_fixture_cb_t teardown)
{
test_fixture_t fixture = {
.setup = setup,
.teardown = teardown,
};
array_insert(tcase->fixtures, -1, &fixture);
}
/**
* See header.
*/
void test_case_add_test_name(test_case_t *tcase, char *name,
test_function_cb_t cb, int start, int end)
{
test_function_t fun = {
.name = name,
.cb = cb,
.start = start,
.end = end,
};
array_insert(tcase->functions, -1, &fun);
}
/**
* See header.
*/
void test_case_set_timeout(test_case_t *tcase, int s)
{
tcase->timeout = s;
}
/**
* See header.
*/
void test_suite_add_case(test_suite_t *suite, test_case_t *tcase)
{
array_insert(suite->tcases, -1, tcase);
}
/**
* Let test case fail
*/
static inline void test_failure()
{
siglongjmp(test_restore_point_env, 1);
}
/**
* See header.
*/
void test_fail_vmsg(const char *file, int line, char *fmt, va_list args)
{
vsnprintf(failure_buf, sizeof(failure_buf), fmt, args);
failure_line = line;
failure_file = file;
test_failure();
}
/**
* See header.
*/
void test_fail_msg(const char *file, int line, char *fmt, ...)
{
va_list args;
va_start(args, fmt);
vsnprintf(failure_buf, sizeof(failure_buf), fmt, args);
failure_line = line;
failure_file = file;
va_end(args);
test_failure();
}
/**
* Signal handler catching critical and alarm signals
*/
static void test_sighandler(int signal)
{
char *signame;
bool old = FALSE;
switch (signal)
{
case SIGSEGV:
signame = "SIGSEGV";
break;
case SIGILL:
signame = "SIGILL";
break;
case SIGBUS:
signame = "SIGBUS";
break;
case SIGALRM:
signame = "timeout";
break;
default:
signame = "SIG";
break;
}
if (lib->leak_detective)
{
old = lib->leak_detective->set_state(lib->leak_detective, FALSE);
}
failure_backtrace = backtrace_create(3);
if (lib->leak_detective)
{
lib->leak_detective->set_state(lib->leak_detective, old);
}
test_fail_msg(NULL, 0, "%s(%d)", signame, signal);
}
/**
* See header.
*/
void test_setup_handler()
{
struct sigaction action;
action.sa_handler = test_sighandler;
action.sa_flags = 0;
sigemptyset(&action.sa_mask);
sigaction(SIGSEGV, &action, NULL);
sigaction(SIGILL, &action, NULL);
sigaction(SIGBUS, &action, NULL);
sigaction(SIGALRM, &action, NULL);
}
/**
* See header.
*/
void test_setup_timeout(int s)
{
alarm(s);
}
/**
* See header.
*/
int test_failure_get(char *msg, int len, const char **file)
{
strncpy(msg, failure_buf, len - 1);
msg[len - 1] = 0;
*file = failure_file;
return failure_line;
}
/**
* See header.
*/
backtrace_t *test_failure_backtrace()
{
backtrace_t *bt;
bt = failure_backtrace;
failure_backtrace = NULL;
return bt;
}