source: mainline/uspace/lib/pcut/src/run.c@ 2752620b

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 2752620b was 9eb1ff5, checked in by Vojtech Horky <vojtech.horky@…>, 8 years ago

Update PCUT

Updated PCUT to commit 7ce059f.

Notable changes include:

  • overall summary is printed when tests finish
  • when tests passed, the status message does not use the word 'failure'
  • program exit code is zero only when all tests passed

These changes fixes tickets 713 and 714.

http://www.helenos.org/ticket/713
http://www.helenos.org/ticket/714

  • Property mode set to 100644
File size: 7.2 KB
RevLine 
[01579ad]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. */
[9b20126]72static pcut_item_t default_suite;
73static int default_suite_initialized = 0;
74
[9eb1ff5]75static void init_default_suite_when_needed() {
76 if (default_suite_initialized) {
[9b20126]77 return;
[9eb1ff5]78 }
[9b20126]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}
[01579ad]87
88/** Find the suite given test belongs to.
89 *
90 * @param it The test.
91 * @return Always a valid test suite item.
92 */
[9eb1ff5]93static pcut_item_t *pcut_find_parent_suite(pcut_item_t *it) {
[01579ad]94 while (it != NULL) {
[9eb1ff5]95 if (it->kind == PCUT_KIND_TESTSUITE) {
[01579ad]96 return it;
[9eb1ff5]97 }
[01579ad]98 it = it->previous;
99 }
[9b20126]100 init_default_suite_when_needed();
[01579ad]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 */
[9eb1ff5]108static void run_setup_teardown(pcut_setup_func_t func) {
109 if (func != NULL) {
[01579ad]110 func();
[9eb1ff5]111 }
[01579ad]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 */
[9eb1ff5]121static void leave_test(int outcome) {
[9b20126]122 PCUT_DEBUG("leave_test(outcome=%d), will_exit=%s", outcome,
[9eb1ff5]123 leave_means_exit ? "yes" : "no");
124 if (leave_means_exit) {
[01579ad]125 exit(outcome);
[9eb1ff5]126 }
127
[01579ad]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 */
[9eb1ff5]140void pcut_failed_assertion(const char *message) {
[01579ad]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 */
[9eb1ff5]147 if (print_test_error) {
[01579ad]148 pcut_print_fail_message(message);
[9eb1ff5]149 }
150
[01579ad]151 if (execute_teardown_on_failure) {
152 execute_teardown_on_failure = 0;
153 prev_message = message;
[9b20126]154 run_setup_teardown(current_suite->teardown_func);
[9eb1ff5]155
[01579ad]156 /* Tear-down was okay. */
157 if (report_test_result) {
[9eb1ff5]158 pcut_report_test_done(current_test, PCUT_OUTCOME_FAIL,
[01579ad]159 message, NULL, NULL);
160 }
161 } else {
162 if (report_test_result) {
[9eb1ff5]163 pcut_report_test_done(current_test, PCUT_OUTCOME_FAIL,
[01579ad]164 prev_message, message, NULL);
165 }
166 }
[9eb1ff5]167
[01579ad]168 prev_message = NULL;
[9eb1ff5]169
170 leave_test(PCUT_OUTCOME_FAIL); /* No return. */
[01579ad]171}
172
173/** Run a test.
174 *
175 * @param test Test to execute.
176 * @return Error status (zero means success).
177 */
[9eb1ff5]178static int run_test(pcut_item_t *test) {
[01579ad]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);
[9eb1ff5]186 if (test_finished) {
187 return PCUT_OUTCOME_FAIL;
188 }
[01579ad]189#endif
[9eb1ff5]190
191 if (report_test_result) {
[01579ad]192 pcut_report_test_start(test);
[9eb1ff5]193 }
194
[01579ad]195 current_suite = pcut_find_parent_suite(test);
196 current_test = test;
[9eb1ff5]197
[9b20126]198 pcut_hook_before_test(test);
[9eb1ff5]199
[01579ad]200 /*
201 * If anything goes wrong, execute the tear-down function
202 * as well.
203 */
204 execute_teardown_on_failure = 1;
[9eb1ff5]205
[01579ad]206 /*
207 * Run the set-up function.
208 */
[9b20126]209 run_setup_teardown(current_suite->setup_func);
[9eb1ff5]210
[01579ad]211 /*
212 * The setup function was performed, it is time to run
213 * the actual test.
214 */
[9b20126]215 test->test_func();
[9eb1ff5]216
[01579ad]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;
[9b20126]222 run_setup_teardown(current_suite->teardown_func);
[9eb1ff5]223
[01579ad]224 /*
225 * If we got here, it means everything went well with
226 * this test.
227 */
[9eb1ff5]228 if (report_test_result) {
229 pcut_report_test_done(current_test, PCUT_OUTCOME_PASS,
230 NULL, NULL, NULL);
231 }
232
233 return PCUT_OUTCOME_PASS;
[01579ad]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 */
[9eb1ff5]244int pcut_run_test_forked(pcut_item_t *test) {
245 int rc;
246
[01579ad]247 report_test_result = 0;
248 print_test_error = 1;
249 leave_means_exit = 1;
[9eb1ff5]250
251 rc = run_test(test);
252
[01579ad]253 current_test = NULL;
254 current_suite = NULL;
[9eb1ff5]255
[01579ad]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 */
[9eb1ff5]267int pcut_run_test_single(pcut_item_t *test) {
268 int rc;
269
[01579ad]270 report_test_result = 1;
271 print_test_error = 0;
272 leave_means_exit = 0;
[9eb1ff5]273
274 rc = run_test(test);
275
[01579ad]276 current_test = NULL;
277 current_suite = NULL;
[9eb1ff5]278
[01579ad]279 return rc;
280}
281
[134ac5d]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 */
[9eb1ff5]287int pcut_get_test_timeout(pcut_item_t *test) {
[134ac5d]288 int timeout = PCUT_DEFAULT_TEST_TIMEOUT;
[9b20126]289 pcut_extra_t *extras = test->extras;
[9eb1ff5]290
291
[134ac5d]292 while (extras->type != PCUT_EXTRA_LAST) {
[9eb1ff5]293 if (extras->type == PCUT_EXTRA_TIMEOUT) {
[134ac5d]294 timeout = extras->timeout;
[9eb1ff5]295 }
[134ac5d]296 extras++;
297 }
[9eb1ff5]298
[134ac5d]299 return timeout;
300}
Note: See TracBrowser for help on using the repository browser.