LCOV - code coverage report
Current view: top level - glib/glib - gtester.c (source / functions) Hit Total Coverage
Test: unnamed Lines: 276 442 62.4 %
Date: 2024-04-16 05:15:53 Functions: 16 18 88.9 %
Branches: 121 259 46.7 %

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

Generated by: LCOV version 1.14