source: mainline/uspace/lib/pcut/src/main.c@ 1d2f85e

Last change on this file since 1d2f85e was 08e103d4, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 7 years ago

Use clearer naming for string length functions

This and the following commit change the names of functions, as well as
their documentation, to use unambiguous terms "bytes" and "code points"
instead of ambiguous terms "size", "length", and "characters".

  • Property mode set to 100644
File size: 8.3 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 * The main control loop of the whole library.
32 */
33
34#include "internal.h"
35#include "report/report.h"
[4b54bd9]36
37#pragma warning(push, 0)
[01579ad]38#include <assert.h>
39#include <stdlib.h>
40#include <stdio.h>
[4b54bd9]41#pragma warning(pop)
42
[01579ad]43
44/** Current running mode. */
45int pcut_run_mode = PCUT_RUN_MODE_FORKING;
46
[9b20126]47/** Empty list to bypass special handling for NULL. */
48static pcut_main_extra_t empty_main_extra[] = {
49 PCUT_MAIN_EXTRA_SET_LAST
50};
51
52/** Helper for iteration over main extras. */
53#define FOR_EACH_MAIN_EXTRA(extras, it) \
54 for (it = extras; it->type != PCUT_MAIN_EXTRA_LAST; it++)
[01579ad]55
56/** Checks whether the argument is an option followed by a number.
57 *
58 * @param arg Argument from the user.
59 * @param opt Option, including the leading dashes.
60 * @param value Where to store the integer value.
61 * @return Whether @p arg is @p opt followed by a number.
62 */
[4b54bd9]63int pcut_is_arg_with_number(const char *arg, const char *opt, int *value) {
[08e103d4]64 int opt_len = pcut_str_bytes(opt);
[4b54bd9]65 if (! pcut_str_start_equals(arg, opt, opt_len)) {
[01579ad]66 return 0;
67 }
[9b20126]68 *value = pcut_str_to_int(arg + opt_len);
[01579ad]69 return 1;
70}
71
72
73/** Find item by its id.
74 *
75 * @param first List to search.
76 * @param id Id to find.
77 * @return The item with given id.
78 * @retval NULL No item with such id exists in the list.
79 */
[4b54bd9]80static pcut_item_t *pcut_find_by_id(pcut_item_t *first, int id) {
[01579ad]81 pcut_item_t *it = pcut_get_real(first);
82 while (it != NULL) {
83 if (it->id == id) {
84 return it;
85 }
86 it = pcut_get_real_next(it);
87 }
88 return NULL;
89}
90
91/** Run the whole test suite.
92 *
93 * @param suite Suite to run.
94 * @param last Pointer to first item after this suite is stored here.
95 * @param prog_path Path to the current binary (used in forked mode).
[9eb1ff5]96 * @return Error code.
[01579ad]97 */
[4b54bd9]98static int run_suite(pcut_item_t *suite, pcut_item_t **last, const char *prog_path) {
[9b20126]99 int is_first_test = 1;
100 int total_count = 0;
[9eb1ff5]101 int ret_code = PCUT_OUTCOME_PASS;
102 int ret_code_tmp;
[9b20126]103
[01579ad]104 pcut_item_t *it = pcut_get_real_next(suite);
105 if ((it == NULL) || (it->kind == PCUT_KIND_TESTSUITE)) {
106 goto leave_no_print;
107 }
108
109 for (; it != NULL; it = pcut_get_real_next(it)) {
110 if (it->kind == PCUT_KIND_TESTSUITE) {
111 goto leave_ok;
112 }
113 if (it->kind != PCUT_KIND_TEST) {
114 continue;
115 }
116
117 if (is_first_test) {
118 pcut_report_suite_start(suite);
119 is_first_test = 0;
120 }
121
122 if (pcut_run_mode == PCUT_RUN_MODE_FORKING) {
[9eb1ff5]123 ret_code_tmp = pcut_run_test_forking(prog_path, it);
[01579ad]124 } else {
[9eb1ff5]125 ret_code_tmp = pcut_run_test_single(it);
[01579ad]126 }
[9eb1ff5]127
128 /*
129 * Override final return code in case of failure.
130 *
131 * In this case we suppress any special error codes as
132 * to the outside, there was a failure.
133 */
134 if (ret_code_tmp != PCUT_OUTCOME_PASS) {
135 ret_code = PCUT_OUTCOME_FAIL;
136 }
137
[01579ad]138 total_count++;
139 }
140
141leave_ok:
142 if (total_count > 0) {
143 pcut_report_suite_done(suite);
144 }
145
146leave_no_print:
147 if (last != NULL) {
148 *last = it;
149 }
[9eb1ff5]150
151 return ret_code;
[01579ad]152}
153
154/** Add direct pointers to set-up/tear-down functions to a suites.
155 *
156 * At start-up, set-up and tear-down functions are scattered in the
157 * list as siblings of suites and tests.
158 * This puts them into the structure describing the suite itself.
159 *
160 * @param first First item of the list.
161 */
[4b54bd9]162static void set_setup_teardown_callbacks(pcut_item_t *first) {
[01579ad]163 pcut_item_t *active_suite = NULL;
[9b20126]164 pcut_item_t *it;
165 for (it = first; it != NULL; it = pcut_get_real_next(it)) {
[01579ad]166 if (it->kind == PCUT_KIND_TESTSUITE) {
167 active_suite = it;
168 } else if (it->kind == PCUT_KIND_SETUP) {
169 if (active_suite != NULL) {
[9b20126]170 active_suite->setup_func = it->setup_func;
[01579ad]171 }
172 it->kind = PCUT_KIND_SKIP;
173 } else if (it->kind == PCUT_KIND_TEARDOWN) {
174 if (active_suite != NULL) {
[9b20126]175 active_suite->teardown_func = it->teardown_func;
[01579ad]176 }
177 it->kind = PCUT_KIND_SKIP;
178 } else {
179 /* Not interesting right now. */
180 }
181 }
182}
183
184/** The main function of PCUT.
185 *
186 * This function is expected to be called as the only function in
187 * normal main().
188 *
189 * @param last Pointer to the last item defined by PCUT_TEST macros.
190 * @param argc Original argc of the program.
191 * @param argv Original argv of the program.
192 * @return Program exit code.
193 */
[4b54bd9]194int pcut_main(pcut_item_t *last, int argc, char *argv[]) {
[01579ad]195 pcut_item_t *items = pcut_fix_list_get_real_head(last);
[9b20126]196 pcut_item_t *it;
197 pcut_main_extra_t *main_extras = last->main_extras;
198 pcut_main_extra_t *main_extras_it;
[01579ad]199
200 int run_only_suite = -1;
201 int run_only_test = -1;
202
[9eb1ff5]203 int rc, rc_tmp;
204
[9b20126]205 if (main_extras == NULL) {
206 main_extras = empty_main_extra;
207 }
208
[01579ad]209 pcut_report_register_handler(&pcut_report_tap);
210
[9b20126]211 FOR_EACH_MAIN_EXTRA(main_extras, main_extras_it) {
212 if (main_extras_it->type == PCUT_MAIN_EXTRA_REPORT_XML) {
213 pcut_report_register_handler(&pcut_report_xml);
214 }
215 if (main_extras_it->type == PCUT_MAIN_EXTRA_PREINIT_HOOK) {
216 main_extras_it->preinit_hook(&argc, &argv);
217 }
218 }
219
[01579ad]220 if (argc > 1) {
221 int i;
222 for (i = 1; i < argc; i++) {
223 pcut_is_arg_with_number(argv[i], "-s", &run_only_suite);
224 pcut_is_arg_with_number(argv[i], "-t", &run_only_test);
225 if (pcut_str_equals(argv[i], "-l")) {
226 pcut_print_tests(items);
[9eb1ff5]227 return PCUT_OUTCOME_PASS;
[01579ad]228 }
229 if (pcut_str_equals(argv[i], "-x")) {
230 pcut_report_register_handler(&pcut_report_xml);
231 }
232#ifndef PCUT_NO_LONG_JUMP
233 if (pcut_str_equals(argv[i], "-u")) {
234 pcut_run_mode = PCUT_RUN_MODE_SINGLE;
235 }
236#endif
237 }
238 }
239
240 setvbuf(stdout, NULL, _IONBF, 0);
241 set_setup_teardown_callbacks(items);
242
[9b20126]243 FOR_EACH_MAIN_EXTRA(main_extras, main_extras_it) {
244 if (main_extras_it->type == PCUT_MAIN_EXTRA_INIT_HOOK) {
245 main_extras_it->init_hook();
246 }
247 }
248
[01579ad]249 PCUT_DEBUG("run_only_suite = %d run_only_test = %d", run_only_suite, run_only_test);
250
251 if ((run_only_suite >= 0) && (run_only_test >= 0)) {
252 printf("Specify either -s or -t!\n");
[9eb1ff5]253 return PCUT_OUTCOME_BAD_INVOCATION;
[01579ad]254 }
255
256 if (run_only_suite > 0) {
257 pcut_item_t *suite = pcut_find_by_id(items, run_only_suite);
258 if (suite == NULL) {
259 printf("Suite not found, aborting!\n");
[9eb1ff5]260 return PCUT_OUTCOME_BAD_INVOCATION;
[01579ad]261 }
262 if (suite->kind != PCUT_KIND_TESTSUITE) {
263 printf("Invalid suite id!\n");
[9eb1ff5]264 return PCUT_OUTCOME_BAD_INVOCATION;
[01579ad]265 }
266
267 run_suite(suite, NULL, argv[0]);
[9eb1ff5]268 return PCUT_OUTCOME_PASS;
[01579ad]269 }
270
271 if (run_only_test > 0) {
272 pcut_item_t *test = pcut_find_by_id(items, run_only_test);
273 if (test == NULL) {
274 printf("Test not found, aborting!\n");
[9eb1ff5]275 return PCUT_OUTCOME_BAD_INVOCATION;
[01579ad]276 }
277 if (test->kind != PCUT_KIND_TEST) {
278 printf("Invalid test id!\n");
[9eb1ff5]279 return PCUT_OUTCOME_BAD_INVOCATION;
[01579ad]280 }
281
282 if (pcut_run_mode == PCUT_RUN_MODE_SINGLE) {
283 rc = pcut_run_test_single(test);
284 } else {
285 rc = pcut_run_test_forked(test);
286 }
287
288 return rc;
289 }
290
291 /* Otherwise, run the whole thing. */
292 pcut_report_init(items);
293
[9eb1ff5]294 rc = PCUT_OUTCOME_PASS;
295
[9b20126]296 it = items;
[01579ad]297 while (it != NULL) {
298 if (it->kind == PCUT_KIND_TESTSUITE) {
299 pcut_item_t *tmp;
[9eb1ff5]300 rc_tmp = run_suite(it, &tmp, argv[0]);
301 if (rc_tmp != PCUT_OUTCOME_PASS) {
302 rc = rc_tmp;
303 }
[01579ad]304 it = tmp;
305 } else {
306 it = pcut_get_real_next(it);
307 }
308 }
309
310 pcut_report_done();
311
[9eb1ff5]312 return rc;
[01579ad]313}
Note: See TracBrowser for help on using the repository browser.