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