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