1deb9a5e6d867ac22ab66fe6ce4451cdeb44af81
[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 <string.h>
22 #include <stdlib.h>
23 #include <unistd.h>
24 #include <unistd.h>
25 #include <fcntl.h>
26 #include <errno.h>
27 #include <signal.h>
28
29 /* the read buffer size in bytes */
30 #define READ_BUFFER_SIZE 4096
31
32 /* --- prototypes --- */
33 static void     parse_args      (gint           *argc_p,
34                                  gchar        ***argv_p);
35
36 /* --- variables --- */
37 static GIOChannel  *ioc_report = NULL;
38 static gboolean     subtest_running = FALSE;
39 static gboolean     subtest_io_pending = FALSE;
40 static gboolean     gtester_quiet = TRUE;
41 static gboolean     gtester_verbose = FALSE;
42 static gboolean     gtester_list_tests = FALSE;
43 static gboolean     subtest_mode_fatal = FALSE;
44 static gboolean     subtest_mode_perf = FALSE;
45 static gboolean     subtest_mode_quick = TRUE;
46 static const gchar *subtest_seedstr = NULL;
47 static GSList      *subtest_paths = NULL;
48 static const gchar *outpu_filename = NULL;
49
50 /* --- functions --- */
51 static gboolean
52 child_report_cb (GIOChannel  *source,
53                  GIOCondition condition,
54                  gpointer     data)
55 {
56   GTestLogBuffer *tlb = data;
57   GIOStatus status = G_IO_STATUS_NORMAL;
58   gsize length = 0;
59   do
60     {
61       guint8 buffer[READ_BUFFER_SIZE];
62       GError *error = NULL;
63       status = g_io_channel_read_chars (source, (gchar*) buffer, sizeof (buffer), &length, &error);
64       if (length)
65         {
66           GTestLogMsg *msg;
67           g_test_log_buffer_push (tlb, length, buffer);
68           do
69             {
70               msg = g_test_log_buffer_pop (tlb);
71               if (msg)
72                 {
73                   guint ui;
74                   /* print message, this should be written to an XML log file */
75                   g_printerr ("{*GTLOG(%s)", g_test_log_type_name (msg->log_type));
76                   for (ui = 0; ui < msg->n_strings; ui++)
77                     g_printerr (":{%s}", msg->strings[ui]);
78                   if (msg->n_nums)
79                     {
80                       g_printerr (":(");
81                       for (ui = 0; ui < msg->n_nums; ui++)
82                         g_printerr ("%s%.16Lg", ui ? ";" : "", msg->nums[ui]);
83                       g_printerr (")");
84                     }
85                   g_printerr (":GTLOG*}\n");
86                   g_test_log_msg_free (msg);
87                 }
88             }
89           while (msg);
90         }
91       g_clear_error (&error);
92       /* ignore the io channel status, which seems to be bogus especially for non blocking fds */
93       (void) status;
94     }
95   while (length > 0);
96   if (condition & (G_IO_ERR | G_IO_HUP))
97     {
98       /* if there's no data to read and select() reports an error or hangup,
99        * the fd must have been closed remotely
100        */
101       subtest_io_pending = FALSE;
102       return FALSE;
103     }
104   return TRUE; /* keep polling */
105 }
106
107 static void
108 child_watch_cb (GPid     pid,
109                 gint     status,
110                 gpointer data)
111 {
112   g_spawn_close_pid (pid);
113   subtest_running = FALSE;
114 }
115
116 static gchar*
117 queue_gfree (GSList **slistp,
118              gchar   *string)
119 {
120   *slistp = g_slist_prepend (*slistp, string);
121   return string;
122 }
123
124 static void
125 unset_cloexec_fdp (gpointer fdp_data)
126 {
127   int r, *fdp = fdp_data;
128   do
129     r = fcntl (*fdp, F_SETFD, 0 /* FD_CLOEXEC */);
130   while (r < 0 && errno == EINTR);
131 }
132
133 static void
134 launch_test (const char *binary)
135 {
136   GTestLogBuffer *tlb;
137   GSList *slist, *free_list = NULL;
138   GError *error = NULL;
139   const gchar *argv[20 + g_slist_length (subtest_paths)];
140   GPid pid = 0;
141   gint report_pipe[2] = { -1, -1 };
142   gint i = 0;
143
144   if (pipe (report_pipe) < 0)
145     {
146       if (subtest_mode_fatal)
147         g_error ("Failed to open pipe for test binary: %s: %s", binary, g_strerror (errno));
148       else
149         g_warning ("Failed to open pipe for test binary: %s: %s", binary, g_strerror (errno));
150       return;
151     }
152
153   /* setup argv */
154   argv[i++] = binary;
155   if (gtester_quiet)
156     argv[i++] = "--quiet";
157   if (gtester_verbose)
158     argv[i++] = "--verbose";
159   // argv[i++] = "--debug-log";
160   argv[i++] = queue_gfree (&free_list, g_strdup_printf ("--GTestLogFD=%u", report_pipe[1]));
161   if (!subtest_mode_fatal)
162     argv[i++] = "--keep-going";
163   if (subtest_mode_quick)
164     argv[i++] = "-m=quick";
165   else
166     argv[i++] = "-m=slow";
167   if (subtest_mode_perf)
168     argv[i++] = "-m=perf";
169   if (subtest_seedstr)
170     argv[i++] = queue_gfree (&free_list, g_strdup_printf ("--seed=%s", subtest_seedstr));
171   for (slist = subtest_paths; slist; slist = slist->next)
172     argv[i++] = queue_gfree (&free_list, g_strdup_printf ("-p=%s", (gchar*) slist->data));
173   if (gtester_list_tests)
174     argv[i++] = "-l";
175   argv[i++] = NULL;
176
177   g_spawn_async_with_pipes (NULL, /* g_get_current_dir() */
178                             (gchar**) argv,
179                             NULL, /* envp */
180                             G_SPAWN_DO_NOT_REAP_CHILD, /* G_SPAWN_SEARCH_PATH */
181                             unset_cloexec_fdp, &report_pipe[1], /* pre-exec callback */
182                             &pid,
183                             NULL,       /* standard_input */
184                             NULL,       /* standard_output */
185                             NULL,       /* standard_error */
186                             &error);
187   g_slist_foreach (free_list, (void(*)(void*,void*)) g_free, NULL);
188   g_slist_free (free_list);
189   free_list = NULL;
190   close (report_pipe[1]);
191
192   if (error)
193     {
194       close (report_pipe[0]);
195       if (subtest_mode_fatal)
196         g_error ("Failed to execute test binary: %s: %s", argv[0], error->message);
197       else
198         g_warning ("Failed to execute test binary: %s: %s", argv[0], error->message);
199       g_clear_error (&error);
200       return;
201     }
202
203   subtest_running = TRUE;
204   subtest_io_pending = TRUE;
205   tlb = g_test_log_buffer_new();
206   if (report_pipe[0] >= 0)
207     {
208       ioc_report = g_io_channel_unix_new (report_pipe[0]);
209       g_io_channel_set_flags (ioc_report, G_IO_FLAG_NONBLOCK, NULL);
210       g_io_channel_set_encoding (ioc_report, NULL, NULL);
211       g_io_channel_set_buffered (ioc_report, FALSE);
212       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);
213       g_io_channel_unref (ioc_report);
214     }
215   g_child_watch_add_full (G_PRIORITY_DEFAULT + 1, pid, child_watch_cb, NULL, NULL);
216
217   while (subtest_running ||             /* FALSE once child exits */
218          subtest_io_pending ||          /* FALSE once ioc_report closes */
219          g_main_context_pending (NULL)) /* TRUE while idler, etc are running */
220     g_main_context_iteration (NULL, TRUE);
221
222   close (report_pipe[0]);
223   g_test_log_buffer_free (tlb);
224 }
225
226 static void
227 usage (gboolean just_version)
228 {
229   if (just_version)
230     {
231       g_print ("gtester version %d.%d.%d\n", GLIB_MAJOR_VERSION, GLIB_MINOR_VERSION, GLIB_MICRO_VERSION);
232       return;
233     }
234   g_print ("Usage: gtester [OPTIONS] testprogram...\n");
235   /*        12345678901234567890123456789012345678901234567890123456789012345678901234567890 */
236   g_print ("Options:\n");
237   g_print ("  -h, --help                  show this help message\n");
238   g_print ("  -v, --version               print version informations\n");
239   g_print ("  --g-fatal-warnings          make warnings fatal (abort)\n");
240   g_print ("  -k, --keep-going            continue running after tests failed\n");
241   g_print ("  -l                          list paths of available test cases\n");
242   g_print ("  -m=perf, -m=slow, -m=quick  run test cases in mode perf, slow or quick (default)\n");
243   g_print ("  -p=TESTPATH                 only start test cases matching TESTPATH\n");
244   g_print ("  --seed=SEEDSTRING           start all tests with random number seed SEEDSTRING\n");
245   g_print ("  -o=LOGFILE                  write the test log to LOGFILE\n");
246   g_print ("  -q, --quiet                 suppress unnecessary output\n");
247   g_print ("  --verbose                   produce additional output\n");
248 }
249
250 static void
251 parse_args (gint    *argc_p,
252             gchar ***argv_p)
253 {
254   guint argc = *argc_p;
255   gchar **argv = *argv_p;
256   guint i, e;
257   /* parse known args */
258   for (i = 1; i < argc; i++)
259     {
260       if (strcmp (argv[i], "--g-fatal-warnings") == 0)
261         {
262           GLogLevelFlags fatal_mask = (GLogLevelFlags) g_log_set_always_fatal ((GLogLevelFlags) G_LOG_FATAL_MASK);
263           fatal_mask = (GLogLevelFlags) (fatal_mask | G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL);
264           g_log_set_always_fatal (fatal_mask);
265           argv[i] = NULL;
266         }
267       else if (strcmp (argv[i], "-h") == 0 || strcmp (argv[i], "--help") == 0)
268         {
269           usage (FALSE);
270           exit (0);
271           argv[i] = NULL;
272         }
273       else if (strcmp (argv[i], "-v") == 0 || strcmp (argv[i], "--version") == 0)
274         {
275           usage (TRUE);
276           exit (0);
277           argv[i] = NULL;
278         }
279       else if (strcmp (argv[i], "--keep-going") == 0 ||
280                strcmp (argv[i], "-k") == 0)
281         {
282           subtest_mode_fatal = FALSE;
283           argv[i] = NULL;
284         }
285       else if (strcmp ("-p", argv[i]) == 0 || strncmp ("-p=", argv[i], 3) == 0)
286         {
287           gchar *equal = argv[i] + 2;
288           if (*equal == '=')
289             subtest_paths = g_slist_prepend (subtest_paths, equal + 1);
290           else if (i + 1 < argc)
291             {
292               argv[i++] = NULL;
293               subtest_paths = g_slist_prepend (subtest_paths, argv[i]);
294             }
295           argv[i] = NULL;
296         }
297       else if (strcmp ("-o", argv[i]) == 0 || strncmp ("-o=", argv[i], 3) == 0)
298         {
299           gchar *equal = argv[i] + 2;
300           if (*equal == '=')
301             outpu_filename = equal + 1;
302           else if (i + 1 < argc)
303             {
304               argv[i++] = NULL;
305               outpu_filename = argv[i];
306             }
307           argv[i] = NULL;
308         }
309       else if (strcmp ("-m", argv[i]) == 0 || strncmp ("-m=", argv[i], 3) == 0)
310         {
311           gchar *equal = argv[i] + 2;
312           const gchar *mode = "";
313           if (*equal == '=')
314             mode = equal + 1;
315           else if (i + 1 < argc)
316             {
317               argv[i++] = NULL;
318               mode = argv[i];
319             }
320           if (strcmp (mode, "perf") == 0)
321             subtest_mode_perf = TRUE;
322           else if (strcmp (mode, "slow") == 0)
323             subtest_mode_quick = FALSE;
324           else if (strcmp (mode, "quick") == 0)
325             {
326               subtest_mode_quick = TRUE;
327               subtest_mode_perf = FALSE;
328             }
329           else
330             g_error ("unknown test mode: -m %s", mode);
331           argv[i] = NULL;
332         }
333       else if (strcmp ("-q", argv[i]) == 0 || strcmp ("--quiet", argv[i]) == 0)
334         {
335           gtester_quiet = TRUE;
336           gtester_verbose = FALSE;
337           argv[i] = NULL;
338         }
339       else if (strcmp ("--verbose", argv[i]) == 0)
340         {
341           gtester_quiet = FALSE;
342           gtester_verbose = TRUE;
343           argv[i] = NULL;
344         }
345       else if (strcmp ("-l", argv[i]) == 0)
346         {
347           gtester_list_tests = TRUE;
348           argv[i] = NULL;
349         }
350       else if (strcmp ("--seed", argv[i]) == 0 || strncmp ("--seed=", argv[i], 7) == 0)
351         {
352           gchar *equal = argv[i] + 6;
353           if (*equal == '=')
354             subtest_seedstr = equal + 1;
355           else if (i + 1 < argc)
356             {
357               argv[i++] = NULL;
358               subtest_seedstr = argv[i];
359             }
360           argv[i] = NULL;
361         }
362     }
363   /* collapse argv */
364   e = 1;
365   for (i = 1; i < argc; i++)
366     if (argv[i])
367       {
368         argv[e++] = argv[i];
369         if (i >= e)
370           argv[i] = NULL;
371       }
372   *argc_p = e;
373 }
374
375 int
376 main (int    argc,
377       char **argv)
378 {
379   guint ui;
380
381   /* some unices need SA_RESTART for SIGCHLD to return -EAGAIN for io.
382    * we must fiddle with sigaction() *before* glib is used, otherwise
383    * we could revoke signal hanmdler setups from glib initialization code.
384    */
385   if (TRUE * 0)
386     {
387       struct sigaction sa;
388       struct sigaction osa;
389       sa.sa_handler = SIG_DFL;
390       sigfillset (&sa.sa_mask);
391       sa.sa_flags = SA_RESTART;
392       sigaction (SIGCHLD, &sa, &osa);
393     }
394
395   g_set_prgname (argv[0]);
396   parse_args (&argc, &argv);
397
398   if (argc <= 1)
399     {
400       usage (FALSE);
401       return 1;
402     }
403
404   for (ui = 1; ui < argc; ui++)
405     {
406       const char *binary = argv[ui];
407       launch_test (binary);
408     }
409
410   /* we only get here on success or if !subtest_mode_fatal */
411   return 0;
412 }