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