added g_test_add_data_func() to pass data into tests. allow data arguments
[platform/upstream/glib.git] / glib / gtester.c
1 /* GLib testing framework runner
2  * Copyright (C) 2007 Sven Herzberg
3  * Copyright (C) 2007 Tim Janik
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18  * Boston, MA 02111-1307, USA.
19  */
20 #include <glib.h>
21 #include <gstdio.h>
22 #include <string.h>
23 #include <stdlib.h>
24 #include <unistd.h>
25 #include <fcntl.h>
26 #include <sys/wait.h>
27 #include <errno.h>
28 #include <signal.h>
29
30 /* the read buffer size in bytes */
31 #define READ_BUFFER_SIZE 4096
32
33 /* --- prototypes --- */
34 static int      main_selftest   (int    argc,
35                                  char **argv);
36 static void     parse_args      (gint           *argc_p,
37                                  gchar        ***argv_p);
38
39 /* --- variables --- */
40 static GIOChannel  *ioc_report = NULL;
41 static gboolean     gtester_quiet = FALSE;
42 static gboolean     gtester_verbose = FALSE;
43 static gboolean     gtester_list_tests = FALSE;
44 static gboolean     gtester_selftest = FALSE;
45 static gboolean     subtest_running = FALSE;
46 static gint         subtest_exitstatus = 0;
47 static gboolean     subtest_io_pending = FALSE;
48 static gboolean     subtest_quiet = TRUE;
49 static gboolean     subtest_verbose = FALSE;
50 static gboolean     subtest_mode_fatal = TRUE;
51 static gboolean     subtest_mode_perf = FALSE;
52 static gboolean     subtest_mode_quick = TRUE;
53 static const gchar *subtest_seedstr = NULL;
54 static GSList      *subtest_paths = NULL;
55 static GSList      *subtest_args = NULL;
56 static gboolean     testcase_open = FALSE;
57 static guint        testcase_count = 0;
58 static guint        testcase_fail_count = 0;
59 static const gchar *output_filename = NULL;
60 static guint        log_indent = 0;
61 static gint         log_fd = -1;
62
63 /* --- functions --- */
64 static const char*
65 sindent (guint n)
66 {
67   static const char spaces[] = "                                                                                                    ";
68   int l = sizeof (spaces) - 1;
69   n = MIN (n, l);
70   return spaces + l - n;
71 }
72
73 static void G_GNUC_PRINTF (1, 2)
74 test_log_printfe (const char *format,
75                   ...)
76 {
77   char *result;
78   int r;
79   va_list args;
80   va_start (args, format);
81   result = g_markup_vprintf_escaped (format, args);
82   va_end (args);
83   do
84     r = write (log_fd, result, strlen (result));
85   while (r < 0 && errno == EINTR);
86   g_free (result);
87 }
88
89 static void
90 terminate (void)
91 {
92   kill (getpid(), SIGTERM);
93   abort();
94 }
95
96 static void
97 testcase_close (long double duration,
98                 guint       exit_status,
99                 guint       n_forks)
100 {
101   g_return_if_fail (testcase_open > 0);
102   test_log_printfe ("%s<duration>%.6Lf</duration>\n", sindent (log_indent), duration);
103   test_log_printfe ("%s<status exit-status=\"%d\" n-forks=\"%d\"/>\n",
104                     sindent (log_indent), exit_status, n_forks);
105   log_indent -= 2;
106   test_log_printfe ("%s</testcase>\n", sindent (log_indent));
107   testcase_open--;
108   if (gtester_verbose)
109     g_print ("%s\n", exit_status ? "FAIL" : "OK");
110   if (exit_status)
111     testcase_fail_count += 1;
112   if (subtest_mode_fatal && testcase_fail_count)
113     terminate();
114 }
115
116 static void
117 test_log_msg (GTestLogMsg *msg)
118 {
119   switch (msg->log_type)
120     {
121     case G_TEST_LOG_NONE:
122       break;
123     case G_TEST_LOG_ERROR:
124       g_printerr ("%s\n", msg->strings[0]);
125       break;
126     case G_TEST_LOG_START_BINARY:
127       test_log_printfe ("%s<binary file=\"%s\"/>\n", sindent (log_indent), msg->strings[0]);
128       test_log_printfe ("%s<random-seed>%s</random-seed>\n", sindent (log_indent), msg->strings[1]);
129       break;
130     case G_TEST_LOG_LIST_CASE:
131       g_print ("%s\n", msg->strings[0]);
132       break;
133     case G_TEST_LOG_START_CASE:
134       testcase_count++;
135       if (gtester_verbose)
136         {
137           gchar *sc = g_strconcat (msg->strings[0], ":", NULL);
138           gchar *sleft = g_strdup_printf ("%-68s", sc);
139           g_free (sc);
140           g_print ("%70s ", sleft);
141           g_free (sleft);
142         }
143       g_return_if_fail (testcase_open == 0);
144       testcase_open++;
145       test_log_printfe ("%s<testcase path=\"%s\">\n", sindent (log_indent), msg->strings[0]);
146       log_indent += 2;
147       break;
148     case G_TEST_LOG_SKIP_CASE:
149       if (TRUE && gtester_verbose) // enable to debug test case skipping logic
150         {
151           gchar *sc = g_strconcat (msg->strings[0], ":", NULL);
152           gchar *sleft = g_strdup_printf ("%-68s", sc);
153           g_free (sc);
154           g_print ("%70s SKIPPED\n", sleft);
155           g_free (sleft);
156         }
157       test_log_printfe ("%s<testcase path=\"%s\" skipped=\"1\"/>\n", sindent (log_indent), msg->strings[0]);
158       break;
159     case G_TEST_LOG_STOP_CASE:
160       testcase_close (msg->nums[2], (int) msg->nums[0], (int) msg->nums[1]);
161       break;
162     case G_TEST_LOG_MIN_RESULT:
163     case G_TEST_LOG_MAX_RESULT:
164       test_log_printfe ("%s<performance minimize=\"%d\" maximize=\"%d\" value=\"%.16Lg\">\n",
165                         sindent (log_indent), msg->log_type == G_TEST_LOG_MIN_RESULT, msg->log_type == G_TEST_LOG_MAX_RESULT, msg->nums[0]);
166       test_log_printfe ("%s%s\n", sindent (log_indent + 2), msg->strings[0]);
167       test_log_printfe ("%s</performance>\n", sindent (log_indent));
168       break;
169     case G_TEST_LOG_MESSAGE:
170       test_log_printfe ("%s<message>\n%s\n%s</message>\n", sindent (log_indent), msg->strings[0], sindent (log_indent));
171       break;
172     }
173 }
174
175 static gboolean
176 child_report_cb (GIOChannel  *source,
177                  GIOCondition condition,
178                  gpointer     data)
179 {
180   GTestLogBuffer *tlb = data;
181   GIOStatus status = G_IO_STATUS_NORMAL;
182   gsize length = 0;
183   do
184     {
185       guint8 buffer[READ_BUFFER_SIZE];
186       GError *error = NULL;
187       status = g_io_channel_read_chars (source, (gchar*) buffer, sizeof (buffer), &length, &error);
188       if (length)
189         {
190           GTestLogMsg *msg;
191           g_test_log_buffer_push (tlb, length, buffer);
192           do
193             {
194               msg = g_test_log_buffer_pop (tlb);
195               if (msg)
196                 {
197                   test_log_msg (msg);
198                   g_test_log_msg_free (msg);
199                 }
200             }
201           while (msg);
202         }
203       g_clear_error (&error);
204       /* ignore the io channel status, which seems to be bogus especially for non blocking fds */
205       (void) status;
206     }
207   while (length > 0);
208   if (condition & (G_IO_ERR | G_IO_HUP))
209     {
210       /* if there's no data to read and select() reports an error or hangup,
211        * the fd must have been closed remotely
212        */
213       subtest_io_pending = FALSE;
214       return FALSE;
215     }
216   return TRUE; /* keep polling */
217 }
218
219 static void
220 child_watch_cb (GPid     pid,
221                 gint     status,
222                 gpointer data)
223 {
224   g_spawn_close_pid (pid);
225   if (WIFEXITED (status)) /* normal exit */
226     subtest_exitstatus = WEXITSTATUS (status);
227   else /* signal or core dump, etc */
228     subtest_exitstatus = 0xffffffff;
229   subtest_running = FALSE;
230 }
231
232 static gchar*
233 queue_gfree (GSList **slistp,
234              gchar   *string)
235 {
236   *slistp = g_slist_prepend (*slistp, string);
237   return string;
238 }
239
240 static void
241 unset_cloexec_fdp (gpointer fdp_data)
242 {
243   int r, *fdp = fdp_data;
244   do
245     r = fcntl (*fdp, F_SETFD, 0 /* FD_CLOEXEC */);
246   while (r < 0 && errno == EINTR);
247 }
248
249 static gboolean
250 launch_test_binary (const char *binary,
251                     guint       skip_tests)
252 {
253   GTestLogBuffer *tlb;
254   GSList *slist, *free_list = NULL;
255   GError *error = NULL;
256   const gchar *argv[99 + g_slist_length (subtest_args) + g_slist_length (subtest_paths)];
257   GPid pid = 0;
258   gint report_pipe[2] = { -1, -1 };
259   gint i = 0;
260
261   if (pipe (report_pipe) < 0)
262     {
263       if (subtest_mode_fatal)
264         g_error ("Failed to open pipe for test binary: %s: %s", binary, g_strerror (errno));
265       else
266         g_warning ("Failed to open pipe for test binary: %s: %s", binary, g_strerror (errno));
267       return FALSE;
268     }
269
270   /* setup argv */
271   argv[i++] = binary;
272   for (slist = subtest_args; slist; slist = slist->next)
273     argv[i++] = (gchar*) slist->data;
274   // argv[i++] = "--debug-log";
275   if (subtest_quiet)
276     argv[i++] = "--quiet";
277   if (subtest_verbose)
278     argv[i++] = "--verbose";
279   if (!subtest_mode_fatal)
280     argv[i++] = "--keep-going";
281   if (subtest_mode_quick)
282     argv[i++] = "-m=quick";
283   else
284     argv[i++] = "-m=slow";
285   if (subtest_mode_perf)
286     argv[i++] = "-m=perf";
287   if (gtester_list_tests)
288     argv[i++] = "-l";
289   if (subtest_seedstr)
290     argv[i++] = queue_gfree (&free_list, g_strdup_printf ("--seed=%s", subtest_seedstr));
291   argv[i++] = queue_gfree (&free_list, g_strdup_printf ("--GTestLogFD=%u", report_pipe[1]));
292   if (skip_tests)
293     argv[i++] = queue_gfree (&free_list, g_strdup_printf ("--GTestSkipCount=%u", skip_tests));
294   for (slist = subtest_paths; slist; slist = slist->next)
295     argv[i++] = queue_gfree (&free_list, g_strdup_printf ("-p=%s", (gchar*) slist->data));
296   argv[i++] = NULL;
297
298   g_spawn_async_with_pipes (NULL, /* g_get_current_dir() */
299                             (gchar**) argv,
300                             NULL, /* envp */
301                             G_SPAWN_DO_NOT_REAP_CHILD, /* G_SPAWN_SEARCH_PATH */
302                             unset_cloexec_fdp, &report_pipe[1], /* pre-exec callback */
303                             &pid,
304                             NULL,       /* standard_input */
305                             NULL,       /* standard_output */
306                             NULL,       /* standard_error */
307                             &error);
308   g_slist_foreach (free_list, (void(*)(void*,void*)) g_free, NULL);
309   g_slist_free (free_list);
310   free_list = NULL;
311   close (report_pipe[1]);
312
313   if (!gtester_quiet)
314     g_print ("(pid=%lu)\n", (unsigned long) pid);
315
316   if (error)
317     {
318       close (report_pipe[0]);
319       if (subtest_mode_fatal)
320         g_error ("Failed to execute test binary: %s: %s", argv[0], error->message);
321       else
322         g_warning ("Failed to execute test binary: %s: %s", argv[0], error->message);
323       g_clear_error (&error);
324       return FALSE;
325     }
326
327   subtest_running = TRUE;
328   subtest_io_pending = TRUE;
329   tlb = g_test_log_buffer_new();
330   if (report_pipe[0] >= 0)
331     {
332       ioc_report = g_io_channel_unix_new (report_pipe[0]);
333       g_io_channel_set_flags (ioc_report, G_IO_FLAG_NONBLOCK, NULL);
334       g_io_channel_set_encoding (ioc_report, NULL, NULL);
335       g_io_channel_set_buffered (ioc_report, FALSE);
336       g_io_add_watch_full (ioc_report, G_PRIORITY_DEFAULT - 1, G_IO_IN | G_IO_ERR | G_IO_HUP, child_report_cb, tlb, NULL);
337       g_io_channel_unref (ioc_report);
338     }
339   g_child_watch_add_full (G_PRIORITY_DEFAULT + 1, pid, child_watch_cb, NULL, NULL);
340
341   while (subtest_running ||             /* FALSE once child exits */
342          subtest_io_pending ||          /* FALSE once ioc_report closes */
343          g_main_context_pending (NULL)) /* TRUE while idler, etc are running */
344     g_main_context_iteration (NULL, TRUE);
345
346   close (report_pipe[0]);
347   g_test_log_buffer_free (tlb);
348
349   return TRUE;
350 }
351
352 static void
353 launch_test (const char *binary)
354 {
355   gboolean success = TRUE;
356   GTimer *btimer = g_timer_new();
357   gboolean need_restart;
358   testcase_count = 0;
359   testcase_fail_count = 0;
360   if (!gtester_quiet)
361     g_print ("TEST: %s... ", binary);
362
363  retry:
364   test_log_printfe ("%s<testbinary path=\"%s\">\n", sindent (log_indent), binary);
365   log_indent += 2;
366   g_timer_start (btimer);
367   subtest_exitstatus = 0;
368   success &= launch_test_binary (binary, testcase_count);
369   success &= subtest_exitstatus == 0;
370   need_restart = testcase_open != 0;
371   if (testcase_open)
372     testcase_close (0, -999, 0);
373   g_timer_stop (btimer);
374   test_log_printfe ("%s<duration>%.6f</duration>\n", sindent (log_indent), g_timer_elapsed (btimer, NULL));
375   log_indent -= 2;
376   test_log_printfe ("%s</testbinary>\n", sindent (log_indent));
377   if (need_restart)
378     {
379       /* restart test binary, skipping processed test cases */
380       goto retry;
381     }
382
383   if (!gtester_quiet)
384     g_print ("%s: %s\n", testcase_fail_count || !success ? "FAIL" : "PASS", binary);
385   g_timer_destroy (btimer);
386   if (subtest_mode_fatal && !success)
387     terminate();
388 }
389
390 static void
391 usage (gboolean just_version)
392 {
393   if (just_version)
394     {
395       g_print ("gtester version %d.%d.%d\n", GLIB_MAJOR_VERSION, GLIB_MINOR_VERSION, GLIB_MICRO_VERSION);
396       return;
397     }
398   g_print ("Usage: gtester [OPTIONS] testprogram...\n");
399   /*        12345678901234567890123456789012345678901234567890123456789012345678901234567890 */
400   g_print ("Options:\n");
401   g_print ("  -h, --help                  show this help message\n");
402   g_print ("  -v, --version               print version informations\n");
403   g_print ("  --g-fatal-warnings          make warnings fatal (abort)\n");
404   g_print ("  -k, --keep-going            continue running after tests failed\n");
405   g_print ("  -l                          list paths of available test cases\n");
406   g_print ("  -m=perf, -m=slow, -m=quick  run test cases in mode perf, slow or quick (default)\n");
407   g_print ("  -p=TESTPATH                 only start test cases matching TESTPATH\n");
408   g_print ("  --seed=SEEDSTRING           start all tests with random number seed SEEDSTRING\n");
409   g_print ("  -o=LOGFILE                  write the test log to LOGFILE\n");
410   g_print ("  -q, --quiet                 suppress per test binary output\n");
411   g_print ("  --verbose                   report success per testcase\n");
412 }
413
414 static void
415 parse_args (gint    *argc_p,
416             gchar ***argv_p)
417 {
418   guint argc = *argc_p;
419   gchar **argv = *argv_p;
420   guint i, e;
421   /* parse known args */
422   for (i = 1; i < argc; i++)
423     {
424       if (strcmp (argv[i], "--g-fatal-warnings") == 0)
425         {
426           GLogLevelFlags fatal_mask = (GLogLevelFlags) g_log_set_always_fatal ((GLogLevelFlags) G_LOG_FATAL_MASK);
427           fatal_mask = (GLogLevelFlags) (fatal_mask | G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL);
428           g_log_set_always_fatal (fatal_mask);
429           argv[i] = NULL;
430         }
431       else if (strcmp (argv[i], "--gtester-selftest") == 0)
432         {
433           gtester_selftest = TRUE;
434           argv[i] = NULL;
435           break;        // stop parsing regular gtester arguments
436         }
437       else if (strcmp (argv[i], "-h") == 0 || strcmp (argv[i], "--help") == 0)
438         {
439           usage (FALSE);
440           exit (0);
441           argv[i] = NULL;
442         }
443       else if (strcmp (argv[i], "-v") == 0 || strcmp (argv[i], "--version") == 0)
444         {
445           usage (TRUE);
446           exit (0);
447           argv[i] = NULL;
448         }
449       else if (strcmp (argv[i], "--keep-going") == 0 ||
450                strcmp (argv[i], "-k") == 0)
451         {
452           subtest_mode_fatal = FALSE;
453           argv[i] = NULL;
454         }
455       else if (strcmp ("-p", argv[i]) == 0 || strncmp ("-p=", argv[i], 3) == 0)
456         {
457           gchar *equal = argv[i] + 2;
458           if (*equal == '=')
459             subtest_paths = g_slist_prepend (subtest_paths, equal + 1);
460           else if (i + 1 < argc)
461             {
462               argv[i++] = NULL;
463               subtest_paths = g_slist_prepend (subtest_paths, argv[i]);
464             }
465           argv[i] = NULL;
466         }
467       else if (strcmp ("--test-arg", argv[i]) == 0 || strncmp ("--test-arg=", argv[i], 11) == 0)
468         {
469           gchar *equal = argv[i] + 10;
470           if (*equal == '=')
471             subtest_args = g_slist_prepend (subtest_args, equal + 1);
472           else if (i + 1 < argc)
473             {
474               argv[i++] = NULL;
475               subtest_args = g_slist_prepend (subtest_args, argv[i]);
476             }
477           argv[i] = NULL;
478         }
479       else if (strcmp ("-o", argv[i]) == 0 || strncmp ("-o=", argv[i], 3) == 0)
480         {
481           gchar *equal = argv[i] + 2;
482           if (*equal == '=')
483             output_filename = equal + 1;
484           else if (i + 1 < argc)
485             {
486               argv[i++] = NULL;
487               output_filename = argv[i];
488             }
489           argv[i] = NULL;
490         }
491       else if (strcmp ("-m", argv[i]) == 0 || strncmp ("-m=", argv[i], 3) == 0)
492         {
493           gchar *equal = argv[i] + 2;
494           const gchar *mode = "";
495           if (*equal == '=')
496             mode = equal + 1;
497           else if (i + 1 < argc)
498             {
499               argv[i++] = NULL;
500               mode = argv[i];
501             }
502           if (strcmp (mode, "perf") == 0)
503             subtest_mode_perf = TRUE;
504           else if (strcmp (mode, "slow") == 0)
505             subtest_mode_quick = FALSE;
506           else if (strcmp (mode, "quick") == 0)
507             {
508               subtest_mode_quick = TRUE;
509               subtest_mode_perf = FALSE;
510             }
511           else
512             g_error ("unknown test mode: -m %s", mode);
513           argv[i] = NULL;
514         }
515       else if (strcmp ("-q", argv[i]) == 0 || strcmp ("--quiet", argv[i]) == 0)
516         {
517           gtester_quiet = TRUE;
518           gtester_verbose = FALSE;
519           argv[i] = NULL;
520         }
521       else if (strcmp ("--verbose", argv[i]) == 0)
522         {
523           gtester_quiet = FALSE;
524           gtester_verbose = TRUE;
525           argv[i] = NULL;
526         }
527       else if (strcmp ("-l", argv[i]) == 0)
528         {
529           gtester_list_tests = TRUE;
530           argv[i] = NULL;
531         }
532       else if (strcmp ("--seed", argv[i]) == 0 || strncmp ("--seed=", argv[i], 7) == 0)
533         {
534           gchar *equal = argv[i] + 6;
535           if (*equal == '=')
536             subtest_seedstr = equal + 1;
537           else if (i + 1 < argc)
538             {
539               argv[i++] = NULL;
540               subtest_seedstr = argv[i];
541             }
542           argv[i] = NULL;
543         }
544     }
545   /* collapse argv */
546   e = 1;
547   for (i = 1; i < argc; i++)
548     if (argv[i])
549       {
550         argv[e++] = argv[i];
551         if (i >= e)
552           argv[i] = NULL;
553       }
554   *argc_p = e;
555 }
556
557 int
558 main (int    argc,
559       char **argv)
560 {
561   guint ui;
562
563   /* some unices need SA_RESTART for SIGCHLD to return -EAGAIN for io.
564    * we must fiddle with sigaction() *before* glib is used, otherwise
565    * we could revoke signal hanmdler setups from glib initialization code.
566    */
567   if (TRUE)
568     {
569       struct sigaction sa;
570       struct sigaction osa;
571       sa.sa_handler = SIG_DFL;
572       sigfillset (&sa.sa_mask);
573       sa.sa_flags = SA_RESTART;
574       sigaction (SIGCHLD, &sa, &osa);
575     }
576
577   g_set_prgname (argv[0]);
578   parse_args (&argc, &argv);
579   if (gtester_selftest)
580     return main_selftest (argc, argv);
581
582   if (argc <= 1)
583     {
584       usage (FALSE);
585       return 1;
586     }
587
588   if (output_filename)
589     {
590       log_fd = g_open (output_filename, O_WRONLY | O_CREAT | O_TRUNC, 0666);
591       if (log_fd < 0)
592         g_error ("Failed to open log file '%s': %s", output_filename, g_strerror (errno));
593     }
594
595   test_log_printfe ("<?xml version=\"1.0\"?>\n");
596   test_log_printfe ("%s<gtester>\n", sindent (log_indent));
597   log_indent += 2;
598   for (ui = 1; ui < argc; ui++)
599     {
600       const char *binary = argv[ui];
601       launch_test (binary);
602       /* we only get here on success or if !subtest_mode_fatal */
603     }
604   log_indent -= 2;
605   test_log_printfe ("%s</gtester>\n", sindent (log_indent));
606
607   close (log_fd);
608
609   return 0;
610 }
611
612 static void
613 fixture_setup (guint        *fix,
614                gconstpointer test_data)
615 {
616   g_assert_cmphex (*fix, ==, 0);
617   *fix = 0xdeadbeef;
618 }
619 static void
620 fixture_test (guint        *fix,
621               gconstpointer test_data)
622 {
623   g_assert_cmphex (*fix, ==, 0xdeadbeef);
624   g_test_message ("This is a test message API test message.");
625   g_test_bug_base ("http://www.example.com/bugtracker/");
626   g_test_bug ("123");
627   g_test_bug_base ("http://www.example.com/bugtracker?bugnum=%s;cmd=showbug");
628   g_test_bug ("456");
629 }
630 static void
631 fixture_teardown (guint        *fix,
632                   gconstpointer test_data)
633 {
634   g_assert_cmphex (*fix, ==, 0xdeadbeef);
635 }
636
637 static int
638 main_selftest (int    argc,
639                char **argv)
640 {
641   /* gtester main() for --gtester-selftest invokations */
642   g_test_init (&argc, &argv, NULL);
643   g_test_add ("/gtester/fixture-test", guint, NULL, fixture_setup, fixture_test, fixture_teardown);
644   return g_test_run();
645 }