embox

Форк
0
186 строк · 4.6 Кб
1
/**
2
 * @file
3
 * @brief Test suite invocation and runtime support.
4
 *
5
 * @date 04.12.08
6
 * @author Anton Bondarev
7
 *         - Initial implementation
8
 * @author Eldar Abusalimov
9
 *         - Separating from tests registry code
10
 *         - Test fixtures and assertions support
11
 */
12

13
#include <assert.h>
14
#include <errno.h>
15
#include <setjmp.h>
16
#include <stddef.h>
17
#include <stdint.h>
18
#include <string.h>
19

20
#include <framework/test/api.h>
21
#include <framework/test/assert.h>
22
#include <framework/test/emit.h>
23
#include <kernel/panic.h>
24
#include <util/location.h>
25
#include <util/log.h>
26

27
/**
28
 * Runtime context for a test case.
29
 */
30
struct test_run_context {
31
	jmp_buf before_run;
32
	struct test_emit_buffer emitting;
33
};
34

35
static struct test_run_context *current;
36

37
#define EMIT_BUFFER_SZ 64
38

39
static char emit_buffer[EMIT_BUFFER_SZ];
40

41
static int test_case_run(const struct test_case *test_case,
42
    const struct __test_fixture_ops *fixtures);
43
static const struct __test_assertion_point *test_run(test_case_run_t run);
44

45
static void handle_suite_fixture_failure(const struct test_suite *, int code,
46
    int setup);
47
static void handle_suite_result(const struct test_suite *, int failures,
48
    int total);
49

50
static void handle_case_fixture_failure(const struct test_case *, int code,
51
    int setup);
52
static void handle_case_result(const struct test_case *,
53
    const struct __test_assertion_point *failure);
54

55
int test_suite_run(const struct test_suite *test) {
56
	const struct test_case *test_case;
57
	const struct __test_fixture_ops *fixture_ops;
58
	__test_fixture_op_t fx_op;
59
	int failures = 0, total = 0;
60
	int ret;
61

62
	if (!test) {
63
		return -EINVAL;
64
	}
65

66
	fixture_ops = &test->suite_fixture_ops;
67

68
	log_info("running %s.%s", test_package(test), test_name(test));
69

70
	if ((fx_op = *fixture_ops->p_setup) && (ret = fx_op()) != 0) {
71
		handle_suite_fixture_failure(test, ret, 1);
72
		return -EINTR;
73
	}
74

75
	array_spread_nullterm_foreach(test_case, test->test_cases) {
76
		if ((ret = test_case_run(test_case, &test->case_fixture_ops)) != 0) {
77
			++failures;
78
		}
79
		++total;
80
		// TODO this looks ugly.
81
		if (ret == -EINTR) {
82
			break;
83
		}
84
	}
85

86
	if ((fx_op = *fixture_ops->p_teardown) && (ret = fx_op()) != 0) {
87
		handle_suite_fixture_failure(test, ret, 0);
88
		return -EINTR;
89
	}
90

91
	handle_suite_result(test, failures, total);
92

93
	return failures;
94
}
95

96
static int test_case_run(const struct test_case *test_case,
97
    const struct __test_fixture_ops *fixtures) {
98
	const struct __test_assertion_point *failure;
99
	__test_fixture_op_t fx_op;
100
	int ret;
101

102
	if ((fx_op = *fixtures->p_setup) && (ret = fx_op()) != 0) {
103
		handle_case_fixture_failure(test_case, ret, 1);
104
		return -EINTR;
105
	}
106

107
	failure = test_run(test_case->run);
108

109
	if ((fx_op = *fixtures->p_teardown) && (ret = fx_op()) != 0) {
110
		handle_case_fixture_failure(test_case, ret, 0);
111
		return -EINTR;
112
	}
113

114
	handle_case_result(test_case, failure);
115

116
	return !!failure;
117
}
118

119
static const struct __test_assertion_point *test_run(test_case_run_t run) {
120
	struct test_run_context ctx;
121
	int caught;
122

123
	current = &ctx;
124
	test_emit_buffer_init(&current->emitting, emit_buffer, EMIT_BUFFER_SZ);
125
	if (!(caught = setjmp(ctx.before_run))) {
126
		run();
127
	}
128
	current = NULL;
129

130
	return (const struct __test_assertion_point *)(uintptr_t)caught;
131
}
132

133
struct test_emit_buffer *__test_emit_buffer_current(void) {
134
	assert(current != NULL);
135
	return &current->emitting;
136
}
137

138
void __test_assertion_handle(int pass,
139
    const struct __test_assertion_point *point) {
140
	if (pass) {
141
		return;
142
	}
143

144
	assert(point);
145

146
	if (current) {
147
		longjmp(current->before_run, (intptr_t)point);
148
	}
149
	else {
150
		handle_case_result(NULL, point);
151
		panic("\ntest_assert failed inside fixture\n");
152
	}
153
}
154

155
static void handle_suite_fixture_failure(const struct test_suite *test_suite,
156
    int code, int setup) {
157
	log_error("suite fixture %s failed with code %d: %s",
158
	    setup ? "setup" : "tear down", code, strerror(-code));
159
}
160

161
static void handle_suite_result(const struct test_suite *test_suite,
162
    int failures, int total) {
163
	if (failures > 0) {
164
		log_error("testing \"%s\": %d/%d failures", test_suite->description,
165
		    failures, total);
166
	}
167
}
168

169
static void handle_case_fixture_failure(const struct test_case *test_case,
170
    int code, int setup) {
171
	log_error("case fixture %s failed with code %d: %s",
172
	    setup ? "setup" : "tear down", code, strerror(-code));
173
}
174

175
static void handle_case_result(const struct test_case *test_case,
176
    const struct __test_assertion_point *failure) {
177
	const struct location __attribute__((unused)) * test_loc;
178
	const struct location_func __attribute__((unused)) * fail_loc;
179

180
	if (!failure) {
181
		return;
182
	}
183

184
	fail_loc = &failure->location;
185
	log_error("failure at %s:%d", fail_loc->at.file, fail_loc->at.line);
186
}
187

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.