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