1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
|
/*
* 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)
|