/* * This is the only header included in any c test file */ #pragma once #include "kpl.h" typedef enum : int32_t { KPL_TEST_ERROR_LINE_NUMBER_INIT = -1, } kpl_test_enum; typedef struct _kpl_test kpl_test; typedef void kpl_test_fn(__attribute__((unused)) kpl_test *_test); /* * The kpl_test object is used to build a static singly linked list and a static tree * The list is for running all tests and moving failed tests to an error linked list * The tree is used for running tests by name */ typedef struct _kpl_test { KPL_TREE_HEADER(_kpl_test); int32_t error_line_number; // -1 line number for no error struct _kpl_test *list_next; const char *source_file, *name, *error_message; // static c strings only kpl_test_fn *test_fn; } kpl_test; // Per test object, lists and trees are globals void _kpl_test_add(kpl_test *_test); // do not call outside KPL_TEST macro #define _KPL_TEST_FN_DEFINITION(NAME) static void NAME(__attribute__((unused)) kpl_test *_test) /* * Each test is a static function added to the test list and tree by a static gnu constructor function * The NAME becomes the function name _NAME becomes the constructor name, only one name can be used per file */ #define KPL_TEST(NAME) _KPL_TEST_FN_DEFINITION(NAME); \ static void __attribute__((constructor)) _ ## NAME(void) { \ static kpl_test _test = { \ .tree_left = NULL, .tree_right = NULL, .tree_duplicate = NULL, \ .tree_height = KPL_TREE_TREE_HEIGHT_INIT, \ .error_line_number = KPL_TEST_ERROR_LINE_NUMBER_INIT, \ .list_next = NULL, \ .source_file = __FILE__, .name = #NAME, .error_message = NULL, \ .test_fn = NAME \ }; \ _kpl_test_add(&_test); \ } \ _KPL_TEST_FN_DEFINITION(NAME) /* * MESSAGE is a static c string, sets the error fields in a test once, aborting the rest of test * Can only be called within a KPL_TEST */ #define KPL_FAIL(MESSAGE) do { \ _test->error_line_number = __LINE__; \ _test->error_message = MESSAGE; \ return; \ } while (0) /* * CONDITION is statement evaluating to true or false, MESSAGE is a static c string, false invokes KPL_FAIL * Can only be called within KPL_TEST */ #define KPL_ASSERT(CONDITION, MESSAGE) do { \ if (!(CONDITION)) \ KPL_FAIL(#CONDITION "; " MESSAGE); \ } while (0)