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