gtestutils.c 62.3 KB
Newer Older
1
/* GLib testing utilities
2 3
 * Copyright (C) 2007 Imendio AB
 * Authors: Tim Janik, Sven Herzberg
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */
20

Tim Janik's avatar
Tim Janik committed
21
#include "config.h"
22

23
#include "gtestutils.h"
24

25
#include <sys/types.h>
26
#ifdef G_OS_UNIX
27
#include <sys/wait.h>
28
#include <sys/time.h>
29
#include <fcntl.h>
30
#endif
Tim Janik's avatar
Tim Janik committed
31 32
#include <string.h>
#include <stdlib.h>
Matthias Clasen's avatar
Matthias Clasen committed
33
#include <stdio.h>
34
#ifdef HAVE_UNISTD_H
35
#include <unistd.h>
36
#endif
37 38 39
#ifdef G_OS_WIN32
#include <io.h>
#endif
40 41 42 43 44
#include <errno.h>
#include <signal.h>
#ifdef HAVE_SYS_SELECT_H
#include <sys/select.h>
#endif /* HAVE_SYS_SELECT_H */
45 46 47 48 49 50 51 52

#include "gmain.h"
#include "gpattern.h"
#include "grand.h"
#include "gstrfuncs.h"
#include "gtimer.h"

#include "galias.h"
53
 
54 55 56 57
/* Global variable for storing assertion messages; this is the counterpart to
 * glibc's (private) __abort_msg variable, and allows developers and crash
 * analysis systems like Apport and ABRT to fish out assertion messages from
 * core dumps, instead of having to catch them on screen output. */
58
char *__glib_assert_msg = NULL;
Tim Janik's avatar
Tim Janik committed
59 60 61 62 63 64

/* --- structures --- */
struct GTestCase
{
  gchar  *name;
  guint   fixture_size;
65 66 67 68
  void   (*fixture_setup)    (void*, gconstpointer);
  void   (*fixture_test)     (void*, gconstpointer);
  void   (*fixture_teardown) (void*, gconstpointer);
  gpointer test_data;
Tim Janik's avatar
Tim Janik committed
69 70 71 72 73 74 75
};
struct GTestSuite
{
  gchar  *name;
  GSList *suites;
  GSList *cases;
};
76 77 78 79 80 81 82
typedef struct DestroyEntry DestroyEntry;
struct DestroyEntry
{
  DestroyEntry *next;
  GDestroyNotify destroy_func;
  gpointer       destroy_data;
};
Tim Janik's avatar
Tim Janik committed
83

84
/* --- prototypes --- */
85 86 87 88 89 90 91 92 93
static void     test_run_seed                   (const gchar *rseed);
static void     test_trap_clear                 (void);
static guint8*  g_test_log_dump                 (GTestLogMsg *msg,
                                                 guint       *len);
static void     gtest_default_log_handler       (const gchar    *log_domain,
                                                 GLogLevelFlags  log_level,
                                                 const gchar    *message,
                                                 gpointer        unused_data);

94

Tim Janik's avatar
Tim Janik committed
95
/* --- variables --- */
Tim Janik's avatar
Tim Janik committed
96
static int         test_log_fd = -1;
Tim Janik's avatar
Tim Janik committed
97 98 99
static gboolean    test_mode_fatal = TRUE;
static gboolean    g_test_run_once = TRUE;
static gboolean    test_run_list = FALSE;
Tim Janik's avatar
Tim Janik committed
100 101
static gchar      *test_run_seedstr = NULL;
static GRand      *test_run_rand = NULL;
Tim Janik's avatar
Tim Janik committed
102
static gchar      *test_run_name = "";
Tim Janik's avatar
Tim Janik committed
103
static guint       test_run_forks = 0;
104 105
static guint       test_run_count = 0;
static guint       test_skip_count = 0;
Tim Janik's avatar
Tim Janik committed
106 107
static GTimer     *test_user_timer = NULL;
static double      test_user_stamp = 0;
Tim Janik's avatar
Tim Janik committed
108 109
static GSList     *test_paths = NULL;
static GTestSuite *test_suite_root = NULL;
110 111 112 113
static int         test_trap_last_status = 0;
static int         test_trap_last_pid = 0;
static char       *test_trap_last_stdout = NULL;
static char       *test_trap_last_stderr = NULL;
114
static char       *test_uri_base = NULL;
Tim Janik's avatar
Tim Janik committed
115
static gboolean    test_debug_log = FALSE;
116
static DestroyEntry *test_destroy_queue = NULL;
117
static GTestConfig mutable_test_config_vars = {
118
  FALSE,        /* test_initialized */
119 120 121 122 123
  TRUE,         /* test_quick */
  FALSE,        /* test_perf */
  FALSE,        /* test_verbose */
  FALSE,        /* test_quiet */
};
124
const GTestConfig * const g_test_config_vars = &mutable_test_config_vars;
Tim Janik's avatar
Tim Janik committed
125 126

/* --- functions --- */
Tim Janik's avatar
Tim Janik committed
127 128
const char*
g_test_log_type_name (GTestLogType log_type)
Tim Janik's avatar
Tim Janik committed
129
{
Tim Janik's avatar
Tim Janik committed
130
  switch (log_type)
Tim Janik's avatar
Tim Janik committed
131
    {
132 133
    case G_TEST_LOG_NONE:               return "none";
    case G_TEST_LOG_ERROR:              return "error";
Tim Janik's avatar
Tim Janik committed
134 135
    case G_TEST_LOG_START_BINARY:       return "binary";
    case G_TEST_LOG_LIST_CASE:          return "list";
136
    case G_TEST_LOG_SKIP_CASE:          return "skip";
Tim Janik's avatar
Tim Janik committed
137 138 139 140
    case G_TEST_LOG_START_CASE:         return "start";
    case G_TEST_LOG_STOP_CASE:          return "stop";
    case G_TEST_LOG_MIN_RESULT:         return "minperf";
    case G_TEST_LOG_MAX_RESULT:         return "maxperf";
141
    case G_TEST_LOG_MESSAGE:            return "message";
Tim Janik's avatar
Tim Janik committed
142
    }
143
  return "???";
Tim Janik's avatar
Tim Janik committed
144 145 146
}

static void
147 148 149
g_test_log_send (guint         n_bytes,
                 const guint8 *buffer)
{
Tim Janik's avatar
Tim Janik committed
150 151 152 153 154 155 156
  if (test_log_fd >= 0)
    {
      int r;
      do
        r = write (test_log_fd, buffer, n_bytes);
      while (r < 0 && errno == EINTR);
    }
157 158
  if (test_debug_log)
    {
159
      GTestLogBuffer *lbuffer = g_test_log_buffer_new ();
160 161 162 163
      GTestLogMsg *msg;
      guint ui;
      g_test_log_buffer_push (lbuffer, n_bytes, buffer);
      msg = g_test_log_buffer_pop (lbuffer);
164 165
      g_warn_if_fail (msg != NULL);
      g_warn_if_fail (lbuffer->data->len == 0);
166 167
      g_test_log_buffer_free (lbuffer);
      /* print message */
Tim Janik's avatar
Tim Janik committed
168
      g_printerr ("{*LOG(%s)", g_test_log_type_name (msg->log_type));
169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184
      for (ui = 0; ui < msg->n_strings; ui++)
        g_printerr (":{%s}", msg->strings[ui]);
      if (msg->n_nums)
        {
          g_printerr (":(");
          for (ui = 0; ui < msg->n_nums; ui++)
            g_printerr ("%s%.16Lg", ui ? ";" : "", msg->nums[ui]);
          g_printerr (")");
        }
      g_printerr (":LOG*}\n");
      g_test_log_msg_free (msg);
    }
}

static void
g_test_log (GTestLogType lbit,
Tim Janik's avatar
Tim Janik committed
185 186 187 188 189 190
            const gchar *string1,
            const gchar *string2,
            guint        n_args,
            long double *largs)
{
  gboolean fail = lbit == G_TEST_LOG_STOP_CASE && largs[0] != 0;
191 192 193 194
  GTestLogMsg msg;
  gchar *astrings[3] = { NULL, NULL, NULL };
  guint8 *dbuffer;
  guint32 dbufferlen;
Tim Janik's avatar
Tim Janik committed
195 196 197

  switch (lbit)
    {
198 199 200 201
    case G_TEST_LOG_START_BINARY:
      if (g_test_verbose())
        g_print ("GTest: random seed: %s\n", string2);
      break;
Tim Janik's avatar
Tim Janik committed
202
    case G_TEST_LOG_STOP_CASE:
203 204 205
      if (g_test_verbose())
        g_print ("GTest: result: %s\n", fail ? "FAIL" : "OK");
      else if (!g_test_quiet())
Tim Janik's avatar
Tim Janik committed
206 207 208 209 210
        g_print ("%s\n", fail ? "FAIL" : "OK");
      if (fail && test_mode_fatal)
        abort();
      break;
    case G_TEST_LOG_MIN_RESULT:
211
      if (g_test_verbose())
Tim Janik's avatar
Tim Janik committed
212 213 214
        g_print ("(MINPERF:%s)\n", string1);
      break;
    case G_TEST_LOG_MAX_RESULT:
215
      if (g_test_verbose())
Tim Janik's avatar
Tim Janik committed
216 217
        g_print ("(MAXPERF:%s)\n", string1);
      break;
218 219 220 221
    case G_TEST_LOG_MESSAGE:
      if (g_test_verbose())
        g_print ("(MSG: %s)\n", string1);
      break;
Tim Janik's avatar
Tim Janik committed
222 223 224
    default: ;
    }

225 226 227 228 229 230 231 232 233 234
  msg.log_type = lbit;
  msg.n_strings = (string1 != NULL) + (string1 && string2);
  msg.strings = astrings;
  astrings[0] = (gchar*) string1;
  astrings[1] = astrings[0] ? (gchar*) string2 : NULL;
  msg.n_nums = n_args;
  msg.nums = largs;
  dbuffer = g_test_log_dump (&msg, &dbufferlen);
  g_test_log_send (dbufferlen, dbuffer);
  g_free (dbuffer);
Tim Janik's avatar
Tim Janik committed
235 236 237 238

  switch (lbit)
    {
    case G_TEST_LOG_START_CASE:
239 240 241
      if (g_test_verbose())
        g_print ("GTest: run: %s\n", string1);
      else if (!g_test_quiet())
Tim Janik's avatar
Tim Janik committed
242 243 244 245 246 247
        g_print ("%s: ", string1);
      break;
    default: ;
    }
}

248 249 250
/* We intentionally parse the command line without GOptionContext
 * because otherwise you would never be able to test it.
 */
Tim Janik's avatar
Tim Janik committed
251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273
static void
parse_args (gint    *argc_p,
            gchar ***argv_p)
{
  guint argc = *argc_p;
  gchar **argv = *argv_p;
  guint i, e;
  /* parse known args */
  for (i = 1; i < argc; i++)
    {
      if (strcmp (argv[i], "--g-fatal-warnings") == 0)
        {
          GLogLevelFlags fatal_mask = (GLogLevelFlags) g_log_set_always_fatal ((GLogLevelFlags) G_LOG_FATAL_MASK);
          fatal_mask = (GLogLevelFlags) (fatal_mask | G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL);
          g_log_set_always_fatal (fatal_mask);
          argv[i] = NULL;
        }
      else if (strcmp (argv[i], "--keep-going") == 0 ||
               strcmp (argv[i], "-k") == 0)
        {
          test_mode_fatal = FALSE;
          argv[i] = NULL;
        }
Tim Janik's avatar
Tim Janik committed
274 275 276 277 278
      else if (strcmp (argv[i], "--debug-log") == 0)
        {
          test_debug_log = TRUE;
          argv[i] = NULL;
        }
Tim Janik's avatar
Tim Janik committed
279
      else if (strcmp ("--GTestLogFD", argv[i]) == 0 || strncmp ("--GTestLogFD=", argv[i], 13) == 0)
Tim Janik's avatar
Tim Janik committed
280
        {
Tim Janik's avatar
Tim Janik committed
281
          gchar *equal = argv[i] + 12;
Tim Janik's avatar
Tim Janik committed
282
          if (*equal == '=')
Tim Janik's avatar
Tim Janik committed
283
            test_log_fd = g_ascii_strtoull (equal + 1, NULL, 0);
Tim Janik's avatar
Tim Janik committed
284 285 286
          else if (i + 1 < argc)
            {
              argv[i++] = NULL;
Tim Janik's avatar
Tim Janik committed
287
              test_log_fd = g_ascii_strtoull (argv[i], NULL, 0);
Tim Janik's avatar
Tim Janik committed
288 289 290
            }
          argv[i] = NULL;
        }
291 292 293 294 295 296 297 298 299 300 301 302
      else if (strcmp ("--GTestSkipCount", argv[i]) == 0 || strncmp ("--GTestSkipCount=", argv[i], 17) == 0)
        {
          gchar *equal = argv[i] + 16;
          if (*equal == '=')
            test_skip_count = g_ascii_strtoull (equal + 1, NULL, 0);
          else if (i + 1 < argc)
            {
              argv[i++] = NULL;
              test_skip_count = g_ascii_strtoull (argv[i], NULL, 0);
            }
          argv[i] = NULL;
        }
Tim Janik's avatar
Tim Janik committed
303
      else if (strcmp ("-p", argv[i]) == 0 || strncmp ("-p=", argv[i], 3) == 0)
Tim Janik's avatar
Tim Janik committed
304 305 306
        {
          gchar *equal = argv[i] + 2;
          if (*equal == '=')
Tim Janik's avatar
Tim Janik committed
307
            test_paths = g_slist_prepend (test_paths, equal + 1);
Tim Janik's avatar
Tim Janik committed
308 309 310
          else if (i + 1 < argc)
            {
              argv[i++] = NULL;
Tim Janik's avatar
Tim Janik committed
311
              test_paths = g_slist_prepend (test_paths, argv[i]);
Tim Janik's avatar
Tim Janik committed
312 313 314 315 316 317 318 319 320 321 322 323 324 325 326
            }
          argv[i] = NULL;
        }
      else if (strcmp ("-m", argv[i]) == 0 || strncmp ("-m=", argv[i], 3) == 0)
        {
          gchar *equal = argv[i] + 2;
          const gchar *mode = "";
          if (*equal == '=')
            mode = equal + 1;
          else if (i + 1 < argc)
            {
              argv[i++] = NULL;
              mode = argv[i];
            }
          if (strcmp (mode, "perf") == 0)
327
            mutable_test_config_vars.test_perf = TRUE;
Tim Janik's avatar
Tim Janik committed
328
          else if (strcmp (mode, "slow") == 0)
329
            mutable_test_config_vars.test_quick = FALSE;
330 331
          else if (strcmp (mode, "thorough") == 0)
            mutable_test_config_vars.test_quick = FALSE;
Tim Janik's avatar
Tim Janik committed
332 333
          else if (strcmp (mode, "quick") == 0)
            {
334 335
              mutable_test_config_vars.test_quick = TRUE;
              mutable_test_config_vars.test_perf = FALSE;
Tim Janik's avatar
Tim Janik committed
336 337 338 339 340 341 342
            }
          else
            g_error ("unknown test mode: -m %s", mode);
          argv[i] = NULL;
        }
      else if (strcmp ("-q", argv[i]) == 0 || strcmp ("--quiet", argv[i]) == 0)
        {
343 344
          mutable_test_config_vars.test_quiet = TRUE;
          mutable_test_config_vars.test_verbose = FALSE;
Tim Janik's avatar
Tim Janik committed
345 346 347 348
          argv[i] = NULL;
        }
      else if (strcmp ("--verbose", argv[i]) == 0)
        {
349 350
          mutable_test_config_vars.test_quiet = FALSE;
          mutable_test_config_vars.test_verbose = TRUE;
Tim Janik's avatar
Tim Janik committed
351 352 353 354 355 356 357
          argv[i] = NULL;
        }
      else if (strcmp ("-l", argv[i]) == 0)
        {
          test_run_list = TRUE;
          argv[i] = NULL;
        }
Tim Janik's avatar
Tim Janik committed
358
      else if (strcmp ("--seed", argv[i]) == 0 || strncmp ("--seed=", argv[i], 7) == 0)
Tim Janik's avatar
Tim Janik committed
359
        {
Tim Janik's avatar
Tim Janik committed
360
          gchar *equal = argv[i] + 6;
Tim Janik's avatar
Tim Janik committed
361
          if (*equal == '=')
Tim Janik's avatar
Tim Janik committed
362
            test_run_seedstr = equal + 1;
Tim Janik's avatar
Tim Janik committed
363 364 365
          else if (i + 1 < argc)
            {
              argv[i++] = NULL;
Tim Janik's avatar
Tim Janik committed
366
              test_run_seedstr = argv[i];
Tim Janik's avatar
Tim Janik committed
367 368 369
            }
          argv[i] = NULL;
        }
370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390
      else if (strcmp ("-?", argv[i]) == 0 || strcmp ("--help", argv[i]) == 0)
        {
          printf ("Usage:\n"
                  "  %s [OPTION...]\n\n"
                  "Help Options:\n"
                  "  -?, --help                     Show help options\n"
                  "Test Options:\n"
                  "  -l                             List test cases available in a test executable\n"
                  "  -seed=RANDOMSEED               Provide a random seed to reproduce test\n"
                  "                                 runs using random numbers\n"
                  "  --verbose                      Run tests verbosely\n"
                  "  -q, --quiet                    Run tests quietly\n"
                  "  -p TESTPATH                    execute all tests matching TESTPATH\n"
                  "  -m {perf|slow|thorough|quick}  Execute tests according modes\n"
                  "  --debug-log                    debug test logging output\n"
                  "  -k, --keep-going               gtester-specific argument\n"
                  "  --GTestLogFD=N                 gtester-specific argument\n"
                  "  --GTestSkipCount=N             gtester-specific argument\n",
                  argv[0]);
          exit (0);
        }
Tim Janik's avatar
Tim Janik committed
391 392 393 394 395 396 397 398 399 400 401 402 403
    }
  /* collapse argv */
  e = 1;
  for (i = 1; i < argc; i++)
    if (argv[i])
      {
        argv[e++] = argv[i];
        if (i >= e)
          argv[i] = NULL;
      }
  *argc_p = e;
}

404 405 406 407 408 409
/**
 * g_test_init:
 * @argc: Address of the @argc parameter of the main() function.
 *        Changed if any arguments were handled.
 * @argv: Address of the @argv parameter of main().
 *        Any parameters understood by g_test_init() stripped before return.
Matthias Clasen's avatar
Matthias Clasen committed
410
 * @Varargs: Reserved for future extension. Currently, you must pass %NULL.
411 412 413 414 415
 *
 * Initialize the GLib testing framework, e.g. by seeding the
 * test random number generator, the name for g_get_prgname()
 * and parsing test related command line args.
 * So far, the following arguments are understood:
Matthias Clasen's avatar
Matthias Clasen committed
416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486
 * <variablelist>
 *   <varlistentry>
 *     <term><option>-l</option></term>
 *     <listitem><para>
 *       list test cases available in a test executable.
 *     </para></listitem>
 *   </varlistentry>
 *   <varlistentry>
 *     <term><option>--seed=<replaceable>RANDOMSEED</replaceable></option></term>
 *     <listitem><para>
 *       provide a random seed to reproduce test runs using random numbers.
 *     </para></listitem>
 *     </varlistentry>
 *     <varlistentry>
 *       <term><option>--verbose</option></term>
 *       <listitem><para>run tests verbosely.</para></listitem>
 *     </varlistentry>
 *     <varlistentry>
 *       <term><option>-q</option>, <option>--quiet</option></term>
 *       <listitem><para>run tests quietly.</para></listitem>
 *     </varlistentry>
 *     <varlistentry>
 *       <term><option>-p <replaceable>TESTPATH</replaceable></option></term>
 *       <listitem><para>
 *         execute all tests matching <replaceable>TESTPATH</replaceable>.
 *       </para></listitem>
 *     </varlistentry>
 *     <varlistentry>
 *       <term><option>-m {perf|slow|thorough|quick}</option></term>
 *       <listitem><para>
 *         execute tests according to these test modes:
 *         <variablelist>
 *           <varlistentry>
 *             <term>perf</term>
 *             <listitem><para>
 *               performance tests, may take long and report results.
 *             </para></listitem>
 *           </varlistentry>
 *           <varlistentry>
 *             <term>slow, thorough</term>
 *             <listitem><para>
 *               slow and thorough tests, may take quite long and 
 *               maximize coverage.
 *             </para></listitem>
 *           </varlistentry>
 *           <varlistentry>
 *             <term>quick</term>
 *             <listitem><para>
 *               quick tests, should run really quickly and give good coverage.
 *             </para></listitem>
 *           </varlistentry>
 *         </variablelist>
 *       </para></listitem>
 *     </varlistentry>
 *     <varlistentry>
 *       <term><option>--debug-log</option></term>
 *       <listitem><para>debug test logging output.</para></listitem>
 *     </varlistentry>
 *     <varlistentry>
 *       <term><option>-k</option>, <option>--keep-going</option></term>
 *       <listitem><para>gtester-specific argument.</para></listitem>
 *     </varlistentry>
 *     <varlistentry>
 *       <term><option>--GTestLogFD <replaceable>N</replaceable></option></term>
 *       <listitem><para>gtester-specific argument.</para></listitem>
 *     </varlistentry>
 *     <varlistentry>
 *       <term><option>--GTestSkipCount <replaceable>N</replaceable></option></term>
 *       <listitem><para>gtester-specific argument.</para></listitem>
 *     </varlistentry>
 *  </variablelist>
487 488
 *
 * Since: 2.16
489
 */
Tim Janik's avatar
Tim Janik committed
490
void
491 492
g_test_init (int    *argc,
             char ***argv,
Tim Janik's avatar
Tim Janik committed
493 494
             ...)
{
Tim Janik's avatar
Tim Janik committed
495
  static char seedstr[4 + 4 * 8 + 1];
Tim Janik's avatar
Tim Janik committed
496 497
  va_list args;
  gpointer vararg1;
498 499 500
  /* make warnings and criticals fatal for all test programs */
  GLogLevelFlags fatal_mask = (GLogLevelFlags) g_log_set_always_fatal ((GLogLevelFlags) G_LOG_FATAL_MASK);
  fatal_mask = (GLogLevelFlags) (fatal_mask | G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL);
501
  g_log_set_always_fatal (fatal_mask);
502
  /* check caller args */
Tim Janik's avatar
Tim Janik committed
503 504
  g_return_if_fail (argc != NULL);
  g_return_if_fail (argv != NULL);
505 506
  g_return_if_fail (g_test_config_vars->test_initialized == FALSE);
  mutable_test_config_vars.test_initialized = TRUE;
Tim Janik's avatar
Tim Janik committed
507 508 509 510 511 512

  va_start (args, argv);
  vararg1 = va_arg (args, gpointer); /* reserved for future extensions */
  va_end (args);
  g_return_if_fail (vararg1 == NULL);

Tim Janik's avatar
Tim Janik committed
513 514 515 516 517
  /* setup random seed string */
  g_snprintf (seedstr, sizeof (seedstr), "R02S%08x%08x%08x%08x", g_random_int(), g_random_int(), g_random_int(), g_random_int());
  test_run_seedstr = seedstr;

  /* parse args, sets up mode, changes seed, etc. */
Tim Janik's avatar
Tim Janik committed
518
  parse_args (argc, argv);
Tim Janik's avatar
Tim Janik committed
519 520
  if (!g_get_prgname())
    g_set_prgname ((*argv)[0]);
Tim Janik's avatar
Tim Janik committed
521

Tim Janik's avatar
Tim Janik committed
522 523 524 525 526
  /* verify GRand reliability, needed for reliable seeds */
  if (1)
    {
      GRand *rg = g_rand_new_with_seed (0xc8c49fb6);
      guint32 t1 = g_rand_int (rg), t2 = g_rand_int (rg), t3 = g_rand_int (rg), t4 = g_rand_int (rg);
527
      /* g_print ("GRand-current: 0x%x 0x%x 0x%x 0x%x\n", t1, t2, t3, t4); */
Tim Janik's avatar
Tim Janik committed
528 529 530 531
      if (t1 != 0xfab39f9b || t2 != 0xb948fb0e || t3 != 0x3d31be26 || t4 != 0x43a19d66)
        g_warning ("random numbers are not GRand-2.2 compatible, seeds may be broken (check $G_RANDOM_VERSION)");
      g_rand_free (rg);
    }
Tim Janik's avatar
Tim Janik committed
532

Tim Janik's avatar
Tim Janik committed
533 534
  /* check rand seed */
  test_run_seed (test_run_seedstr);
Tim Janik's avatar
Tim Janik committed
535

Tim Janik's avatar
Tim Janik committed
536
  /* report program start */
537
  g_log_set_default_handler (gtest_default_log_handler, NULL);
Tim Janik's avatar
Tim Janik committed
538
  g_test_log (G_TEST_LOG_START_BINARY, g_get_prgname(), test_run_seedstr, 0, NULL);
Tim Janik's avatar
Tim Janik committed
539 540 541 542 543 544 545 546 547 548 549
}

static void
test_run_seed (const gchar *rseed)
{
  guint seed_failed = 0;
  if (test_run_rand)
    g_rand_free (test_run_rand);
  test_run_rand = NULL;
  while (strchr (" \t\v\r\n\f", *rseed))
    rseed++;
550
  if (strncmp (rseed, "R02S", 4) == 0)  /* seed for random generator 02 (GRand-2.2) */
Tim Janik's avatar
Tim Janik committed
551 552
    {
      const char *s = rseed + 4;
553
      if (strlen (s) >= 32)             /* require 4 * 8 chars */
Tim Janik's avatar
Tim Janik committed
554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578
        {
          guint32 seedarray[4];
          gchar *p, hexbuf[9] = { 0, };
          memcpy (hexbuf, s + 0, 8);
          seedarray[0] = g_ascii_strtoull (hexbuf, &p, 16);
          seed_failed += p != NULL && *p != 0;
          memcpy (hexbuf, s + 8, 8);
          seedarray[1] = g_ascii_strtoull (hexbuf, &p, 16);
          seed_failed += p != NULL && *p != 0;
          memcpy (hexbuf, s + 16, 8);
          seedarray[2] = g_ascii_strtoull (hexbuf, &p, 16);
          seed_failed += p != NULL && *p != 0;
          memcpy (hexbuf, s + 24, 8);
          seedarray[3] = g_ascii_strtoull (hexbuf, &p, 16);
          seed_failed += p != NULL && *p != 0;
          if (!seed_failed)
            {
              test_run_rand = g_rand_new_with_seed_array (seedarray, 4);
              return;
            }
        }
    }
  g_error ("Unknown or invalid random seed: %s", rseed);
}

579 580 581
/**
 * g_test_rand_int:
 *
582
 * Get a reproducible random integer number.
Matthias Clasen's avatar
Matthias Clasen committed
583
 *
584
 * The random numbers generated by the g_test_rand_*() family of functions
585 586
 * change with every new test program start, unless the --seed option is
 * given when starting test programs.
Matthias Clasen's avatar
Matthias Clasen committed
587
 *
588 589 590 591 592
 * For individual test cases however, the random number generator is
 * reseeded, to avoid dependencies between tests and to make --seed
 * effective for all test cases.
 *
 * Returns: a random number from the seeded random number generator.
593 594
 *
 * Since: 2.16
595
 */
Tim Janik's avatar
Tim Janik committed
596 597 598 599 600 601
gint32
g_test_rand_int (void)
{
  return g_rand_int (test_run_rand);
}

602 603 604 605 606
/**
 * g_test_rand_int_range:
 * @begin: the minimum value returned by this function
 * @end:   the smallest value not to be returned by this function
 *
607
 * Get a reproducible random integer number out of a specified range,
608 609
 * see g_test_rand_int() for details on test case random numbers.
 *
610
 * Returns: a number with @begin <= number < @end.
611 612
 * 
 * Since: 2.16
613
 */
Tim Janik's avatar
Tim Janik committed
614 615 616 617 618 619 620
gint32
g_test_rand_int_range (gint32          begin,
                       gint32          end)
{
  return g_rand_int_range (test_run_rand, begin, end);
}

621 622 623
/**
 * g_test_rand_double:
 *
624
 * Get a reproducible random floating point number,
625 626
 * see g_test_rand_int() for details on test case random numbers.
 *
Matthias Clasen's avatar
Matthias Clasen committed
627
 * Returns: a random number from the seeded random number generator.
628 629
 *
 * Since: 2.16
630
 */
Tim Janik's avatar
Tim Janik committed
631 632 633 634 635 636
double
g_test_rand_double (void)
{
  return g_rand_double (test_run_rand);
}

637 638 639 640 641
/**
 * g_test_rand_double_range:
 * @range_start: the minimum value returned by this function
 * @range_end: the minimum value not returned by this function
 *
642
 * Get a reproducible random floating pointer number out of a specified range,
643 644
 * see g_test_rand_int() for details on test case random numbers.
 *
645
 * Returns: a number with @range_start <= number < @range_end.
646 647
 *
 * Since: 2.16
648
 */
Tim Janik's avatar
Tim Janik committed
649 650 651 652 653
double
g_test_rand_double_range (double          range_start,
                          double          range_end)
{
  return g_rand_double_range (test_run_rand, range_start, range_end);
Tim Janik's avatar
Tim Janik committed
654 655
}

656 657 658 659 660
/**
 * g_test_timer_start:
 *
 * Start a timing test. Call g_test_timer_elapsed() when the task is supposed
 * to be done. Call this function again to restart the timer.
661 662
 *
 * Since: 2.16
663
 */
Tim Janik's avatar
Tim Janik committed
664 665 666 667 668 669 670 671 672
void
g_test_timer_start (void)
{
  if (!test_user_timer)
    test_user_timer = g_timer_new();
  test_user_stamp = 0;
  g_timer_start (test_user_timer);
}

673 674 675 676
/**
 * g_test_timer_elapsed:
 *
 * Get the time since the last start of the timer with g_test_timer_start().
677 678
 *
 * Returns: the time since the last start of the timer, as a double
679 680
 *
 * Since: 2.16
681
 */
Tim Janik's avatar
Tim Janik committed
682 683 684 685 686 687 688
double
g_test_timer_elapsed (void)
{
  test_user_stamp = test_user_timer ? g_timer_elapsed (test_user_timer, NULL) : 0;
  return test_user_stamp;
}

689 690 691 692
/**
 * g_test_timer_last:
 *
 * Report the last result of g_test_timer_elapsed().
693 694
 *
 * Returns: the last result of g_test_timer_elapsed(), as a double
695 696
 *
 * Since: 2.16
697
 */
Tim Janik's avatar
Tim Janik committed
698 699 700 701 702 703
double
g_test_timer_last (void)
{
  return test_user_stamp;
}

704 705 706 707
/**
 * g_test_minimized_result:
 * @minimized_quantity: the reported value
 * @format: the format string of the report message
Matthias Clasen's avatar
Matthias Clasen committed
708
 * @Varargs: arguments to pass to the printf() function
709 710 711 712 713 714
 *
 * Report the result of a performance or measurement test.
 * The test should generally strive to minimize the reported
 * quantities (smaller values are better than larger ones),
 * this and @minimized_quantity can determine sorting
 * order for test result reports.
715 716
 *
 * Since: 2.16
717
 */
Tim Janik's avatar
Tim Janik committed
718 719 720 721 722 723 724 725 726 727 728 729 730 731 732
void
g_test_minimized_result (double          minimized_quantity,
                         const char     *format,
                         ...)
{
  long double largs = minimized_quantity;
  gchar *buffer;
  va_list args;
  va_start (args, format);
  buffer = g_strdup_vprintf (format, args);
  va_end (args);
  g_test_log (G_TEST_LOG_MIN_RESULT, buffer, NULL, 1, &largs);
  g_free (buffer);
}

733
/**
734
 * g_test_maximized_result:
735 736
 * @maximized_quantity: the reported value
 * @format: the format string of the report message
Matthias Clasen's avatar
Matthias Clasen committed
737
 * @Varargs: arguments to pass to the printf() function
738 739 740 741 742 743
 *
 * Report the result of a performance or measurement test.
 * The test should generally strive to maximize the reported
 * quantities (larger values are better than smaller ones),
 * this and @maximized_quantity can determine sorting
 * order for test result reports.
744 745
 *
 * Since: 2.16
746
 */
Tim Janik's avatar
Tim Janik committed
747 748 749 750 751 752 753 754 755 756 757 758 759 760 761
void
g_test_maximized_result (double          maximized_quantity,
                         const char     *format,
                         ...)
{
  long double largs = maximized_quantity;
  gchar *buffer;
  va_list args;
  va_start (args, format);
  buffer = g_strdup_vprintf (format, args);
  va_end (args);
  g_test_log (G_TEST_LOG_MAX_RESULT, buffer, NULL, 1, &largs);
  g_free (buffer);
}

762 763 764 765 766 767
/**
 * g_test_message:
 * @format: the format string
 * @...:    printf-like arguments to @format
 *
 * Add a message to the test report.
768 769
 *
 * Since: 2.16
770
 */
771 772 773 774 775 776 777 778 779 780 781 782 783
void
g_test_message (const char *format,
                ...)
{
  gchar *buffer;
  va_list args;
  va_start (args, format);
  buffer = g_strdup_vprintf (format, args);
  va_end (args);
  g_test_log (G_TEST_LOG_MESSAGE, buffer, NULL, 0, NULL);
  g_free (buffer);
}

784 785 786 787 788
/**
 * g_test_bug_base:
 * @uri_pattern: the base pattern for bug URIs
 *
 * Specify the base URI for bug reports.
Matthias Clasen's avatar
Matthias Clasen committed
789
 *
790 791 792 793 794 795 796 797 798
 * The base URI is used to construct bug report messages for
 * g_test_message() when g_test_bug() is called.
 * Calling this function outside of a test case sets the
 * default base URI for all test cases. Calling it from within
 * a test case changes the base URI for the scope of the test
 * case only.
 * Bug URIs are constructed by appending a bug specific URI
 * portion to @uri_pattern, or by replacing the special string
 * '%s' within @uri_pattern if that is present.
799 800
 *
 * Since: 2.16
801
 */
802 803 804 805 806 807 808
void
g_test_bug_base (const char *uri_pattern)
{
  g_free (test_uri_base);
  test_uri_base = g_strdup (uri_pattern);
}

809 810 811 812 813 814 815 816
/**
 * g_test_bug:
 * @bug_uri_snippet: Bug specific bug tracker URI portion.
 *
 * This function adds a message to test reports that
 * associates a bug URI with a test case.
 * Bug URIs are constructed from a base URI set with g_test_bug_base()
 * and @bug_uri_snippet.
817 818
 *
 * Since: 2.16
819
 */
820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838
void
g_test_bug (const char *bug_uri_snippet)
{
  char *c;
  g_return_if_fail (test_uri_base != NULL);
  g_return_if_fail (bug_uri_snippet != NULL);
  c = strstr (test_uri_base, "%s");
  if (c)
    {
      char *b = g_strndup (test_uri_base, c - test_uri_base);
      char *s = g_strconcat (b, bug_uri_snippet, c + 2, NULL);
      g_free (b);
      g_test_message ("Bug Reference: %s", s);
      g_free (s);
    }
  else
    g_test_message ("Bug Reference: %s%s", test_uri_base, bug_uri_snippet);
}

839 840 841 842 843 844
/**
 * g_test_get_root:
 *
 * Get the toplevel test suite for the test path API.
 *
 * Returns: the toplevel #GTestSuite
845 846
 *
 * Since: 2.16
847
 */
Tim Janik's avatar
Tim Janik committed
848 849 850 851 852 853 854 855 856 857 858 859
GTestSuite*
g_test_get_root (void)
{
  if (!test_suite_root)
    {
      test_suite_root = g_test_create_suite ("root");
      g_free (test_suite_root->name);
      test_suite_root->name = g_strdup ("");
    }
  return test_suite_root;
}

860 861 862 863 864 865
/**
 * g_test_run:
 *
 * Runs all tests under the toplevel suite which can be retrieved
 * with g_test_get_root(). Similar to g_test_run_suite(), the test
 * cases to be run are filtered according to
Matthias Clasen's avatar
Matthias Clasen committed
866 867
 * test path arguments (-p <replaceable>testpath</replaceable>) as 
 * parsed by g_test_init().
868 869
 * g_test_run_suite() or g_test_run() may only be called once
 * in a program.
870 871
 *
 * Returns: 0 on success
872 873
 *
 * Since: 2.16
874
 */
Tim Janik's avatar
Tim Janik committed
875 876 877 878 879 880
int
g_test_run (void)
{
  return g_test_run_suite (g_test_get_root());
}

881 882 883 884
/**
 * g_test_create_case:
 * @test_name:     the name for the test case
 * @data_size:     the size of the fixture data structure
885
 * @test_data:     test data argument for the test functions
886 887 888 889 890 891 892 893 894 895 896 897
 * @data_setup:    the function to set up the fixture data
 * @data_test:     the actual test function
 * @data_teardown: the function to teardown the fixture data
 *
 * Create a new #GTestCase, named @test_name, this API is fairly
 * low level, calling g_test_add() or g_test_add_func() is preferable.
 * When this test is executed, a fixture structure of size @data_size
 * will be allocated and filled with 0s. Then data_setup() is called
 * to initialize the fixture. After fixture setup, the actual test
 * function data_test() is called. Once the test run completed, the
 * fixture structure is torn down  by calling data_teardown() and
 * after that the memory is released.
898
 *
899 900 901 902 903 904
 * Splitting up a test run into fixture setup, test function and
 * fixture teardown is most usful if the same fixture is used for
 * multiple tests. In this cases, g_test_create_case() will be
 * called with the same fixture, but varying @test_name and
 * @data_test arguments.
 *
905
 * Returns: a newly allocated #GTestCase.
906 907
 *
 * Since: 2.16
908
 */
Tim Janik's avatar
Tim Janik committed
909 910 911
GTestCase*
g_test_create_case (const char     *test_name,
                    gsize           data_size,
912
                    gconstpointer   test_data,
Tim Janik's avatar
Tim Janik committed
913 914 915 916
                    void          (*data_setup) (void),
                    void          (*data_test) (void),
                    void          (*data_teardown) (void))
{
917
  GTestCase *tc;
Tim Janik's avatar
Tim Janik committed
918 919 920 921
  g_return_val_if_fail (test_name != NULL, NULL);
  g_return_val_if_fail (strchr (test_name, '/') == NULL, NULL);
  g_return_val_if_fail (test_name[0] != 0, NULL);
  g_return_val_if_fail (data_test != NULL, NULL);
922
  tc = g_slice_new0 (GTestCase);
Tim Janik's avatar
Tim Janik committed
923
  tc->name = g_strdup (test_name);
924
  tc->test_data = (gpointer) test_data;
Tim Janik's avatar
Tim Janik committed
925 926 927 928 929 930 931
  tc->fixture_size = data_size;
  tc->fixture_setup = (void*) data_setup;
  tc->fixture_test = (void*) data_test;
  tc->fixture_teardown = (void*) data_teardown;
  return tc;
}

932 933 934
void
g_test_add_vtable (const char     *testpath,
                   gsize           data_size,
935
                   gconstpointer   test_data,
936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956
                   void          (*data_setup)    (void),
                   void          (*fixture_test_func) (void),
                   void          (*data_teardown) (void))
{
  gchar **segments;
  guint ui;
  GTestSuite *suite;

  g_return_if_fail (testpath != NULL);
  g_return_if_fail (testpath[0] == '/');
  g_return_if_fail (fixture_test_func != NULL);

  suite = g_test_get_root();
  segments = g_strsplit (testpath, "/", -1);
  for (ui = 0; segments[ui] != NULL; ui++)
    {
      const char *seg = segments[ui];
      gboolean islast = segments[ui + 1] == NULL;
      if (islast && !seg[0])
        g_error ("invalid test case path: %s", testpath);
      else if (!seg[0])
957
        continue;       /* initial or duplicate slash */
958 959 960 961 962 963 964 965
      else if (!islast)
        {
          GTestSuite *csuite = g_test_create_suite (seg);
          g_test_suite_add_suite (suite, csuite);
          suite = csuite;
        }
      else /* islast */
        {
966
          GTestCase *tc = g_test_create_case (seg, data_size, test_data, data_setup, fixture_test_func, data_teardown);
967 968 969 970 971 972
          g_test_suite_add (suite, tc);
        }
    }
  g_strfreev (segments);
}

973 974
/**
 * g_test_add_func:
975
 * @testpath:   Slash-separated test case path name for the test.
976 977 978 979 980
 * @test_func:  The test function to invoke for this test.
 *
 * Create a new test case, similar to g_test_create_case(). However
 * the test is assumed to use no fixture, and test suites are automatically
 * created on the fly and added to the root fixture, based on the
981
 * slash-separated portions of @testpath.
982 983
 *
 * Since: 2.16
984
 */
985 986 987 988 989 990 991
void
g_test_add_func (const char     *testpath,
                 void          (*test_func) (void))
{
  g_return_if_fail (testpath != NULL);
  g_return_if_fail (testpath[0] == '/');
  g_return_if_fail (test_func != NULL);
992 993 994 995 996
  g_test_add_vtable (testpath, 0, NULL, NULL, test_func, NULL);
}

/**
 * g_test_add_data_func:
997
 * @testpath:   Slash-separated test case path name for the test.
998 999 1000 1001 1002 1003
 * @test_data:  Test data argument for the test function.
 * @test_func:  The test function to invoke for this test.
 *
 * Create a new test case, similar to g_test_create_case(). However
 * the test is assumed to use no fixture, and test suites are automatically
 * created on the fly and added to the root fixture, based on the
1004
 * slash-separated portions of @testpath. The @test_data argument
1005
 * will be passed as first argument to @test_func.
1006 1007
 *
 * Since: 2.16
1008 1009 1010 1011 1012 1013 1014 1015 1016 1017
 */
void
g_test_add_data_func (const char     *testpath,
                      gconstpointer   test_data,
                      void          (*test_func) (gconstpointer))
{
  g_return_if_fail (testpath != NULL);
  g_return_if_fail (testpath[0] == '/');
  g_return_if_fail (test_func != NULL);
  g_test_add_vtable (testpath, 0, test_data, NULL, (void(*)(void)) test_func, NULL);
1018 1019
}

1020 1021 1022 1023 1024 1025 1026
/**
 * g_test_create_suite:
 * @suite_name: a name for the suite
 *
 * Create a new test suite with the name @suite_name.
 *
 * Returns: A newly allocated #GTestSuite instance.
1027 1028
 *
 * Since: 2.16
1029
 */
Tim Janik's avatar
Tim Janik committed
1030 1031 1032
GTestSuite*
g_test_create_suite (const char *suite_name)
{
1033
  GTestSuite *ts;
Tim Janik's avatar
Tim Janik committed
1034 1035 1036
  g_return_val_if_fail (suite_name != NULL, NULL);
  g_return_val_if_fail (strchr (suite_name, '/') == NULL, NULL);
  g_return_val_if_fail (suite_name[0] != 0, NULL);
1037
  ts = g_slice_new0 (GTestSuite);
Tim Janik's avatar
Tim Janik committed
1038 1039 1040 1041
  ts->name = g_strdup (suite_name);
  return ts;
}

1042 1043 1044 1045 1046 1047
/**
 * g_test_suite_add:
 * @suite: a #GTestSuite
 * @test_case: a #GTestCase
 *
 * Adds @test_case to @suite.
1048 1049
 *
 * Since: 2.16
1050
 */
Tim Janik's avatar
Tim Janik committed
1051 1052 1053 1054 1055 1056 1057 1058 1059
void
g_test_suite_add (GTestSuite     *suite,
                  GTestCase      *test_case)
{
  g_return_if_fail (suite != NULL);
  g_return_if_fail (test_case != NULL);
  suite->cases = g_slist_prepend (suite->cases, test_case);
}

1060 1061 1062 1063 1064 1065
/**
 * g_test_suite_add_suite:
 * @suite:       a #GTestSuite
 * @nestedsuite: another #GTestSuite
 *
 * Adds @nestedsuite to @suite.
1066 1067
 *
 * Since: 2.16
1068
 */
Tim Janik's avatar
Tim Janik committed
1069 1070 1071 1072 1073 1074 1075 1076 1077
void
g_test_suite_add_suite (GTestSuite     *suite,
                        GTestSuite     *nestedsuite)
{
  g_return_if_fail (suite != NULL);
  g_return_if_fail (nestedsuite != NULL);
  suite->suites = g_slist_prepend (suite->suites, nestedsuite);
}

1078 1079 1080 1081 1082 1083 1084
/**
 * g_test_queue_free:
 * @gfree_pointer: the pointer to be stored.
 *
 * Enqueue a pointer to be released with g_free() during the next
 * teardown phase. This is equivalent to calling g_test_queue_destroy()
 * with a destroy callback of g_free().
1085 1086
 *
 * Since: 2.16
1087
 */
Tim Janik's avatar
Tim Janik committed
1088 1089 1090 1091
void
g_test_queue_free (gpointer gfree_pointer)
{
  if (gfree_pointer)
1092 1093 1094
    g_test_queue_destroy (g_free, gfree_pointer);
}

1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105
/**
 * g_test_queue_destroy:
 * @destroy_func:       Destroy callback for teardown phase.
 * @destroy_data:       Destroy callback data.
 *
 * This function enqueus a callback @destroy_func() to be executed
 * during the next test case teardown phase. This is most useful
 * to auto destruct allocted test resources at the end of a test run.
 * Resources are released in reverse queue order, that means enqueueing
 * callback A before callback B will cause B() to be called before
 * A() during teardown.
1106 1107
 *
 * Since: 2.16
1108
 */
1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119
void
g_test_queue_destroy (GDestroyNotify destroy_func,
                      gpointer       destroy_data)
{
  DestroyEntry *dentry;
  g_return_if_fail (destroy_func != NULL);
  dentry = g_slice_new0 (DestroyEntry);
  dentry->destroy_func = destroy_func;
  dentry->destroy_data = destroy_data;
  dentry->next = test_destroy_queue;
  test_destroy_queue = dentry;
Tim Janik's avatar
Tim Janik committed
1120 1121 1122 1123 1124
}

static int
test_case_run (GTestCase *tc)
{
1125
  gchar *old_name = test_run_name, *old_base = g_strdup (test_uri_base);
Tim Janik's avatar
Tim Janik committed
1126
  test_run_name = g_strconcat (old_name, "/", tc->name, NULL);
1127
  if (++test_run_count <= test_skip_count)
1128 1129
    g_test_log (G_TEST_LOG_SKIP_CASE, test_run_name, NULL, 0, NULL);
  else if (test_run_list)
Tim Janik's avatar
Tim Janik committed
1130 1131 1132 1133
    {
      g_print ("%s\n", test_run_name);
      g_test_log (G_TEST_LOG_LIST_CASE, test_run_name, NULL, 0, NULL);
    }
1134
  else
Tim Janik's avatar
Tim Janik committed
1135
    {
Tim Janik's avatar
Tim Janik committed
1136 1137
      GTimer *test_run_timer = g_timer_new();
      long double largs[3];
1138
      void *fixture;
Tim Janik's avatar
Tim Janik committed
1139 1140
      g_test_log (G_TEST_LOG_START_CASE, test_run_name, NULL, 0, NULL);
      test_run_forks = 0;
1141
      g_test_log_set_fatal_handler (NULL, NULL);
Tim Janik's avatar
Tim Janik committed
1142
      g_timer_start (test_run_timer);
1143
      fixture = tc->fixture_size ? g_malloc0 (tc->fixture_size) : tc->test_data;
Tim Janik's avatar
Tim Janik committed
1144
      test_run_seed (test_run_seedstr);
1145
      if (tc->fixture_setup)
1146 1147
        tc->fixture_setup (fixture, tc->test_data);
      tc->fixture_test (fixture, tc->test_data);
1148
      test_trap_clear();
1149
      while (test_destroy_queue)
1150
        {
1151 1152 1153 1154
          DestroyEntry *dentry = test_destroy_queue;
          test_destroy_queue = dentry->next;
          dentry->destroy_func (dentry->destroy_data);
          g_slice_free (DestroyEntry, dentry);
1155
        }
1156
      if (tc->fixture_teardown)
1157 1158 1159
        tc->fixture_teardown (fixture, tc->test_data);
      if (tc->fixture_size)
        g_free (fixture);
Tim Janik's avatar
Tim Janik committed
1160
      g_timer_stop (test_run_timer);
1161
      largs[0] = 0; /* OK */
Tim Janik's avatar
Tim Janik committed
1162 1163 1164
      largs[1] = test_run_forks;
      largs[2] = g_timer_elapsed (test_run_timer, NULL);
      g_test_log (G_TEST_LOG_STOP_CASE, NULL, NULL, G_N_ELEMENTS (largs), largs);
1165
      g_timer_destroy (test_run_timer);
Tim Janik's avatar
Tim Janik committed
1166 1167 1168
    }
  g_free (test_run_name);
  test_run_name = old_name;
1169 1170
  g_free (test_uri_base);
  test_uri_base = old_base;
Tim Janik's avatar
Tim Janik committed
1171 1172 1173 1174
  return 0;
}

static int
1175 1176
g_test_run_suite_internal (GTestSuite *suite,
                           const char *path)
Tim Janik's avatar
Tim Janik committed
1177
{
1178 1179
  guint n_bad = 0, n_good = 0, bad_suite = 0, l;
  gchar *rest, *old_name = test_run_name;
Tim Janik's avatar
Tim Janik committed
1180 1181
  GSList *slist, *reversed;
  g_return_val_if_fail (suite != NULL, -1);
1182 1183 1184 1185 1186
  while (path[0] == '/')
    path++;
  l = strlen (path);
  rest = strchr (path, '/');
  l = rest ? MIN (l, rest - path) : l;
Tim Janik's avatar
Tim Janik committed
1187 1188 1189 1190 1191
  test_run_name = suite->name[0] == 0 ? g_strdup (test_run_name) : g_strconcat (old_name, "/", suite->name, NULL);
  reversed = g_slist_reverse (g_slist_copy (suite->cases));
  for (slist = reversed; slist; slist = slist->next)
    {
      GTestCase *tc = slist->data;
1192 1193 1194 1195 1196 1197
      guint n = l ? strlen (tc->name) : 0;
      if (l == n && strncmp (path, tc->name, n) == 0)
        {
          n_good++;
          n_bad += test_case_run (tc) != 0;
        }
Tim Janik's avatar
Tim Janik committed
1198 1199 1200 1201 1202 1203
    }
  g_slist_free (reversed);
  reversed = g_slist_reverse (g_slist_copy (suite->suites));
  for (slist = reversed; slist; slist = slist->next)
    {
      GTestSuite *ts = slist->data;
1204 1205 1206
      guint n = l ? strlen (ts->name) : 0;
      if (l == n && strncmp (path, ts->name, n) == 0)
        bad_suite += g_test_run_suite_internal (ts, rest ? rest : "") != 0;
Tim Janik's avatar
Tim Janik committed
1207 1208 1209 1210 1211 1212 1213
    }
  g_slist_free (reversed);
  g_free (test_run_name);
  test_run_name = old_name;
  return n_bad || bad_suite;
}

1214 1215 1216 1217 1218 1219
/**
 * g_test_run_suite:
 * @suite: a #GTestSuite
 *
 * Execute the tests within @suite and all nested #GTestSuites.
 * The test suites to be executed are filtered according to
Matthias Clasen's avatar
Matthias Clasen committed
1220 1221
 * test path arguments (-p <replaceable>testpath</replaceable>) 
 * as parsed by g_test_init().
1222 1223
 * g_test_run_suite() or g_test_run() may only be called once
 * in a program.
1224 1225
 *
 * Returns: 0 on success
1226 1227
 *
 * Since: 2.16
1228
 */
Tim Janik's avatar
Tim Janik committed
1229 1230 1231
int
g_test_run_suite (GTestSuite *suite)
{
1232
  guint n_bad = 0;
1233
  g_return_val_if_fail (g_test_config_vars->test_initialized, -1);
Tim Janik's avatar
Tim Janik committed
1234 1235
  g_return_val_if_fail (g_test_run_once == TRUE, -1);
  g_test_run_once = FALSE;
1236 1237 1238 1239 1240
  if (!test_paths)
    test_paths = g_slist_prepend (test_paths, "");
  while (test_paths)
    {
      const char *rest, *path = test_paths->data;
1241
      guint l, n = strlen (suite->name);
1242 1243 1244
      test_paths = g_slist_delete_link (test_paths, test_paths);
      while (path[0] == '/')
        path++;
1245 1246 1247 1248 1249 1250
      if (!n) /* root suite, run unconditionally */
        {
          n_bad += 0 != g_test_run_suite_internal (suite, path);
          continue;
        }
      /* regular suite, match path */
1251 1252 1253
      rest = strchr (path, '/');
      l = strlen (path);
      l = rest ? MIN (l, rest - path) : l;
Tim Janik's avatar
Tim Janik committed
1254
      if ((!l || l == n) && strncmp (path, suite->name, n) == 0)
1255 1256 1257
        n_bad += 0 != g_test_run_suite_internal (suite, rest ? rest : "");
    }
  return n_bad;
Tim Janik's avatar
Tim Janik committed
1258 1259
}

1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298
static void
gtest_default_log_handler (const gchar    *log_domain,
                           GLogLevelFlags  log_level,
                           const gchar    *message,
                           gpointer        unused_data)
{
  const gchar *strv[16];
  gchar *msg;
  guint i = 0;
  if (log_domain)
    {
      strv[i++] = log_domain;
      strv[i++] = "-";
    }
  if (log_level & G_LOG_FLAG_FATAL)
    strv[i++] = "FATAL-";
  if (log_level & G_LOG_FLAG_RECURSION)
    strv[i++] = "RECURSIVE-";
  if (log_level & G_LOG_LEVEL_ERROR)
    strv[i++] = "ERROR";
  if (log_level & G_LOG_LEVEL_CRITICAL)
    strv[i++] = "CRITICAL";
  if (log_level & G_LOG_LEVEL_WARNING)
    strv[i++] = "WARNING";
  if (log_level & G_LOG_LEVEL_MESSAGE)
    strv[i++] = "MESSAGE";
  if (log_level & G_LOG_LEVEL_INFO)
    strv[i++] = "INFO";
  if (log_level & G_LOG_LEVEL_DEBUG)
    strv[i++] = "DEBUG";
  strv[i++] = ": ";
  strv[i++] = message;
  strv[i++] = NULL;
  msg = g_strjoinv ("", (gchar**) strv);
  g_test_log (G_TEST_LOG_ERROR, msg, NULL, 0, NULL);
  g_log_default_handler (log_domain, log_level, message, unused_data);
  g_free (msg);
}

Tim Janik's avatar
Tim Janik committed
1299 1300 1301 1302 1303 1304 1305 1306
void
g_assertion_message (const char     *domain,
                     const char     *file,
                     int             line,
                     const char     *func,
                     const char     *message)
{
  char lstr[32];
1307
  char *s;
1308 1309
  if (!message)
    message = "code should not be reached";
Tim Janik's avatar
Tim Janik committed
1310
  g_snprintf (lstr, 32, "%d", line);
1311
  s = g_strconcat (domain ? domain : "", domain && domain[0] ? ":" : "",
1312
                   "ERROR:", file, ":", lstr, ":",
1313 1314
                   func, func[0] ? ":" : "",
                   " ", message, NULL);
1315
  g_printerr ("**\n%s\n", s);
1316 1317

  /* store assertion message in global variable, so that it can be found in a
1318 1319
   * core dump */
  if (__glib_assert_msg != NULL)
1320
      /* free the old one */
1321 1322 1323
      free (__glib_assert_msg);
  __glib_assert_msg = (char*) malloc (strlen (s) + 1);
  strcpy (__glib_assert_msg, s);
1324

1325
  g_test_log (G_TEST_LOG_ERROR, s, NULL, 0, NULL);
Tim Janik's avatar
Tim Janik committed
1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356
  g_free (s);
  abort();
}

void
g_assertion_message_expr (const char     *domain,
                          const char     *file,
                          int             line,
                          const char     *func,
                          const char     *expr)
{
  char *s = g_strconcat ("assertion failed: (", expr, ")", NULL);
  g_assertion_message (domain, file, line, func, s);
  g_free (s);
}

void
g_assertion_message_cmpnum (const char     *domain,
                            const char     *file,
                            int             line,
                            const char     *func,
                            const char     *expr,
                            long double     arg1,
                            const char     *cmp,
                            long double     arg2,
                            char            numtype)
{
  char *s = NULL;
  switch (numtype)
    {
    case 'i':   s = g_strdup_printf ("assertion failed (%s): (%.0Lf %s %.0Lf)", expr, arg1, cmp, arg2); break;
Matthias Clasen's avatar
Matthias Clasen committed
1357
    case 'x':   s = g_strdup_printf ("assertion failed (%s): (0x%08" G_GINT64_MODIFIER "x %s 0x%08" G_GINT64_MODIFIER "x)", expr, (guint64) arg1, cmp, (guint64) arg2); break;
Tim Janik's avatar
Tim Janik committed
1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386
    case 'f':   s = g_strdup_printf ("assertion failed (%s): (%.9Lg %s %.9Lg)", expr, arg1, cmp, arg2); break;
      /* ideally use: floats=%.7g double=%.17g */
    }
  g_assertion_message (domain, file, line, func, s);
  g_free (s);
}

void
g_assertion_message_cmpstr (const char     *domain,
                            const char     *file,
                            int             line,
                            const char     *func,
                            const char     *expr,
                            const char     *arg1,
                            const char     *cmp,
                            const char     *arg2)
{
  char *a1, *a2, *s, *t1 = NULL, *t2 = NULL;
  a1 = arg1 ? g_strconcat ("\"", t1 = g_strescape (arg1, NULL), "\"", NULL) : g_strdup ("NULL");
  a2 = arg2 ? g_strconcat ("\"", t2 = g_strescape (arg2, NULL), "\"", NULL) : g_strdup ("NULL");
  g_free (t1);
  g_free (t2);
  s = g_strdup_printf ("assertion failed (%s): (%s %s %s)", expr, a1, cmp, a2);
  g_free (a1);
  g_free (a2);
  g_assertion_message (domain, file, line, func, s);
  g_free (s);
}

1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420
void
g_assertion_message_error (const char     *domain,
			   const char     *file,
			   int             line,
			   const char     *func,
			   const char     *expr,
			   GError         *error,
			   GQuark          error_domain,
			   int             error_code)
{
  GString *gstring;

  /* This is used by both g_assert_error() and g_assert_no_error(), so there
   * are three cases: expected an error but got the wrong error, expected
   * an error but got no error, and expected no error but got an error.
   */

  gstring = g_string_new ("assertion failed ");
  if (error_domain)
      g_string_append_printf (gstring, "(%s == (%s, %d)): ", expr,
			      g_quark_to_string (error_domain), error_code);
  else
    g_string_append_printf (gstring, "(%s == NULL): ", expr);

  if (error)
      g_string_append_printf (gstring, "%s (%s, %d)", error->message,
			      g_quark_to_string (error->domain), error->code);
  else
    g_string_append_printf (gstring, "%s is NULL", expr);

  g_assertion_message (domain, file, line, func, gstring->str);
  g_string_free (gstring, TRUE);
}

1421 1422 1423 1424 1425
/**
 * g_strcmp0:
 * @str1: a C string or %NULL
 * @str2: another C string or %NULL
 *
Matthias Clasen's avatar
Matthias Clasen committed