aboutsummaryrefslogtreecommitdiff
path: root/include/kpl_test.h
blob: 70a99b20e9043b40362e5f4244a8b488f0e4e900 (plain)
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_duplicates = 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)