blob: 88c1089d342ec10b495691c1fd92fc063cef4460 [file] [log] [blame]
// Copyright 2016 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#pragma once
/*
* The Unittest API.
*
* The API consists of some functions for invoking Unittest, all prefixed
* with unittest_, and some macros for registering testcases as well as
* performing tests.
*
* Sample usage:
*
* A test case runs a collection of tests like this, with
* BEGIN_TEST_CASE and END_TEST_CASE and the beginning and end of the
* function and RUN_TEST to call each individual test, as follows:
*
* BEGIN_TEST_CASE(foo_tests);
*
* RUN_TEST(test_foo);
* RUN_TEST(test_bar);
* RUN_TEST(test_baz);
*
* END_TEST_CASE(foo_tests);
*
* This creates a static function foo_tests() and registers it with the
* unit test framework. foo_tests() can be executed either by a shell
* command or by a call to run_all_tests(), which runs all registered
* unit tests.
*
* A test looks like this, using the BEGIN_TEST and END_TEST macros at
* the beginning and end of the test and the EXPECT_* macros to
* validate test results, as shown:
*
* static bool test_foo(void)
* {
* BEGIN_TEST;
*
* ...declare variables and do stuff...
* int foo_value = foo_func();
* ...See if the stuff produced the correct value...
* EXPECT_EQ(1, foo_value, "foo_func failed");
* ... there are EXPECT_* macros for many conditions...
* EXPECT_TRUE(foo_condition(), "condition should be true");
* EXPECT_NE(ZX_ERR_TIMED_OUT, foo_event(), "event timed out");
*
* END_TEST;
* }
*
* The main() function of the test is expected to call unittest_run_all_tests.
* By default it will run all registered tests, but it also provides an option
* for running individual tests. Run the test binary with --help for details.
*
* Test binaries may recognize their own command line options. Make sure they
* don't interfere with Unittests's options. See unittest/README.md for rules
* on argv processing. To have test-specific options included in --help
* output register a function that prints the test-specific help with
* unittest_register_test_help_printer().
*/
#include <stdarg.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <zircon/compiler.h>
#ifdef __Fuchsia__
#include <zircon/types.h>
#define UNITTEST_CRASH_HANDLER_SUPPORTED
#endif // __Fuchsia__
// The following helper function makes the "msg" argument optional in
// C++, so that you can write either of the following:
// ASSERT_EQ(x, y, "Check that x equals y");
// ASSERT_EQ(x, y);
// (We could allow the latter in C by making unittest_get_message() a
// var-args function, but that would be less type safe.)
static inline const char* unittest_get_message(const char* arg) {
return arg;
}
#ifdef __cplusplus
static inline const char* unittest_get_message() {
return "<no message>";
}
#endif
// A workaround to help static analyzer identify assertion failures
#if defined(__clang__)
#define ZX_ANALYZER_CREATE_SINK __attribute__((annotate("zx_create_sink")))
#else
#define ZX_ANALYZER_CREATE_SINK //no-op
#endif
// This function will help terminate the static analyzer when it reaches
// an assertion failure site which returns from test case function. The bugs
// discovered by the static analyzer will be suppressed as they are expected
// by the test cases.
static inline void unittest_returns_early(void) ZX_ANALYZER_CREATE_SINK {}
__BEGIN_CDECLS
extern int utest_verbosity_level;
typedef enum test_type {
TEST_SMALL = 0x00000001,
TEST_MEDIUM = 0x00000002,
TEST_LARGE = 0x00000004,
TEST_PERFORMANCE = 0x00000008,
TEST_ALL = 0xFFFFFFFF,
} test_type_t;
#define TEST_ENV_NAME "RUNTESTS_TEST_CLASS"
#define TEST_DEFAULT (TEST_SMALL | TEST_MEDIUM)
extern test_type_t utest_test_type;
// An environment variable may be used to specify the timeout.
// An env var is used because runtests doesn't make assumptions about what
// arguments we understand.
#define WATCHDOG_ENV_NAME "RUNTESTS_WATCHDOG_TIMEOUT"
/*
* Type for unit test result Output
*/
typedef void (*test_output_func)(const char* line, int len, void* arg);
/*
* Printf dedicated to the unittest library
* the default output is the printf
*/
void unittest_printf_critical(const char* format, ...)
__attribute__((format (printf, 1, 2)));
/*
* Printf dedicated to the unittest library, prints output if
* verbosity of any level is enabled.
*/
#define unittest_printf(format, ...) \
do { \
if (utest_verbosity_level > 0) \
unittest_printf_critical(format, ##__VA_ARGS__); \
} while (0)
/*
* Printf dedicated to the unittest library which output
* depends on the verbosity level.
*/
#define unittest_level_printf(level, format, ...) \
do { \
if (utest_verbosity_level >= (level)) \
unittest_printf_critical(format, ##__VA_ARGS__); \
} while (0)
/*
* Function to set the callback for printing
* the unit test output
*/
void unittest_set_output_function(test_output_func fun, void* arg);
/*
* Function to restore output callback to
* default_printf.
*/
void unittest_restore_output_function(void);
/*
* Function to set the verbosity level. This affects
* the output of unittest_printf().
*/
int unittest_set_verbosity_level(int new_level);
#define UNITTEST_FAIL_TRACEF_FORMAT " [FAILED]\n %s:%d:%s:\n "
/*
* Format the error string
*/
#define UNITTEST_FAIL_TRACEF(str, x...) \
do { \
unittest_printf_critical( \
UNITTEST_FAIL_TRACEF_FORMAT str, \
__FILE__, __LINE__, __PRETTY_FUNCTION__, ##x); \
} while (0)
/*
* Format a tracing message
*/
#define UNITTEST_TRACEF(level, str, x...) \
do { \
if (utest_verbosity_level >= (level)) { \
unittest_printf_critical( \
"%s:%d:%s:\n " str, \
__FILE__, __LINE__, __PRETTY_FUNCTION__, ##x); \
} \
} while (0)
/*
* Internal-only.
* Used by macros to check that the test state is set up correctly.
*/
#define UT_ASSERT_VALID_TEST_STATE \
do { \
if (current_test_info == NULL) { \
unittest_printf_critical( \
"FATAL: %s:%d:%s: Invalid state for EXPECT/ASSERT: " \
"possible missing BEGIN_TEST or BEGIN_HELPER\n", \
__FILE__, __LINE__, __PRETTY_FUNCTION__); \
exit(101); /* Arbitrary, atypical exit status */ \
} \
} while (0)
/*
* BEGIN_TEST_CASE and END_TEST_CASE define a function that calls RUN_TEST. The
* test_name parameter specifies an optional test name to run. If null, all
* tests will be run.
*/
#define BEGIN_TEST_CASE(case_name) \
bool case_name(bool list_only, const char* test_name_matching) { \
bool all_success = true; \
if (list_only) { \
unittest_printf_critical("\nCASE %s\n", #case_name); \
} else { \
unittest_printf_critical("\nCASE %-50s [STARTED] \n", \
#case_name); \
}
#define DEFINE_REGISTER_TEST_CASE(case_name) \
__attribute__((constructor)) static void _register_##case_name(void) { \
unittest_register_test_case(&_##case_name##_element); \
}
#define END_TEST_CASE(case_name) \
if (list_only) { \
unittest_printf_critical("CASE %s\n", #case_name); \
} else if (all_success) { \
unittest_printf_critical("CASE %-50s [PASSED]\n", #case_name); \
} else { \
unittest_printf_critical("CASE %-50s [FAILED]\n", #case_name); \
} \
return all_success; \
} \
static struct test_case_element _##case_name##_element = { \
.next = NULL, \
.failed_next = NULL, \
.name = #case_name, \
.test_case = case_name, \
}; \
DEFINE_REGISTER_TEST_CASE(case_name)
#define RUN_NAMED_TEST_TYPE(name, test, test_type, enable_crash_handler) \
if (!test_name_matching || strcmp(test_name_matching, name) == 0) { \
if (list_only) { \
unittest_printf_critical(" %s\n", name); \
} else { \
unittest_run_named_test(name, test, test_type, &current_test_info, \
&all_success, enable_crash_handler); \
} \
}
#define TEST_CASE_ELEMENT(case_name) &_##case_name##_element
/*
* Test classes:
*
* Small: Isolated tests for functions and classes. These must be totally
* synchronous and single-threaded. These tests should be parallelizable;
* there shouldn't be any shared resources between them.
*
* Medium: Single-process integration tests. Ideally these are also synchronous
* and single-threaded but they might run through a large chunk of code in each
* test case, or they might use disk, making them a bit slower.
*
* Large: Multi-process (or particularly incomprehensible single-process)
* integration tests. These tests are often too flaky to run in a CQ, and we
* should try to limit how many we have.
*
* Performance: Tests which are expected to pass, but which are measured
* using other metrics (thresholds, statistical techniques) to identify
* regressions.
*/
// TODO(INTK-312): Need to fine tune these. The current values are quite
// conservative until the bots provide more appropriate values for bot
// purposes.
// TODO(ZX-2104): An alternative is to machine generate timeouts for each
// test via training runs. Taking that on will require more research.
#define DEFAULT_BASE_TIMEOUT_SECONDS 20
// Timeout scale for each of the test classes, from the base timeout.
#define TEST_TIMEOUT_FACTOR_SMALL 1
// TODO(ZX-2103): fvm-test:TestSliceAccessNonContiguousPhysical is a medium
// test that runs for 130 seconds. IWBN to make the medium timeout factor
// smaller.
#define TEST_TIMEOUT_FACTOR_MEDIUM 10
// TODO(ZX-2107): Some large tests are really large.
#define TEST_TIMEOUT_FACTOR_LARGE 100
#define TEST_TIMEOUT_FACTOR_PERFORMANCE 100
// Called by tests that for whatever reason want to disable their timeout.
// An example is really long running tests (ZX-2107).
void unittest_cancel_timeout(void);
#define RUN_TEST_SMALL(test) RUN_NAMED_TEST_TYPE(#test, test, TEST_SMALL, false)
#define RUN_TEST_MEDIUM(test) RUN_NAMED_TEST_TYPE(#test, test, TEST_MEDIUM, false)
#define RUN_TEST_LARGE(test) RUN_NAMED_TEST_TYPE(#test, test, TEST_LARGE, false)
#define RUN_TEST_PERFORMANCE(test) RUN_NAMED_TEST_TYPE(#test, test, TEST_PERFORMANCE, false)
#define RUN_NAMED_TEST_SMALL(name, test) RUN_NAMED_TEST_TYPE(name, test, TEST_SMALL, false)
#define RUN_NAMED_TEST_MEDIUM(name, test) RUN_NAMED_TEST_TYPE(name, test, TEST_MEDIUM, false)
#define RUN_NAMED_TEST_LARGE(name, test) RUN_NAMED_TEST_TYPE(name, test, TEST_LARGE, false)
#define RUN_NAMED_TEST_PERFORMANCE(name, test) RUN_NAMED_TEST_TYPE(name, test, TEST_PERFORMANCE, false)
// "RUN_TEST" implies the test is small
#define RUN_TEST(test) RUN_NAMED_TEST_TYPE(#test, test, TEST_SMALL, false)
#define RUN_NAMED_TEST(name, test) RUN_NAMED_TEST_TYPE(name, test, TEST_SMALL, false)
#ifdef UNITTEST_CRASH_HANDLER_SUPPORTED
#define RUN_TEST_ENABLE_CRASH_HANDLER(test) RUN_NAMED_TEST_TYPE(#test, test, TEST_SMALL, true)
/**
* Registers the process or thread as expected to crash. Tests utilizing this
* should be run with RUN_TEST_ENABLE_CRASH_HANDLER. If a crash occurs and
* matches a registered process or thread, it is not bubbled up to the crashlogger
* and the test continues. If any crash was registered but did not occur,
* the test fails.
* Unregistered crashes will also fail the test.
*
* A use case could be as follows:
*
* static bool test_foo_process_expected_crash(void)
* {
* BEGIN_TEST;
*
* ...create a process...
* zx_handle_t process;
* zx_handle_t vmar;
* ASSERT_EQ(zx_process_create(zx_job_default(), fooName, sizeof(fooName),
* 0, &process, &vmar),
* ZX_OK, ""));
* ...register the process as expected to crash...
* REGISTER_CRASH(process);
* ...trigger the crash...
*
* END_TEST;
* }
*/
#define REGISTER_CRASH(handle) \
unittest_register_crash(current_test_info, handle)
#endif // UNITTEST_CRASH_HANDLER_SUPPORTED
/*
* BEGIN_TEST and END_TEST go in a function that is called by RUN_TEST
* and that call the EXPECT_ macros.
*/
#define BEGIN_TEST \
do { \
UT_ASSERT_VALID_TEST_STATE; \
} while (0)
#define END_TEST \
do { \
UT_ASSERT_VALID_TEST_STATE; \
return current_test_info->all_ok; \
} while (0)
/*
* BEGIN_HELPER and END_HELPER let helper threads and files use
* the ASSERT_*,EXPECT_* macros, which require an in-scope, non-NULL
* |test_info* current_test_info|.
*
* This header file defines a static |current_test_info|, which is unlocked and
* should only be touched by the main thread; also, it is not visible to
* functions in other compilation units.
*
* Example usage:
*
* bool my_helper_in_another_file_or_thread() {
* BEGIN_HELPER;
* // Use ASSERT_* or EXPECT_*
* END_HELPER; // Returns false if any EXPECT calls failed.
* }
*/
// Intentionally shadows the global current_test_info to avoid accidentally
// leaking dangling stack pointers.
#define BEGIN_HELPER \
struct test_info _ut_helper_test_info = { .all_ok = true, .crash_list = NULL }; \
struct test_info* current_test_info = &_ut_helper_test_info; \
// By referring to _ut_helper_test_info, we guarantee that
// END_HELPER is matched with BEGIN_HELPER.
#define END_HELPER \
return _ut_helper_test_info.all_ok
#ifdef __cplusplus
#define AUTO_TYPE_VAR(type) auto
#else
#define AUTO_TYPE_VAR(type) __typeof__(type)
#endif
#define RET_FALSE do { unittest_returns_early(); return false; } while (0)
#define DONOT_RET
#define UT_CMP(op, lhs, rhs, lhs_str, rhs_str, ret, ...) \
do { \
UT_ASSERT_VALID_TEST_STATE; \
UNITTEST_TRACEF(2, "%s %s %s\n", lhs_str, #op, rhs_str); \
const AUTO_TYPE_VAR(lhs) _lhs_val = (lhs); \
const AUTO_TYPE_VAR(rhs) _rhs_val = (rhs); \
if (!(_lhs_val op _rhs_val)) { \
UNITTEST_FAIL_TRACEF( \
"%s:\n" \
" Comparison failed: %s %s %s is false\n" \
" Specifically, %lld (0x%llx) %s %lld (0x%llx) is false\n", \
unittest_get_message(__VA_ARGS__), \
lhs_str, #op, rhs_str, (long long int)_lhs_val, \
(unsigned long long)_lhs_val, \
#op, (long long int)_rhs_val, \
(unsigned long long)_rhs_val); \
current_test_info->all_ok = false; \
ret; \
} \
} while (0)
#define UT_TRUE(actual, ret, ...) \
do { \
UT_ASSERT_VALID_TEST_STATE; \
UNITTEST_TRACEF(2, "%s\n", #actual); \
if (!(actual)) { \
UNITTEST_FAIL_TRACEF("%s: %s is false\n", \
unittest_get_message(__VA_ARGS__), \
#actual); \
current_test_info->all_ok = false; \
ret; \
} \
} while (0)
#define UT_FALSE(actual, ret, ...) \
do { \
UT_ASSERT_VALID_TEST_STATE; \
UNITTEST_TRACEF(2, "!(%s)\n", #actual); \
if (actual) { \
UNITTEST_FAIL_TRACEF("%s: %s is true\n", \
unittest_get_message(__VA_ARGS__), \
#actual); \
current_test_info->all_ok = false; \
ret; \
} \
} while (0)
#define UT_NULL(actual, ret, ...) \
do { \
UT_ASSERT_VALID_TEST_STATE; \
UNITTEST_TRACEF(2, "(%s) == NULL\n", #actual); \
if (actual != NULL) { \
UNITTEST_FAIL_TRACEF("%s: %s is non-null!\n", \
unittest_get_message(__VA_ARGS__), \
#actual); \
current_test_info->all_ok = false; \
ret; \
} \
} while (0)
#define UT_NONNULL(actual, ret, ...) \
do { \
UT_ASSERT_VALID_TEST_STATE; \
UNITTEST_TRACEF(2, "(%s) != NULL\n", #actual); \
if (actual == NULL) { \
UNITTEST_FAIL_TRACEF("%s: %s is null!\n", \
unittest_get_message(__VA_ARGS__), \
#actual); \
current_test_info->all_ok = false; \
ret; \
} \
} while (0)
#define UT_BYTES_EQ(expected, actual, length, msg, ret) \
do { \
UT_ASSERT_VALID_TEST_STATE; \
UNITTEST_TRACEF(2, "bytes_eq(%s, %s, %s)\n", \
#expected, #actual, #length); \
if (!unittest_expect_bytes_eq((expected), (actual), (length), msg)) { \
current_test_info->all_ok = false; \
ret; \
} \
} while (0)
#define UT_BYTES_NE(bytes1, bytes2, length, msg, ret) \
do { \
UT_ASSERT_VALID_TEST_STATE; \
UNITTEST_TRACEF(2, "bytes_ne(%s, %s, %s)\n", \
#bytes1, #bytes2, #length); \
size_t _length = (length); \
if (!memcmp(bytes1, bytes2, _length)) { \
UNITTEST_FAIL_TRACEF( \
"%s: %s and %s are the same; " \
"expected different\n", \
msg, #bytes1, #bytes2); \
hexdump8(bytes1, _length); \
current_test_info->all_ok = false; \
ret; \
} \
} while (0)
/* Check that two strings are equal. */
#define UT_STR_EQ(str1, str2, ret, ...) \
do { \
UT_ASSERT_VALID_TEST_STATE; \
UNITTEST_TRACEF(2, "str_eq(%s, %s)\n", #str1, #str2); \
/* Note that we should not do the following here: \
* const char* str1_val = str1; \
* That does not work in C++ if str1 is string.c_str(): the \
* storage for the C string will get deallocated before the \
* string is used. Instead we must use a helper function. */ \
if (!unittest_expect_str_eq((str1), (str2), #str1, #str2, \
unittest_get_message(__VA_ARGS__), \
__FILE__, __LINE__, \
__PRETTY_FUNCTION__)) { \
current_test_info->all_ok = false; \
ret; \
} \
} while (0)
/* Check that two strings are not equal. */
#define UT_STR_NE(str1, str2, ret, ...) \
do { \
UT_ASSERT_VALID_TEST_STATE; \
UNITTEST_TRACEF(2, "str_ne(%s, %s)\n", #str1, #str2); \
if (!unittest_expect_str_ne((str1), (str2), #str1, #str2, \
unittest_get_message(__VA_ARGS__), \
__FILE__, __LINE__, \
__PRETTY_FUNCTION__)) { \
current_test_info->all_ok = false; \
ret; \
} \
} while (0)
/* Check that str1 contains str2. */
#define UT_STR_STR(str1, str2, ret, ...) \
do { \
UT_ASSERT_VALID_TEST_STATE; \
UNITTEST_TRACEF(2, "str_str(%s, %s)\n", #str1, #str2); \
/* Note that we should not do the following here: \
* const char* str1_val = str1; \
* That does not work in C++ if str1 is string.c_str(): the \
* storage for the C string will get deallocated before the \
* string is used. Instead we must use a helper function. */ \
if (!unittest_expect_str_str((str1), (str2), #str1, #str2, \
unittest_get_message(__VA_ARGS__), \
__FILE__, __LINE__, \
__PRETTY_FUNCTION__)) { \
current_test_info->all_ok = false; \
ret; \
} \
} while (0)
#define EXPECT_CMP(op, lhs, rhs, lhs_str, rhs_str, ...) \
UT_CMP(op, lhs, rhs, lhs_str, rhs_str, DONOT_RET, ##__VA_ARGS__)
/*
* Use the EXPECT_* macros to check test results.
*/
#define EXPECT_EQ(lhs, rhs, ...) EXPECT_CMP(==, lhs, rhs, #lhs, #rhs, ##__VA_ARGS__)
#define EXPECT_NE(lhs, rhs, ...) EXPECT_CMP(!=, lhs, rhs, #lhs, #rhs, ##__VA_ARGS__)
#define EXPECT_LE(lhs, rhs, ...) EXPECT_CMP(<=, lhs, rhs, #lhs, #rhs, ##__VA_ARGS__)
#define EXPECT_GE(lhs, rhs, ...) EXPECT_CMP(>=, lhs, rhs, #lhs, #rhs, ##__VA_ARGS__)
#define EXPECT_LT(lhs, rhs, ...) EXPECT_CMP(<, lhs, rhs, #lhs, #rhs, ##__VA_ARGS__)
#define EXPECT_GT(lhs, rhs, ...) EXPECT_CMP(>, lhs, rhs, #lhs, #rhs, ##__VA_ARGS__)
#define EXPECT_TRUE(actual, ...) UT_TRUE(actual, DONOT_RET, ##__VA_ARGS__)
#define EXPECT_FALSE(actual, ...) UT_FALSE(actual, DONOT_RET, ##__VA_ARGS__)
#define EXPECT_NULL(actual, ...) UT_NULL(actual, DONOT_RET, ##__VA_ARGS__)
#define EXPECT_NONNULL(actual, ...) UT_NONNULL(actual, DONOT_RET, ##__VA_ARGS__)
#define EXPECT_BYTES_EQ(expected, actual, length, msg) UT_BYTES_EQ(expected, actual, length, msg, DONOT_RET)
#define EXPECT_BYTES_NE(bytes1, bytes2, length, msg) UT_BYTES_NE(bytes1, bytes2, length, msg, DONOT_RET)
#define EXPECT_STR_EQ(str1, str2, ...) UT_STR_EQ(str1, str2, DONOT_RET, ##__VA_ARGS__)
#define EXPECT_STR_NE(str1, str2, ...) UT_STR_NE(str1, str2, DONOT_RET, ##__VA_ARGS__)
/*
* The ASSERT_* macros are similar to the EXPECT_* macros except that
* they return on failure.
*/
#define ASSERT_NOT_NULL(p) \
do { \
UT_ASSERT_VALID_TEST_STATE; \
if (!p) { \
UNITTEST_FAIL_TRACEF("ERROR: NULL pointer\n"); \
return false; \
} \
} while (0)
#define ASSERT_CMP(op, lhs, rhs, lhs_str, rhs_str, ...) \
UT_CMP(op, lhs, rhs, lhs_str, rhs_str, RET_FALSE, ##__VA_ARGS__)
#define ASSERT_EQ(lhs, rhs, ...) ASSERT_CMP(==, lhs, rhs, #lhs, #rhs, ##__VA_ARGS__)
#define ASSERT_NE(lhs, rhs, ...) ASSERT_CMP(!=, lhs, rhs, #lhs, #rhs, ##__VA_ARGS__)
#define ASSERT_LE(lhs, rhs, ...) ASSERT_CMP(<=, lhs, rhs, #lhs, #rhs, ##__VA_ARGS__)
#define ASSERT_GE(lhs, rhs, ...) ASSERT_CMP(>=, lhs, rhs, #lhs, #rhs, ##__VA_ARGS__)
#define ASSERT_LT(lhs, rhs, ...) ASSERT_CMP(<, lhs, rhs, #lhs, #rhs, ##__VA_ARGS__)
#define ASSERT_GT(lhs, rhs, ...) ASSERT_CMP(>, lhs, rhs, #lhs, #rhs, ##__VA_ARGS__)
#define ASSERT_TRUE(actual, ...) UT_TRUE(actual, RET_FALSE, ##__VA_ARGS__)
#define ASSERT_FALSE(actual, ...) UT_FALSE(actual, RET_FALSE, ##__VA_ARGS__)
#define ASSERT_NULL(actual, ...) UT_NULL(actual, RET_FALSE, ##__VA_ARGS__)
#define ASSERT_NONNULL(actual, ...) UT_NONNULL(actual, RET_FALSE, ##__VA_ARGS__)
#define ASSERT_BYTES_EQ(expected, actual, length, msg) UT_BYTES_EQ(expected, actual, length, msg, RET_FALSE)
#define ASSERT_BYTES_NE(bytes1, bytes2, length, msg) UT_BYTES_NE(bytes1, bytes2, length, msg, RET_FALSE)
#define ASSERT_STR_EQ(str1, str2, ...) UT_STR_EQ(str1, str2, RET_FALSE, ##__VA_ARGS__)
#define ASSERT_STR_NE(str1, str2, ...) UT_STR_NE(str1, str2, RET_FALSE, ##__VA_ARGS__)
#define ASSERT_STR_STR(str1, str2, ...) UT_STR_STR(str1, str2, RET_FALSE, ##__VA_ARGS__)
#ifdef UNITTEST_CRASH_HANDLER_SUPPORTED
/**
* Runs the given function in a separate thread, and fails if the function does not crash.
* This is a blocking call.
*
* static void crash(void* arg) {
* ...trigger the crash...
* }
*
* static bool test_crash(void)
* {
* BEGIN_TEST;
*
* ...construct arg...
*
* ASSERT_DEATH(crash, arg, "msg about crash");
*
* END_TEST;
* }
*/
#define ASSERT_DEATH(fn, arg, msg) ASSERT_TRUE(unittest_run_death_fn(fn, arg), msg)
#define ASSERT_NO_DEATH(fn, arg, msg) ASSERT_TRUE(unittest_run_no_death_fn(fn, arg), msg)
#endif // UNITTEST_CRASH_HANDLER_SUPPORTED
/*
* The list of test cases is made up of these elements.
*/
struct test_case_element {
struct test_case_element* next;
struct test_case_element* failed_next;
const char* name;
bool (*test_case)(bool list_only, const char* test_name_matching);
};
/* List of processes or threads which are expected to crash. */
typedef struct crash_list* crash_list_t;
/*
* Struct to store current test case info
*/
struct test_info {
bool all_ok;
crash_list_t crash_list;
};
/*
* Object which stores current test info
*/
__UNUSED static struct test_info* current_test_info;
/*
* Registers a test case with the unit test framework.
*/
void unittest_register_test_case(struct test_case_element* elem);
/*
* Runs all registered test cases.
*/
bool unittest_run_all_tests(int argc, char** argv);
/*
* Runs a single test case.
*/
bool unittest_run_one_test(struct test_case_element* elem, test_type_t type);
/*
* Register a function to print test-specific options in the output of --help.
* Only one help printer may be registered, each new call replaces any
* previously registered function.
*/
typedef void unittest_help_printer_type(FILE* output);
void unittest_register_test_help_printer(unittest_help_printer_type* func);
/*
* Returns false if expected does not equal actual and prints msg and a hexdump8
* of the input buffers.
*/
bool unittest_expect_bytes_eq(const uint8_t* expected, const uint8_t* actual, size_t len,
const char* msg);
bool 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);
bool 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);
bool 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);
/* Used to implement RUN_TEST() and other variants. */
void unittest_run_named_test(const char* name, bool (*test)(void),
test_type_t test_type,
struct test_info** current_test_info,
bool* all_success, bool enable_crash_handler);
#ifdef UNITTEST_CRASH_HANDLER_SUPPORTED
void unittest_register_crash(struct test_info* current_test_info, zx_handle_t handle);
bool unittest_run_death_fn(void (*fn_to_run)(void*), void* arg);
bool unittest_run_no_death_fn(void (*fn_to_run)(void*), void* arg);
#endif // UNITTEST_CRASH_HANDLER_SUPPORTED
__END_CDECLS