os/ossrv/glib/glib/gtester.c
changeset 0 bde4ae8d615e
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/os/ossrv/glib/glib/gtester.c	Fri Jun 15 03:10:57 2012 +0200
     1.3 @@ -0,0 +1,711 @@
     1.4 +/* GLib testing framework runner
     1.5 + * Copyright (C) 2007 Sven Herzberg
     1.6 + * Copyright (C) 2007 Tim Janik
     1.7 + *
     1.8 + * This library is free software; you can redistribute it and/or
     1.9 + * modify it under the terms of the GNU Lesser General Public
    1.10 + * License as published by the Free Software Foundation; either
    1.11 + * version 2 of the License, or (at your option) any later version.
    1.12 + *
    1.13 + * This library is distributed in the hope that it will be useful,
    1.14 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
    1.15 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    1.16 + * Lesser General Public License for more details.
    1.17 + *
    1.18 + * You should have received a copy of the GNU Lesser General Public
    1.19 + * License along with this library; if not, write to the
    1.20 + * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    1.21 + * Boston, MA 02111-1307, USA.
    1.22 + */
    1.23 +#include <glib.h>
    1.24 +#include <gstdio.h>
    1.25 +#include <string.h>
    1.26 +#include <stdlib.h>
    1.27 +#include <unistd.h>
    1.28 +#include <fcntl.h>
    1.29 +#include <sys/wait.h>
    1.30 +#include <errno.h>
    1.31 +#include <signal.h>
    1.32 +
    1.33 +/* the read buffer size in bytes */
    1.34 +#define READ_BUFFER_SIZE 4096
    1.35 +
    1.36 +/* --- prototypes --- */
    1.37 +static int      main_selftest   (int    argc,
    1.38 +                                 char **argv);
    1.39 +static void     parse_args      (gint           *argc_p,
    1.40 +                                 gchar        ***argv_p);
    1.41 +
    1.42 +/* --- variables --- */
    1.43 +static GIOChannel  *ioc_report = NULL;
    1.44 +static gboolean     gtester_quiet = FALSE;
    1.45 +static gboolean     gtester_verbose = FALSE;
    1.46 +static gboolean     gtester_list_tests = FALSE;
    1.47 +static gboolean     gtester_selftest = FALSE;
    1.48 +static gboolean     subtest_running = FALSE;
    1.49 +static gint         subtest_exitstatus = 0;
    1.50 +static gboolean     subtest_io_pending = FALSE;
    1.51 +static gboolean     subtest_quiet = TRUE;
    1.52 +static gboolean     subtest_verbose = FALSE;
    1.53 +static gboolean     subtest_mode_fatal = TRUE;
    1.54 +static gboolean     subtest_mode_perf = FALSE;
    1.55 +static gboolean     subtest_mode_quick = TRUE;
    1.56 +static const gchar *subtest_seedstr = NULL;
    1.57 +static gchar       *subtest_last_seed = NULL;
    1.58 +static GSList      *subtest_paths = NULL;
    1.59 +static GSList      *subtest_args = NULL;
    1.60 +static gboolean     testcase_open = FALSE;
    1.61 +static guint        testcase_count = 0;
    1.62 +static guint        testcase_fail_count = 0;
    1.63 +static const gchar *output_filename = NULL;
    1.64 +static guint        log_indent = 0;
    1.65 +static gint         log_fd = -1;
    1.66 +
    1.67 +/* --- functions --- */
    1.68 +static const char*
    1.69 +sindent (guint n)
    1.70 +{
    1.71 +  static const char spaces[] = "                                                                                                    ";
    1.72 +  int l = sizeof (spaces) - 1;
    1.73 +  n = MIN (n, l);
    1.74 +  return spaces + l - n;
    1.75 +}
    1.76 +
    1.77 +static void G_GNUC_PRINTF (1, 2)
    1.78 +test_log_printfe (const char *format,
    1.79 +                  ...)
    1.80 +{
    1.81 +  char *result;
    1.82 +  int r;
    1.83 +  va_list args;
    1.84 +  va_start (args, format);
    1.85 +  result = g_markup_vprintf_escaped (format, args);
    1.86 +  va_end (args);
    1.87 +  do
    1.88 +    r = write (log_fd, result, strlen (result));
    1.89 +  while (r < 0 && errno == EINTR);
    1.90 +  g_free (result);
    1.91 +}
    1.92 +
    1.93 +static void
    1.94 +terminate (void)
    1.95 +{
    1.96 +  kill (getpid(), SIGTERM);
    1.97 +  abort();
    1.98 +}
    1.99 +
   1.100 +static void
   1.101 +testcase_close (long double duration,
   1.102 +                gint        exit_status,
   1.103 +                guint       n_forks)
   1.104 +{
   1.105 +  g_return_if_fail (testcase_open > 0);
   1.106 +  test_log_printfe ("%s<duration>%.6Lf</duration>\n", sindent (log_indent), duration);
   1.107 +  test_log_printfe ("%s<status exit-status=\"%d\" n-forks=\"%d\" result=\"%s\"/>\n",
   1.108 +                    sindent (log_indent), exit_status, n_forks,
   1.109 +                    exit_status ? "failed" : "success");
   1.110 +  log_indent -= 2;
   1.111 +  test_log_printfe ("%s</testcase>\n", sindent (log_indent));
   1.112 +  testcase_open--;
   1.113 +  if (gtester_verbose)
   1.114 +    g_print ("%s\n", exit_status ? "FAIL" : "OK");
   1.115 +  if (exit_status && subtest_last_seed)
   1.116 +    g_print ("GTester: last random seed: %s\n", subtest_last_seed);
   1.117 +  if (exit_status)
   1.118 +    testcase_fail_count += 1;
   1.119 +  if (subtest_mode_fatal && testcase_fail_count)
   1.120 +    terminate();
   1.121 +}
   1.122 +
   1.123 +static void
   1.124 +test_log_msg (GTestLogMsg *msg)
   1.125 +{
   1.126 +  switch (msg->log_type)
   1.127 +    {
   1.128 +      guint i;
   1.129 +      gchar **strv;
   1.130 +    case G_TEST_LOG_NONE:
   1.131 +      break;
   1.132 +    case G_TEST_LOG_ERROR:
   1.133 +      strv = g_strsplit (msg->strings[0], "\n", -1);
   1.134 +      for (i = 0; strv[i]; i++)
   1.135 +        test_log_printfe ("%s<error>%s</error>\n", sindent (log_indent), strv[i]);
   1.136 +      g_strfreev (strv);
   1.137 +      break;
   1.138 +    case G_TEST_LOG_START_BINARY:
   1.139 +      test_log_printfe ("%s<binary file=\"%s\"/>\n", sindent (log_indent), msg->strings[0]);
   1.140 +      subtest_last_seed = g_strdup (msg->strings[1]);
   1.141 +      test_log_printfe ("%s<random-seed>%s</random-seed>\n", sindent (log_indent), subtest_last_seed);
   1.142 +      break;
   1.143 +    case G_TEST_LOG_LIST_CASE:
   1.144 +      g_print ("%s\n", msg->strings[0]);
   1.145 +      break;
   1.146 +    case G_TEST_LOG_START_CASE:
   1.147 +      testcase_count++;
   1.148 +      if (gtester_verbose)
   1.149 +        {
   1.150 +          gchar *sc = g_strconcat (msg->strings[0], ":", NULL);
   1.151 +          gchar *sleft = g_strdup_printf ("%-68s", sc);
   1.152 +          g_free (sc);
   1.153 +          g_print ("%70s ", sleft);
   1.154 +          g_free (sleft);
   1.155 +        }
   1.156 +      g_return_if_fail (testcase_open == 0);
   1.157 +      testcase_open++;
   1.158 +      test_log_printfe ("%s<testcase path=\"%s\">\n", sindent (log_indent), msg->strings[0]);
   1.159 +      log_indent += 2;
   1.160 +      break;
   1.161 +    case G_TEST_LOG_SKIP_CASE:
   1.162 +      if (FALSE && gtester_verbose) /* enable to debug test case skipping logic */
   1.163 +        {
   1.164 +          gchar *sc = g_strconcat (msg->strings[0], ":", NULL);
   1.165 +          gchar *sleft = g_strdup_printf ("%-68s", sc);
   1.166 +          g_free (sc);
   1.167 +          g_print ("%70s SKIPPED\n", sleft);
   1.168 +          g_free (sleft);
   1.169 +        }
   1.170 +      test_log_printfe ("%s<testcase path=\"%s\" skipped=\"1\"/>\n", sindent (log_indent), msg->strings[0]);
   1.171 +      break;
   1.172 +    case G_TEST_LOG_STOP_CASE:
   1.173 +      testcase_close (msg->nums[2], (int) msg->nums[0], (int) msg->nums[1]);
   1.174 +      break;
   1.175 +    case G_TEST_LOG_MIN_RESULT:
   1.176 +    case G_TEST_LOG_MAX_RESULT:
   1.177 +      test_log_printfe ("%s<performance minimize=\"%d\" maximize=\"%d\" value=\"%.16Lg\">\n",
   1.178 +                        sindent (log_indent), msg->log_type == G_TEST_LOG_MIN_RESULT, msg->log_type == G_TEST_LOG_MAX_RESULT, msg->nums[0]);
   1.179 +      test_log_printfe ("%s%s\n", sindent (log_indent + 2), msg->strings[0]);
   1.180 +      test_log_printfe ("%s</performance>\n", sindent (log_indent));
   1.181 +      break;
   1.182 +    case G_TEST_LOG_MESSAGE:
   1.183 +      test_log_printfe ("%s<message>\n%s\n%s</message>\n", sindent (log_indent), msg->strings[0], sindent (log_indent));
   1.184 +      break;
   1.185 +    }
   1.186 +}
   1.187 +
   1.188 +static gboolean
   1.189 +child_report_cb (GIOChannel  *source,
   1.190 +                 GIOCondition condition,
   1.191 +                 gpointer     data)
   1.192 +{
   1.193 +  GTestLogBuffer *tlb = data;
   1.194 +  GIOStatus status = G_IO_STATUS_NORMAL;
   1.195 +  gboolean first_read_eof = FALSE, first_read = TRUE;
   1.196 +  gsize length = 0;
   1.197 +  do
   1.198 +    {
   1.199 +      guint8 buffer[READ_BUFFER_SIZE];
   1.200 +      GError *error = NULL;
   1.201 +      status = g_io_channel_read_chars (source, (gchar*) buffer, sizeof (buffer), &length, &error);
   1.202 +      if (first_read && (condition & G_IO_IN))
   1.203 +        {
   1.204 +          /* on some unixes (MacOS) we need to detect non-blocking fd EOF
   1.205 +           * by an IO_IN select/poll followed by read()==0.
   1.206 +           */
   1.207 +          first_read_eof = length == 0;
   1.208 +        }
   1.209 +      first_read = FALSE;
   1.210 +      if (length)
   1.211 +        {
   1.212 +          GTestLogMsg *msg;
   1.213 +          g_test_log_buffer_push (tlb, length, buffer);
   1.214 +          do
   1.215 +            {
   1.216 +              msg = g_test_log_buffer_pop (tlb);
   1.217 +              if (msg)
   1.218 +                {
   1.219 +                  test_log_msg (msg);
   1.220 +                  g_test_log_msg_free (msg);
   1.221 +                }
   1.222 +            }
   1.223 +          while (msg);
   1.224 +        }
   1.225 +      g_clear_error (&error);
   1.226 +      /* ignore the io channel status, which will report intermediate EOFs for non blocking fds */
   1.227 +      (void) status;
   1.228 +    }
   1.229 +  while (length > 0);
   1.230 +  /* g_print ("LASTIOSTATE: first_read_eof=%d condition=%d\n", first_read_eof, condition); */
   1.231 +  if (first_read_eof || (condition & (G_IO_ERR | G_IO_HUP)))
   1.232 +    {
   1.233 +      /* if there's no data to read and select() reports an error or hangup,
   1.234 +       * the fd must have been closed remotely
   1.235 +       */
   1.236 +      subtest_io_pending = FALSE;
   1.237 +      return FALSE;
   1.238 +    }
   1.239 +  return TRUE; /* keep polling */
   1.240 +}
   1.241 +
   1.242 +static void
   1.243 +child_watch_cb (GPid     pid,
   1.244 +		gint     status,
   1.245 +		gpointer data)
   1.246 +{
   1.247 +  g_spawn_close_pid (pid);
   1.248 +  if (WIFEXITED (status)) /* normal exit */
   1.249 +    subtest_exitstatus = WEXITSTATUS (status);
   1.250 +  else /* signal or core dump, etc */
   1.251 +    subtest_exitstatus = 0xffffffff;
   1.252 +  subtest_running = FALSE;
   1.253 +}
   1.254 +
   1.255 +static gchar*
   1.256 +queue_gfree (GSList **slistp,
   1.257 +             gchar   *string)
   1.258 +{
   1.259 +  *slistp = g_slist_prepend (*slistp, string);
   1.260 +  return string;
   1.261 +}
   1.262 +
   1.263 +static void
   1.264 +unset_cloexec_fdp (gpointer fdp_data)
   1.265 +{
   1.266 +  int r, *fdp = fdp_data;
   1.267 +  do
   1.268 +    r = fcntl (*fdp, F_SETFD, 0 /* FD_CLOEXEC */);
   1.269 +  while (r < 0 && errno == EINTR);
   1.270 +}
   1.271 +
   1.272 +static gboolean
   1.273 +launch_test_binary (const char *binary,
   1.274 +                    guint       skip_tests)
   1.275 +{
   1.276 +  GTestLogBuffer *tlb;
   1.277 +  GSList *slist, *free_list = NULL;
   1.278 +  GError *error = NULL;
   1.279 +  int argc = 0;
   1.280 +  const gchar **argv;
   1.281 +  GPid pid = 0;
   1.282 +  gint report_pipe[2] = { -1, -1 };
   1.283 +  guint child_report_cb_id = 0;
   1.284 +  gboolean loop_pending;
   1.285 +  gint i = 0;
   1.286 +
   1.287 +  if (pipe (report_pipe) < 0)
   1.288 +    {
   1.289 +      if (subtest_mode_fatal)
   1.290 +        g_error ("Failed to open pipe for test binary: %s: %s", binary, g_strerror (errno));
   1.291 +      else
   1.292 +        g_warning ("Failed to open pipe for test binary: %s: %s", binary, g_strerror (errno));
   1.293 +      return FALSE;
   1.294 +    }
   1.295 +
   1.296 +  /* setup argc */
   1.297 +  for (slist = subtest_args; slist; slist = slist->next)
   1.298 +    argc++;
   1.299 +  /* argc++; */
   1.300 +  if (subtest_quiet)
   1.301 +    argc++;
   1.302 +  if (subtest_verbose)
   1.303 +    argc++;
   1.304 +  if (!subtest_mode_fatal)
   1.305 +    argc++;
   1.306 +  if (subtest_mode_quick)
   1.307 +    argc++;
   1.308 +  else
   1.309 +    argc++;
   1.310 +  if (subtest_mode_perf)
   1.311 +    argc++;
   1.312 +  if (gtester_list_tests)
   1.313 +    argc++;
   1.314 +  if (subtest_seedstr)
   1.315 +    argc++;
   1.316 +  argc++;
   1.317 +  if (skip_tests)
   1.318 +    argc++;
   1.319 +  for (slist = subtest_paths; slist; slist = slist->next)
   1.320 +    argc++;
   1.321 +
   1.322 +  /* setup argv */
   1.323 +  argv = g_malloc ((argc + 2) * sizeof(gchar *));
   1.324 +  argv[i++] = binary;
   1.325 +  for (slist = subtest_args; slist; slist = slist->next)
   1.326 +    argv[i++] = (gchar*) slist->data;
   1.327 +  /* argv[i++] = "--debug-log"; */
   1.328 +  if (subtest_quiet)
   1.329 +    argv[i++] = "--quiet";
   1.330 +  if (subtest_verbose)
   1.331 +    argv[i++] = "--verbose";
   1.332 +  if (!subtest_mode_fatal)
   1.333 +    argv[i++] = "--keep-going";
   1.334 +  if (subtest_mode_quick)
   1.335 +    argv[i++] = "-m=quick";
   1.336 +  else
   1.337 +    argv[i++] = "-m=slow";
   1.338 +  if (subtest_mode_perf)
   1.339 +    argv[i++] = "-m=perf";
   1.340 +  if (gtester_list_tests)
   1.341 +    argv[i++] = "-l";
   1.342 +  if (subtest_seedstr)
   1.343 +    argv[i++] = queue_gfree (&free_list, g_strdup_printf ("--seed=%s", subtest_seedstr));
   1.344 +  argv[i++] = queue_gfree (&free_list, g_strdup_printf ("--GTestLogFD=%u", report_pipe[1]));
   1.345 +  if (skip_tests)
   1.346 +    argv[i++] = queue_gfree (&free_list, g_strdup_printf ("--GTestSkipCount=%u", skip_tests));
   1.347 +  for (slist = subtest_paths; slist; slist = slist->next)
   1.348 +    argv[i++] = queue_gfree (&free_list, g_strdup_printf ("-p=%s", (gchar*) slist->data));
   1.349 +  argv[i++] = NULL;
   1.350 +
   1.351 +  g_spawn_async_with_pipes (NULL, /* g_get_current_dir() */
   1.352 +                            (gchar**) argv,
   1.353 +                            NULL, /* envp */
   1.354 +                            G_SPAWN_DO_NOT_REAP_CHILD, /* G_SPAWN_SEARCH_PATH */
   1.355 +                            unset_cloexec_fdp, &report_pipe[1], /* pre-exec callback */
   1.356 +                            &pid,
   1.357 +                            NULL,       /* standard_input */
   1.358 +                            NULL,       /* standard_output */
   1.359 +                            NULL,       /* standard_error */
   1.360 +                            &error);
   1.361 +  g_slist_foreach (free_list, (void(*)(void*,void*)) g_free, NULL);
   1.362 +  g_slist_free (free_list);
   1.363 +  free_list = NULL;
   1.364 +  close (report_pipe[1]);
   1.365 +
   1.366 +  if (!gtester_quiet)
   1.367 +    g_print ("(pid=%lu)\n", (unsigned long) pid);
   1.368 +
   1.369 +  if (error)
   1.370 +    {
   1.371 +      close (report_pipe[0]);
   1.372 +      if (subtest_mode_fatal)
   1.373 +        g_error ("Failed to execute test binary: %s: %s", argv[0], error->message);
   1.374 +      else
   1.375 +        g_warning ("Failed to execute test binary: %s: %s", argv[0], error->message);
   1.376 +      g_clear_error (&error);
   1.377 +      g_free (argv);
   1.378 +      return FALSE;
   1.379 +    }
   1.380 +  g_free (argv);
   1.381 +
   1.382 +  subtest_running = TRUE;
   1.383 +  subtest_io_pending = TRUE;
   1.384 +  tlb = g_test_log_buffer_new();
   1.385 +  if (report_pipe[0] >= 0)
   1.386 +    {
   1.387 +      ioc_report = g_io_channel_unix_new (report_pipe[0]);
   1.388 +      g_io_channel_set_flags (ioc_report, G_IO_FLAG_NONBLOCK, NULL);
   1.389 +      g_io_channel_set_encoding (ioc_report, NULL, NULL);
   1.390 +      g_io_channel_set_buffered (ioc_report, FALSE);
   1.391 +      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);
   1.392 +      g_io_channel_unref (ioc_report);
   1.393 +    }
   1.394 +  g_child_watch_add_full (G_PRIORITY_DEFAULT + 1, pid, child_watch_cb, NULL, NULL);
   1.395 +
   1.396 +  loop_pending = g_main_context_pending (NULL);
   1.397 +  while (subtest_running ||     /* FALSE once child exits */
   1.398 +         subtest_io_pending ||  /* FALSE once ioc_report closes */
   1.399 +         loop_pending)          /* TRUE while idler, etc are running */
   1.400 +    {
   1.401 +      /* g_print ("LOOPSTATE: subtest_running=%d subtest_io_pending=%d\n", subtest_running, subtest_io_pending); */
   1.402 +      /* check for unexpected hangs that are not signalled on report_pipe */
   1.403 +      if (!subtest_running &&   /* child exited */
   1.404 +          subtest_io_pending && /* no EOF detected on report_pipe */
   1.405 +          !loop_pending)        /* no IO events pending however */
   1.406 +        break;
   1.407 +      g_main_context_iteration (NULL, TRUE);
   1.408 +      loop_pending = g_main_context_pending (NULL);
   1.409 +    }
   1.410 +
   1.411 +  g_source_remove (child_report_cb_id);
   1.412 +  close (report_pipe[0]);
   1.413 +  g_test_log_buffer_free (tlb);
   1.414 +
   1.415 +  return TRUE;
   1.416 +}
   1.417 +
   1.418 +static void
   1.419 +launch_test (const char *binary)
   1.420 +{
   1.421 +  gboolean success = TRUE;
   1.422 +  GTimer *btimer = g_timer_new();
   1.423 +  gboolean need_restart;
   1.424 +  testcase_count = 0;
   1.425 +  testcase_fail_count = 0;
   1.426 +  if (!gtester_quiet)
   1.427 +    g_print ("TEST: %s... ", binary);
   1.428 +
   1.429 + retry:
   1.430 +  test_log_printfe ("%s<testbinary path=\"%s\">\n", sindent (log_indent), binary);
   1.431 +  log_indent += 2;
   1.432 +  g_timer_start (btimer);
   1.433 +  subtest_exitstatus = 0;
   1.434 +  success &= launch_test_binary (binary, testcase_count);
   1.435 +  success &= subtest_exitstatus == 0;
   1.436 +  need_restart = testcase_open != 0;
   1.437 +  if (testcase_open)
   1.438 +    testcase_close (0, -256, 0);
   1.439 +  g_timer_stop (btimer);
   1.440 +  test_log_printfe ("%s<duration>%.6f</duration>\n", sindent (log_indent), g_timer_elapsed (btimer, NULL));
   1.441 +  log_indent -= 2;
   1.442 +  test_log_printfe ("%s</testbinary>\n", sindent (log_indent));
   1.443 +  g_free (subtest_last_seed);
   1.444 +  subtest_last_seed = NULL;
   1.445 +  if (need_restart)
   1.446 +    {
   1.447 +      /* restart test binary, skipping processed test cases */
   1.448 +      goto retry;
   1.449 +    }
   1.450 +
   1.451 +  if (!gtester_quiet)
   1.452 +    g_print ("%s: %s\n", testcase_fail_count || !success ? "FAIL" : "PASS", binary);
   1.453 +  g_timer_destroy (btimer);
   1.454 +  if (subtest_mode_fatal && !success)
   1.455 +    terminate();
   1.456 +}
   1.457 +
   1.458 +static void
   1.459 +usage (gboolean just_version)
   1.460 +{
   1.461 +  if (just_version)
   1.462 +    {
   1.463 +      g_print ("gtester version %d.%d.%d\n", GLIB_MAJOR_VERSION, GLIB_MINOR_VERSION, GLIB_MICRO_VERSION);
   1.464 +      return;
   1.465 +    }
   1.466 +  g_print ("Usage: gtester [OPTIONS] testprogram...\n");
   1.467 +  /*        12345678901234567890123456789012345678901234567890123456789012345678901234567890 */
   1.468 +  g_print ("Options:\n");
   1.469 +  g_print ("  -h, --help                  show this help message\n");
   1.470 +  g_print ("  -v, --version               print version informations\n");
   1.471 +  g_print ("  --g-fatal-warnings          make warnings fatal (abort)\n");
   1.472 +  g_print ("  -k, --keep-going            continue running after tests failed\n");
   1.473 +  g_print ("  -l                          list paths of available test cases\n");
   1.474 +  g_print ("  -m=perf, -m=slow, -m=quick -m=thorough\n");
   1.475 +  g_print ("                              run test cases in mode perf, slow/thorough or quick (default)\n");
   1.476 +  g_print ("  -p=TESTPATH                 only start test cases matching TESTPATH\n");
   1.477 +  g_print ("  --seed=SEEDSTRING           start all tests with random number seed SEEDSTRING\n");
   1.478 +  g_print ("  -o=LOGFILE                  write the test log to LOGFILE\n");
   1.479 +  g_print ("  -q, --quiet                 suppress per test binary output\n");
   1.480 +  g_print ("  --verbose                   report success per testcase\n");
   1.481 +}
   1.482 +
   1.483 +static void
   1.484 +parse_args (gint    *argc_p,
   1.485 +            gchar ***argv_p)
   1.486 +{
   1.487 +  guint argc = *argc_p;
   1.488 +  gchar **argv = *argv_p;
   1.489 +  guint i, e;
   1.490 +  /* parse known args */
   1.491 +  for (i = 1; i < argc; i++)
   1.492 +    {
   1.493 +      if (strcmp (argv[i], "--g-fatal-warnings") == 0)
   1.494 +        {
   1.495 +          GLogLevelFlags fatal_mask = (GLogLevelFlags) g_log_set_always_fatal ((GLogLevelFlags) G_LOG_FATAL_MASK);
   1.496 +          fatal_mask = (GLogLevelFlags) (fatal_mask | G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL);
   1.497 +          g_log_set_always_fatal (fatal_mask);
   1.498 +          argv[i] = NULL;
   1.499 +        }
   1.500 +      else if (strcmp (argv[i], "--gtester-selftest") == 0)
   1.501 +        {
   1.502 +          gtester_selftest = TRUE;
   1.503 +          argv[i] = NULL;
   1.504 +          break;        /* stop parsing regular gtester arguments */
   1.505 +        }
   1.506 +      else if (strcmp (argv[i], "-h") == 0 || strcmp (argv[i], "--help") == 0)
   1.507 +        {
   1.508 +          usage (FALSE);
   1.509 +          exit (0);
   1.510 +          argv[i] = NULL;
   1.511 +        }
   1.512 +      else if (strcmp (argv[i], "-v") == 0 || strcmp (argv[i], "--version") == 0)
   1.513 +        {
   1.514 +          usage (TRUE);
   1.515 +          exit (0);
   1.516 +          argv[i] = NULL;
   1.517 +        }
   1.518 +      else if (strcmp (argv[i], "--keep-going") == 0 ||
   1.519 +               strcmp (argv[i], "-k") == 0)
   1.520 +        {
   1.521 +          subtest_mode_fatal = FALSE;
   1.522 +          argv[i] = NULL;
   1.523 +        }
   1.524 +      else if (strcmp ("-p", argv[i]) == 0 || strncmp ("-p=", argv[i], 3) == 0)
   1.525 +        {
   1.526 +          gchar *equal = argv[i] + 2;
   1.527 +          if (*equal == '=')
   1.528 +            subtest_paths = g_slist_prepend (subtest_paths, equal + 1);
   1.529 +          else if (i + 1 < argc)
   1.530 +            {
   1.531 +              argv[i++] = NULL;
   1.532 +              subtest_paths = g_slist_prepend (subtest_paths, argv[i]);
   1.533 +            }
   1.534 +          argv[i] = NULL;
   1.535 +        }
   1.536 +      else if (strcmp ("--test-arg", argv[i]) == 0 || strncmp ("--test-arg=", argv[i], 11) == 0)
   1.537 +        {
   1.538 +          gchar *equal = argv[i] + 10;
   1.539 +          if (*equal == '=')
   1.540 +            subtest_args = g_slist_prepend (subtest_args, equal + 1);
   1.541 +          else if (i + 1 < argc)
   1.542 +            {
   1.543 +              argv[i++] = NULL;
   1.544 +              subtest_args = g_slist_prepend (subtest_args, argv[i]);
   1.545 +            }
   1.546 +          argv[i] = NULL;
   1.547 +        }
   1.548 +      else if (strcmp ("-o", argv[i]) == 0 || strncmp ("-o=", argv[i], 3) == 0)
   1.549 +        {
   1.550 +          gchar *equal = argv[i] + 2;
   1.551 +          if (*equal == '=')
   1.552 +            output_filename = equal + 1;
   1.553 +          else if (i + 1 < argc)
   1.554 +            {
   1.555 +              argv[i++] = NULL;
   1.556 +              output_filename = argv[i];
   1.557 +            }
   1.558 +          argv[i] = NULL;
   1.559 +        }
   1.560 +      else if (strcmp ("-m", argv[i]) == 0 || strncmp ("-m=", argv[i], 3) == 0)
   1.561 +        {
   1.562 +          gchar *equal = argv[i] + 2;
   1.563 +          const gchar *mode = "";
   1.564 +          if (*equal == '=')
   1.565 +            mode = equal + 1;
   1.566 +          else if (i + 1 < argc)
   1.567 +            {
   1.568 +              argv[i++] = NULL;
   1.569 +              mode = argv[i];
   1.570 +            }
   1.571 +          if (strcmp (mode, "perf") == 0)
   1.572 +            subtest_mode_perf = TRUE;
   1.573 +          else if (strcmp (mode, "slow") == 0 || strcmp (mode, "thorough") == 0)
   1.574 +            subtest_mode_quick = FALSE;
   1.575 +          else if (strcmp (mode, "quick") == 0)
   1.576 +            {
   1.577 +              subtest_mode_quick = TRUE;
   1.578 +              subtest_mode_perf = FALSE;
   1.579 +            }
   1.580 +          else
   1.581 +            g_error ("unknown test mode: -m %s", mode);
   1.582 +          argv[i] = NULL;
   1.583 +        }
   1.584 +      else if (strcmp ("-q", argv[i]) == 0 || strcmp ("--quiet", argv[i]) == 0)
   1.585 +        {
   1.586 +          gtester_quiet = TRUE;
   1.587 +          gtester_verbose = FALSE;
   1.588 +          argv[i] = NULL;
   1.589 +        }
   1.590 +      else if (strcmp ("--verbose", argv[i]) == 0)
   1.591 +        {
   1.592 +          gtester_quiet = FALSE;
   1.593 +          gtester_verbose = TRUE;
   1.594 +          argv[i] = NULL;
   1.595 +        }
   1.596 +      else if (strcmp ("-l", argv[i]) == 0)
   1.597 +        {
   1.598 +          gtester_list_tests = TRUE;
   1.599 +          argv[i] = NULL;
   1.600 +        }
   1.601 +      else if (strcmp ("--seed", argv[i]) == 0 || strncmp ("--seed=", argv[i], 7) == 0)
   1.602 +        {
   1.603 +          gchar *equal = argv[i] + 6;
   1.604 +          if (*equal == '=')
   1.605 +            subtest_seedstr = equal + 1;
   1.606 +          else if (i + 1 < argc)
   1.607 +            {
   1.608 +              argv[i++] = NULL;
   1.609 +              subtest_seedstr = argv[i];
   1.610 +            }
   1.611 +          argv[i] = NULL;
   1.612 +        }
   1.613 +    }
   1.614 +  /* collapse argv */
   1.615 +  e = 1;
   1.616 +  for (i = 1; i < argc; i++)
   1.617 +    if (argv[i])
   1.618 +      {
   1.619 +        argv[e++] = argv[i];
   1.620 +        if (i >= e)
   1.621 +          argv[i] = NULL;
   1.622 +      }
   1.623 +  *argc_p = e;
   1.624 +}
   1.625 +
   1.626 +int
   1.627 +main (int    argc,
   1.628 +      char **argv)
   1.629 +{
   1.630 +  guint ui;
   1.631 +
   1.632 +  /* some unices need SA_RESTART for SIGCHLD to return -EAGAIN for io.
   1.633 +   * we must fiddle with sigaction() *before* glib is used, otherwise
   1.634 +   * we could revoke signal hanmdler setups from glib initialization code.
   1.635 +   */
   1.636 +  if (TRUE)
   1.637 +    {
   1.638 +      struct sigaction sa;
   1.639 +      struct sigaction osa;
   1.640 +      sa.sa_handler = SIG_DFL;
   1.641 +      sigfillset (&sa.sa_mask);
   1.642 +      sa.sa_flags = SA_RESTART;
   1.643 +      sigaction (SIGCHLD, &sa, &osa);
   1.644 +    }
   1.645 +
   1.646 +  g_set_prgname (argv[0]);
   1.647 +  parse_args (&argc, &argv);
   1.648 +  if (gtester_selftest)
   1.649 +    return main_selftest (argc, argv);
   1.650 +
   1.651 +  if (argc <= 1)
   1.652 +    {
   1.653 +      usage (FALSE);
   1.654 +      return 1;
   1.655 +    }
   1.656 +
   1.657 +  if (output_filename)
   1.658 +    {
   1.659 +      log_fd = g_open (output_filename, O_WRONLY | O_CREAT | O_TRUNC, 0666);
   1.660 +      if (log_fd < 0)
   1.661 +        g_error ("Failed to open log file '%s': %s", output_filename, g_strerror (errno));
   1.662 +    }
   1.663 +
   1.664 +  test_log_printfe ("<?xml version=\"1.0\"?>\n");
   1.665 +  test_log_printfe ("%s<gtester>\n", sindent (log_indent));
   1.666 +  log_indent += 2;
   1.667 +  for (ui = 1; ui < argc; ui++)
   1.668 +    {
   1.669 +      const char *binary = argv[ui];
   1.670 +      launch_test (binary);
   1.671 +      /* we only get here on success or if !subtest_mode_fatal */
   1.672 +    }
   1.673 +  log_indent -= 2;
   1.674 +  test_log_printfe ("%s</gtester>\n", sindent (log_indent));
   1.675 +
   1.676 +  close (log_fd);
   1.677 +
   1.678 +  return 0;
   1.679 +}
   1.680 +
   1.681 +static void
   1.682 +fixture_setup (guint        *fix,
   1.683 +               gconstpointer test_data)
   1.684 +{
   1.685 +  g_assert_cmphex (*fix, ==, 0);
   1.686 +  *fix = 0xdeadbeef;
   1.687 +}
   1.688 +static void
   1.689 +fixture_test (guint        *fix,
   1.690 +              gconstpointer test_data)
   1.691 +{
   1.692 +  g_assert_cmphex (*fix, ==, 0xdeadbeef);
   1.693 +  g_test_message ("This is a test message API test message.");
   1.694 +  g_test_bug_base ("http://www.example.com/bugtracker/");
   1.695 +  g_test_bug ("123");
   1.696 +  g_test_bug_base ("http://www.example.com/bugtracker?bugnum=%s;cmd=showbug");
   1.697 +  g_test_bug ("456");
   1.698 +}
   1.699 +static void
   1.700 +fixture_teardown (guint        *fix,
   1.701 +                  gconstpointer test_data)
   1.702 +{
   1.703 +  g_assert_cmphex (*fix, ==, 0xdeadbeef);
   1.704 +}
   1.705 +
   1.706 +static int
   1.707 +main_selftest (int    argc,
   1.708 +               char **argv)
   1.709 +{
   1.710 +  /* gtester main() for --gtester-selftest invokations */
   1.711 +  g_test_init (&argc, &argv, NULL);
   1.712 +  g_test_add ("/gtester/fixture-test", guint, NULL, fixture_setup, fixture_test, fixture_teardown);
   1.713 +  return g_test_run();
   1.714 +}