blob: 10aa164e111d45682a3dd6b0971b0ec98029c655 [file] [log] [blame] [edit]
#ifndef UTEST_UTEST_H
#define UTEST_UTEST_H
/*
* Header file with infrastructure needed for userspace unit tests:
* - Assertion functions.
* - Test structures.
* - Launcher functions for test suites.
*/
#include <malloc.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <timing.h>
#include <execinfo.h>
/*
* Macros for assertions.
*/
#define UT_ASSERT(test) \
UT_ASSERT_M("", test)
#define UT_ASSERT_M(message, test) \
do { \
if (!(test)) { \
char fmt[] = "Assertion failure in %s() at %s:%d: %s"; \
sprintf(utest_msg, fmt, __FUNCTION__, __FILE__, __LINE__, message); \
return false; \
} \
} while (0)
/*
* Structs and macros for registering test cases.
*/
struct utest {
char name[256]; // Name of the test function.
bool (*func)(void); // Name of the test function, should be equal to 'name'.
bool enabled; // Whether or not to run the test.
};
/* Used for defining an userspace test structure entry inline. */
#define UTEST_REG(name) \
{"test_" #name, test_##name, true}
/*
* Creates all the runnable code for a test suite.
*/
#define TEST_SUITE(__suite_name) \
char utest_msg[1024]; \
char suite_name[] = __suite_name;
#define RUN_TEST_SUITE(utests, num_utests, whitelist, whitelist_len) \
do { \
if (whitelist_len > 0) \
apply_whitelist(whitelist, whitelist_len, utests, num_utests); \
run_utests(suite_name, utests, num_utests); \
} while (0)
/* Disables all the tests not passed through a whitelist. */
static void apply_whitelist(char *whitelist[], int whitelist_len,
struct utest tests[], int num_tests) {
for (int i=0; i<num_tests; i++) {
struct utest *test = &tests[i];
if (test->enabled) {
for (int j = 0; j < whitelist_len; ++j) {
test->enabled = false;
if (strcmp(test->name, whitelist[j]) == 0) {
test->enabled = true;
break;
}
}
}
}
}
static int run_utests(char *suite_name, struct utest tests[], int num_tests) {
extern char utest_msg[];
printf("<-- BEGIN_USERSPACE_%s_TESTS -->\n", suite_name);
for (int i=0; i<num_tests; i++) {
struct utest *test = &tests[i];
if (test->enabled) {
uint64_t start = read_tsc();
bool result = test->func();
uint64_t end = read_tsc();
uint64_t et_us = tsc2usec(end - start) % 1000000;
uint64_t et_s = tsc2sec(end - start);
char fmt[] = "\t%s [%s](%llu.%06llus) %s\n";
if (result) {
printf(fmt, "PASSED", test->name, et_s, et_us, "");
} else {
printf(fmt, "FAILED", test->name, et_s, et_us, utest_msg);
}
} else {
printf("\tDISABLED [%s]\n", test->name);
}
}
printf("<-- END_USERSPACE_%s_TESTS -->\n", suite_name);
}
#endif // UTEST_UTEST_H