1 // Copyright 2016 The Fuchsia Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include <unittest/unittest.h>
6
7 #include <stdbool.h>
8 #include <stddef.h>
9 #include <stdint.h>
10 #include <stdio.h>
11 #include <string.h>
12 #include <sys/time.h>
13
14 #include <pretty/hexdump.h>
15
16 #include "watchdog.h"
17
18 #ifdef UNITTEST_CRASH_HANDLER_SUPPORTED
19 #include "crash-handler.h"
20 #include "crash-list.h"
21 #endif // UNITTEST_CRASH_HANDLER_SUPPORTED
22
23 // Some strings that are used for comparison purposes can be pretty long, and
24 // when printing the failure message it's important to see what the failing
25 // text is. That's why this is as large as it is.
26 #define PRINT_BUFFER_SIZE (4096)
27
28 using nsecs_t = uint64_t;
29
now()30 static nsecs_t now() {
31 #ifdef __Fuchsia__
32 return zx_clock_get_monotonic();
33 #else
34 // clock_gettime(CLOCK_MONOTONIC) would be better but may not exist on the host
35 struct timeval tv;
36 if (gettimeofday(&tv, nullptr) < 0)
37 return 0u;
38 return tv.tv_sec * 1000000000ull + tv.tv_usec * 1000ull;
39 #endif
40 }
41
42 /**
43 * \brief Default function to dump unit test results
44 *
45 * \param[in] line is the buffer to dump
46 * \param[in] len is the length of the buffer to dump
47 * \param[in] arg can be any kind of arguments needed to dump the values
48 */
default_printf(const char * line,int len,void * arg)49 static void default_printf(const char* line, int len, void* arg) {
50 fputs(line, stdout);
51 fflush(stdout);
52 }
53
54 // Default output function is the printf
55 static test_output_func out_func = default_printf;
56 // Buffer the argument to be sent to the output function
57 static void* out_func_arg = nullptr;
58
59 // Controls the behavior of unittest_printf.
60 // To override, specify v=N on the command line.
61 int utest_verbosity_level = 0;
62
63 // Controls the types of tests which are executed.
64 // Multiple test types can be "OR-ed" together to
65 // run a subset of all tests.
66 test_type_t utest_test_type = static_cast<test_type>(TEST_DEFAULT);
67
68 /**
69 * \brief Function called to dump results
70 *
71 * This function will call the out_func callback
72 */
unittest_printf_critical(const char * format,...)73 void unittest_printf_critical(const char* format, ...) {
74 static char print_buffer[PRINT_BUFFER_SIZE];
75
76 va_list argp;
77 va_start(argp, format);
78
79 if (out_func) {
80 // Format the string
81 vsnprintf(print_buffer, PRINT_BUFFER_SIZE, format, argp);
82 out_func(print_buffer, PRINT_BUFFER_SIZE, out_func_arg);
83 }
84
85 va_end(argp);
86 }
87
unittest_expect_bytes_eq(const uint8_t * expected,const uint8_t * actual,size_t len,const char * msg)88 bool unittest_expect_bytes_eq(const uint8_t* expected, const uint8_t* actual, size_t len,
89 const char* msg) {
90 if (memcmp(expected, actual, len)) {
91 printf("%s. expected\n", msg);
92 hexdump8(expected, len);
93 printf("actual\n");
94 hexdump8(actual, len);
95 return false;
96 }
97 return true;
98 }
99
unittest_expect_str_eq(const char * str1_value,const char * str2_value,const char * str1_expr,const char * str2_expr,const char * msg,const char * source_filename,int source_line_num,const char * source_function)100 bool unittest_expect_str_eq(const char* str1_value, const char* str2_value,
101 const char* str1_expr, const char* str2_expr,
102 const char* msg,
103 const char* source_filename, int source_line_num,
104 const char* source_function) {
105 if (strcmp(str1_value, str2_value)) {
106 unittest_printf_critical(
107 UNITTEST_FAIL_TRACEF_FORMAT
108 "%s:\n"
109 " Comparison failed: strings not equal:\n"
110 " String 1 expression: %s\n"
111 " String 2 expression: %s\n"
112 " String 1 value: \"%s\"\n"
113 " String 2 value: \"%s\"\n",
114 source_filename, source_line_num, source_function,
115 msg, str1_expr, str2_expr, str1_value, str2_value);
116 return false;
117 }
118 return true;
119 }
120
unittest_expect_str_ne(const char * str1_value,const char * str2_value,const char * str1_expr,const char * str2_expr,const char * msg,const char * source_filename,int source_line_num,const char * source_function)121 bool unittest_expect_str_ne(const char* str1_value, const char* str2_value,
122 const char* str1_expr, const char* str2_expr,
123 const char* msg,
124 const char* source_filename, int source_line_num,
125 const char* source_function) {
126 if (!strcmp(str1_value, str2_value)) {
127 unittest_printf_critical(
128 UNITTEST_FAIL_TRACEF_FORMAT
129 "%s:\n"
130 " Comparison failed: strings are equal,"
131 " but expected different strings:\n"
132 " String 1 expression: %s\n"
133 " String 2 expression: %s\n"
134 " Value of both strings: \"%s\"\n",
135 source_filename, source_line_num, source_function,
136 msg, str1_expr, str2_expr, str1_value);
137 return false;
138 }
139 return true;
140 }
141
unittest_expect_str_str(const char * str1_value,const char * str2_value,const char * str1_expr,const char * str2_expr,const char * msg,const char * source_filename,int source_line_num,const char * source_function)142 bool unittest_expect_str_str(const char* str1_value, const char* str2_value,
143 const char* str1_expr, const char* str2_expr,
144 const char* msg,
145 const char* source_filename, int source_line_num,
146 const char* source_function) {
147 if (!strstr(str1_value, str2_value)) {
148 unittest_printf_critical(
149 UNITTEST_FAIL_TRACEF_FORMAT
150 "%s:\n"
151 " Comparison failed: String 1 does not"
152 " contain String 2:\n"
153 " String 1 expression: %s\n"
154 " String 2 expression: %s\n"
155 " Value of both strings: \"%s\"\n",
156 source_filename, source_line_num, source_function,
157 msg, str1_expr, str2_expr, str1_value);
158 return false;
159 }
160 return true;
161 }
162
unittest_set_output_function(test_output_func fun,void * arg)163 void unittest_set_output_function(test_output_func fun, void* arg) {
164 out_func = fun;
165 out_func_arg = arg;
166 }
167
unittest_restore_output_function()168 void unittest_restore_output_function() {
169 out_func = default_printf;
170 out_func_arg = nullptr;
171 }
172
unittest_set_verbosity_level(int new_level)173 int unittest_set_verbosity_level(int new_level) {
174 int out = utest_verbosity_level;
175 utest_verbosity_level = new_level;
176 return out;
177 }
178
179 #ifdef UNITTEST_CRASH_HANDLER_SUPPORTED
unittest_register_crash(struct test_info * current_test_info,zx_handle_t handle)180 void unittest_register_crash(struct test_info* current_test_info, zx_handle_t handle) {
181 crash_list_register(current_test_info->crash_list, handle);
182 }
183
unittest_run_death_fn(void (* fn_to_run)(void *),void * arg)184 bool unittest_run_death_fn(void (*fn_to_run)(void*), void* arg) {
185 test_result_t test_result;
186 zx_status_t status = run_fn_with_crash_handler(fn_to_run, arg, &test_result);
187 return status == ZX_OK && test_result == TEST_CRASHED;
188 }
189
unittest_run_no_death_fn(void (* fn_to_run)(void *),void * arg)190 bool unittest_run_no_death_fn(void (*fn_to_run)(void*), void* arg) {
191 test_result_t test_result;
192 zx_status_t status = run_fn_with_crash_handler(fn_to_run, arg, &test_result);
193 return status == ZX_OK && test_result != TEST_CRASHED;
194 }
195 #endif // UNITTEST_CRASH_HANDLER_SUPPORTED
196
unittest_run_test(const char * name,bool (* test)(),struct test_info ** current_test_info,bool * all_success,bool enable_crash_handler)197 static void unittest_run_test(const char* name,
198 bool (*test)(),
199 struct test_info** current_test_info,
200 bool* all_success,
201 bool enable_crash_handler) {
202 unittest_printf_critical(" %-51s [RUNNING]", name);
203 nsecs_t start_time = now();
204 test_info test_info = {.all_ok = true, nullptr};
205 *current_test_info = &test_info;
206 // The crash handler is disabled by default. To enable, the test should
207 // be run with RUN_TEST_ENABLE_CRASH_HANDLER.
208 if (enable_crash_handler) {
209 #ifdef UNITTEST_CRASH_HANDLER_SUPPORTED
210 test_info.crash_list = crash_list_new();
211
212 test_result_t test_result;
213 zx_status_t status =
214 run_test_with_crash_handler(test_info.crash_list, test, &test_result);
215 if (status != ZX_OK || test_result == TEST_FAILED) {
216 test_info.all_ok = false;
217 }
218
219 // Check if there were any processes registered to crash but didn't.
220 bool missing_crash = crash_list_delete(test_info.crash_list);
221 if (missing_crash) {
222 // TODO: display which expected crash did not occur.
223 UNITTEST_FAIL_TRACEF("Expected crash did not occur\n");
224 test_info.all_ok = false;
225 }
226 #else // UNITTEST_CRASH_HANDLER_SUPPORTED
227 UNITTEST_FAIL_TRACEF("Crash tests not supported\n");
228 test_info.all_ok = false;
229 #endif // UNITTEST_CRASH_HANDLER_SUPPORTED
230 } else if (!test()) {
231 test_info.all_ok = false;
232 }
233
234 // Recheck all_ok in case there was a failure in a C++ destructor
235 // after the "return" statement in END_TEST.
236 if (!test_info.all_ok) {
237 *all_success = false;
238 }
239
240 nsecs_t end_time = now();
241 uint64_t time_taken_ms = (end_time - start_time) / 1000000;
242 unittest_printf_critical(" [%s] (%d ms)\n", test_info.all_ok ? "PASSED" : "FAILED",
243 static_cast<int>(time_taken_ms));
244
245 *current_test_info = nullptr;
246 }
247
248 template <typename F>
run_with_watchdog(test_type_t test_type,const char * name,F fn)249 void run_with_watchdog(test_type_t test_type, const char* name, F fn) {
250 if (watchdog_is_enabled()) {
251 watchdog_start(test_type, name);
252 fn();
253 watchdog_cancel();
254 } else {
255 fn();
256 }
257 }
258
unittest_run_named_test(const char * name,bool (* test)(),test_type_t test_type,struct test_info ** current_test_info,bool * all_success,bool enable_crash_handler)259 void unittest_run_named_test(const char* name, bool (*test)(), test_type_t test_type,
260 struct test_info** current_test_info, bool* all_success,
261 bool enable_crash_handler) {
262 if (utest_test_type & test_type) {
263 run_with_watchdog(test_type, name, [&]() {
264 unittest_run_test(name, test, current_test_info, all_success, enable_crash_handler);
265 });
266 } else {
267 unittest_printf_critical(" %-51s [IGNORED]\n", name);
268 }
269 }
270
unittest_cancel_timeout(void)271 void unittest_cancel_timeout(void) {
272 watchdog_cancel();
273 }
274