Add an assert for UTEST that takes a format string
[akaros.git] / user / utest / include / utest.h
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, ...)                                               \
26         do {                                                                         \
27                 if (!(test)) {                                                           \
28                         char fmt[] = "Assertion failure in %s() at %s:%d: %s";               \
29                         sprintf(utest_msg, fmt, __FUNCTION__, __FILE__, __LINE__, message);  \
30                         __VA_ARGS__;                                                         \
31                         return false;                                                        \
32                 }                                                                        \
33         } while (0)
34
35
36 /* If 'test' fails, Sets an assert message, which can be a format string, and
37  * returns false. */
38 #define UT_ASSERT_FMT(message, test, ...)                                      \
39         do {                                                                       \
40                 if (!(test)) {                                                         \
41                         char fmt[] = "Assertion failure in %s() at %s:%d: " #message;      \
42                         sprintf(utest_msg, fmt, __func__, __FILE__, __LINE__,              \
43                                 ##__VA_ARGS__);                                            \
44                         return false;                                                      \
45                 }                                                                      \
46         } while (0)
47
48 /*
49  * Structs and macros for registering test cases.
50  */
51 struct utest {
52         char name[256]; // Name of the test function.
53         bool (*func)(void); // Name of the test function, should be equal to 'name'.
54         bool enabled; // Whether or not to run the test.
55 };
56
57 /* Used for defining an userspace test structure entry inline. */
58 #define UTEST_REG(name) \
59         {"test_" #name, test_##name, true}
60
61 /*
62  * Creates all the runnable code for a test suite.
63  */
64 #define TEST_SUITE(__suite_name)                                                 \
65         char utest_msg[1024];                                                        \
66         char suite_name[] = __suite_name;
67
68 #define RUN_TEST_SUITE(utests, num_utests, whitelist, whitelist_len)             \
69         do {                                                                         \
70                 if (whitelist_len > 0)                                                   \
71                         apply_whitelist(whitelist, whitelist_len, utests, num_utests);       \
72                 run_utests(suite_name, utests, num_utests);                              \
73         } while (0)
74
75 /* Disables all the tests not passed through a whitelist. */
76 static void apply_whitelist(char *whitelist[], int whitelist_len,
77                                 struct utest tests[], int num_tests) {
78         for (int i=0; i<num_tests; i++) {
79                 struct utest *test = &tests[i];
80                 if (test->enabled) {
81                         for (int j = 0; j < whitelist_len; ++j) {
82                                 test->enabled = false;
83                                 if (strcmp(test->name, whitelist[j]) == 0) {
84                                         test->enabled = true;
85                                         break;
86                                 }
87                         }
88                 }
89         }
90 }
91
92 static int run_utests(char *suite_name, struct utest tests[], int num_tests) {
93         extern char utest_msg[];
94         printf("<-- BEGIN_USERSPACE_%s_TESTS -->\n", suite_name);
95
96         for (int i=0; i<num_tests; i++) {
97                 struct utest *test = &tests[i];
98                 if (test->enabled) {
99                         uint64_t start = read_tsc();
100                         bool result = test->func();
101                         uint64_t end = read_tsc();
102                         uint64_t et_us = tsc2usec(end - start) % 1000000;
103                         uint64_t et_s = tsc2sec(end - start);
104
105                         char fmt[] = "\t%s   [%s](%llu.%06llus)   %s\n";
106                         if (result) {
107                                 printf(fmt, "PASSED", test->name, et_s, et_us, "");
108                         } else {
109                                 printf(fmt, "FAILED", test->name, et_s, et_us, utest_msg);
110                         }
111                 } else {
112                         printf("\tDISABLED [%s]\n", test->name);
113                 }
114         }
115
116         printf("<-- END_USERSPACE_%s_TESTS -->\n", suite_name);
117 }
118
119 __END_DECLS