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