akaros/user/utest/include/utest.h
<<
>>
Prefs
   1#pragma once
   2
   3/*
   4 * Header file with infrastructure needed for userspace unit tests:
   5 *  - Assertion functions.
   6 *  - Test structures.
   7 *  - Launcher functions for test suites.
   8 */
   9
  10#include <malloc.h>
  11#include <stdbool.h>
  12#include <stdio.h>
  13#include <string.h>
  14#include <parlib/timing.h>
  15#include <execinfo.h>
  16
  17__BEGIN_DECLS
  18
  19/* 
  20 * Macros for assertions. 
  21 */
  22#define UT_ASSERT(test, ...)                                                 \
  23        UT_ASSERT_M(#test, test, __VA_ARGS__)
  24
  25#define UT_ASSERT_M(message, test, ...)                                        \
  26do {                                                                           \
  27        if (!(test)) {                                                         \
  28                char fmt[] = "Assertion failure in %s() at %s:%d: %s";         \
  29                sprintf(utest_msg, fmt, __FUNCTION__, __FILE__, __LINE__,      \
  30                        message);                                              \
  31                __VA_ARGS__;                                                   \
  32                return false;                                                  \
  33        }                                                                      \
  34} while (0)
  35
  36
  37/* If 'test' fails, Sets an assert message, which can be a format string, and
  38 * returns false. */
  39#define UT_ASSERT_FMT(message, test, ...)                                      \
  40do {                                                                           \
  41        if (!(test)) {                                                         \
  42                char fmt[] = "Assertion failure in %s() at %s:%d: " #message;  \
  43                sprintf(utest_msg, fmt, __func__, __FILE__, __LINE__,          \
  44                        ##__VA_ARGS__);                                        \
  45                return false;                                                  \
  46        }                                                                      \
  47} while (0)
  48
  49/*
  50 * Structs and macros for registering test cases.
  51 */
  52struct utest {
  53        char name[256]; // Name of the test function.
  54        bool (*func)(void); // Name of the test function, should be = to 'name'.
  55        bool enabled; // Whether or not to run the test.
  56};
  57
  58/* Used for defining an userspace test structure entry inline. */
  59#define UTEST_REG(name) \
  60        {"test_" #name, test_##name, true}
  61
  62/*
  63 * Creates all the runnable code for a test suite.
  64 */
  65#define TEST_SUITE(__suite_name)                                               \
  66        char utest_msg[1024];                                                  \
  67        char suite_name[] = __suite_name;
  68
  69#define RUN_TEST_SUITE(utests, num_utests, whitelist, whitelist_len)           \
  70do {                                                                           \
  71        if (whitelist_len > 0)                                                 \
  72                apply_whitelist(whitelist, whitelist_len, utests, num_utests); \
  73        run_utests(suite_name, utests, num_utests);                            \
  74} while (0)
  75
  76/* Disables all the tests not passed through a whitelist. */
  77static void apply_whitelist(char *whitelist[], int whitelist_len,
  78                            struct utest tests[], int num_tests)
  79{
  80        for (int i = 0; i < num_tests; i++) {
  81                struct utest *test = &tests[i];
  82
  83                if (test->enabled) {
  84                        for (int j = 0; j < whitelist_len; ++j) {
  85                                test->enabled = false;
  86                                if (strcmp(test->name, whitelist[j]) == 0) {
  87                                        test->enabled = true;
  88                                        break;
  89                                }
  90                        }
  91                }
  92        }
  93}
  94
  95static void run_utests(char *suite_name, struct utest tests[], int num_tests)
  96{
  97        extern char utest_msg[];
  98        printf("<-- BEGIN_USERSPACE_%s_TESTS -->\n", suite_name);
  99
 100        for (int i=0; i<num_tests; i++) {
 101                struct utest *test = &tests[i];
 102                if (test->enabled) {
 103                        uint64_t start = read_tsc();
 104                        bool result = test->func();
 105                        uint64_t end = read_tsc();
 106                        uint64_t et_us = tsc2usec(end - start) % 1000000;
 107                        uint64_t et_s = tsc2sec(end - start);
 108
 109                        char fmt[] = "\t%s   [%s](%llu.%06llus)   %s\n";
 110                        if (result) {
 111                                printf(fmt, "PASSED", test->name, et_s, et_us,
 112                                       "");
 113                        } else {
 114                                printf(fmt, "FAILED", test->name, et_s, et_us,
 115                                       utest_msg);
 116                        }
 117                } else {
 118                        printf("\tDISABLED [%s]\n", test->name);
 119                }
 120        }
 121
 122        printf("<-- END_USERSPACE_%s_TESTS -->\n", suite_name);
 123}
 124
 125__END_DECLS
 126