Implemented test logging basics.
[platform/upstream/glib.git] / glib / gtestframework.c
1 /* GLib testing framework examples
2  * Copyright (C) 2007 Tim Janik
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19 #include "config.h"
20 #include "gtestframework.h"
21 #include <sys/types.h>
22 #include <sys/wait.h>
23 #include <fcntl.h>
24 #include <string.h>
25 #include <stdlib.h>
26 #include <unistd.h>
27 #include <errno.h>
28 #include <signal.h>
29 #ifdef HAVE_SYS_SELECT_H
30 #include <sys/select.h>
31 #endif /* HAVE_SYS_SELECT_H */
32
33 /* --- structures --- */
34 struct GTestCase
35 {
36   gchar  *name;
37   guint   fixture_size;
38   void (*fixture_setup) (void*);
39   void (*fixture_test) (void*);
40   void (*fixture_teardown) (void*);
41 };
42 struct GTestSuite
43 {
44   gchar  *name;
45   GSList *suites;
46   GSList *cases;
47 };
48
49 /* --- prototypes --- */
50 static void                     test_run_seed           (const gchar *rseed);
51 static void                     test_trap_clear         (void);
52
53 /* --- variables --- */
54 static int         test_stdmsg = 1;
55 static gboolean    test_mode_quick = TRUE;
56 static gboolean    test_mode_perf = FALSE;
57 static gboolean    test_mode_fatal = TRUE;
58 static gboolean    g_test_initialized = FALSE;
59 static gboolean    g_test_run_once = TRUE;
60 static gboolean    test_run_quiet = FALSE;
61 static gboolean    test_run_verbose = FALSE;
62 static gboolean    test_run_list = FALSE;
63 static gchar      *test_run_output = NULL;
64 static gchar      *test_run_seedstr = NULL;
65 static GRand      *test_run_rand = NULL;
66 static gchar      *test_run_name = "";
67 static guint       test_run_forks = 0;
68 static GTimer     *test_user_timer = NULL;
69 static double      test_user_stamp = 0;
70 static GSList     *test_paths = NULL;
71 static GTestSuite *test_suite_root = NULL;
72 static GSList     *test_run_free_queue = NULL;
73 static int         test_trap_last_status = 0;
74 static int         test_trap_last_pid = 0;
75 static char       *test_trap_last_stdout = NULL;
76 static char       *test_trap_last_stderr = NULL;
77 static gboolean    test_debug_log = FALSE;
78
79 /* --- functions --- */
80 typedef enum {
81   G_TEST_LOG_NONE,
82   G_TEST_LOG_ERROR,             // s:msg
83   G_TEST_LOG_START_BINARY,      // s:binaryname s:seed
84   G_TEST_LOG_LIST_CASE,         // s:testpath
85   G_TEST_LOG_START_CASE,        // s:testpath
86   G_TEST_LOG_STOP_CASE,         // d:status d:nforks d:elapsed
87   G_TEST_LOG_MIN_RESULT,        // s:blurb d:result
88   G_TEST_LOG_MAX_RESULT,        // s:blurb d:result
89 } GTestLogBit;
90
91 static const char*
92 test_log_bit (GTestLogBit lbit)
93 {
94   switch (lbit)
95     {
96     case G_TEST_LOG_START_BINARY:       return "binary";
97     case G_TEST_LOG_LIST_CASE:          return "list";
98     case G_TEST_LOG_START_CASE:         return "start";
99     case G_TEST_LOG_STOP_CASE:          return "stop";
100     case G_TEST_LOG_MIN_RESULT:         return "minperf";
101     case G_TEST_LOG_MAX_RESULT:         return "maxperf";
102     default:                            return "???";
103     }
104 }
105
106 static void
107 g_test_log (GTestLogBit  lbit,
108             const gchar *string1,
109             const gchar *string2,
110             guint        n_args,
111             long double *largs)
112 {
113   gboolean fail = lbit == G_TEST_LOG_STOP_CASE && largs[0] != 0;
114   const char *bit = test_log_bit (lbit);
115
116   switch (lbit)
117     {
118     case G_TEST_LOG_STOP_CASE:
119       if (!test_run_quiet)
120         g_print ("%s\n", fail ? "FAIL" : "OK");
121       if (fail && test_mode_fatal)
122         abort();
123       break;
124     case G_TEST_LOG_MIN_RESULT:
125       if (test_run_verbose)
126         g_print ("(MINPERF:%s)\n", string1);
127       break;
128     case G_TEST_LOG_MAX_RESULT:
129       if (test_run_verbose)
130         g_print ("(MAXPERF:%s)\n", string1);
131       break;
132     default: ;
133     }
134
135   if (test_debug_log)
136     g_printerr ("{*LOG(%s)", bit);
137   if (test_debug_log && string1)
138     g_printerr (":{%s}", string1);
139   if (test_debug_log && string2)
140     g_printerr (":{%s}", string2);
141   if (n_args)
142     {
143       guint i;
144       if (test_debug_log)
145         g_printerr (":(");
146       for (i = 0; i < n_args; i++)
147         {
148           if (i && test_debug_log)
149             g_printerr (";");
150           if (test_debug_log)
151             g_printerr ("%.16Lg", largs[i]);
152         }
153       if (test_debug_log)
154         g_printerr (")");
155     }
156   if (test_debug_log)
157     g_printerr (":LOG*}\n");
158
159   switch (lbit)
160     {
161     case G_TEST_LOG_START_CASE:
162       if (!test_run_quiet)
163         g_print ("%s: ", string1);
164       break;
165     default: ;
166     }
167 }
168
169 static void
170 parse_args (gint    *argc_p,
171             gchar ***argv_p)
172 {
173   guint argc = *argc_p;
174   gchar **argv = *argv_p;
175   guint i, e;
176   /* parse known args */
177   for (i = 1; i < argc; i++)
178     {
179       if (strcmp (argv[i], "--g-fatal-warnings") == 0)
180         {
181           GLogLevelFlags fatal_mask = (GLogLevelFlags) g_log_set_always_fatal ((GLogLevelFlags) G_LOG_FATAL_MASK);
182           fatal_mask = (GLogLevelFlags) (fatal_mask | G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL);
183           g_log_set_always_fatal (fatal_mask);
184           argv[i] = NULL;
185         }
186       else if (strcmp (argv[i], "--keep-going") == 0 ||
187                strcmp (argv[i], "-k") == 0)
188         {
189           test_mode_fatal = FALSE;
190           argv[i] = NULL;
191         }
192       else if (strcmp (argv[i], "--debug-log") == 0)
193         {
194           test_debug_log = TRUE;
195           argv[i] = NULL;
196         }
197       else if (strcmp ("-p", argv[i]) == 0 || strncmp ("-p=", argv[i], 3) == 0)
198         {
199           gchar *equal = argv[i] + 2;
200           if (*equal == '=')
201             test_paths = g_slist_prepend (test_paths, equal + 1);
202           else if (i + 1 < argc)
203             {
204               argv[i++] = NULL;
205               test_paths = g_slist_prepend (test_paths, argv[i]);
206             }
207           argv[i] = NULL;
208         }
209       else if (strcmp ("-o", argv[i]) == 0 || strncmp ("-o=", argv[i], 3) == 0)
210         {
211           gchar *equal = argv[i] + 2;
212           if (*equal == '=')
213             test_run_output = equal + 1;
214           else if (i + 1 < argc)
215             {
216               argv[i++] = NULL;
217               test_run_output = argv[i];
218             }
219           argv[i] = NULL;
220         }
221       else if (strcmp ("-m", argv[i]) == 0 || strncmp ("-m=", argv[i], 3) == 0)
222         {
223           gchar *equal = argv[i] + 2;
224           const gchar *mode = "";
225           if (*equal == '=')
226             mode = equal + 1;
227           else if (i + 1 < argc)
228             {
229               argv[i++] = NULL;
230               mode = argv[i];
231             }
232           if (strcmp (mode, "perf") == 0)
233             test_mode_perf = TRUE;
234           else if (strcmp (mode, "slow") == 0)
235             test_mode_quick = FALSE;
236           else if (strcmp (mode, "quick") == 0)
237             {
238               test_mode_quick = TRUE;
239               test_mode_perf = FALSE;
240             }
241           else
242             g_error ("unknown test mode: -m %s", mode);
243           argv[i] = NULL;
244         }
245       else if (strcmp ("-q", argv[i]) == 0 || strcmp ("--quiet", argv[i]) == 0)
246         {
247           test_run_quiet = TRUE;
248           test_run_verbose = FALSE;
249           argv[i] = NULL;
250         }
251       else if (strcmp ("--verbose", argv[i]) == 0)
252         {
253           test_run_quiet = FALSE;
254           test_run_verbose = TRUE;
255           argv[i] = NULL;
256         }
257       else if (strcmp ("-l", argv[i]) == 0)
258         {
259           test_run_list = TRUE;
260           argv[i] = NULL;
261         }
262       else if (strcmp ("--seed", argv[i]) == 0 || strncmp ("--seed=", argv[i], 7) == 0)
263         {
264           gchar *equal = argv[i] + 6;
265           if (*equal == '=')
266             test_run_seedstr = equal + 1;
267           else if (i + 1 < argc)
268             {
269               argv[i++] = NULL;
270               test_run_seedstr = argv[i];
271             }
272           argv[i] = NULL;
273         }
274     }
275   /* collapse argv */
276   e = 1;
277   for (i = 1; i < argc; i++)
278     if (argv[i])
279       {
280         argv[e++] = argv[i];
281         if (i >= e)
282           argv[i] = NULL;
283       }
284   *argc_p = e;
285 }
286
287 void
288 g_test_init (int            *argc,
289              char         ***argv,
290              ...)
291 {
292   static char seedstr[4 + 4 * 8 + 1];
293   va_list args;
294   gpointer vararg1;
295   g_return_if_fail (argc != NULL);
296   g_return_if_fail (argv != NULL);
297   g_return_if_fail (g_test_initialized == FALSE);
298   g_test_initialized = TRUE;
299
300   va_start (args, argv);
301   vararg1 = va_arg (args, gpointer); /* reserved for future extensions */
302   va_end (args);
303   g_return_if_fail (vararg1 == NULL);
304
305   /* setup random seed string */
306   g_snprintf (seedstr, sizeof (seedstr), "R02S%08x%08x%08x%08x", g_random_int(), g_random_int(), g_random_int(), g_random_int());
307   test_run_seedstr = seedstr;
308
309   /* parse args, sets up mode, changes seed, etc. */
310   parse_args (argc, argv);
311   if (!g_get_prgname())
312     g_set_prgname ((*argv)[0]);
313
314   /* verify GRand reliability, needed for reliable seeds */
315   if (1)
316     {
317       GRand *rg = g_rand_new_with_seed (0xc8c49fb6);
318       guint32 t1 = g_rand_int (rg), t2 = g_rand_int (rg), t3 = g_rand_int (rg), t4 = g_rand_int (rg);
319       // g_print ("GRand-current: 0x%x 0x%x 0x%x 0x%x\n", t1, t2, t3, t4);
320       if (t1 != 0xfab39f9b || t2 != 0xb948fb0e || t3 != 0x3d31be26 || t4 != 0x43a19d66)
321         g_warning ("random numbers are not GRand-2.2 compatible, seeds may be broken (check $G_RANDOM_VERSION)");
322       g_rand_free (rg);
323     }
324
325   /* check rand seed */
326   test_run_seed (test_run_seedstr);
327
328   /* report program start */
329   g_test_log (G_TEST_LOG_START_BINARY, g_get_prgname(), test_run_seedstr, 0, NULL);
330 }
331
332 static void
333 test_run_seed (const gchar *rseed)
334 {
335   guint seed_failed = 0;
336   if (test_run_rand)
337     g_rand_free (test_run_rand);
338   test_run_rand = NULL;
339   while (strchr (" \t\v\r\n\f", *rseed))
340     rseed++;
341   if (strncmp (rseed, "R02S", 4) == 0)  // seed for random generator 02 (GRand-2.2)
342     {
343       const char *s = rseed + 4;
344       if (strlen (s) >= 32)             // require 4 * 8 chars
345         {
346           guint32 seedarray[4];
347           gchar *p, hexbuf[9] = { 0, };
348           memcpy (hexbuf, s + 0, 8);
349           seedarray[0] = g_ascii_strtoull (hexbuf, &p, 16);
350           seed_failed += p != NULL && *p != 0;
351           memcpy (hexbuf, s + 8, 8);
352           seedarray[1] = g_ascii_strtoull (hexbuf, &p, 16);
353           seed_failed += p != NULL && *p != 0;
354           memcpy (hexbuf, s + 16, 8);
355           seedarray[2] = g_ascii_strtoull (hexbuf, &p, 16);
356           seed_failed += p != NULL && *p != 0;
357           memcpy (hexbuf, s + 24, 8);
358           seedarray[3] = g_ascii_strtoull (hexbuf, &p, 16);
359           seed_failed += p != NULL && *p != 0;
360           if (!seed_failed)
361             {
362               test_run_rand = g_rand_new_with_seed_array (seedarray, 4);
363               return;
364             }
365         }
366     }
367   g_error ("Unknown or invalid random seed: %s", rseed);
368 }
369
370 gint32
371 g_test_rand_int (void)
372 {
373   return g_rand_int (test_run_rand);
374 }
375
376 gint32
377 g_test_rand_int_range (gint32          begin,
378                        gint32          end)
379 {
380   return g_rand_int_range (test_run_rand, begin, end);
381 }
382
383 double
384 g_test_rand_double (void)
385 {
386   return g_rand_double (test_run_rand);
387 }
388
389 double
390 g_test_rand_double_range (double          range_start,
391                           double          range_end)
392 {
393   return g_rand_double_range (test_run_rand, range_start, range_end);
394 }
395
396 void
397 g_test_timer_start (void)
398 {
399   if (!test_user_timer)
400     test_user_timer = g_timer_new();
401   test_user_stamp = 0;
402   g_timer_start (test_user_timer);
403 }
404
405 double
406 g_test_timer_elapsed (void)
407 {
408   test_user_stamp = test_user_timer ? g_timer_elapsed (test_user_timer, NULL) : 0;
409   return test_user_stamp;
410 }
411
412 double
413 g_test_timer_last (void)
414 {
415   return test_user_stamp;
416 }
417
418 void
419 g_test_minimized_result (double          minimized_quantity,
420                          const char     *format,
421                          ...)
422 {
423   long double largs = minimized_quantity;
424   gchar *buffer;
425   va_list args;
426   va_start (args, format);
427   buffer = g_strdup_vprintf (format, args);
428   va_end (args);
429   g_test_log (G_TEST_LOG_MIN_RESULT, buffer, NULL, 1, &largs);
430   g_free (buffer);
431 }
432
433 void
434 g_test_maximized_result (double          maximized_quantity,
435                          const char     *format,
436                          ...)
437 {
438   long double largs = maximized_quantity;
439   gchar *buffer;
440   va_list args;
441   va_start (args, format);
442   buffer = g_strdup_vprintf (format, args);
443   va_end (args);
444   g_test_log (G_TEST_LOG_MAX_RESULT, buffer, NULL, 1, &largs);
445   g_free (buffer);
446 }
447
448 GTestSuite*
449 g_test_get_root (void)
450 {
451   if (!test_suite_root)
452     {
453       test_suite_root = g_test_create_suite ("root");
454       g_free (test_suite_root->name);
455       test_suite_root->name = g_strdup ("");
456     }
457   return test_suite_root;
458 }
459
460 int
461 g_test_run (void)
462 {
463   return g_test_run_suite (g_test_get_root());
464 }
465
466 GTestCase*
467 g_test_create_case (const char     *test_name,
468                     gsize           data_size,
469                     void          (*data_setup) (void),
470                     void          (*data_test) (void),
471                     void          (*data_teardown) (void))
472 {
473   g_return_val_if_fail (test_name != NULL, NULL);
474   g_return_val_if_fail (strchr (test_name, '/') == NULL, NULL);
475   g_return_val_if_fail (test_name[0] != 0, NULL);
476   g_return_val_if_fail (data_test != NULL, NULL);
477   GTestCase *tc = g_slice_new0 (GTestCase);
478   tc->name = g_strdup (test_name);
479   tc->fixture_size = data_size;
480   tc->fixture_setup = (void*) data_setup;
481   tc->fixture_test = (void*) data_test;
482   tc->fixture_teardown = (void*) data_teardown;
483   return tc;
484 }
485
486 void
487 g_test_add_vtable (const char     *testpath,
488                    gsize           data_size,
489                    void          (*data_setup)    (void),
490                    void          (*fixture_test_func) (void),
491                    void          (*data_teardown) (void))
492 {
493   gchar **segments;
494   guint ui;
495   GTestSuite *suite;
496
497   g_return_if_fail (testpath != NULL);
498   g_return_if_fail (testpath[0] == '/');
499   g_return_if_fail (fixture_test_func != NULL);
500
501   suite = g_test_get_root();
502   segments = g_strsplit (testpath, "/", -1);
503   for (ui = 0; segments[ui] != NULL; ui++)
504     {
505       const char *seg = segments[ui];
506       gboolean islast = segments[ui + 1] == NULL;
507       if (islast && !seg[0])
508         g_error ("invalid test case path: %s", testpath);
509       else if (!seg[0])
510         continue;       // initial or duplicate slash
511       else if (!islast)
512         {
513           GTestSuite *csuite = g_test_create_suite (seg);
514           g_test_suite_add_suite (suite, csuite);
515           suite = csuite;
516         }
517       else /* islast */
518         {
519           GTestCase *tc = g_test_create_case (seg, data_size, data_setup, fixture_test_func, data_teardown);
520           g_test_suite_add (suite, tc);
521         }
522     }
523   g_strfreev (segments);
524 }
525
526 void
527 g_test_add_func (const char     *testpath,
528                  void          (*test_func) (void))
529 {
530   g_return_if_fail (testpath != NULL);
531   g_return_if_fail (testpath[0] == '/');
532   g_return_if_fail (test_func != NULL);
533   g_test_add_vtable (testpath, 0, NULL, test_func, NULL);
534 }
535
536 GTestSuite*
537 g_test_create_suite (const char *suite_name)
538 {
539   g_return_val_if_fail (suite_name != NULL, NULL);
540   g_return_val_if_fail (strchr (suite_name, '/') == NULL, NULL);
541   g_return_val_if_fail (suite_name[0] != 0, NULL);
542   GTestSuite *ts = g_slice_new0 (GTestSuite);
543   ts->name = g_strdup (suite_name);
544   return ts;
545 }
546
547 void
548 g_test_suite_add (GTestSuite     *suite,
549                   GTestCase      *test_case)
550 {
551   g_return_if_fail (suite != NULL);
552   g_return_if_fail (test_case != NULL);
553   suite->cases = g_slist_prepend (suite->cases, test_case);
554 }
555
556 void
557 g_test_suite_add_suite (GTestSuite     *suite,
558                         GTestSuite     *nestedsuite)
559 {
560   g_return_if_fail (suite != NULL);
561   g_return_if_fail (nestedsuite != NULL);
562   suite->suites = g_slist_prepend (suite->suites, nestedsuite);
563 }
564
565 void
566 g_test_queue_free (gpointer gfree_pointer)
567 {
568   if (gfree_pointer)
569     test_run_free_queue = g_slist_prepend (test_run_free_queue, gfree_pointer);
570 }
571
572 static int
573 test_case_run (GTestCase *tc)
574 {
575   gchar *old_name;
576   old_name = test_run_name;
577   test_run_name = g_strconcat (old_name, "/", tc->name, NULL);
578   if (test_run_list)
579     {
580       g_print ("%s\n", test_run_name);
581       g_test_log (G_TEST_LOG_LIST_CASE, test_run_name, NULL, 0, NULL);
582     }
583   else
584     {
585       GTimer *test_run_timer = g_timer_new();
586       long double largs[3];
587       g_test_log (G_TEST_LOG_START_CASE, test_run_name, NULL, 0, NULL);
588       test_run_forks = 0;
589       g_timer_start (test_run_timer);
590       void *fixture = g_malloc0 (tc->fixture_size);
591       test_run_seed (test_run_seedstr);
592       if (tc->fixture_setup)
593         tc->fixture_setup (fixture);
594       tc->fixture_test (fixture);
595       test_trap_clear();
596       while (test_run_free_queue)
597         {
598           gpointer freeme = test_run_free_queue->data;
599           test_run_free_queue = g_slist_delete_link (test_run_free_queue, test_run_free_queue);
600           g_free (freeme);
601         }
602       if (tc->fixture_teardown)
603         tc->fixture_teardown (fixture);
604       g_free (fixture);
605       g_timer_stop (test_run_timer);
606       largs[0] = 0; // OK
607       largs[1] = test_run_forks;
608       largs[2] = g_timer_elapsed (test_run_timer, NULL);
609       g_test_log (G_TEST_LOG_STOP_CASE, NULL, NULL, G_N_ELEMENTS (largs), largs);
610     }
611   g_free (test_run_name);
612   test_run_name = old_name;
613   /* FIXME: need reporting here */
614   return 0;
615 }
616
617 static int
618 g_test_run_suite_internal (GTestSuite *suite,
619                            const char *path)
620 {
621   guint n_bad = 0, n_good = 0, bad_suite = 0, l;
622   gchar *rest, *old_name = test_run_name;
623   GSList *slist, *reversed;
624   g_return_val_if_fail (suite != NULL, -1);
625   while (path[0] == '/')
626     path++;
627   l = strlen (path);
628   rest = strchr (path, '/');
629   l = rest ? MIN (l, rest - path) : l;
630   test_run_name = suite->name[0] == 0 ? g_strdup (test_run_name) : g_strconcat (old_name, "/", suite->name, NULL);
631   reversed = g_slist_reverse (g_slist_copy (suite->cases));
632   for (slist = reversed; slist; slist = slist->next)
633     {
634       GTestCase *tc = slist->data;
635       guint n = l ? strlen (tc->name) : 0;
636       if (l == n && strncmp (path, tc->name, n) == 0)
637         {
638           n_good++;
639           n_bad += test_case_run (tc) != 0;
640         }
641     }
642   g_slist_free (reversed);
643   reversed = g_slist_reverse (g_slist_copy (suite->suites));
644   for (slist = reversed; slist; slist = slist->next)
645     {
646       GTestSuite *ts = slist->data;
647       guint n = l ? strlen (ts->name) : 0;
648       if (l == n && strncmp (path, ts->name, n) == 0)
649         bad_suite += g_test_run_suite_internal (ts, rest ? rest : "") != 0;
650     }
651   g_slist_free (reversed);
652   g_free (test_run_name);
653   test_run_name = old_name;
654   return n_bad || bad_suite;
655 }
656
657 int
658 g_test_run_suite (GTestSuite *suite)
659 {
660   guint n_bad = 0;
661   g_return_val_if_fail (g_test_initialized == TRUE, -1);
662   g_return_val_if_fail (g_test_run_once == TRUE, -1);
663   g_test_run_once = FALSE;
664   if (!test_paths)
665     test_paths = g_slist_prepend (test_paths, "");
666   while (test_paths)
667     {
668       const char *rest, *path = test_paths->data;
669       guint l, n;
670       test_paths = g_slist_delete_link (test_paths, test_paths);
671       while (path[0] == '/')
672         path++;
673       rest = strchr (path, '/');
674       l = strlen (path);
675       l = rest ? MIN (l, rest - path) : l;
676       n = l ? strlen (suite->name) : 0;
677       if (l == n && strncmp (path, suite->name, n) == 0)
678         n_bad += 0 != g_test_run_suite_internal (suite, rest ? rest : "");
679     }
680   return n_bad;
681 }
682
683 void
684 g_assertion_message (const char     *domain,
685                      const char     *file,
686                      int             line,
687                      const char     *func,
688                      const char     *message)
689 {
690   char lstr[32];
691   g_snprintf (lstr, 32, "%d", line);
692   char *s = g_strconcat (domain ? domain : "", domain && domain[0] ? ":" : "",
693                          file, ":", lstr, ":",
694                          func, func[0] ? ":" : "",
695                          " ", message, NULL);
696   g_printerr ("**\n** %s\n", s);
697   g_free (s);
698   abort();
699 }
700
701 void
702 g_assertion_message_expr (const char     *domain,
703                           const char     *file,
704                           int             line,
705                           const char     *func,
706                           const char     *expr)
707 {
708   char *s = g_strconcat ("assertion failed: (", expr, ")", NULL);
709   g_assertion_message (domain, file, line, func, s);
710   g_free (s);
711 }
712
713 void
714 g_assertion_message_cmpnum (const char     *domain,
715                             const char     *file,
716                             int             line,
717                             const char     *func,
718                             const char     *expr,
719                             long double     arg1,
720                             const char     *cmp,
721                             long double     arg2,
722                             char            numtype)
723 {
724   char *s = NULL;
725   switch (numtype)
726     {
727     case 'i':   s = g_strdup_printf ("assertion failed (%s): (%.0Lf %s %.0Lf)", expr, arg1, cmp, arg2); break;
728     case 'x':   s = g_strdup_printf ("assertion failed (%s): (0x%08Lx %s 0x%08Lx)", expr, (guint64) arg1, cmp, (guint64) arg2); break;
729     case 'f':   s = g_strdup_printf ("assertion failed (%s): (%.9Lg %s %.9Lg)", expr, arg1, cmp, arg2); break;
730       /* ideally use: floats=%.7g double=%.17g */
731     }
732   g_assertion_message (domain, file, line, func, s);
733   g_free (s);
734 }
735
736 void
737 g_assertion_message_cmpstr (const char     *domain,
738                             const char     *file,
739                             int             line,
740                             const char     *func,
741                             const char     *expr,
742                             const char     *arg1,
743                             const char     *cmp,
744                             const char     *arg2)
745 {
746   char *a1, *a2, *s, *t1 = NULL, *t2 = NULL;
747   a1 = arg1 ? g_strconcat ("\"", t1 = g_strescape (arg1, NULL), "\"", NULL) : g_strdup ("NULL");
748   a2 = arg2 ? g_strconcat ("\"", t2 = g_strescape (arg2, NULL), "\"", NULL) : g_strdup ("NULL");
749   g_free (t1);
750   g_free (t2);
751   s = g_strdup_printf ("assertion failed (%s): (%s %s %s)", expr, a1, cmp, a2);
752   g_free (a1);
753   g_free (a2);
754   g_assertion_message (domain, file, line, func, s);
755   g_free (s);
756 }
757
758 int
759 g_strcmp0 (const char     *str1,
760            const char     *str2)
761 {
762   if (!str1)
763     return -(str1 != str2);
764   if (!str2)
765     return str1 != str2;
766   return strcmp (str1, str2);
767 }
768
769 static int /* 0 on success */
770 kill_child (int  pid,
771             int *status,
772             int  patience)
773 {
774   int wr;
775   if (patience >= 3)    /* try graceful reap */
776     {
777       if (waitpid (pid, status, WNOHANG) > 0)
778         return 0;
779     }
780   if (patience >= 2)    /* try SIGHUP */
781     {
782       kill (pid, SIGHUP);
783       if (waitpid (pid, status, WNOHANG) > 0)
784         return 0;
785       g_usleep (20 * 1000); /* give it some scheduling/shutdown time */
786       if (waitpid (pid, status, WNOHANG) > 0)
787         return 0;
788       g_usleep (50 * 1000); /* give it some scheduling/shutdown time */
789       if (waitpid (pid, status, WNOHANG) > 0)
790         return 0;
791       g_usleep (100 * 1000); /* give it some scheduling/shutdown time */
792       if (waitpid (pid, status, WNOHANG) > 0)
793         return 0;
794     }
795   if (patience >= 1)    /* try SIGTERM */
796     {
797       kill (pid, SIGTERM);
798       if (waitpid (pid, status, WNOHANG) > 0)
799         return 0;
800       g_usleep (200 * 1000); /* give it some scheduling/shutdown time */
801       if (waitpid (pid, status, WNOHANG) > 0)
802         return 0;
803       g_usleep (400 * 1000); /* give it some scheduling/shutdown time */
804       if (waitpid (pid, status, WNOHANG) > 0)
805         return 0;
806     }
807   /* finish it off */
808   kill (pid, SIGKILL);
809   do
810     wr = waitpid (pid, status, 0);
811   while (wr < 0 && errno == EINTR);
812   return wr;
813 }
814
815 static inline int
816 g_string_must_read (GString *gstring,
817                     int      fd)
818 {
819 #define STRING_BUFFER_SIZE     4096
820   char buf[STRING_BUFFER_SIZE];
821   gssize bytes;
822  again:
823   bytes = read (fd, buf, sizeof (buf));
824   if (bytes == 0)
825     return 0; /* EOF, calling this function assumes data is available */
826   else if (bytes > 0)
827     {
828       g_string_append_len (gstring, buf, bytes);
829       return 1;
830     }
831   else if (bytes < 0 && errno == EINTR)
832     goto again;
833   else /* bytes < 0 */
834     {
835       g_warning ("failed to read() from child process (%d): %s", test_trap_last_pid, g_strerror (errno));
836       return 1; /* ignore error after warning */
837     }
838 }
839
840 static inline void
841 g_string_write_out (GString *gstring,
842                     int      outfd,
843                     int     *stringpos)
844 {
845   if (*stringpos < gstring->len)
846     {
847       int r;
848       do
849         r = write (outfd, gstring->str + *stringpos, gstring->len - *stringpos);
850       while (r < 0 && errno == EINTR);
851       *stringpos += MAX (r, 0);
852     }
853 }
854
855 static int
856 sane_dup2 (int fd1,
857            int fd2)
858 {
859   int ret;
860   do
861     ret = dup2 (fd1, fd2);
862   while (ret < 0 && errno == EINTR);
863   return ret;
864 }
865
866 static void
867 test_trap_clear (void)
868 {
869   test_trap_last_status = 0;
870   test_trap_last_pid = 0;
871   g_free (test_trap_last_stdout);
872   test_trap_last_stdout = NULL;
873   g_free (test_trap_last_stderr);
874   test_trap_last_stderr = NULL;
875 }
876
877 static guint64
878 test_time_stamp (void)
879 {
880   GTimeVal tv;
881   guint64 stamp;
882   g_get_current_time (&tv);
883   stamp = tv.tv_sec;
884   stamp = stamp * 1000000 + tv.tv_usec;
885   return stamp;
886 }
887
888 gboolean
889 g_test_trap_fork (guint64        usec_timeout,
890                   GTestTrapFlags test_trap_flags)
891 {
892   int stdout_pipe[2] = { -1, -1 };
893   int stderr_pipe[2] = { -1, -1 };
894   int stdtst_pipe[2] = { -1, -1 };
895   test_trap_clear();
896   if (pipe (stdout_pipe) < 0 || pipe (stderr_pipe) < 0 || pipe (stdtst_pipe) < 0)
897     g_error ("failed to create pipes to fork test program: %s", g_strerror (errno));
898   signal (SIGCHLD, SIG_DFL);
899   test_trap_last_pid = fork ();
900   if (test_trap_last_pid < 0)
901     g_error ("failed to fork test program: %s", g_strerror (errno));
902   if (test_trap_last_pid == 0)  /* child */
903     {
904       int fd0 = -1;
905       close (stdout_pipe[0]);
906       close (stderr_pipe[0]);
907       close (stdtst_pipe[0]);
908       if (!(test_trap_flags & G_TEST_TRAP_INHERIT_STDIN))
909         fd0 = open ("/dev/null", O_RDONLY);
910       if (sane_dup2 (stdout_pipe[1], 1) < 0 || sane_dup2 (stderr_pipe[1], 2) < 0 || (fd0 >= 0 && sane_dup2 (fd0, 0) < 0))
911         g_error ("failed to dup2() in forked test program: %s", g_strerror (errno));
912       if (fd0 >= 3)
913         close (fd0);
914       if (stdout_pipe[1] >= 3)
915         close (stdout_pipe[1]);
916       if (stderr_pipe[1] >= 3)
917         close (stderr_pipe[1]);
918       test_stdmsg = stdtst_pipe[1];
919       return TRUE;
920     }
921   else                          /* parent */
922     {
923       GString *sout = g_string_new (NULL);
924       GString *serr = g_string_new (NULL);
925       GString *stst = g_string_new (NULL);
926       guint64 sstamp;
927       int soutpos = 0, serrpos = 0, ststpos = 0, wr, need_wait = TRUE;
928       test_run_forks++;
929       close (stdout_pipe[1]);
930       close (stderr_pipe[1]);
931       close (stdtst_pipe[1]);
932       sstamp = test_time_stamp();
933       /* read data until we get EOF on all pipes */
934       while (stdout_pipe[0] >= 0 || stderr_pipe[0] >= 0 || stdtst_pipe[0] > 0)
935         {
936           fd_set fds;
937           struct timeval tv;
938           FD_ZERO (&fds);
939           if (stdout_pipe[0] >= 0)
940             FD_SET (stdout_pipe[0], &fds);
941           if (stderr_pipe[0] >= 0)
942             FD_SET (stderr_pipe[0], &fds);
943           if (stdtst_pipe[0] >= 0)
944             FD_SET (stdtst_pipe[0], &fds);
945           tv.tv_sec = 0;
946           tv.tv_usec = MIN (usec_timeout ? usec_timeout : 1000000, 100 * 1000); // sleep at most 0.5 seconds to catch clock skews, etc.
947           int ret = select (MAX (MAX (stdout_pipe[0], stderr_pipe[0]), stdtst_pipe[0]) + 1, &fds, NULL, NULL, &tv);
948           if (ret < 0 && errno != EINTR)
949             {
950               g_warning ("Unexpected error in select() while reading from child process (%d): %s", test_trap_last_pid, g_strerror (errno));
951               break;
952             }
953           if (stdout_pipe[0] >= 0 && FD_ISSET (stdout_pipe[0], &fds) &&
954               g_string_must_read (sout, stdout_pipe[0]) == 0)
955             {
956               close (stdout_pipe[0]);
957               stdout_pipe[0] = -1;
958             }
959           if (stderr_pipe[0] >= 0 && FD_ISSET (stderr_pipe[0], &fds) &&
960               g_string_must_read (serr, stderr_pipe[0]) == 0)
961             {
962               close (stderr_pipe[0]);
963               stderr_pipe[0] = -1;
964             }
965           if (stdtst_pipe[0] >= 0 && FD_ISSET (stdtst_pipe[0], &fds) &&
966               g_string_must_read (stst, stdtst_pipe[0]) == 0)
967             {
968               close (stdtst_pipe[0]);
969               stdtst_pipe[0] = -1;
970             }
971           if (!(test_trap_flags & G_TEST_TRAP_SILENCE_STDOUT))
972             g_string_write_out (sout, 1, &soutpos);
973           if (!(test_trap_flags & G_TEST_TRAP_SILENCE_STDERR))
974             g_string_write_out (serr, 2, &serrpos);
975           if (TRUE) // FIXME: needs capturing into log file
976             g_string_write_out (stst, 1, &ststpos);
977           if (usec_timeout)
978             {
979               guint64 nstamp = test_time_stamp();
980               int status = 0;
981               sstamp = MIN (sstamp, nstamp); // guard against backwards clock skews
982               if (usec_timeout < nstamp - sstamp)
983                 {
984                   /* timeout reached, need to abort the child now */
985                   kill_child (test_trap_last_pid, &status, 3);
986                   test_trap_last_status = 1024; /* timeout */
987                   if (0 && WIFSIGNALED (status))
988                     g_printerr ("%s: child timed out and received: %s\n", G_STRFUNC, g_strsignal (WTERMSIG (status)));
989                   need_wait = FALSE;
990                   break;
991                 }
992             }
993         }
994       close (stdout_pipe[0]);
995       close (stderr_pipe[0]);
996       close (stdtst_pipe[0]);
997       if (need_wait)
998         {
999           int status = 0;
1000           do
1001             wr = waitpid (test_trap_last_pid, &status, 0);
1002           while (wr < 0 && errno == EINTR);
1003           if (WIFEXITED (status)) /* normal exit */
1004             test_trap_last_status = WEXITSTATUS (status); /* 0..255 */
1005           else if (WIFSIGNALED (status))
1006             test_trap_last_status = (WTERMSIG (status) << 12); /* signalled */
1007           else /* WCOREDUMP (status) */
1008             test_trap_last_status = 512; /* coredump */
1009         }
1010       test_trap_last_stdout = g_string_free (sout, FALSE);
1011       test_trap_last_stderr = g_string_free (serr, FALSE);
1012       g_string_free (stst, TRUE);
1013       return FALSE;
1014     }
1015 }
1016
1017 gboolean
1018 g_test_trap_has_passed (void)
1019 {
1020   return test_trap_last_status == 0; /* exit_status == 0 && !signal && !coredump */
1021 }
1022
1023 gboolean
1024 g_test_trap_reached_timeout (void)
1025 {
1026   return 0 != (test_trap_last_status & 1024); /* timeout flag */
1027 }
1028
1029 void
1030 g_test_trap_assertions (const char     *domain,
1031                         const char     *file,
1032                         int             line,
1033                         const char     *func,
1034                         gboolean        must_pass,
1035                         gboolean        must_fail,
1036                         const char     *stdout_pattern,
1037                         const char     *stderr_pattern)
1038 {
1039   if (test_trap_last_pid == 0)
1040     g_error ("child process failed to exit after g_test_trap_fork() and before g_test_trap_assert*()");
1041   if (must_pass && !g_test_trap_has_passed())
1042     {
1043       char *msg = g_strdup_printf ("child process (%d) of test trap failed unexpectedly", test_trap_last_pid);
1044       g_assertion_message (domain, file, line, func, msg);
1045       g_free (msg);
1046     }
1047   if (must_fail && g_test_trap_has_passed())
1048     {
1049       char *msg = g_strdup_printf ("child process (%d) did not fail as expected", test_trap_last_pid);
1050       g_assertion_message (domain, file, line, func, msg);
1051       g_free (msg);
1052     }
1053   if (stdout_pattern && !g_pattern_match_simple (stdout_pattern, test_trap_last_stdout))
1054     {
1055       char *msg = g_strdup_printf ("stdout of child process (%d) failed to match: %s", test_trap_last_pid, stdout_pattern);
1056       g_assertion_message (domain, file, line, func, msg);
1057       g_free (msg);
1058     }
1059   if (stderr_pattern && !g_pattern_match_simple (stderr_pattern, test_trap_last_stderr))
1060     {
1061       char *msg = g_strdup_printf ("stderr of child process (%d) failed to match: %s", test_trap_last_pid, stderr_pattern);
1062       g_assertion_message (domain, file, line, func, msg);
1063       g_free (msg);
1064     }
1065 }