source: mainline/uspace/lib/pcut/src/run.c@ 9b20126

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 9b20126 was 9b20126, checked in by Vojtech Horky <vojtechhorky@…>, 11 years ago

Update PCUT to newest version

  • Property mode set to 100644
File size: 7.2 KB
Line 
1/*
2 * Copyright (c) 2012-2013 Vojtech Horky
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @file
30 *
31 * Test execution routines.
32 */
33
34#include "internal.h"
35#ifndef PCUT_NO_LONG_JUMP
36#include <setjmp.h>
37#endif
38
39#ifndef PCUT_NO_LONG_JUMP
40/** Long-jump buffer. */
41static jmp_buf start_test_jump;
42#endif
43
44/** Whether to run a tear-down function on a failure.
45 *
46 * Used to determine whether we are already in a tear-down context.
47 */
48static int execute_teardown_on_failure;
49
50/** Whether to report test result at all.
51 *
52 * Used to determine whether we are the forked or the parent process.
53 */
54static int report_test_result;
55
56/** Whether to print test error.
57 *
58 * Used to determine whether we are the forked or the parent process.
59 */
60static int print_test_error;
61
62/** Whether leaving a test means a process exit. */
63static int leave_means_exit;
64
65/** Pointer to currently running test. */
66static pcut_item_t *current_test = NULL;
67
68/** Pointer to current test suite. */
69static pcut_item_t *current_suite = NULL;
70
71/** A NULL-like suite. */
72static pcut_item_t default_suite;
73static int default_suite_initialized = 0;
74
75static void init_default_suite_when_needed() {
76 if (default_suite_initialized) {
77 return;
78 }
79 default_suite.id = -1;
80 default_suite.kind = PCUT_KIND_TESTSUITE;
81 default_suite.previous = NULL;
82 default_suite.next = NULL;
83 default_suite.name = "Default";
84 default_suite.setup_func = NULL;
85 default_suite.teardown_func = NULL;
86}
87
88/** Find the suite given test belongs to.
89 *
90 * @param it The test.
91 * @return Always a valid test suite item.
92 */
93static pcut_item_t *pcut_find_parent_suite(pcut_item_t *it) {
94 while (it != NULL) {
95 if (it->kind == PCUT_KIND_TESTSUITE) {
96 return it;
97 }
98 it = it->previous;
99 }
100 init_default_suite_when_needed();
101 return &default_suite;
102}
103
104/** Run a set-up (tear-down) function.
105 *
106 * @param func Function to run (can be NULL).
107 */
108static void run_setup_teardown(pcut_setup_func_t func) {
109 if (func != NULL) {
110 func();
111 }
112}
113
114/** Terminate current test with given outcome.
115 *
116 * @warning This function may execute a long jump or terminate
117 * current process.
118 *
119 * @param outcome Outcome of the current test.
120 */
121static void leave_test(int outcome) {
122 PCUT_DEBUG("leave_test(outcome=%d), will_exit=%s", outcome,
123 leave_means_exit ? "yes" : "no");
124 if (leave_means_exit) {
125 exit(outcome);
126 }
127
128#ifndef PCUT_NO_LONG_JUMP
129 longjmp(start_test_jump, 1);
130#endif
131}
132
133/** Process a failed assertion.
134 *
135 * @warning This function calls leave_test() and typically will not
136 * return.
137 *
138 * @param message Message describing the failure.
139 */
140void pcut_failed_assertion(const char *message) {
141 static const char *prev_message = NULL;
142 /*
143 * The assertion failed. We need to abort the current test,
144 * inform the user and perform some clean-up. That could
145 * include running the tear-down routine.
146 */
147 if (print_test_error) {
148 pcut_print_fail_message(message);
149 }
150
151 if (execute_teardown_on_failure) {
152 execute_teardown_on_failure = 0;
153 prev_message = message;
154 run_setup_teardown(current_suite->teardown_func);
155
156 /* Tear-down was okay. */
157 if (report_test_result) {
158 pcut_report_test_done(current_test, TEST_OUTCOME_FAIL,
159 message, NULL, NULL);
160 }
161 } else {
162 if (report_test_result) {
163 pcut_report_test_done(current_test, TEST_OUTCOME_FAIL,
164 prev_message, message, NULL);
165 }
166 }
167
168 prev_message = NULL;
169
170 leave_test(TEST_OUTCOME_FAIL); /* No return. */
171}
172
173/** Run a test.
174 *
175 * @param test Test to execute.
176 * @return Error status (zero means success).
177 */
178static int run_test(pcut_item_t *test) {
179 /*
180 * Set here as the returning point in case of test failure.
181 * If we get here, it means something failed during the
182 * test execution.
183 */
184#ifndef PCUT_NO_LONG_JUMP
185 int test_finished = setjmp(start_test_jump);
186 if (test_finished) {
187 return 1;
188 }
189#endif
190
191 if (report_test_result) {
192 pcut_report_test_start(test);
193 }
194
195 current_suite = pcut_find_parent_suite(test);
196 current_test = test;
197
198 pcut_hook_before_test(test);
199
200 /*
201 * If anything goes wrong, execute the tear-down function
202 * as well.
203 */
204 execute_teardown_on_failure = 1;
205
206 /*
207 * Run the set-up function.
208 */
209 run_setup_teardown(current_suite->setup_func);
210
211 /*
212 * The setup function was performed, it is time to run
213 * the actual test.
214 */
215 test->test_func();
216
217 /*
218 * Finally, run the tear-down function. We need to clear
219 * the flag to prevent endless loop.
220 */
221 execute_teardown_on_failure = 0;
222 run_setup_teardown(current_suite->teardown_func);
223
224 /*
225 * If we got here, it means everything went well with
226 * this test.
227 */
228 if (report_test_result) {
229 pcut_report_test_done(current_test, TEST_OUTCOME_PASS,
230 NULL, NULL, NULL);
231 }
232
233 return 0;
234}
235
236/** Run a test in a forked mode.
237 *
238 * Forked mode means that the caller of the test is already a new
239 * process running this test only.
240 *
241 * @param test Test to execute.
242 * @return Error status (zero means success).
243 */
244int pcut_run_test_forked(pcut_item_t *test) {
245 int rc;
246
247 report_test_result = 0;
248 print_test_error = 1;
249 leave_means_exit = 1;
250
251 rc = run_test(test);
252
253 current_test = NULL;
254 current_suite = NULL;
255
256 return rc;
257}
258
259/** Run a test in a single mode.
260 *
261 * Single mode means that the test is called in the context of the
262 * parent process, that is no new process is forked.
263 *
264 * @param test Test to execute.
265 * @return Error status (zero means success).
266 */
267int pcut_run_test_single(pcut_item_t *test) {
268 int rc;
269
270 report_test_result = 1;
271 print_test_error = 0;
272 leave_means_exit = 0;
273
274 rc = run_test(test);
275
276 current_test = NULL;
277 current_suite = NULL;
278
279 return rc;
280}
281
282/** Tells time-out length for a given test.
283 *
284 * @param test Test for which the time-out is questioned.
285 * @return Timeout in seconds.
286 */
287int pcut_get_test_timeout(pcut_item_t *test) {
288 int timeout = PCUT_DEFAULT_TEST_TIMEOUT;
289 pcut_extra_t *extras = test->extras;
290
291
292 while (extras->type != PCUT_EXTRA_LAST) {
293 if (extras->type == PCUT_EXTRA_TIMEOUT) {
294 timeout = extras->timeout;
295 }
296 extras++;
297 }
298
299 return timeout;
300}
Note: See TracBrowser for help on using the repository browser.