Branch data Line data Source code
1 : : /* GLib testing framework runner
2 : : * Copyright (C) 2007 Sven Herzberg
3 : : * Copyright (C) 2007 Tim Janik
4 : : *
5 : : * SPDX-License-Identifier: LGPL-2.1-or-later
6 : : *
7 : : * This library is free software; you can redistribute it and/or
8 : : * modify it under the terms of the GNU Lesser General Public
9 : : * License as published by the Free Software Foundation; either
10 : : * version 2.1 of the License, or (at your option) any later version.
11 : : *
12 : : * This library is distributed in the hope that it will be useful,
13 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 : : * Lesser General Public License for more details.
16 : : *
17 : : * You should have received a copy of the GNU Lesser General Public
18 : : * License along with this library; if not, see <http://www.gnu.org/licenses/>.
19 : : */
20 : : #include "config.h"
21 : :
22 : : #include <glib.h>
23 : : #include <glib-unix.h>
24 : : #include <gstdio.h>
25 : : #include <string.h>
26 : : #include <stdlib.h>
27 : : #include <unistd.h>
28 : : #include <fcntl.h>
29 : : #include <sys/wait.h>
30 : : #include <errno.h>
31 : : #include <signal.h>
32 : :
33 : : /* the read buffer size in bytes */
34 : : #define READ_BUFFER_SIZE 4096
35 : :
36 : : /* --- prototypes --- */
37 : : static int main_selftest (int argc,
38 : : char **argv);
39 : : static void parse_args (gint *argc_p,
40 : : gchar ***argv_p);
41 : :
42 : : /* --- variables --- */
43 : : static GIOChannel *ioc_report = NULL;
44 : : static gboolean gtester_quiet = FALSE;
45 : : static gboolean gtester_verbose = FALSE;
46 : : static gboolean gtester_list_tests = FALSE;
47 : : static gboolean gtester_selftest = FALSE;
48 : : static gboolean gtester_ignore_deprecation = FALSE;
49 : : static gboolean subtest_running = FALSE;
50 : : static gint subtest_exitstatus = 0;
51 : : static gboolean subtest_io_pending = FALSE;
52 : : static gboolean subtest_quiet = TRUE;
53 : : static gboolean subtest_verbose = FALSE;
54 : : static gboolean subtest_mode_fatal = TRUE;
55 : : static gboolean subtest_mode_perf = FALSE;
56 : : static gboolean subtest_mode_quick = TRUE;
57 : : static gboolean subtest_mode_undefined = TRUE;
58 : : static const gchar *subtest_seedstr = NULL;
59 : : static gchar *subtest_last_seed = NULL;
60 : : static GSList *subtest_paths = NULL;
61 : : static GSList *skipped_paths = NULL;
62 : : static GSList *subtest_args = NULL;
63 : : static gboolean testcase_open = FALSE;
64 : : static guint testcase_count = 0;
65 : : static guint testcase_fail_count = 0;
66 : : static const gchar *output_filename = NULL;
67 : : static guint log_indent = 0;
68 : : static gint log_fd = -1;
69 : :
70 : : /* --- functions --- */
71 : : static const char*
72 : 19 : sindent (guint n)
73 : : {
74 : : static const char spaces[] = " ";
75 : 19 : gsize l = sizeof (spaces) - 1;
76 : 19 : n = MIN (n, l);
77 : 19 : return spaces + l - n;
78 : : }
79 : :
80 : : static void G_GNUC_PRINTF (1, 2)
81 : 17 : test_log_printfe (const char *format,
82 : : ...)
83 : : {
84 : : char *result;
85 : : int r;
86 : : va_list args;
87 : 17 : va_start (args, format);
88 : 17 : result = g_markup_vprintf_escaped (format, args);
89 : 17 : va_end (args);
90 : : do
91 : 17 : r = write (log_fd, result, strlen (result));
92 : 17 : while (r < 0 && errno == EINTR);
93 : 17 : g_free (result);
94 : 17 : }
95 : :
96 : : static void
97 : 0 : terminate (void)
98 : : {
99 : 0 : kill (getpid(), SIGTERM);
100 : 0 : g_abort();
101 : : }
102 : :
103 : : static void
104 : 1 : testcase_close (long double duration,
105 : : gint exit_status,
106 : : guint n_forks)
107 : : {
108 : : gboolean success;
109 : :
110 : 1 : g_return_if_fail (testcase_open > 0);
111 : 1 : test_log_printfe ("%s<duration>%.6Lf</duration>\n", sindent (log_indent), duration);
112 : 1 : success = exit_status == G_TEST_RUN_SUCCESS || exit_status == G_TEST_RUN_SKIPPED;
113 : 1 : test_log_printfe ("%s<status exit-status=\"%d\" n-forks=\"%d\" result=\"%s\"/>\n",
114 : : sindent (log_indent), exit_status, n_forks,
115 : : success ? "success" : "failed");
116 : 1 : log_indent -= 2;
117 : 1 : test_log_printfe ("%s</testcase>\n", sindent (log_indent));
118 : 1 : testcase_open--;
119 : 1 : if (gtester_verbose)
120 : : {
121 : 0 : switch (exit_status)
122 : : {
123 : 0 : case G_TEST_RUN_SUCCESS:
124 : 0 : g_print ("OK\n");
125 : 0 : break;
126 : 0 : case G_TEST_RUN_SKIPPED:
127 : 0 : g_print ("SKIP\n");
128 : 0 : break;
129 : 0 : default:
130 : 0 : g_print ("FAIL\n");
131 : 0 : break;
132 : : }
133 : : }
134 : 1 : if (!success && subtest_last_seed)
135 : 0 : g_print ("GTester: last random seed: %s\n", subtest_last_seed);
136 : 1 : if (!success)
137 : 0 : testcase_fail_count += 1;
138 : 1 : if (subtest_mode_fatal && !success)
139 : 0 : terminate();
140 : : }
141 : :
142 : : static void
143 : 11 : test_log_msg (GTestLogMsg *msg)
144 : : {
145 : 11 : switch (msg->log_type)
146 : : {
147 : : guint i;
148 : : gchar **strv;
149 : 4 : case G_TEST_LOG_NONE:
150 : : case G_TEST_LOG_START_SUITE:
151 : : case G_TEST_LOG_STOP_SUITE:
152 : 4 : break;
153 : 0 : case G_TEST_LOG_ERROR:
154 : 0 : strv = g_strsplit (msg->strings[0], "\n", -1);
155 : 0 : for (i = 0; strv[i]; i++)
156 : 0 : test_log_printfe ("%s<error>%s</error>\n", sindent (log_indent), strv[i]);
157 : 0 : g_strfreev (strv);
158 : 0 : break;
159 : 1 : case G_TEST_LOG_START_BINARY:
160 : 1 : test_log_printfe ("%s<binary file=\"%s\"/>\n", sindent (log_indent), msg->strings[0]);
161 : 1 : subtest_last_seed = g_strdup (msg->strings[1]);
162 : 1 : test_log_printfe ("%s<random-seed>%s</random-seed>\n", sindent (log_indent), subtest_last_seed);
163 : 1 : break;
164 : 0 : case G_TEST_LOG_LIST_CASE:
165 : 0 : g_print ("%s\n", msg->strings[0]);
166 : 0 : break;
167 : 1 : case G_TEST_LOG_START_CASE:
168 : 1 : testcase_count++;
169 : 1 : if (gtester_verbose)
170 : : {
171 : 0 : gchar *sc = g_strconcat (msg->strings[0], ":", NULL);
172 : 0 : gchar *sleft = g_strdup_printf ("%-68s", sc);
173 : 0 : g_free (sc);
174 : 0 : g_print ("%70s ", sleft);
175 : 0 : g_free (sleft);
176 : : }
177 : 1 : g_return_if_fail (testcase_open == 0);
178 : 1 : testcase_open++;
179 : 1 : test_log_printfe ("%s<testcase path=\"%s\">\n", sindent (log_indent), msg->strings[0]);
180 : 1 : log_indent += 2;
181 : 1 : break;
182 : 0 : case G_TEST_LOG_SKIP_CASE:
183 : : if (FALSE && gtester_verbose) /* enable to debug test case skipping logic */
184 : : {
185 : : gchar *sc = g_strconcat (msg->strings[0], ":", NULL);
186 : : gchar *sleft = g_strdup_printf ("%-68s", sc);
187 : : g_free (sc);
188 : : g_print ("%70s SKIPPED\n", sleft);
189 : : g_free (sleft);
190 : : }
191 : 0 : test_log_printfe ("%s<testcase path=\"%s\" skipped=\"1\"/>\n", sindent (log_indent), msg->strings[0]);
192 : 0 : break;
193 : 1 : case G_TEST_LOG_STOP_CASE:
194 : 1 : testcase_close (msg->nums[2], (int) msg->nums[0], (int) msg->nums[1]);
195 : 1 : break;
196 : 0 : case G_TEST_LOG_MIN_RESULT:
197 : : case G_TEST_LOG_MAX_RESULT:
198 : 0 : test_log_printfe ("%s<performance minimize=\"%d\" maximize=\"%d\" value=\"%.16Lg\">\n",
199 : 0 : sindent (log_indent), msg->log_type == G_TEST_LOG_MIN_RESULT, msg->log_type == G_TEST_LOG_MAX_RESULT, msg->nums[0]);
200 : 0 : test_log_printfe ("%s%s\n", sindent (log_indent + 2), msg->strings[0]);
201 : 0 : test_log_printfe ("%s</performance>\n", sindent (log_indent));
202 : 0 : break;
203 : 4 : case G_TEST_LOG_MESSAGE:
204 : 4 : test_log_printfe ("%s<message>\n%s\n%s</message>\n", sindent (log_indent), msg->strings[0], sindent (log_indent));
205 : 4 : break;
206 : : }
207 : : }
208 : :
209 : : static gboolean
210 : 2 : child_report_cb (GIOChannel *source,
211 : : GIOCondition condition,
212 : : gpointer data)
213 : : {
214 : 2 : GTestLogBuffer *tlb = data;
215 : 2 : GIOStatus status = G_IO_STATUS_NORMAL;
216 : 2 : gboolean first_read_eof = FALSE, first_read = TRUE;
217 : 2 : gsize length = 0;
218 : : do
219 : : {
220 : : guint8 buffer[READ_BUFFER_SIZE];
221 : 3 : GError *error = NULL;
222 : 3 : status = g_io_channel_read_chars (source, (gchar*) buffer, sizeof (buffer), &length, &error);
223 : 3 : if (first_read && (condition & G_IO_IN))
224 : : {
225 : : /* on some unixes (MacOS) we need to detect non-blocking fd EOF
226 : : * by an IO_IN select/poll followed by read()==0.
227 : : */
228 : 1 : first_read_eof = length == 0;
229 : : }
230 : 3 : first_read = FALSE;
231 : 3 : if (length)
232 : : {
233 : : GTestLogMsg *msg;
234 : 1 : g_test_log_buffer_push (tlb, length, buffer);
235 : : do
236 : : {
237 : 12 : msg = g_test_log_buffer_pop (tlb);
238 : 12 : if (msg)
239 : : {
240 : 11 : test_log_msg (msg);
241 : 11 : g_test_log_msg_free (msg);
242 : : }
243 : : }
244 : 12 : while (msg);
245 : : }
246 : 3 : g_clear_error (&error);
247 : : /* ignore the io channel status, which will report intermediate EOFs for non blocking fds */
248 : : (void) status;
249 : : }
250 : 3 : while (length > 0);
251 : : /* g_print ("LASTIOSTATE: first_read_eof=%d condition=%d\n", first_read_eof, condition); */
252 : 2 : if (first_read_eof || (condition & (G_IO_ERR | G_IO_HUP)))
253 : : {
254 : : /* if there's no data to read and select() reports an error or hangup,
255 : : * the fd must have been closed remotely
256 : : */
257 : 1 : subtest_io_pending = FALSE;
258 : 1 : return FALSE;
259 : : }
260 : 1 : return TRUE; /* keep polling */
261 : : }
262 : :
263 : : static void
264 : 1 : child_watch_cb (GPid pid,
265 : : gint status,
266 : : gpointer data)
267 : : {
268 : 1 : g_spawn_close_pid (pid);
269 : 1 : if (WIFEXITED (status)) /* normal exit */
270 : 1 : subtest_exitstatus = WEXITSTATUS (status);
271 : : else /* signal or core dump, etc */
272 : 0 : subtest_exitstatus = 0xffffffff;
273 : 1 : subtest_running = FALSE;
274 : 1 : }
275 : :
276 : : static gchar*
277 : 1 : queue_gfree (GSList **slistp,
278 : : gchar *string)
279 : : {
280 : 1 : *slistp = g_slist_prepend (*slistp, string);
281 : 1 : return string;
282 : : }
283 : :
284 : : static void
285 : 1 : unset_cloexec_fdp (gpointer fdp_data)
286 : : {
287 : 1 : int r, *fdp = fdp_data;
288 : : do
289 : 1 : r = fcntl (*fdp, F_SETFD, 0 /* FD_CLOEXEC */);
290 : 1 : while (r < 0 && errno == EINTR);
291 : 1 : }
292 : :
293 : : static gboolean
294 : 1 : launch_test_binary (const char *binary,
295 : : guint skip_tests)
296 : : {
297 : : GTestLogBuffer *tlb;
298 : 1 : GSList *slist, *free_list = NULL;
299 : 1 : GError *error = NULL;
300 : 1 : int argc = 0;
301 : : const gchar **argv;
302 : 1 : GPid pid = 0;
303 : 1 : gint report_pipe[2] = { -1, -1 };
304 : 1 : guint child_report_cb_id = 0;
305 : : gboolean loop_pending;
306 : 1 : gint i = 0;
307 : :
308 : 1 : if (!g_unix_open_pipe (report_pipe, O_CLOEXEC, &error))
309 : : {
310 : 0 : if (subtest_mode_fatal)
311 : 0 : g_error ("Failed to open pipe for test binary: %s: %s", binary, error->message);
312 : : else
313 : 0 : g_warning ("Failed to open pipe for test binary: %s: %s", binary, error->message);
314 : 0 : g_clear_error (&error);
315 : 0 : return FALSE;
316 : : }
317 : :
318 : : /* setup argc */
319 : 2 : for (slist = subtest_args; slist; slist = slist->next)
320 : 1 : argc++;
321 : : /* argc++; */
322 : 1 : if (subtest_quiet)
323 : 1 : argc++;
324 : 1 : if (subtest_verbose)
325 : 0 : argc++;
326 : 1 : if (!subtest_mode_fatal)
327 : 1 : argc++;
328 : : /* Either -m=quick or -m=slow is always appended. */
329 : 1 : argc++;
330 : 1 : if (subtest_mode_perf)
331 : 0 : argc++;
332 : 1 : if (!subtest_mode_undefined)
333 : 0 : argc++;
334 : 1 : if (gtester_list_tests)
335 : 0 : argc++;
336 : 1 : if (subtest_seedstr)
337 : 0 : argc++;
338 : 1 : argc++;
339 : 1 : if (skip_tests)
340 : 0 : argc++;
341 : 1 : for (slist = subtest_paths; slist; slist = slist->next)
342 : 0 : argc++;
343 : 1 : for (slist = skipped_paths; slist; slist = slist->next)
344 : 0 : argc++;
345 : :
346 : : /* setup argv */
347 : 1 : argv = g_malloc ((argc + 2) * sizeof(gchar *));
348 : 1 : argv[i++] = binary;
349 : 2 : for (slist = subtest_args; slist; slist = slist->next)
350 : 1 : argv[i++] = (gchar*) slist->data;
351 : : /* argv[i++] = "--debug-log"; */
352 : 1 : if (subtest_quiet)
353 : 1 : argv[i++] = "--quiet";
354 : 1 : if (subtest_verbose)
355 : 0 : argv[i++] = "--verbose";
356 : 1 : if (!subtest_mode_fatal)
357 : 1 : argv[i++] = "--keep-going";
358 : 1 : if (subtest_mode_quick)
359 : 1 : argv[i++] = "-m=quick";
360 : : else
361 : 0 : argv[i++] = "-m=slow";
362 : 1 : if (subtest_mode_perf)
363 : 0 : argv[i++] = "-m=perf";
364 : 1 : if (!subtest_mode_undefined)
365 : 0 : argv[i++] = "-m=no-undefined";
366 : 1 : if (gtester_list_tests)
367 : 0 : argv[i++] = "-l";
368 : 1 : if (subtest_seedstr)
369 : 0 : argv[i++] = queue_gfree (&free_list, g_strdup_printf ("--seed=%s", subtest_seedstr));
370 : 1 : argv[i++] = queue_gfree (&free_list, g_strdup_printf ("--GTestLogFD=%u", report_pipe[1]));
371 : 1 : if (skip_tests)
372 : 0 : argv[i++] = queue_gfree (&free_list, g_strdup_printf ("--GTestSkipCount=%u", skip_tests));
373 : 1 : for (slist = subtest_paths; slist; slist = slist->next)
374 : 0 : argv[i++] = queue_gfree (&free_list, g_strdup_printf ("-p=%s", (gchar*) slist->data));
375 : 1 : for (slist = skipped_paths; slist; slist = slist->next)
376 : 0 : argv[i++] = queue_gfree (&free_list, g_strdup_printf ("-s=%s", (gchar*) slist->data));
377 : 1 : argv[i++] = NULL;
378 : :
379 : 1 : g_spawn_async_with_pipes (NULL, /* g_get_current_dir() */
380 : : (gchar**) argv,
381 : : NULL, /* envp */
382 : : G_SPAWN_DO_NOT_REAP_CHILD, /* G_SPAWN_SEARCH_PATH */
383 : : unset_cloexec_fdp, &report_pipe[1], /* pre-exec callback */
384 : : &pid,
385 : : NULL, /* standard_input */
386 : : NULL, /* standard_output */
387 : : NULL, /* standard_error */
388 : : &error);
389 : 1 : g_slist_foreach (free_list, (void(*)(void*,void*)) g_free, NULL);
390 : 1 : g_slist_free (free_list);
391 : 1 : free_list = NULL;
392 : 1 : close (report_pipe[1]);
393 : :
394 : 1 : if (!gtester_quiet)
395 : 0 : g_print ("(pid=%lu)\n", (unsigned long) pid);
396 : :
397 : 1 : if (error)
398 : : {
399 : 0 : close (report_pipe[0]);
400 : 0 : if (subtest_mode_fatal)
401 : 0 : g_error ("Failed to execute test binary: %s: %s", argv[0], error->message);
402 : : else
403 : 0 : g_warning ("Failed to execute test binary: %s: %s", argv[0], error->message);
404 : 0 : g_clear_error (&error);
405 : 0 : g_free (argv);
406 : 0 : return FALSE;
407 : : }
408 : 1 : g_free (argv);
409 : :
410 : 1 : subtest_running = TRUE;
411 : 1 : subtest_io_pending = TRUE;
412 : 1 : tlb = g_test_log_buffer_new();
413 : 1 : if (report_pipe[0] >= 0)
414 : : {
415 : 1 : ioc_report = g_io_channel_unix_new (report_pipe[0]);
416 : 1 : g_io_channel_set_flags (ioc_report, G_IO_FLAG_NONBLOCK, NULL);
417 : 1 : g_io_channel_set_encoding (ioc_report, NULL, NULL);
418 : 1 : g_io_channel_set_buffered (ioc_report, FALSE);
419 : 1 : child_report_cb_id = g_io_add_watch_full (ioc_report, G_PRIORITY_DEFAULT - 1, G_IO_IN | G_IO_ERR | G_IO_HUP, child_report_cb, tlb, NULL);
420 : 1 : g_io_channel_unref (ioc_report);
421 : : }
422 : 1 : g_child_watch_add_full (G_PRIORITY_DEFAULT + 1, pid, child_watch_cb, NULL, NULL);
423 : :
424 : 1 : loop_pending = g_main_context_pending (NULL);
425 : 2 : while (subtest_running || /* FALSE once child exits */
426 : 5 : subtest_io_pending || /* FALSE once ioc_report closes */
427 : : loop_pending) /* TRUE while idler, etc are running */
428 : : {
429 : : /* g_print ("LOOPSTATE: subtest_running=%d subtest_io_pending=%d\n", subtest_running, subtest_io_pending); */
430 : : /* check for unexpected hangs that are not signalled on report_pipe */
431 : 3 : if (!subtest_running && /* child exited */
432 : 0 : subtest_io_pending && /* no EOF detected on report_pipe */
433 : : !loop_pending) /* no IO events pending however */
434 : 0 : break;
435 : 3 : g_main_context_iteration (NULL, TRUE);
436 : 3 : loop_pending = g_main_context_pending (NULL);
437 : : }
438 : :
439 : 1 : if (subtest_io_pending)
440 : 0 : g_source_remove (child_report_cb_id);
441 : :
442 : 1 : close (report_pipe[0]);
443 : 1 : g_test_log_buffer_free (tlb);
444 : :
445 : 1 : return TRUE;
446 : : }
447 : :
448 : : static void
449 : 1 : launch_test (const char *binary)
450 : : {
451 : 1 : gboolean success = TRUE;
452 : 1 : GTimer *btimer = g_timer_new();
453 : : gboolean need_restart;
454 : :
455 : 1 : testcase_count = 0;
456 : 1 : if (!gtester_quiet)
457 : 0 : g_print ("TEST: %s... ", binary);
458 : :
459 : 1 : retry:
460 : 1 : test_log_printfe ("%s<testbinary path=\"%s\">\n", sindent (log_indent), binary);
461 : 1 : log_indent += 2;
462 : 1 : g_timer_start (btimer);
463 : 1 : subtest_exitstatus = 0;
464 : 1 : success &= launch_test_binary (binary, testcase_count);
465 : 1 : success &= subtest_exitstatus == 0;
466 : 1 : need_restart = testcase_open != 0;
467 : 1 : if (testcase_open)
468 : 0 : testcase_close (0, -256, 0);
469 : 1 : g_timer_stop (btimer);
470 : 1 : test_log_printfe ("%s<duration>%.6f</duration>\n", sindent (log_indent), g_timer_elapsed (btimer, NULL));
471 : 1 : log_indent -= 2;
472 : 1 : test_log_printfe ("%s</testbinary>\n", sindent (log_indent));
473 : 1 : g_free (subtest_last_seed);
474 : 1 : subtest_last_seed = NULL;
475 : 1 : if (need_restart)
476 : : {
477 : : /* restart test binary, skipping processed test cases */
478 : 0 : goto retry;
479 : : }
480 : :
481 : : /* count the inability to run a test as a failure */
482 : 1 : if (!success && testcase_count == 0)
483 : 0 : testcase_fail_count++;
484 : :
485 : 1 : if (!gtester_quiet)
486 : 0 : g_print ("%s: %s\n", !success ? "FAIL" : "PASS", binary);
487 : 1 : g_timer_destroy (btimer);
488 : 1 : if (subtest_mode_fatal && !success)
489 : 0 : terminate();
490 : 1 : }
491 : :
492 : : static void
493 : 0 : usage (gboolean just_version)
494 : : {
495 : 0 : if (just_version)
496 : : {
497 : 0 : g_print ("gtester version %d.%d.%d\n", GLIB_MAJOR_VERSION, GLIB_MINOR_VERSION, GLIB_MICRO_VERSION);
498 : 0 : return;
499 : : }
500 : 0 : g_print ("Usage:\n");
501 : 0 : g_print ("gtester [OPTIONS] testprogram...\n\n");
502 : : /* 12345678901234567890123456789012345678901234567890123456789012345678901234567890 */
503 : 0 : g_print ("Help Options:\n");
504 : 0 : g_print (" -h, --help Show this help message\n\n");
505 : 0 : g_print ("Utility Options:\n");
506 : 0 : g_print (" -v, --version Print version information\n");
507 : 0 : g_print (" --g-fatal-warnings Make warnings fatal (abort)\n");
508 : 0 : g_print (" -k, --keep-going Continue running after tests failed\n");
509 : 0 : g_print (" -l List paths of available test cases\n");
510 : 0 : g_print (" -m {perf|slow|thorough|quick} Run test cases according to mode\n");
511 : 0 : g_print (" -m {undefined|no-undefined} Run test cases according to mode\n");
512 : 0 : g_print (" -p=TESTPATH Only start test cases matching TESTPATH\n");
513 : 0 : g_print (" -s=TESTPATH Skip test cases matching TESTPATH\n");
514 : 0 : g_print (" --seed=SEEDSTRING Start tests with random seed SEEDSTRING\n");
515 : 0 : g_print (" -o=LOGFILE Write the test log to LOGFILE\n");
516 : 0 : g_print (" -q, --quiet Suppress per test binary output\n");
517 : 0 : g_print (" --verbose Report success per testcase\n");
518 : : }
519 : :
520 : : static void
521 : 2 : parse_args (gint *argc_p,
522 : : gchar ***argv_p)
523 : : {
524 : 2 : guint argc = *argc_p;
525 : 2 : gchar **argv = *argv_p;
526 : : guint i, e;
527 : : /* parse known args */
528 : 8 : for (i = 1; i < argc; i++)
529 : : {
530 : 7 : if (strcmp (argv[i], "--g-fatal-warnings") == 0)
531 : : {
532 : 0 : GLogLevelFlags fatal_mask = (GLogLevelFlags) g_log_set_always_fatal ((GLogLevelFlags) G_LOG_FATAL_MASK);
533 : 0 : fatal_mask = (GLogLevelFlags) (fatal_mask | G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL);
534 : 0 : g_log_set_always_fatal (fatal_mask);
535 : 0 : argv[i] = NULL;
536 : : }
537 : 7 : else if (strcmp (argv[i], "--gtester-selftest") == 0)
538 : : {
539 : 1 : gtester_selftest = TRUE;
540 : 1 : argv[i] = NULL;
541 : 1 : break; /* stop parsing regular gtester arguments */
542 : : }
543 : 6 : else if (strcmp (argv[i], "-h") == 0 || strcmp (argv[i], "--help") == 0)
544 : : {
545 : 0 : usage (FALSE);
546 : 0 : exit (0);
547 : : argv[i] = NULL;
548 : : }
549 : 6 : else if (strcmp (argv[i], "-v") == 0 || strcmp (argv[i], "--version") == 0)
550 : : {
551 : 0 : usage (TRUE);
552 : 0 : exit (0);
553 : : argv[i] = NULL;
554 : : }
555 : 6 : else if (strcmp (argv[i], "--keep-going") == 0 ||
556 : 6 : strcmp (argv[i], "-k") == 0)
557 : : {
558 : 1 : subtest_mode_fatal = FALSE;
559 : 1 : argv[i] = NULL;
560 : : }
561 : 5 : else if (strcmp ("-p", argv[i]) == 0 || strncmp ("-p=", argv[i], 3) == 0)
562 : 0 : {
563 : 0 : gchar *equal = argv[i] + 2;
564 : 0 : if (*equal == '=')
565 : 0 : subtest_paths = g_slist_prepend (subtest_paths, equal + 1);
566 : 0 : else if (i + 1 < argc)
567 : : {
568 : 0 : argv[i++] = NULL;
569 : 0 : subtest_paths = g_slist_prepend (subtest_paths, argv[i]);
570 : : }
571 : 0 : argv[i] = NULL;
572 : : }
573 : 5 : else if (strcmp ("-s", argv[i]) == 0 || strncmp ("-s=", argv[i], 3) == 0)
574 : 0 : {
575 : 0 : gchar *equal = argv[i] + 2;
576 : 0 : if (*equal == '=')
577 : 0 : skipped_paths = g_slist_prepend (skipped_paths, equal + 1);
578 : 0 : else if (i + 1 < argc)
579 : : {
580 : 0 : argv[i++] = NULL;
581 : 0 : skipped_paths = g_slist_prepend (skipped_paths, argv[i]);
582 : : }
583 : 0 : argv[i] = NULL;
584 : : }
585 : 5 : else if (strcmp ("--test-arg", argv[i]) == 0 || strncmp ("--test-arg=", argv[i], 11) == 0)
586 : 1 : {
587 : 1 : gchar *equal = argv[i] + 10;
588 : 1 : if (*equal == '=')
589 : 1 : subtest_args = g_slist_prepend (subtest_args, equal + 1);
590 : 0 : else if (i + 1 < argc)
591 : : {
592 : 0 : argv[i++] = NULL;
593 : 0 : subtest_args = g_slist_prepend (subtest_args, argv[i]);
594 : : }
595 : 1 : argv[i] = NULL;
596 : : }
597 : 4 : else if (strcmp ("-o", argv[i]) == 0 || strncmp ("-o=", argv[i], 3) == 0)
598 : 1 : {
599 : 1 : gchar *equal = argv[i] + 2;
600 : 1 : if (*equal == '=')
601 : 0 : output_filename = equal + 1;
602 : 1 : else if (i + 1 < argc)
603 : : {
604 : 1 : argv[i++] = NULL;
605 : 1 : output_filename = argv[i];
606 : : }
607 : 1 : argv[i] = NULL;
608 : : }
609 : 3 : else if (strcmp ("-m", argv[i]) == 0 || strncmp ("-m=", argv[i], 3) == 0)
610 : 0 : {
611 : 0 : gchar *equal = argv[i] + 2;
612 : 0 : const gchar *mode = "";
613 : 0 : if (*equal == '=')
614 : 0 : mode = equal + 1;
615 : 0 : else if (i + 1 < argc)
616 : : {
617 : 0 : argv[i++] = NULL;
618 : 0 : mode = argv[i];
619 : : }
620 : 0 : if (strcmp (mode, "perf") == 0)
621 : 0 : subtest_mode_perf = TRUE;
622 : 0 : else if (strcmp (mode, "slow") == 0 || strcmp (mode, "thorough") == 0)
623 : 0 : subtest_mode_quick = FALSE;
624 : 0 : else if (strcmp (mode, "quick") == 0)
625 : : {
626 : 0 : subtest_mode_quick = TRUE;
627 : 0 : subtest_mode_perf = FALSE;
628 : : }
629 : 0 : else if (strcmp (mode, "undefined") == 0)
630 : 0 : subtest_mode_undefined = TRUE;
631 : 0 : else if (strcmp (mode, "no-undefined") == 0)
632 : 0 : subtest_mode_undefined = FALSE;
633 : : else
634 : 0 : g_error ("unknown test mode: -m %s", mode);
635 : 0 : argv[i] = NULL;
636 : : }
637 : 3 : else if (strcmp ("-q", argv[i]) == 0 || strcmp ("--quiet", argv[i]) == 0)
638 : : {
639 : 1 : gtester_quiet = TRUE;
640 : 1 : gtester_verbose = FALSE;
641 : 1 : argv[i] = NULL;
642 : : }
643 : 2 : else if (strcmp ("--verbose", argv[i]) == 0)
644 : : {
645 : 0 : gtester_quiet = FALSE;
646 : 0 : gtester_verbose = TRUE;
647 : 0 : argv[i] = NULL;
648 : : }
649 : 2 : else if (strcmp ("-l", argv[i]) == 0)
650 : : {
651 : 0 : gtester_list_tests = TRUE;
652 : 0 : argv[i] = NULL;
653 : : }
654 : 2 : else if (strcmp ("--seed", argv[i]) == 0 || strncmp ("--seed=", argv[i], 7) == 0)
655 : 0 : {
656 : 0 : gchar *equal = argv[i] + 6;
657 : 0 : if (*equal == '=')
658 : 0 : subtest_seedstr = equal + 1;
659 : 0 : else if (i + 1 < argc)
660 : : {
661 : 0 : argv[i++] = NULL;
662 : 0 : subtest_seedstr = argv[i];
663 : : }
664 : 0 : argv[i] = NULL;
665 : : }
666 : 2 : else if (strcmp ("--i-know-this-is-deprecated", argv[i]) == 0)
667 : : {
668 : 1 : gtester_ignore_deprecation = TRUE;
669 : 1 : argv[i] = NULL;
670 : : }
671 : : }
672 : : /* collapse argv */
673 : 2 : e = 0;
674 : 16 : for (i = 0; i < argc; i++)
675 : 14 : if (argv[i])
676 : : {
677 : 7 : argv[e++] = argv[i];
678 : 7 : if (i >= e)
679 : 5 : argv[i] = NULL;
680 : : }
681 : 2 : *argc_p = e;
682 : 2 : }
683 : :
684 : : int
685 : 2 : main (int argc,
686 : : char **argv)
687 : : {
688 : : gint ui;
689 : :
690 : 2 : g_set_prgname (argv[0]);
691 : 2 : parse_args (&argc, &argv);
692 : 2 : if (gtester_selftest)
693 : 1 : return main_selftest (argc, argv);
694 : :
695 : 1 : if (argc <= 1)
696 : : {
697 : 0 : usage (FALSE);
698 : 0 : return 1;
699 : : }
700 : :
701 : 1 : if (!gtester_ignore_deprecation)
702 : 0 : g_warning ("Deprecated: Since GLib 2.62, gtester and gtester-report are "
703 : : "deprecated. Port to TAP.");
704 : :
705 : 1 : if (output_filename)
706 : : {
707 : : int errsv;
708 : 1 : log_fd = g_open (output_filename, O_WRONLY | O_CREAT | O_TRUNC, 0666);
709 : 1 : errsv = errno;
710 : 1 : if (log_fd < 0)
711 : 0 : g_error ("Failed to open log file '%s': %s", output_filename, g_strerror (errsv));
712 : : }
713 : :
714 : 1 : test_log_printfe ("<?xml version=\"1.0\"?>\n");
715 : 1 : test_log_printfe ("<!-- Deprecated: Since GLib 2.62, gtester and "
716 : : "gtester-report are deprecated. Port to TAP. -->\n");
717 : 1 : test_log_printfe ("%s<gtester>\n", sindent (log_indent));
718 : 1 : log_indent += 2;
719 : 2 : for (ui = 1; ui < argc; ui++)
720 : : {
721 : 1 : const char *binary = argv[ui];
722 : 1 : launch_test (binary);
723 : : /* we only get here on success or if !subtest_mode_fatal */
724 : : }
725 : 1 : log_indent -= 2;
726 : 1 : test_log_printfe ("%s</gtester>\n", sindent (log_indent));
727 : :
728 : 1 : close (log_fd);
729 : :
730 : 1 : return testcase_fail_count == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
731 : : }
732 : :
733 : : static void
734 : 1 : fixture_setup (guint *fix,
735 : : gconstpointer test_data)
736 : : {
737 : 1 : g_assert_cmphex (*fix, ==, 0);
738 : 1 : *fix = 0xdeadbeef;
739 : 1 : }
740 : : static void
741 : 1 : fixture_test (guint *fix,
742 : : gconstpointer test_data)
743 : : {
744 : 1 : g_assert_cmphex (*fix, ==, 0xdeadbeef);
745 : 1 : g_test_message ("This is a test message API test message.");
746 : 1 : g_test_bug_base ("http://www.example.com/bugtracker/");
747 : 1 : g_test_bug ("123");
748 : 1 : g_test_bug_base ("http://www.example.com/bugtracker?bugnum=%s;cmd=showbug");
749 : 1 : g_test_bug ("456");
750 : 1 : g_test_bug ("https://example.com/no-base-used");
751 : 1 : }
752 : : static void
753 : 1 : fixture_teardown (guint *fix,
754 : : gconstpointer test_data)
755 : : {
756 : 1 : g_assert_cmphex (*fix, ==, 0xdeadbeef);
757 : 1 : }
758 : :
759 : : static int
760 : 1 : main_selftest (int argc,
761 : : char **argv)
762 : : {
763 : : /* gtester main() for --gtester-selftest invocations */
764 : 1 : g_test_init (&argc, &argv, NULL);
765 : 1 : g_test_add ("/gtester/fixture-test", guint, NULL, fixture_setup, fixture_test, fixture_teardown);
766 : 1 : return g_test_run();
767 : : }
|