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