LCOV - code coverage report
Current view: top level - glib/gio/tests - gsubprocess.c (source / functions) Hit Total Coverage
Test: unnamed Lines: 1125 1142 98.5 %
Date: 2024-04-23 05:16:05 Functions: 66 66 100.0 %
Branches: 91 109 83.5 %

           Branch data     Line data    Source code
       1                 :            : #include <gio/gio.h>
       2                 :            : #include <string.h>
       3                 :            : 
       4                 :            : #ifdef G_OS_UNIX
       5                 :            : #include <sys/wait.h>
       6                 :            : #include <glib-unix.h>
       7                 :            : #include <gio/gunixinputstream.h>
       8                 :            : #include <gio/gunixoutputstream.h>
       9                 :            : #include <gio/gfiledescriptorbased.h>
      10                 :            : #include <unistd.h>
      11                 :            : #include <fcntl.h>
      12                 :            : #endif
      13                 :            : 
      14                 :            : #ifdef __linux__
      15                 :            : #include <sys/ptrace.h>
      16                 :            : #endif
      17                 :            : 
      18                 :            : /* We write 2^1 + 2^2 ... + 2^10 or 2047 copies of "Hello World!\n"
      19                 :            :  * ultimately
      20                 :            :  */
      21                 :            : #define TOTAL_HELLOS 2047
      22                 :            : #define HELLO_WORLD "hello world!\n"
      23                 :            : 
      24                 :            : #ifdef G_OS_WIN32
      25                 :            : #define LINEEND "\r\n"
      26                 :            : #define EXEEXT ".exe"
      27                 :            : #define SPLICELEN (TOTAL_HELLOS * (strlen (HELLO_WORLD) + 1)) /* because \r */
      28                 :            : #else
      29                 :            : #define LINEEND "\n"
      30                 :            : #define EXEEXT
      31                 :            : #define SPLICELEN (TOTAL_HELLOS * strlen (HELLO_WORLD))
      32                 :            : #endif
      33                 :            : 
      34                 :            : 
      35                 :            : 
      36                 :            : #ifdef G_OS_WIN32
      37                 :            : #define TESTPROG "gsubprocess-testprog.exe"
      38                 :            : #else
      39                 :            : #define TESTPROG "gsubprocess-testprog"
      40                 :            : #endif
      41                 :            : 
      42                 :            : static GPtrArray *
      43                 :            : get_test_subprocess_args (const char *mode,
      44                 :            :                           ...) G_GNUC_NULL_TERMINATED;
      45                 :            : 
      46                 :            : static GPtrArray *
      47                 :         80 : get_test_subprocess_args (const char *mode,
      48                 :            :                           ...)
      49                 :            : {
      50                 :            :   GPtrArray *ret;
      51                 :            :   char *path;
      52                 :            :   va_list args;
      53                 :            :   gpointer arg;
      54                 :            : 
      55                 :         80 :   ret = g_ptr_array_new_with_free_func (g_free);
      56                 :            : 
      57                 :         80 :   path = g_test_build_filename (G_TEST_BUILT, TESTPROG, NULL);
      58                 :         80 :   g_ptr_array_add (ret, path);
      59                 :         80 :   g_ptr_array_add (ret, g_strdup (mode));
      60                 :            : 
      61                 :         80 :   va_start (args, mode);
      62         [ +  + ]:         97 :   while ((arg = va_arg (args, gpointer)) != NULL)
      63                 :         17 :     g_ptr_array_add (ret, g_strdup (arg));
      64                 :         80 :   va_end (args);
      65                 :            : 
      66                 :         80 :   g_ptr_array_add (ret, NULL);
      67                 :         80 :   return ret;
      68                 :            : }
      69                 :            : 
      70                 :            : static void
      71                 :          1 : test_noop (void)
      72                 :            : {
      73                 :          1 :   GError *local_error = NULL;
      74                 :          1 :   GError **error = &local_error;
      75                 :            :   GPtrArray *args;
      76                 :            :   GSubprocess *proc;
      77                 :            : 
      78                 :          1 :   args = get_test_subprocess_args ("noop", NULL);
      79                 :          1 :   proc = g_subprocess_newv ((const gchar * const *) args->pdata, G_SUBPROCESS_FLAGS_NONE, error);
      80                 :          1 :   g_ptr_array_free (args, TRUE);
      81                 :          1 :   g_assert_no_error (local_error);
      82                 :            : 
      83                 :          1 :   g_subprocess_wait_check (proc, NULL, error);
      84                 :          1 :   g_assert_no_error (local_error);
      85                 :          1 :   g_assert_true (g_subprocess_get_successful (proc));
      86                 :            : 
      87                 :          1 :   g_object_unref (proc);
      88                 :          1 : }
      89                 :            : 
      90                 :            : static void
      91                 :          1 : check_ready (GObject      *source,
      92                 :            :              GAsyncResult *res,
      93                 :            :              gpointer      user_data)
      94                 :            : {
      95                 :            :   gboolean ret;
      96                 :          1 :   GError *error = NULL;
      97                 :            : 
      98                 :          1 :   ret = g_subprocess_wait_check_finish (G_SUBPROCESS (source),
      99                 :            :                                         res,
     100                 :            :                                         &error);
     101                 :          1 :   g_assert_true (ret);
     102                 :          1 :   g_assert_no_error (error);
     103                 :            : 
     104                 :          1 :   g_object_unref (source);
     105                 :          1 : }
     106                 :            : 
     107                 :            : static void
     108                 :          1 : test_noop_all_to_null (void)
     109                 :            : {
     110                 :          1 :   GError *local_error = NULL;
     111                 :          1 :   GError **error = &local_error;
     112                 :            :   GPtrArray *args;
     113                 :            :   GSubprocess *proc;
     114                 :            : 
     115                 :          1 :   args = get_test_subprocess_args ("noop", NULL);
     116                 :          1 :   proc = g_subprocess_newv ((const gchar * const *) args->pdata,
     117                 :            :                             G_SUBPROCESS_FLAGS_STDOUT_SILENCE | G_SUBPROCESS_FLAGS_STDERR_SILENCE,
     118                 :            :                             error);
     119                 :          1 :   g_ptr_array_free (args, TRUE);
     120                 :          1 :   g_assert_no_error (local_error);
     121                 :            : 
     122                 :          1 :   g_subprocess_wait_check_async (proc, NULL, check_ready, NULL);
     123                 :          1 : }
     124                 :            : 
     125                 :            : static void
     126                 :          1 : test_noop_no_wait (void)
     127                 :            : {
     128                 :          1 :   GError *local_error = NULL;
     129                 :          1 :   GError **error = &local_error;
     130                 :            :   GPtrArray *args;
     131                 :            :   GSubprocess *proc;
     132                 :            : 
     133                 :          1 :   args = get_test_subprocess_args ("noop", NULL);
     134                 :          1 :   proc = g_subprocess_newv ((const gchar * const *) args->pdata, G_SUBPROCESS_FLAGS_NONE, error);
     135                 :          1 :   g_ptr_array_free (args, TRUE);
     136                 :          1 :   g_assert_no_error (local_error);
     137                 :            : 
     138                 :          1 :   g_object_unref (proc);
     139                 :          1 : }
     140                 :            : 
     141                 :            : static void
     142                 :          1 : test_noop_stdin_inherit (void)
     143                 :            : {
     144                 :          1 :   GError *local_error = NULL;
     145                 :          1 :   GError **error = &local_error;
     146                 :            :   GPtrArray *args;
     147                 :            :   GSubprocess *proc;
     148                 :            : 
     149                 :          1 :   args = get_test_subprocess_args ("noop", NULL);
     150                 :          1 :   proc = g_subprocess_newv ((const gchar * const *) args->pdata, G_SUBPROCESS_FLAGS_STDIN_INHERIT, error);
     151                 :          1 :   g_ptr_array_free (args, TRUE);
     152                 :          1 :   g_assert_no_error (local_error);
     153                 :            : 
     154                 :          1 :   g_subprocess_wait_check (proc, NULL, error);
     155                 :          1 :   g_assert_no_error (local_error);
     156                 :            : 
     157                 :          1 :   g_object_unref (proc);
     158                 :          1 : }
     159                 :            : 
     160                 :            : #ifdef G_OS_UNIX
     161                 :            : static void
     162                 :          1 : test_search_path (void)
     163                 :            : {
     164                 :          1 :   GError *local_error = NULL;
     165                 :          1 :   GError **error = &local_error;
     166                 :            :   GSubprocess *proc;
     167                 :            : 
     168                 :          1 :   proc = g_subprocess_new (G_SUBPROCESS_FLAGS_NONE, error, "true", NULL);
     169                 :          1 :   g_assert_no_error (local_error);
     170                 :            : 
     171                 :          1 :   g_subprocess_wait_check (proc, NULL, error);
     172                 :          1 :   g_assert_no_error (local_error);
     173                 :            : 
     174                 :          1 :   g_object_unref (proc);
     175                 :          1 : }
     176                 :            : 
     177                 :            : static void
     178                 :          1 : test_search_path_from_envp (void)
     179                 :            : {
     180                 :          1 :   GError *local_error = NULL;
     181                 :          1 :   GError **error = &local_error;
     182                 :            :   GSubprocessLauncher *launcher;
     183                 :            :   GSubprocess *proc;
     184                 :            :   const char *path;
     185                 :            : 
     186                 :          1 :   path = g_test_get_dir (G_TEST_BUILT);
     187                 :            : 
     188                 :          1 :   launcher = g_subprocess_launcher_new (G_SUBPROCESS_FLAGS_SEARCH_PATH_FROM_ENVP);
     189                 :          1 :   g_subprocess_launcher_setenv (launcher, "PATH", path, TRUE);
     190                 :            : 
     191                 :          1 :   proc = g_subprocess_launcher_spawn (launcher, error, TESTPROG, "exit1", NULL);
     192                 :          1 :   g_assert_no_error (local_error);
     193                 :          1 :   g_object_unref (launcher);
     194                 :            : 
     195                 :          1 :   g_subprocess_wait_check (proc, NULL, error);
     196                 :          1 :   g_assert_error (local_error, G_SPAWN_EXIT_ERROR, 1);
     197                 :          1 :   g_clear_error (error);
     198                 :            : 
     199                 :          1 :   g_object_unref (proc);
     200                 :          1 : }
     201                 :            : #endif
     202                 :            : 
     203                 :            : static void
     204                 :          1 : test_exit1 (void)
     205                 :            : {
     206                 :          1 :   GError *local_error = NULL;
     207                 :          1 :   GError **error = &local_error;
     208                 :            :   GPtrArray *args;
     209                 :            :   GSubprocess *proc;
     210                 :            : 
     211                 :          1 :   args = get_test_subprocess_args ("exit1", NULL);
     212                 :          1 :   proc = g_subprocess_newv ((const gchar * const *) args->pdata, G_SUBPROCESS_FLAGS_NONE, error);
     213                 :          1 :   g_ptr_array_free (args, TRUE);
     214                 :          1 :   g_assert_no_error (local_error);
     215                 :            : 
     216                 :          1 :   g_subprocess_wait_check (proc, NULL, error);
     217                 :          1 :   g_assert_error (local_error, G_SPAWN_EXIT_ERROR, 1);
     218                 :          1 :   g_clear_error (error);
     219                 :            : 
     220                 :          1 :   g_object_unref (proc);
     221                 :          1 : }
     222                 :            : 
     223                 :            : typedef struct {
     224                 :            :   GMainLoop    *loop;
     225                 :            :   GCancellable *cancellable;
     226                 :            :   gboolean      cb_called;
     227                 :            : } TestExit1CancelData;
     228                 :            : 
     229                 :            : static gboolean
     230                 :          2 : test_exit1_cancel_idle_quit_cb (gpointer user_data)
     231                 :            : {
     232                 :          2 :   GMainLoop *loop = user_data;
     233                 :          2 :   g_main_loop_quit (loop);
     234                 :          2 :   return G_SOURCE_REMOVE;
     235                 :            : }
     236                 :            : 
     237                 :            : static void
     238                 :          1 : test_exit1_cancel_wait_check_cb (GObject      *source,
     239                 :            :                                  GAsyncResult *result,
     240                 :            :                                  gpointer      user_data)
     241                 :            : {
     242                 :          1 :   GSubprocess *subprocess = G_SUBPROCESS (source);
     243                 :          1 :   TestExit1CancelData *data = user_data;
     244                 :            :   gboolean ret;
     245                 :          1 :   GError *error = NULL;
     246                 :            : 
     247                 :          1 :   g_assert_false (data->cb_called);
     248                 :          1 :   data->cb_called = TRUE;
     249                 :            : 
     250                 :          1 :   ret = g_subprocess_wait_check_finish (subprocess, result, &error);
     251                 :          1 :   g_assert_false (ret);
     252                 :          1 :   g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
     253                 :          1 :   g_clear_error (&error);
     254                 :            : 
     255                 :          1 :   g_idle_add (test_exit1_cancel_idle_quit_cb, data->loop);
     256                 :          1 : }
     257                 :            : 
     258                 :            : static void
     259                 :          1 : test_exit1_cancel (void)
     260                 :            : {
     261                 :          1 :   GError *local_error = NULL;
     262                 :          1 :   GError **error = &local_error;
     263                 :            :   GPtrArray *args;
     264                 :            :   GSubprocess *proc;
     265                 :          1 :   TestExit1CancelData data = { 0 };
     266                 :            : 
     267                 :          1 :   g_test_bug ("https://bugzilla.gnome.org/show_bug.cgi?id=786456");
     268                 :            : 
     269                 :          1 :   args = get_test_subprocess_args ("exit1", NULL);
     270                 :          1 :   proc = g_subprocess_newv ((const gchar * const *) args->pdata, G_SUBPROCESS_FLAGS_NONE, error);
     271                 :          1 :   g_ptr_array_free (args, TRUE);
     272                 :          1 :   g_assert_no_error (local_error);
     273                 :            : 
     274                 :          1 :   data.loop = g_main_loop_new (NULL, FALSE);
     275                 :          1 :   data.cancellable = g_cancellable_new ();
     276                 :          1 :   g_subprocess_wait_check_async (proc, data.cancellable, test_exit1_cancel_wait_check_cb, &data);
     277                 :            : 
     278                 :          1 :   g_subprocess_wait_check (proc, NULL, error);
     279                 :          1 :   g_assert_error (local_error, G_SPAWN_EXIT_ERROR, 1);
     280                 :          1 :   g_clear_error (error);
     281                 :            : 
     282                 :          1 :   g_cancellable_cancel (data.cancellable);
     283                 :          1 :   g_main_loop_run (data.loop);
     284                 :            : 
     285                 :          1 :   g_object_unref (proc);
     286                 :          1 :   g_main_loop_unref (data.loop);
     287                 :          1 :   g_clear_object (&data.cancellable);
     288                 :          1 : }
     289                 :            : 
     290                 :            : static void
     291                 :          1 : test_exit1_cancel_in_cb_wait_check_cb (GObject      *source,
     292                 :            :                                        GAsyncResult *result,
     293                 :            :                                        gpointer      user_data)
     294                 :            : {
     295                 :          1 :   GSubprocess *subprocess = G_SUBPROCESS (source);
     296                 :          1 :   TestExit1CancelData *data = user_data;
     297                 :            :   gboolean ret;
     298                 :          1 :   GError *error = NULL;
     299                 :            : 
     300                 :          1 :   g_assert_false (data->cb_called);
     301                 :          1 :   data->cb_called = TRUE;
     302                 :            : 
     303                 :          1 :   ret = g_subprocess_wait_check_finish (subprocess, result, &error);
     304                 :          1 :   g_assert_false (ret);
     305                 :          1 :   g_assert_error (error, G_SPAWN_EXIT_ERROR, 1);
     306                 :          1 :   g_clear_error (&error);
     307                 :            : 
     308                 :          1 :   g_cancellable_cancel (data->cancellable);
     309                 :            : 
     310                 :          1 :   g_idle_add (test_exit1_cancel_idle_quit_cb, data->loop);
     311                 :          1 : }
     312                 :            : 
     313                 :            : static void
     314                 :          1 : test_exit1_cancel_in_cb (void)
     315                 :            : {
     316                 :          1 :   GError *local_error = NULL;
     317                 :          1 :   GError **error = &local_error;
     318                 :            :   GPtrArray *args;
     319                 :            :   GSubprocess *proc;
     320                 :          1 :   TestExit1CancelData data = { 0 };
     321                 :            : 
     322                 :          1 :   g_test_bug ("https://bugzilla.gnome.org/show_bug.cgi?id=786456");
     323                 :            : 
     324                 :          1 :   args = get_test_subprocess_args ("exit1", NULL);
     325                 :          1 :   proc = g_subprocess_newv ((const gchar * const *) args->pdata, G_SUBPROCESS_FLAGS_NONE, error);
     326                 :          1 :   g_ptr_array_free (args, TRUE);
     327                 :          1 :   g_assert_no_error (local_error);
     328                 :            : 
     329                 :          1 :   data.loop = g_main_loop_new (NULL, FALSE);
     330                 :          1 :   data.cancellable = g_cancellable_new ();
     331                 :          1 :   g_subprocess_wait_check_async (proc, data.cancellable, test_exit1_cancel_in_cb_wait_check_cb, &data);
     332                 :            : 
     333                 :          1 :   g_subprocess_wait_check (proc, NULL, error);
     334                 :          1 :   g_assert_error (local_error, G_SPAWN_EXIT_ERROR, 1);
     335                 :          1 :   g_clear_error (error);
     336                 :            : 
     337                 :          1 :   g_main_loop_run (data.loop);
     338                 :            : 
     339                 :          1 :   g_object_unref (proc);
     340                 :          1 :   g_main_loop_unref (data.loop);
     341                 :          1 :   g_clear_object (&data.cancellable);
     342                 :          1 : }
     343                 :            : 
     344                 :            : static gchar *
     345                 :          5 : splice_to_string (GInputStream   *stream,
     346                 :            :                   GError        **error)
     347                 :            : {
     348                 :          5 :   GMemoryOutputStream *buffer = NULL;
     349                 :          5 :   char *ret = NULL;
     350                 :            : 
     351                 :          5 :   buffer = (GMemoryOutputStream*)g_memory_output_stream_new (NULL, 0, g_realloc, g_free);
     352         [ -  + ]:          5 :   if (g_output_stream_splice ((GOutputStream*)buffer, stream, 0, NULL, error) < 0)
     353                 :          0 :     goto out;
     354                 :            : 
     355         [ -  + ]:          5 :   if (!g_output_stream_write ((GOutputStream*)buffer, "\0", 1, NULL, error))
     356                 :          0 :     goto out;
     357                 :            : 
     358         [ -  + ]:          5 :   if (!g_output_stream_close ((GOutputStream*)buffer, NULL, error))
     359                 :          0 :     goto out;
     360                 :            : 
     361                 :          5 :   ret = g_memory_output_stream_steal_data (buffer);
     362                 :          5 :  out:
     363                 :          5 :   g_clear_object (&buffer);
     364                 :          5 :   return ret;
     365                 :            : }
     366                 :            : 
     367                 :            : static void
     368                 :          1 : test_echo1 (void)
     369                 :            : {
     370                 :          1 :   GError *local_error = NULL;
     371                 :          1 :   GError **error = &local_error;
     372                 :            :   GSubprocess *proc;
     373                 :            :   GPtrArray *args;
     374                 :            :   GInputStream *stdout_stream;
     375                 :            :   gchar *result;
     376                 :            : 
     377                 :          1 :   args = get_test_subprocess_args ("echo", "hello", "world!", NULL);
     378                 :          1 :   proc = g_subprocess_newv ((const gchar * const *) args->pdata, G_SUBPROCESS_FLAGS_STDOUT_PIPE, error);
     379                 :          1 :   g_ptr_array_free (args, TRUE);
     380                 :          1 :   g_assert_no_error (local_error);
     381                 :            : 
     382                 :          1 :   stdout_stream = g_subprocess_get_stdout_pipe (proc);
     383                 :            : 
     384                 :          1 :   result = splice_to_string (stdout_stream, error);
     385                 :          1 :   g_assert_no_error (local_error);
     386                 :            : 
     387                 :          1 :   g_assert_cmpstr (result, ==, "hello" LINEEND "world!" LINEEND);
     388                 :            : 
     389                 :          1 :   g_free (result);
     390                 :          1 :   g_object_unref (proc);
     391                 :          1 : }
     392                 :            : 
     393                 :            : #ifdef G_OS_UNIX
     394                 :            : static void
     395                 :          1 : test_echo_merged (void)
     396                 :            : {
     397                 :          1 :   GError *local_error = NULL;
     398                 :          1 :   GError **error = &local_error;
     399                 :            :   GSubprocess *proc;
     400                 :            :   GPtrArray *args;
     401                 :            :   GInputStream *stdout_stream;
     402                 :            :   gchar *result;
     403                 :            : 
     404                 :          1 :   args = get_test_subprocess_args ("echo-stdout-and-stderr", "merge", "this", NULL);
     405                 :          1 :   proc = g_subprocess_newv ((const gchar * const *) args->pdata,
     406                 :            :                             G_SUBPROCESS_FLAGS_STDOUT_PIPE | G_SUBPROCESS_FLAGS_STDERR_MERGE,
     407                 :            :                             error);
     408                 :          1 :   g_ptr_array_free (args, TRUE);
     409                 :          1 :   g_assert_no_error (local_error);
     410                 :            : 
     411                 :          1 :   stdout_stream = g_subprocess_get_stdout_pipe (proc);
     412                 :          1 :   result = splice_to_string (stdout_stream, error);
     413                 :          1 :   g_assert_no_error (local_error);
     414                 :            : 
     415                 :          1 :   g_assert_cmpstr (result, ==, "merge\nmerge\nthis\nthis\n");
     416                 :            : 
     417                 :          1 :   g_free (result);
     418                 :          1 :   g_object_unref (proc);
     419                 :          1 : }
     420                 :            : #endif
     421                 :            : 
     422                 :            : typedef struct {
     423                 :            :   guint events_pending;
     424                 :            :   GMainLoop *loop;
     425                 :            : } TestCatData;
     426                 :            : 
     427                 :            : static void
     428                 :          2 : test_cat_on_input_splice_complete (GObject      *object,
     429                 :            :                                    GAsyncResult *result,
     430                 :            :                                    gpointer      user_data)
     431                 :            : {
     432                 :          2 :   TestCatData *data = user_data;
     433                 :          2 :   GError *error = NULL;
     434                 :            : 
     435                 :          2 :   (void)g_output_stream_splice_finish ((GOutputStream*)object, result, &error);
     436                 :          2 :   g_assert_no_error (error);
     437                 :            : 
     438                 :          2 :   data->events_pending--;
     439         [ +  + ]:          2 :   if (data->events_pending == 0)
     440                 :          1 :     g_main_loop_quit (data->loop);
     441                 :          2 : }
     442                 :            : 
     443                 :            : static void
     444                 :          1 : test_cat_utf8 (void)
     445                 :            : {
     446                 :          1 :   GError *local_error = NULL;
     447                 :          1 :   GError **error = &local_error;
     448                 :            :   GSubprocess *proc;
     449                 :            :   GPtrArray *args;
     450                 :            :   GBytes *input_buf;
     451                 :            :   GBytes *output_buf;
     452                 :          1 :   GInputStream *input_buf_stream = NULL;
     453                 :          1 :   GOutputStream *output_buf_stream = NULL;
     454                 :          1 :   GOutputStream *stdin_stream = NULL;
     455                 :          1 :   GInputStream *stdout_stream = NULL;
     456                 :            :   TestCatData data;
     457                 :            : 
     458                 :          1 :   memset (&data, 0, sizeof (data));
     459                 :          1 :   data.loop = g_main_loop_new (NULL, TRUE);
     460                 :            : 
     461                 :          1 :   args = get_test_subprocess_args ("cat", NULL);
     462                 :          1 :   proc = g_subprocess_newv ((const gchar * const *) args->pdata,
     463                 :            :                             G_SUBPROCESS_FLAGS_STDIN_PIPE | G_SUBPROCESS_FLAGS_STDOUT_PIPE,
     464                 :            :                             error);
     465                 :          1 :   g_ptr_array_free (args, TRUE);
     466                 :          1 :   g_assert_no_error (local_error);
     467                 :            : 
     468                 :          1 :   stdin_stream = g_subprocess_get_stdin_pipe (proc);
     469                 :          1 :   stdout_stream = g_subprocess_get_stdout_pipe (proc);
     470                 :            : 
     471                 :          1 :   input_buf = g_bytes_new_static ("hello, world!", strlen ("hello, world!"));
     472                 :          1 :   input_buf_stream = g_memory_input_stream_new_from_bytes (input_buf);
     473                 :          1 :   g_bytes_unref (input_buf);
     474                 :            : 
     475                 :          1 :   output_buf_stream = g_memory_output_stream_new (NULL, 0, g_realloc, g_free);
     476                 :            : 
     477                 :          1 :   g_output_stream_splice_async (stdin_stream, input_buf_stream, G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE | G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET,
     478                 :            :                                 G_PRIORITY_DEFAULT, NULL, test_cat_on_input_splice_complete,
     479                 :            :                                 &data);
     480                 :          1 :   data.events_pending++;
     481                 :          1 :   g_output_stream_splice_async (output_buf_stream, stdout_stream, G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE | G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET,
     482                 :            :                                 G_PRIORITY_DEFAULT, NULL, test_cat_on_input_splice_complete,
     483                 :            :                                 &data);
     484                 :          1 :   data.events_pending++;
     485                 :            : 
     486                 :          1 :   g_main_loop_run (data.loop);
     487                 :            : 
     488                 :          1 :   g_subprocess_wait_check (proc, NULL, error);
     489                 :          1 :   g_assert_no_error (local_error);
     490                 :            : 
     491                 :          1 :   output_buf = g_memory_output_stream_steal_as_bytes ((GMemoryOutputStream*)output_buf_stream);
     492                 :            : 
     493                 :          1 :   g_assert_cmpmem (g_bytes_get_data (output_buf, NULL),
     494                 :            :                    g_bytes_get_size (output_buf),
     495                 :            :                    "hello, world!", 13);
     496                 :            : 
     497                 :          1 :   g_bytes_unref (output_buf);
     498                 :          1 :   g_main_loop_unref (data.loop);
     499                 :          1 :   g_object_unref (input_buf_stream);
     500                 :          1 :   g_object_unref (output_buf_stream);
     501                 :          1 :   g_object_unref (proc);
     502                 :          1 : }
     503                 :            : 
     504                 :            : static gpointer
     505                 :          1 : cancel_soon (gpointer user_data)
     506                 :            : {
     507                 :          1 :   GCancellable *cancellable = user_data;
     508                 :            : 
     509                 :          1 :   g_usleep (G_TIME_SPAN_SECOND);
     510                 :          1 :   g_cancellable_cancel (cancellable);
     511                 :          1 :   g_object_unref (cancellable);
     512                 :            : 
     513                 :          1 :   return NULL;
     514                 :            : }
     515                 :            : 
     516                 :            : static void
     517                 :          1 : test_cat_eof (void)
     518                 :            : {
     519                 :            :   GCancellable *cancellable;
     520                 :          1 :   GError *error = NULL;
     521                 :            :   GSubprocess *cat;
     522                 :            :   gboolean result;
     523                 :            :   gchar buffer;
     524                 :            :   gssize s;
     525                 :            : 
     526                 :            : #ifdef G_OS_WIN32
     527                 :            :   g_test_skip ("This test has not been ported to Win32");
     528                 :            :   return;
     529                 :            : #endif
     530                 :            : 
     531                 :            :   /* Spawn 'cat' */
     532                 :          1 :   cat = g_subprocess_new (G_SUBPROCESS_FLAGS_STDIN_PIPE | G_SUBPROCESS_FLAGS_STDOUT_PIPE, &error, "cat", NULL);
     533                 :          1 :   g_assert_no_error (error);
     534                 :          1 :   g_assert_nonnull (cat);
     535                 :            : 
     536                 :            :   /* Make sure that reading stdout blocks (until we cancel) */
     537                 :          1 :   cancellable = g_cancellable_new ();
     538                 :          1 :   g_thread_unref (g_thread_new ("cancel thread", cancel_soon, g_object_ref (cancellable)));
     539                 :          1 :   s = g_input_stream_read (g_subprocess_get_stdout_pipe (cat), &buffer, sizeof buffer, cancellable, &error);
     540                 :          1 :   g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
     541                 :          1 :   g_assert_cmpint (s, ==, -1);
     542                 :          1 :   g_object_unref (cancellable);
     543                 :          1 :   g_clear_error (&error);
     544                 :            : 
     545                 :            :   /* Close the stream (EOF on cat's stdin) */
     546                 :          1 :   result = g_output_stream_close (g_subprocess_get_stdin_pipe (cat), NULL, &error);
     547                 :          1 :   g_assert_no_error (error);
     548                 :          1 :   g_assert_true (result);
     549                 :            : 
     550                 :            :   /* Now check that reading cat's stdout gets us an EOF (since it quit) */
     551                 :          1 :   s = g_input_stream_read (g_subprocess_get_stdout_pipe (cat), &buffer, sizeof buffer, NULL, &error);
     552                 :          1 :   g_assert_no_error (error);
     553                 :          1 :   g_assert_false (s);
     554                 :            : 
     555                 :            :   /* Check that the process has exited as a result of the EOF */
     556                 :          1 :   result = g_subprocess_wait (cat, NULL, &error);
     557                 :          1 :   g_assert_no_error (error);
     558                 :          1 :   g_assert_true (g_subprocess_get_if_exited (cat));
     559                 :          1 :   g_assert_cmpint (g_subprocess_get_exit_status (cat), ==, 0);
     560                 :          1 :   g_assert_true (result);
     561                 :            : 
     562                 :          1 :   g_object_unref (cat);
     563                 :          1 : }
     564                 :            : 
     565                 :            : typedef struct {
     566                 :            :   guint events_pending;
     567                 :            :   gboolean caught_error;
     568                 :            :   GError *error;
     569                 :            :   GMainLoop *loop;
     570                 :            : 
     571                 :            :   gint counter;
     572                 :            :   GOutputStream *first_stdin;
     573                 :            : } TestMultiSpliceData;
     574                 :            : 
     575                 :            : static void
     576                 :          3 : on_one_multi_splice_done (GObject       *obj,
     577                 :            :                           GAsyncResult  *res,
     578                 :            :                           gpointer       user_data)
     579                 :            : {
     580                 :          3 :   TestMultiSpliceData *data = user_data;
     581                 :            : 
     582         [ +  - ]:          3 :   if (!data->caught_error)
     583                 :            :     {
     584         [ -  + ]:          3 :       if (g_output_stream_splice_finish ((GOutputStream*)obj, res, &data->error) < 0)
     585                 :          0 :         data->caught_error = TRUE;
     586                 :            :     }
     587                 :            : 
     588                 :          3 :   data->events_pending--;
     589         [ -  + ]:          3 :   if (data->events_pending == 0)
     590                 :          0 :     g_main_loop_quit (data->loop);
     591                 :          3 : }
     592                 :            : 
     593                 :            : static gboolean
     594                 :         12 : on_idle_multisplice (gpointer     user_data)
     595                 :            : {
     596                 :         12 :   TestMultiSpliceData *data = user_data;
     597                 :            : 
     598   [ +  +  -  + ]:         12 :   if (data->counter >= TOTAL_HELLOS || data->caught_error)
     599                 :            :     {
     600         [ -  + ]:          1 :       if (!g_output_stream_close (data->first_stdin, NULL, &data->error))
     601                 :          0 :         data->caught_error = TRUE;
     602                 :          1 :       data->events_pending--;
     603         [ -  + ]:          1 :       if (data->events_pending == 0)
     604                 :            :         {
     605                 :          0 :           g_main_loop_quit (data->loop);
     606                 :            :         }
     607                 :          1 :       return FALSE;
     608                 :            :     }
     609                 :            :   else
     610                 :            :     {
     611                 :            :       int i;
     612         [ +  + ]:       2058 :       for (i = 0; i < data->counter; i++)
     613                 :            :         {
     614                 :            :           gsize bytes_written;
     615         [ -  + ]:       2047 :           if (!g_output_stream_write_all (data->first_stdin, HELLO_WORLD,
     616                 :            :                                           strlen (HELLO_WORLD), &bytes_written,
     617                 :            :                                           NULL, &data->error))
     618                 :            :             {
     619                 :          0 :               data->caught_error = TRUE;
     620                 :          0 :               return FALSE;
     621                 :            :             }
     622                 :            :         }
     623                 :         11 :       data->counter *= 2;
     624                 :         11 :       return TRUE;
     625                 :            :     }
     626                 :            : }
     627                 :            : 
     628                 :            : static void
     629                 :          3 : on_subprocess_exited (GObject         *object,
     630                 :            :                       GAsyncResult    *result,
     631                 :            :                       gpointer         user_data)
     632                 :            : {
     633                 :          3 :   GSubprocess *subprocess = G_SUBPROCESS (object);
     634                 :          3 :   TestMultiSpliceData *data = user_data;
     635                 :          3 :   GError *error = NULL;
     636                 :            : 
     637         [ -  + ]:          3 :   if (!g_subprocess_wait_finish (subprocess, result, &error))
     638                 :            :     {
     639         [ #  # ]:          0 :       if (!data->caught_error)
     640                 :            :         {
     641                 :          0 :           data->caught_error = TRUE;
     642                 :          0 :           g_propagate_error (&data->error, error);
     643                 :            :         }
     644                 :            :     }
     645                 :          3 :   g_spawn_check_wait_status (g_subprocess_get_status (subprocess), &error);
     646                 :          3 :   g_assert_no_error (error);
     647                 :          3 :   data->events_pending--;
     648         [ +  + ]:          3 :   if (data->events_pending == 0)
     649                 :          1 :     g_main_loop_quit (data->loop);
     650                 :          3 : }
     651                 :            : 
     652                 :            : static void
     653                 :          1 : test_multi_1 (void)
     654                 :            : {
     655                 :          1 :   GError *local_error = NULL;
     656                 :          1 :   GError **error = &local_error;
     657                 :            :   GPtrArray *args;
     658                 :            :   GSubprocessLauncher *launcher;
     659                 :            :   GSubprocess *first;
     660                 :            :   GSubprocess *second;
     661                 :            :   GSubprocess *third;
     662                 :            :   GOutputStream *first_stdin;
     663                 :            :   GInputStream *first_stdout;
     664                 :            :   GOutputStream *second_stdin;
     665                 :            :   GInputStream *second_stdout;
     666                 :            :   GOutputStream *third_stdin;
     667                 :            :   GInputStream *third_stdout;
     668                 :            :   GOutputStream *membuf;
     669                 :            :   TestMultiSpliceData data;
     670                 :          1 :   int splice_flags = G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE | G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET;
     671                 :            : 
     672                 :          1 :   args = get_test_subprocess_args ("cat", NULL);
     673                 :          1 :   launcher = g_subprocess_launcher_new (G_SUBPROCESS_FLAGS_STDIN_PIPE | G_SUBPROCESS_FLAGS_STDOUT_PIPE);
     674                 :          1 :   first = g_subprocess_launcher_spawnv (launcher, (const gchar * const *) args->pdata, error);
     675                 :          1 :   g_assert_no_error (local_error);
     676                 :          1 :   second = g_subprocess_launcher_spawnv (launcher, (const gchar * const *) args->pdata, error);
     677                 :          1 :   g_assert_no_error (local_error);
     678                 :          1 :   third = g_subprocess_launcher_spawnv (launcher, (const gchar * const *) args->pdata, error);
     679                 :          1 :   g_assert_no_error (local_error);
     680                 :            : 
     681                 :          1 :   g_ptr_array_free (args, TRUE);
     682                 :            : 
     683                 :          1 :   membuf = g_memory_output_stream_new (NULL, 0, g_realloc, g_free);
     684                 :            : 
     685                 :          1 :   first_stdin = g_subprocess_get_stdin_pipe (first);
     686                 :          1 :   first_stdout = g_subprocess_get_stdout_pipe (first);
     687                 :          1 :   second_stdin = g_subprocess_get_stdin_pipe (second);
     688                 :          1 :   second_stdout = g_subprocess_get_stdout_pipe (second);
     689                 :          1 :   third_stdin = g_subprocess_get_stdin_pipe (third);
     690                 :          1 :   third_stdout = g_subprocess_get_stdout_pipe (third);
     691                 :            : 
     692                 :          1 :   memset (&data, 0, sizeof (data));
     693                 :          1 :   data.loop = g_main_loop_new (NULL, TRUE);
     694                 :          1 :   data.counter = 1;
     695                 :          1 :   data.first_stdin = first_stdin;
     696                 :            : 
     697                 :          1 :   data.events_pending++;
     698                 :          1 :   g_output_stream_splice_async (second_stdin, first_stdout, splice_flags, G_PRIORITY_DEFAULT,
     699                 :            :                                 NULL, on_one_multi_splice_done, &data);
     700                 :          1 :   data.events_pending++;
     701                 :          1 :   g_output_stream_splice_async (third_stdin, second_stdout, splice_flags, G_PRIORITY_DEFAULT,
     702                 :            :                                 NULL, on_one_multi_splice_done, &data);
     703                 :          1 :   data.events_pending++;
     704                 :          1 :   g_output_stream_splice_async (membuf, third_stdout, splice_flags, G_PRIORITY_DEFAULT,
     705                 :            :                                 NULL, on_one_multi_splice_done, &data);
     706                 :            : 
     707                 :          1 :   data.events_pending++;
     708                 :          1 :   g_timeout_add (250, on_idle_multisplice, &data);
     709                 :            : 
     710                 :          1 :   data.events_pending++;
     711                 :          1 :   g_subprocess_wait_async (first, NULL, on_subprocess_exited, &data);
     712                 :          1 :   data.events_pending++;
     713                 :          1 :   g_subprocess_wait_async (second, NULL, on_subprocess_exited, &data);
     714                 :          1 :   data.events_pending++;
     715                 :          1 :   g_subprocess_wait_async (third, NULL, on_subprocess_exited, &data);
     716                 :            : 
     717                 :          1 :   g_main_loop_run (data.loop);
     718                 :            : 
     719                 :          1 :   g_assert_false (data.caught_error);
     720                 :          1 :   g_assert_no_error (data.error);
     721                 :            : 
     722                 :          1 :   g_assert_cmpint (g_memory_output_stream_get_data_size ((GMemoryOutputStream*)membuf), ==, SPLICELEN);
     723                 :            : 
     724                 :          1 :   g_main_loop_unref (data.loop);
     725                 :          1 :   g_object_unref (membuf);
     726                 :          1 :   g_object_unref (launcher);
     727                 :          1 :   g_object_unref (first);
     728                 :          1 :   g_object_unref (second);
     729                 :          1 :   g_object_unref (third);
     730                 :          1 : }
     731                 :            : 
     732                 :            : typedef struct {
     733                 :            :   GSubprocessFlags flags;
     734                 :            :   gboolean is_utf8;
     735                 :            :   gboolean running;
     736                 :            :   GError *error;
     737                 :            : } TestAsyncCommunicateData;
     738                 :            : 
     739                 :            : static void
     740                 :         13 : on_communicate_complete (GObject               *proc,
     741                 :            :                          GAsyncResult          *result,
     742                 :            :                          gpointer               user_data)
     743                 :            : {
     744                 :         13 :   TestAsyncCommunicateData *data = user_data;
     745                 :         13 :   GBytes *stdout_bytes = NULL, *stderr_bytes = NULL;
     746                 :         13 :   char *stdout_str = NULL, *stderr_str = NULL;
     747                 :            :   const guint8 *stdout_data;
     748                 :            :   gsize stdout_len;
     749                 :            : 
     750                 :         13 :   data->running = FALSE;
     751         [ +  + ]:         13 :   if (data->is_utf8)
     752                 :          7 :     (void) g_subprocess_communicate_utf8_finish ((GSubprocess*)proc, result,
     753                 :            :                                                  &stdout_str, &stderr_str, &data->error);
     754                 :            :   else
     755                 :          6 :     (void) g_subprocess_communicate_finish ((GSubprocess*)proc, result,
     756                 :            :                                             &stdout_bytes, &stderr_bytes, &data->error);
     757         [ +  + ]:         13 :   if (data->error)
     758                 :          1 :       return;
     759                 :            : 
     760         [ +  + ]:         12 :   if (data->flags & G_SUBPROCESS_FLAGS_STDOUT_PIPE)
     761                 :            :     {
     762         [ +  + ]:          6 :       if (data->is_utf8)
     763                 :            :         {
     764                 :          3 :           g_assert_nonnull (stdout_str);
     765                 :          3 :           stdout_data = (guint8*)stdout_str;
     766                 :          3 :           stdout_len = strlen (stdout_str);
     767                 :            :         }
     768                 :            :       else
     769                 :            :         {
     770                 :          3 :           g_assert_nonnull (stdout_bytes);
     771                 :          3 :           stdout_data = g_bytes_get_data (stdout_bytes, &stdout_len);
     772                 :            :         }
     773                 :            : 
     774                 :          6 :       g_assert_cmpmem (stdout_data, stdout_len, "# hello world" LINEEND, 13 + strlen (LINEEND));
     775                 :            :     }
     776                 :            :   else
     777                 :            :     {
     778                 :          6 :       g_assert_null (stdout_str);
     779                 :          6 :       g_assert_null (stdout_bytes);
     780                 :            :     }
     781                 :            : 
     782         [ +  + ]:         12 :   if (data->flags & G_SUBPROCESS_FLAGS_STDERR_PIPE)
     783                 :            :     {
     784         [ +  + ]:          4 :       if (data->is_utf8)
     785                 :          2 :         g_assert_nonnull (stderr_str);
     786                 :            :       else
     787                 :          2 :         g_assert_nonnull (stderr_bytes);
     788                 :            :     }
     789                 :            :   else
     790                 :            :     {
     791                 :          8 :       g_assert_null (stderr_str);
     792                 :          8 :       g_assert_null (stderr_bytes);
     793                 :            :     }
     794                 :            : 
     795                 :         12 :   g_clear_pointer (&stdout_bytes, g_bytes_unref);
     796                 :         12 :   g_clear_pointer (&stderr_bytes, g_bytes_unref);
     797                 :         12 :   g_free (stdout_str);
     798                 :         12 :   g_free (stderr_str);
     799                 :            : }
     800                 :            : 
     801                 :            : /* Test g_subprocess_communicate_async() works correctly with a variety of flags,
     802                 :            :  * as passed in via @test_data. */
     803                 :            : static void
     804                 :          6 : test_communicate_async (gconstpointer test_data)
     805                 :            : {
     806                 :          6 :   GSubprocessFlags flags = GPOINTER_TO_INT (test_data);
     807                 :          6 :   GError *error = NULL;
     808                 :            :   GPtrArray *args;
     809                 :          6 :   TestAsyncCommunicateData data = { flags, 0, 0, NULL };
     810                 :            :   GSubprocess *proc;
     811                 :          6 :   GCancellable *cancellable = NULL;
     812                 :            :   GBytes *input;
     813                 :            :   const char *hellostring;
     814                 :            : 
     815                 :          6 :   args = get_test_subprocess_args ("cat", NULL);
     816                 :          6 :   proc = g_subprocess_newv ((const gchar* const*)args->pdata,
     817                 :          6 :                             G_SUBPROCESS_FLAGS_STDIN_PIPE | flags,
     818                 :            :                             &error);
     819                 :          6 :   g_assert_no_error (error);
     820                 :          6 :   g_ptr_array_free (args, TRUE);
     821                 :            : 
     822                 :            :   /* Include a leading hash and trailing newline so that if this gets onto the
     823                 :            :    * test’s stdout, it doesn’t mess up TAP output. */
     824                 :          6 :   hellostring = "# hello world\n";
     825                 :          6 :   input = g_bytes_new_static (hellostring, strlen (hellostring));
     826                 :            : 
     827                 :          6 :   g_subprocess_communicate_async (proc, input,
     828                 :            :                                   cancellable,
     829                 :            :                                   on_communicate_complete, 
     830                 :            :                                   &data);
     831                 :            :   
     832                 :          6 :   data.running = TRUE;
     833         [ +  + ]:         60 :   while (data.running)
     834                 :         54 :     g_main_context_iteration (NULL, TRUE);
     835                 :            : 
     836                 :          6 :   g_assert_no_error (data.error);
     837                 :            : 
     838                 :          6 :   g_bytes_unref (input);
     839                 :          6 :   g_object_unref (proc);
     840                 :          6 : }
     841                 :            : 
     842                 :            : /* Test g_subprocess_communicate() works correctly with a variety of flags,
     843                 :            :  * as passed in via @test_data. */
     844                 :            : static void
     845                 :          6 : test_communicate (gconstpointer test_data)
     846                 :            : {
     847                 :          6 :   GSubprocessFlags flags = GPOINTER_TO_INT (test_data);
     848                 :          6 :   GError *error = NULL;
     849                 :            :   GPtrArray *args;
     850                 :            :   GSubprocess *proc;
     851                 :          6 :   GCancellable *cancellable = NULL;
     852                 :            :   GBytes *input;
     853                 :            :   const gchar *hellostring;
     854                 :            :   GBytes *stdout_bytes, *stderr_bytes;
     855                 :            :   const gchar *stdout_data;
     856                 :            :   gsize stdout_len;
     857                 :            : 
     858                 :          6 :   args = get_test_subprocess_args ("cat", NULL);
     859                 :          6 :   proc = g_subprocess_newv ((const gchar* const*)args->pdata,
     860                 :          6 :                             G_SUBPROCESS_FLAGS_STDIN_PIPE | flags,
     861                 :            :                             &error);
     862                 :          6 :   g_assert_no_error (error);
     863                 :          6 :   g_ptr_array_free (args, TRUE);
     864                 :            : 
     865                 :            :   /* Include a leading hash and trailing newline so that if this gets onto the
     866                 :            :    * test’s stdout, it doesn’t mess up TAP output. */
     867                 :          6 :   hellostring = "# hello world\n";
     868                 :          6 :   input = g_bytes_new_static (hellostring, strlen (hellostring));
     869                 :            : 
     870                 :          6 :   g_subprocess_communicate (proc, input, cancellable, &stdout_bytes, &stderr_bytes, &error);
     871                 :          6 :   g_assert_no_error (error);
     872                 :            : 
     873         [ +  + ]:          6 :   if (flags & G_SUBPROCESS_FLAGS_STDOUT_PIPE)
     874                 :            :     {
     875                 :          3 :       stdout_data = g_bytes_get_data (stdout_bytes, &stdout_len);
     876                 :          3 :       g_assert_cmpmem (stdout_data, stdout_len, "# hello world" LINEEND, 13 + strlen (LINEEND));
     877                 :            :     }
     878                 :            :   else
     879                 :          3 :     g_assert_null (stdout_bytes);
     880         [ +  + ]:          6 :   if (flags & G_SUBPROCESS_FLAGS_STDERR_PIPE)
     881                 :          2 :     g_assert_nonnull (stderr_bytes);
     882                 :            :   else
     883                 :          4 :     g_assert_null (stderr_bytes);
     884                 :            : 
     885                 :          6 :   g_bytes_unref (input);
     886                 :          6 :   g_clear_pointer (&stdout_bytes, g_bytes_unref);
     887                 :          6 :   g_clear_pointer (&stderr_bytes, g_bytes_unref);
     888                 :          6 :   g_object_unref (proc);
     889                 :          6 : }
     890                 :            : 
     891                 :            : typedef struct {
     892                 :            :   GSubprocess  *proc;
     893                 :            :   GCancellable *cancellable;
     894                 :            :   gboolean is_utf8;
     895                 :            :   gboolean running;
     896                 :            :   GError *error;
     897                 :            : } TestCancelledCommunicateData;
     898                 :            : 
     899                 :            : static gboolean
     900                 :         12 : on_test_communicate_cancelled_idle (gpointer user_data)
     901                 :            : {
     902                 :         12 :   TestCancelledCommunicateData *data = user_data;
     903                 :            :   GBytes *input;
     904                 :            :   const gchar *hellostring;
     905                 :         12 :   GBytes *stdout_bytes = NULL, *stderr_bytes = NULL;
     906                 :         12 :   gchar *stdout_buf = NULL, *stderr_buf = NULL;
     907                 :            : 
     908                 :            :   /* Include a leading hash and trailing newline so that if this gets onto the
     909                 :            :    * test’s stdout, it doesn’t mess up TAP output. */
     910                 :         12 :   hellostring = "# hello world\n";
     911                 :         12 :   input = g_bytes_new_static (hellostring, strlen (hellostring));
     912                 :            : 
     913         [ +  + ]:         12 :   if (data->is_utf8)
     914                 :          6 :     g_subprocess_communicate_utf8 (data->proc, hellostring, data->cancellable,
     915                 :            :                                    &stdout_buf, &stderr_buf, &data->error);
     916                 :            :   else
     917                 :          6 :     g_subprocess_communicate (data->proc, input, data->cancellable, &stdout_bytes,
     918                 :            :                               &stderr_bytes, &data->error);
     919                 :            : 
     920                 :         12 :   data->running = FALSE;
     921                 :            : 
     922         [ +  + ]:         12 :   if (data->is_utf8)
     923                 :            :     {
     924                 :          6 :       g_assert_null (stdout_buf);
     925                 :          6 :       g_assert_null (stderr_buf);
     926                 :            :     }
     927                 :            :   else
     928                 :            :     {
     929                 :          6 :       g_assert_null (stdout_bytes);
     930                 :          6 :       g_assert_null (stderr_bytes);
     931                 :            :     }
     932                 :            : 
     933                 :         12 :   g_bytes_unref (input);
     934                 :            : 
     935                 :         12 :   return G_SOURCE_REMOVE;
     936                 :            : }
     937                 :            : 
     938                 :            : /* Test g_subprocess_communicate() can be cancelled correctly */
     939                 :            : static void
     940                 :          6 : test_communicate_cancelled (gconstpointer test_data)
     941                 :            : {
     942                 :          6 :   GSubprocessFlags flags = GPOINTER_TO_INT (test_data);
     943                 :            :   GPtrArray *args;
     944                 :            :   GSubprocess *proc;
     945                 :          6 :   GCancellable *cancellable = NULL;
     946                 :          6 :   GError *error = NULL;
     947                 :          6 :   TestCancelledCommunicateData data = { 0 };
     948                 :            : 
     949                 :          6 :   args = get_test_subprocess_args ("cat", NULL);
     950                 :          6 :   proc = g_subprocess_newv ((const gchar* const*)args->pdata,
     951                 :          6 :                             G_SUBPROCESS_FLAGS_STDIN_PIPE | flags,
     952                 :            :                             &error);
     953                 :          6 :   g_assert_no_error (error);
     954                 :          6 :   g_ptr_array_free (args, TRUE);
     955                 :            : 
     956                 :          6 :   cancellable = g_cancellable_new ();
     957                 :            : 
     958                 :          6 :   data.proc = proc;
     959                 :          6 :   data.cancellable = cancellable;
     960                 :          6 :   data.error = error;
     961                 :            : 
     962                 :          6 :   g_cancellable_cancel (cancellable);
     963                 :          6 :   g_idle_add (on_test_communicate_cancelled_idle, &data);
     964                 :            : 
     965                 :          6 :   data.running = TRUE;
     966         [ +  + ]:         12 :   while (data.running)
     967                 :          6 :     g_main_context_iteration (NULL, TRUE);
     968                 :            : 
     969                 :          6 :   g_assert_error (data.error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
     970                 :          6 :   g_clear_error (&data.error);
     971                 :            : 
     972                 :          6 :   g_object_unref (cancellable);
     973                 :          6 :   g_object_unref (proc);
     974                 :          6 : }
     975                 :            : 
     976                 :            : static void
     977                 :         12 : on_communicate_cancelled_complete (GObject               *proc,
     978                 :            :                                    GAsyncResult          *result,
     979                 :            :                                    gpointer               user_data)
     980                 :            : {
     981                 :         12 :   TestAsyncCommunicateData *data = user_data;
     982                 :         12 :   GBytes *stdout_bytes = NULL, *stderr_bytes = NULL;
     983                 :         12 :   char *stdout_str = NULL, *stderr_str = NULL;
     984                 :            : 
     985                 :         12 :   data->running = FALSE;
     986         [ +  + ]:         12 :   if (data->is_utf8)
     987                 :          6 :     (void) g_subprocess_communicate_utf8_finish ((GSubprocess*)proc, result,
     988                 :            :                                                  &stdout_str, &stderr_str, &data->error);
     989                 :            :   else
     990                 :          6 :     (void) g_subprocess_communicate_finish ((GSubprocess*)proc, result,
     991                 :            :                                             &stdout_bytes, &stderr_bytes, &data->error);
     992                 :            : 
     993         [ +  + ]:         12 :   if (data->is_utf8)
     994                 :            :     {
     995                 :          6 :       g_assert_null (stdout_str);
     996                 :          6 :       g_assert_null (stderr_str);
     997                 :            :     }
     998                 :            :   else
     999                 :            :     {
    1000                 :          6 :       g_assert_null (stdout_bytes);
    1001                 :          6 :       g_assert_null (stderr_bytes);
    1002                 :            :     }
    1003                 :         12 : }
    1004                 :            : 
    1005                 :            : /* Test g_subprocess_communicate_async() can be cancelled correctly,
    1006                 :            :  * as passed in via @test_data. */
    1007                 :            : static void
    1008                 :          6 : test_communicate_cancelled_async (gconstpointer test_data)
    1009                 :            : {
    1010                 :          6 :   GSubprocessFlags flags = GPOINTER_TO_INT (test_data);
    1011                 :          6 :   GError *error = NULL;
    1012                 :            :   GPtrArray *args;
    1013                 :          6 :   TestAsyncCommunicateData data = { 0 };
    1014                 :            :   GSubprocess *proc;
    1015                 :          6 :   GCancellable *cancellable = NULL;
    1016                 :            :   GBytes *input;
    1017                 :            :   const char *hellostring;
    1018                 :            : 
    1019                 :          6 :   args = get_test_subprocess_args ("cat", NULL);
    1020                 :          6 :   proc = g_subprocess_newv ((const gchar* const*)args->pdata,
    1021                 :          6 :                             G_SUBPROCESS_FLAGS_STDIN_PIPE | flags,
    1022                 :            :                             &error);
    1023                 :          6 :   g_assert_no_error (error);
    1024                 :          6 :   g_ptr_array_free (args, TRUE);
    1025                 :            : 
    1026                 :            :   /* Include a leading hash and trailing newline so that if this gets onto the
    1027                 :            :    * test’s stdout, it doesn’t mess up TAP output. */
    1028                 :          6 :   hellostring = "# hello world\n";
    1029                 :          6 :   input = g_bytes_new_static (hellostring, strlen (hellostring));
    1030                 :            : 
    1031                 :          6 :   cancellable = g_cancellable_new ();
    1032                 :            : 
    1033                 :          6 :   g_subprocess_communicate_async (proc, input,
    1034                 :            :                                   cancellable,
    1035                 :            :                                   on_communicate_cancelled_complete,
    1036                 :            :                                   &data);
    1037                 :            : 
    1038                 :          6 :   g_cancellable_cancel (cancellable);
    1039                 :            : 
    1040                 :          6 :   data.running = TRUE;
    1041         [ +  + ]:         24 :   while (data.running)
    1042                 :         18 :     g_main_context_iteration (NULL, TRUE);
    1043                 :            : 
    1044                 :          6 :   g_assert_error (data.error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
    1045                 :          6 :   g_clear_error (&data.error);
    1046                 :            : 
    1047                 :          6 :   g_bytes_unref (input);
    1048                 :          6 :   g_object_unref (cancellable);
    1049                 :          6 :   g_object_unref (proc);
    1050                 :          6 : }
    1051                 :            : 
    1052                 :            : /* Test g_subprocess_communicate_utf8_async() works correctly with a variety of
    1053                 :            :  * flags, as passed in via @test_data. */
    1054                 :            : static void
    1055                 :          6 : test_communicate_utf8_async (gconstpointer test_data)
    1056                 :            : {
    1057                 :          6 :   GSubprocessFlags flags = GPOINTER_TO_INT (test_data);
    1058                 :          6 :   GError *error = NULL;
    1059                 :            :   GPtrArray *args;
    1060                 :          6 :   TestAsyncCommunicateData data = { flags, 0, 0, NULL };
    1061                 :            :   GSubprocess *proc;
    1062                 :          6 :   GCancellable *cancellable = NULL;
    1063                 :            : 
    1064                 :          6 :   args = get_test_subprocess_args ("cat", NULL);
    1065                 :          6 :   proc = g_subprocess_newv ((const gchar* const*)args->pdata,
    1066                 :          6 :                             G_SUBPROCESS_FLAGS_STDIN_PIPE | flags,
    1067                 :            :                             &error);
    1068                 :          6 :   g_assert_no_error (error);
    1069                 :          6 :   g_ptr_array_free (args, TRUE);
    1070                 :            : 
    1071                 :          6 :   data.is_utf8 = TRUE;
    1072                 :          6 :   g_subprocess_communicate_utf8_async (proc, "# hello world\n",
    1073                 :            :                                        cancellable,
    1074                 :            :                                        on_communicate_complete, 
    1075                 :            :                                        &data);
    1076                 :            :   
    1077                 :          6 :   data.running = TRUE;
    1078         [ +  + ]:         62 :   while (data.running)
    1079                 :         56 :     g_main_context_iteration (NULL, TRUE);
    1080                 :            : 
    1081                 :          6 :   g_assert_no_error (data.error);
    1082                 :            : 
    1083                 :          6 :   g_object_unref (proc);
    1084                 :          6 : }
    1085                 :            : 
    1086                 :            : /* Test g_subprocess_communicate_utf8_async() can be cancelled correctly. */
    1087                 :            : static void
    1088                 :          6 : test_communicate_utf8_cancelled_async (gconstpointer test_data)
    1089                 :            : {
    1090                 :          6 :   GSubprocessFlags flags = GPOINTER_TO_INT (test_data);
    1091                 :          6 :   GError *error = NULL;
    1092                 :            :   GPtrArray *args;
    1093                 :          6 :   TestAsyncCommunicateData data = { flags, 0, 0, NULL };
    1094                 :            :   GSubprocess *proc;
    1095                 :          6 :   GCancellable *cancellable = NULL;
    1096                 :            : 
    1097                 :          6 :   args = get_test_subprocess_args ("cat", NULL);
    1098                 :          6 :   proc = g_subprocess_newv ((const gchar* const*)args->pdata,
    1099                 :          6 :                             G_SUBPROCESS_FLAGS_STDIN_PIPE | flags,
    1100                 :            :                             &error);
    1101                 :          6 :   g_assert_no_error (error);
    1102                 :          6 :   g_ptr_array_free (args, TRUE);
    1103                 :            : 
    1104                 :          6 :   cancellable = g_cancellable_new ();
    1105                 :          6 :   data.is_utf8 = TRUE;
    1106                 :          6 :   g_subprocess_communicate_utf8_async (proc, "# hello world\n",
    1107                 :            :                                        cancellable,
    1108                 :            :                                        on_communicate_cancelled_complete,
    1109                 :            :                                        &data);
    1110                 :            : 
    1111                 :          6 :   g_cancellable_cancel (cancellable);
    1112                 :            : 
    1113                 :          6 :   data.running = TRUE;
    1114         [ +  + ]:         24 :   while (data.running)
    1115                 :         18 :     g_main_context_iteration (NULL, TRUE);
    1116                 :            : 
    1117                 :          6 :   g_assert_error (data.error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
    1118                 :          6 :   g_clear_error (&data.error);
    1119                 :            : 
    1120                 :          6 :   g_object_unref (cancellable);
    1121                 :          6 :   g_object_unref (proc);
    1122                 :          6 : }
    1123                 :            : 
    1124                 :            : /* Test g_subprocess_communicate_utf8() works correctly with a variety of flags,
    1125                 :            :  * as passed in via @test_data. */
    1126                 :            : static void
    1127                 :          6 : test_communicate_utf8 (gconstpointer test_data)
    1128                 :            : {
    1129                 :          6 :   GSubprocessFlags flags = GPOINTER_TO_INT (test_data);
    1130                 :          6 :   GError *error = NULL;
    1131                 :            :   GPtrArray *args;
    1132                 :            :   GSubprocess *proc;
    1133                 :          6 :   GCancellable *cancellable = NULL;
    1134                 :            :   const gchar *stdin_buf;
    1135                 :            :   gchar *stdout_buf, *stderr_buf;
    1136                 :            : 
    1137                 :          6 :   args = get_test_subprocess_args ("cat", NULL);
    1138                 :          6 :   proc = g_subprocess_newv ((const gchar* const*)args->pdata,
    1139                 :          6 :                             G_SUBPROCESS_FLAGS_STDIN_PIPE | flags,
    1140                 :            :                             &error);
    1141                 :          6 :   g_assert_no_error (error);
    1142                 :          6 :   g_ptr_array_free (args, TRUE);
    1143                 :            : 
    1144                 :            :   /* Include a leading hash and trailing newline so that if this gets onto the
    1145                 :            :    * test’s stdout, it doesn’t mess up TAP output. */
    1146                 :          6 :   stdin_buf = "# hello world\n";
    1147                 :            : 
    1148                 :          6 :   g_subprocess_communicate_utf8 (proc, stdin_buf, cancellable, &stdout_buf, &stderr_buf, &error);
    1149                 :          6 :   g_assert_no_error (error);
    1150                 :            : 
    1151         [ +  + ]:          6 :   if (flags & G_SUBPROCESS_FLAGS_STDOUT_PIPE)
    1152                 :          3 :     g_assert_cmpstr (stdout_buf, ==, "# hello world" LINEEND);
    1153                 :            :   else
    1154                 :          3 :     g_assert_null (stdout_buf);
    1155         [ +  + ]:          6 :   if (flags & G_SUBPROCESS_FLAGS_STDERR_PIPE)
    1156                 :          2 :     g_assert_nonnull (stderr_buf);
    1157                 :          4 :   else     g_assert_null (stderr_buf);
    1158                 :            : 
    1159                 :          6 :   g_free (stdout_buf);
    1160                 :          6 :   g_free (stderr_buf);
    1161                 :          6 :   g_object_unref (proc);
    1162                 :          6 : }
    1163                 :            : 
    1164                 :            : /* Test g_subprocess_communicate_utf8() can be cancelled correctly */
    1165                 :            : static void
    1166                 :          6 : test_communicate_utf8_cancelled (gconstpointer test_data)
    1167                 :            : {
    1168                 :          6 :   GSubprocessFlags flags = GPOINTER_TO_INT (test_data);
    1169                 :            :   GPtrArray *args;
    1170                 :            :   GSubprocess *proc;
    1171                 :          6 :   GCancellable *cancellable = NULL;
    1172                 :          6 :   GError *error = NULL;
    1173                 :          6 :   TestCancelledCommunicateData data = { 0 };
    1174                 :            : 
    1175                 :          6 :   args = get_test_subprocess_args ("cat", NULL);
    1176                 :          6 :   proc = g_subprocess_newv ((const gchar* const*)args->pdata,
    1177                 :          6 :                             G_SUBPROCESS_FLAGS_STDIN_PIPE | flags,
    1178                 :            :                             &error);
    1179                 :          6 :   g_assert_no_error (error);
    1180                 :          6 :   g_ptr_array_free (args, TRUE);
    1181                 :            : 
    1182                 :          6 :   cancellable = g_cancellable_new ();
    1183                 :            : 
    1184                 :          6 :   data.proc = proc;
    1185                 :          6 :   data.cancellable = cancellable;
    1186                 :          6 :   data.error = error;
    1187                 :            : 
    1188                 :          6 :   g_cancellable_cancel (cancellable);
    1189                 :          6 :   g_idle_add (on_test_communicate_cancelled_idle, &data);
    1190                 :            : 
    1191                 :          6 :   data.is_utf8 = TRUE;
    1192                 :          6 :   data.running = TRUE;
    1193         [ +  + ]:         19 :   while (data.running)
    1194                 :         13 :     g_main_context_iteration (NULL, TRUE);
    1195                 :            : 
    1196                 :          6 :   g_assert_error (data.error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
    1197                 :          6 :   g_clear_error (&data.error);
    1198                 :            : 
    1199                 :          6 :   g_object_unref (cancellable);
    1200                 :          6 :   g_object_unref (proc);
    1201                 :          6 : }
    1202                 :            : 
    1203                 :            : static void
    1204                 :          1 : test_communicate_nothing (void)
    1205                 :            : {
    1206                 :          1 :   GError *error = NULL;
    1207                 :            :   GPtrArray *args;
    1208                 :            :   GSubprocess *proc;
    1209                 :          1 :   GCancellable *cancellable = NULL;
    1210                 :            :   gchar *stdout_buf;
    1211                 :            : 
    1212                 :          1 :   args = get_test_subprocess_args ("cat", NULL);
    1213                 :          1 :   proc = g_subprocess_newv ((const gchar* const*)args->pdata,
    1214                 :            :                             G_SUBPROCESS_FLAGS_STDIN_PIPE
    1215                 :            :                             | G_SUBPROCESS_FLAGS_STDOUT_PIPE
    1216                 :            :                             | G_SUBPROCESS_FLAGS_STDERR_MERGE,
    1217                 :            :                             &error);
    1218                 :          1 :   g_assert_no_error (error);
    1219                 :          1 :   g_ptr_array_free (args, TRUE);
    1220                 :            : 
    1221                 :          1 :   g_subprocess_communicate_utf8 (proc, "", cancellable, &stdout_buf, NULL, &error);
    1222                 :          1 :   g_assert_no_error (error);
    1223                 :            : 
    1224                 :          1 :   g_assert_cmpstr (stdout_buf, ==, "");
    1225                 :            : 
    1226                 :          1 :   g_free (stdout_buf);
    1227                 :            : 
    1228                 :          1 :   g_object_unref (proc);
    1229                 :          1 : }
    1230                 :            : 
    1231                 :            : static void
    1232                 :          1 : test_communicate_utf8_async_invalid (void)
    1233                 :            : {
    1234                 :          1 :   GSubprocessFlags flags = G_SUBPROCESS_FLAGS_STDOUT_PIPE;
    1235                 :          1 :   GError *error = NULL;
    1236                 :            :   GPtrArray *args;
    1237                 :          1 :   TestAsyncCommunicateData data = { flags, 0, 0, NULL };
    1238                 :            :   GSubprocess *proc;
    1239                 :          1 :   GCancellable *cancellable = NULL;
    1240                 :            : 
    1241                 :          1 :   args = get_test_subprocess_args ("cat", NULL);
    1242                 :          1 :   proc = g_subprocess_newv ((const gchar* const*)args->pdata,
    1243                 :          1 :                             G_SUBPROCESS_FLAGS_STDIN_PIPE | flags,
    1244                 :            :                             &error);
    1245                 :          1 :   g_assert_no_error (error);
    1246                 :          1 :   g_ptr_array_free (args, TRUE);
    1247                 :            : 
    1248                 :          1 :   data.is_utf8 = TRUE;
    1249                 :          1 :   g_subprocess_communicate_utf8_async (proc, "\xFF\xFF",
    1250                 :            :                                        cancellable,
    1251                 :            :                                        on_communicate_complete, 
    1252                 :            :                                        &data);
    1253                 :            :   
    1254                 :          1 :   data.running = TRUE;
    1255         [ +  + ]:         11 :   while (data.running)
    1256                 :         10 :     g_main_context_iteration (NULL, TRUE);
    1257                 :            : 
    1258                 :          1 :   g_assert_error (data.error, G_IO_ERROR, G_IO_ERROR_FAILED);
    1259                 :          1 :   g_error_free (data.error);
    1260                 :            : 
    1261                 :          1 :   g_object_unref (proc);
    1262                 :          1 : }
    1263                 :            : 
    1264                 :            : /* Test that invalid UTF-8 received using g_subprocess_communicate_utf8()
    1265                 :            :  * results in an error. */
    1266                 :            : static void
    1267                 :          1 : test_communicate_utf8_invalid (void)
    1268                 :            : {
    1269                 :          1 :   GSubprocessFlags flags = G_SUBPROCESS_FLAGS_STDOUT_PIPE;
    1270                 :          1 :   GError *local_error = NULL;
    1271                 :            :   gboolean ret;
    1272                 :            :   GPtrArray *args;
    1273                 :          1 :   gchar *stdout_str = NULL, *stderr_str = NULL;
    1274                 :            :   GSubprocess *proc;
    1275                 :            : 
    1276                 :          1 :   args = get_test_subprocess_args ("cat", NULL);
    1277                 :          1 :   proc = g_subprocess_newv ((const gchar* const*)args->pdata,
    1278                 :          1 :                             G_SUBPROCESS_FLAGS_STDIN_PIPE | flags,
    1279                 :            :                             &local_error);
    1280                 :          1 :   g_assert_no_error (local_error);
    1281                 :          1 :   g_ptr_array_free (args, TRUE);
    1282                 :            : 
    1283                 :          1 :   ret = g_subprocess_communicate_utf8 (proc, "\xFF\xFF", NULL,
    1284                 :            :                                        &stdout_str, &stderr_str, &local_error);
    1285                 :          1 :   g_assert_error (local_error, G_IO_ERROR, G_IO_ERROR_FAILED);
    1286                 :          1 :   g_error_free (local_error);
    1287                 :          1 :   g_assert_false (ret);
    1288                 :            : 
    1289                 :          1 :   g_assert_null (stdout_str);
    1290                 :          1 :   g_assert_null (stderr_str);
    1291                 :            : 
    1292                 :          1 :   g_object_unref (proc);
    1293                 :          1 : }
    1294                 :            : 
    1295                 :            : static void
    1296                 :          1 : send_terminate (gpointer   user_data)
    1297                 :            : {
    1298                 :          1 :   GSubprocess *proc = user_data;
    1299                 :            : 
    1300                 :          1 :   g_subprocess_force_exit (proc);
    1301                 :          1 : }
    1302                 :            : 
    1303                 :            : static void
    1304                 :          2 : on_request_quit_exited (GObject        *object,
    1305                 :            :                         GAsyncResult   *result,
    1306                 :            :                         gpointer        user_data)
    1307                 :            : {
    1308                 :          2 :   GSubprocess *subprocess = G_SUBPROCESS (object);
    1309                 :          2 :   GError *error = NULL;
    1310                 :            : 
    1311                 :          2 :   g_subprocess_wait_finish (subprocess, result, &error);
    1312                 :          2 :   g_assert_no_error (error);
    1313                 :            : #ifdef G_OS_UNIX
    1314                 :          2 :   g_assert_true (g_subprocess_get_if_signaled (subprocess));
    1315                 :          2 :   g_assert_cmpint (g_subprocess_get_term_sig (subprocess), ==, 9);
    1316                 :            : #endif
    1317                 :          2 :   g_spawn_check_wait_status (g_subprocess_get_status (subprocess), &error);
    1318                 :          2 :   g_assert_nonnull (error);
    1319                 :          2 :   g_clear_error (&error);
    1320                 :            : 
    1321                 :          2 :   g_main_loop_quit ((GMainLoop*)user_data);
    1322                 :          2 : }
    1323                 :            : 
    1324                 :            : static void
    1325                 :          1 : test_terminate (void)
    1326                 :            : {
    1327                 :          1 :   GError *local_error = NULL;
    1328                 :          1 :   GError **error = &local_error;
    1329                 :            :   GSubprocess *proc;
    1330                 :            :   GPtrArray *args;
    1331                 :            :   GMainLoop *loop;
    1332                 :            :   const gchar *id;
    1333                 :            : 
    1334                 :          1 :   args = get_test_subprocess_args ("sleep-forever", NULL);
    1335                 :          1 :   proc = g_subprocess_newv ((const gchar * const *) args->pdata, G_SUBPROCESS_FLAGS_NONE, error);
    1336                 :          1 :   g_ptr_array_free (args, TRUE);
    1337                 :          1 :   g_assert_no_error (local_error);
    1338                 :            : 
    1339                 :          1 :   id = g_subprocess_get_identifier (proc);
    1340                 :          1 :   g_assert_nonnull (id);
    1341                 :            : 
    1342                 :          1 :   loop = g_main_loop_new (NULL, TRUE);
    1343                 :            : 
    1344                 :          1 :   g_subprocess_wait_async (proc, NULL, on_request_quit_exited, loop);
    1345                 :            : 
    1346                 :          1 :   g_timeout_add_seconds_once (3, send_terminate, proc);
    1347                 :            : 
    1348                 :          1 :   g_main_loop_run (loop);
    1349                 :            : 
    1350                 :          1 :   g_main_loop_unref (loop);
    1351                 :          1 :   g_object_unref (proc);
    1352                 :          1 : }
    1353                 :            : 
    1354                 :            : #ifdef G_OS_UNIX
    1355                 :            : static void
    1356                 :          1 : send_signal (gpointer user_data)
    1357                 :            : {
    1358                 :          1 :   GSubprocess *proc = user_data;
    1359                 :            : 
    1360                 :          1 :   g_subprocess_send_signal (proc, SIGKILL);
    1361                 :          1 : }
    1362                 :            : 
    1363                 :            : static void
    1364                 :          1 : test_signal (void)
    1365                 :            : {
    1366                 :          1 :   GError *local_error = NULL;
    1367                 :          1 :   GError **error = &local_error;
    1368                 :            :   GSubprocess *proc;
    1369                 :            :   GPtrArray *args;
    1370                 :            :   GMainLoop *loop;
    1371                 :            : 
    1372                 :          1 :   args = get_test_subprocess_args ("sleep-forever", NULL);
    1373                 :          1 :   proc = g_subprocess_newv ((const gchar * const *) args->pdata, G_SUBPROCESS_FLAGS_NONE, error);
    1374                 :          1 :   g_ptr_array_free (args, TRUE);
    1375                 :          1 :   g_assert_no_error (local_error);
    1376                 :            : 
    1377                 :          1 :   loop = g_main_loop_new (NULL, TRUE);
    1378                 :            : 
    1379                 :          1 :   g_subprocess_wait_async (proc, NULL, on_request_quit_exited, loop);
    1380                 :            : 
    1381                 :          1 :   g_timeout_add_seconds_once (3, send_signal, proc);
    1382                 :            : 
    1383                 :          1 :   g_main_loop_run (loop);
    1384                 :            : 
    1385                 :          1 :   g_main_loop_unref (loop);
    1386                 :          1 :   g_object_unref (proc);
    1387                 :          1 : }
    1388                 :            : #endif
    1389                 :            : 
    1390                 :            : static void
    1391                 :          1 : test_env (void)
    1392                 :            : {
    1393                 :          1 :   GError *local_error = NULL;
    1394                 :          1 :   GError **error = &local_error;
    1395                 :            :   GSubprocessLauncher *launcher;
    1396                 :            :   GSubprocess *proc;
    1397                 :            :   GPtrArray *args;
    1398                 :            :   GInputStream *stdout_stream;
    1399                 :            :   gchar *result;
    1400                 :          1 :   gchar *envp[] = { NULL, "ONE=1", "TWO=1", "THREE=3", "FOUR=1", NULL };
    1401                 :            :   gchar **split;
    1402                 :            : 
    1403                 :          1 :   envp[0] = g_strdup_printf ("PATH=%s", g_getenv ("PATH"));
    1404                 :          1 :   args = get_test_subprocess_args ("env", NULL);
    1405                 :          1 :   launcher = g_subprocess_launcher_new (G_SUBPROCESS_FLAGS_NONE);
    1406                 :          1 :   g_subprocess_launcher_set_flags (launcher, G_SUBPROCESS_FLAGS_STDOUT_PIPE);
    1407                 :          1 :   g_subprocess_launcher_set_environ (launcher, envp);
    1408                 :          1 :   g_subprocess_launcher_setenv (launcher, "TWO", "2", TRUE);
    1409                 :          1 :   g_subprocess_launcher_setenv (launcher, "THREE", "1", FALSE);
    1410                 :          1 :   g_subprocess_launcher_unsetenv (launcher, "FOUR");
    1411                 :            : 
    1412                 :          1 :   g_assert_null (g_subprocess_launcher_getenv (launcher, "FOUR"));
    1413                 :            :    
    1414                 :          1 :   proc = g_subprocess_launcher_spawn (launcher, error, args->pdata[0], "env", NULL);
    1415                 :          1 :   g_ptr_array_free (args, TRUE);
    1416                 :          1 :   g_assert_no_error (local_error);
    1417                 :          1 :   g_free (envp[0]);
    1418                 :            : 
    1419                 :          1 :   stdout_stream = g_subprocess_get_stdout_pipe (proc);
    1420                 :            : 
    1421                 :          1 :   result = splice_to_string (stdout_stream, error);
    1422                 :          1 :   split = g_strsplit (result, LINEEND, -1);
    1423                 :          1 :   g_assert_cmpstr (g_environ_getenv (split, "ONE"), ==, "1");
    1424                 :          1 :   g_assert_cmpstr (g_environ_getenv (split, "TWO"), ==, "2");
    1425                 :          1 :   g_assert_cmpstr (g_environ_getenv (split, "THREE"), ==, "3");
    1426                 :          1 :   g_assert_null (g_environ_getenv (split, "FOUR"));
    1427                 :            : 
    1428                 :          1 :   g_strfreev (split);
    1429                 :          1 :   g_free (result);
    1430                 :          1 :   g_object_unref (proc);
    1431                 :          1 :   g_object_unref (launcher);
    1432                 :          1 : }
    1433                 :            : 
    1434                 :            : /* Test that explicitly inheriting and modifying the parent process’
    1435                 :            :  * environment works. */
    1436                 :            : static void
    1437                 :          1 : test_env_inherit (void)
    1438                 :            : {
    1439                 :          1 :   GError *local_error = NULL;
    1440                 :          1 :   GError **error = &local_error;
    1441                 :            :   GSubprocessLauncher *launcher;
    1442                 :            :   GSubprocess *proc;
    1443                 :            :   GPtrArray *args;
    1444                 :            :   GInputStream *stdout_stream;
    1445                 :            :   gchar *result;
    1446                 :            :   gchar **split;
    1447                 :            : 
    1448                 :          1 :   g_setenv ("TEST_ENV_INHERIT1", "1", TRUE);
    1449                 :          1 :   g_setenv ("TEST_ENV_INHERIT2", "2", TRUE);
    1450                 :            : 
    1451                 :          1 :   args = get_test_subprocess_args ("env", NULL);
    1452                 :          1 :   launcher = g_subprocess_launcher_new (G_SUBPROCESS_FLAGS_NONE);
    1453                 :          1 :   g_subprocess_launcher_set_flags (launcher, G_SUBPROCESS_FLAGS_STDOUT_PIPE);
    1454                 :          1 :   g_subprocess_launcher_set_environ (launcher, NULL);
    1455                 :          1 :   g_subprocess_launcher_setenv (launcher, "TWO", "2", TRUE);
    1456                 :          1 :   g_subprocess_launcher_unsetenv (launcher, "TEST_ENV_INHERIT1");
    1457                 :            : 
    1458                 :          1 :   g_assert_null (g_subprocess_launcher_getenv (launcher, "TEST_ENV_INHERIT1"));
    1459                 :          1 :   g_assert_cmpstr (g_subprocess_launcher_getenv (launcher, "TEST_ENV_INHERIT2"), ==, "2");
    1460                 :          1 :   g_assert_cmpstr (g_subprocess_launcher_getenv (launcher, "TWO"), ==, "2");
    1461                 :            : 
    1462                 :          1 :   proc = g_subprocess_launcher_spawn (launcher, error, args->pdata[0], "env", NULL);
    1463                 :          1 :   g_ptr_array_free (args, TRUE);
    1464                 :          1 :   g_assert_no_error (local_error);
    1465                 :            : 
    1466                 :          1 :   stdout_stream = g_subprocess_get_stdout_pipe (proc);
    1467                 :            : 
    1468                 :          1 :   result = splice_to_string (stdout_stream, error);
    1469                 :          1 :   split = g_strsplit (result, LINEEND, -1);
    1470                 :          1 :   g_assert_null (g_environ_getenv (split, "TEST_ENV_INHERIT1"));
    1471                 :          1 :   g_assert_cmpstr (g_environ_getenv (split, "TEST_ENV_INHERIT2"), ==, "2");
    1472                 :          1 :   g_assert_cmpstr (g_environ_getenv (split, "TWO"), ==, "2");
    1473                 :            : 
    1474                 :          1 :   g_strfreev (split);
    1475                 :          1 :   g_free (result);
    1476                 :          1 :   g_object_unref (proc);
    1477                 :          1 :   g_object_unref (launcher);
    1478                 :          1 : }
    1479                 :            : 
    1480                 :            : static void
    1481                 :          1 : test_cwd (void)
    1482                 :            : {
    1483                 :          1 :   GError *local_error = NULL;
    1484                 :            :   GSubprocessLauncher *launcher;
    1485                 :            :   GSubprocess *proc;
    1486                 :            :   GPtrArray *args;
    1487                 :            :   GInputStream *stdout_stream;
    1488                 :            :   gchar *result;
    1489                 :            :   gsize result_len;
    1490                 :          1 :   const gchar *tmpdir = g_get_tmp_dir ();
    1491                 :          1 :   gchar *tmpdir_basename = NULL, *result_basename = NULL;
    1492                 :            : 
    1493                 :          1 :   args = get_test_subprocess_args ("cwd", NULL);
    1494                 :          1 :   launcher = g_subprocess_launcher_new (G_SUBPROCESS_FLAGS_STDOUT_PIPE);
    1495                 :          1 :   g_subprocess_launcher_set_flags (launcher, G_SUBPROCESS_FLAGS_STDOUT_PIPE);
    1496                 :          1 :   g_subprocess_launcher_set_cwd (launcher, tmpdir);
    1497                 :            : 
    1498                 :          1 :   proc = g_subprocess_launcher_spawnv (launcher, (const char * const *)args->pdata, &local_error);
    1499                 :          1 :   g_ptr_array_free (args, TRUE);
    1500                 :          1 :   g_assert_no_error (local_error);
    1501                 :            : 
    1502                 :          1 :   stdout_stream = g_subprocess_get_stdout_pipe (proc);
    1503                 :            : 
    1504                 :          1 :   result = splice_to_string (stdout_stream, &local_error);
    1505                 :          1 :   g_assert_no_error (local_error);
    1506                 :          1 :   result_len = strlen (result);
    1507                 :            : 
    1508                 :            :   /* The result should end with a line ending */
    1509                 :          1 :   g_assert_cmpstr (result + result_len - strlen (LINEEND), ==, LINEEND);
    1510                 :            : 
    1511                 :            :   /* Not sure if the testprog guarantees to return an absolute path for the cwd,
    1512                 :            :    * so only compare the basenames. */
    1513                 :          1 :   tmpdir_basename = g_path_get_basename (tmpdir);
    1514                 :          1 :   result_basename = g_path_get_basename (g_strstrip (result));
    1515                 :          1 :   g_assert_cmpstr (tmpdir_basename, ==, result_basename);
    1516                 :          1 :   g_free (tmpdir_basename);
    1517                 :          1 :   g_free (result_basename);
    1518                 :            : 
    1519                 :          1 :   g_free (result);
    1520                 :          1 :   g_object_unref (proc);
    1521                 :          1 :   g_object_unref (launcher);
    1522                 :          1 : }
    1523                 :            : #ifdef G_OS_UNIX
    1524                 :            : 
    1525                 :            : static void
    1526                 :          1 : test_subprocess_launcher_close (void)
    1527                 :            : {
    1528                 :          1 :   GError *local_error = NULL;
    1529                 :          1 :   GError **error = &local_error;
    1530                 :            :   GSubprocessLauncher *launcher;
    1531                 :            :   GSubprocess *proc;
    1532                 :            :   GPtrArray *args;
    1533                 :            :   int fd, fd2;
    1534                 :            :   gboolean is_open;
    1535                 :            : 
    1536                 :            :   /* Open two arbitrary FDs. One of them, @fd, will be transferred to the
    1537                 :            :    * launcher, and the other’s FD integer will be used as its target FD, giving
    1538                 :            :    * the mapping `fd → fd2` if a child process were to be spawned.
    1539                 :            :    *
    1540                 :            :    * The launcher will then be closed, which should close @fd but *not* @fd2,
    1541                 :            :    * as the value of @fd2 is only valid as an FD in a child process. (A child
    1542                 :            :    * process is not actually spawned in this test.)
    1543                 :            :    */
    1544                 :          1 :   fd = dup (0);
    1545                 :          1 :   fd2 = dup (0);
    1546                 :          1 :   launcher = g_subprocess_launcher_new (G_SUBPROCESS_FLAGS_NONE);
    1547                 :          1 :   g_subprocess_launcher_take_fd (launcher, fd, fd2);
    1548                 :            : 
    1549                 :          1 :   is_open = fcntl (fd, F_GETFD) != -1;
    1550                 :          1 :   g_assert_true (is_open);
    1551                 :          1 :   is_open = fcntl (fd2, F_GETFD) != -1;
    1552                 :          1 :   g_assert_true (is_open);
    1553                 :            : 
    1554                 :          1 :   g_subprocess_launcher_close (launcher);
    1555                 :            : 
    1556                 :          1 :   is_open = fcntl (fd, F_GETFD) != -1;
    1557                 :          1 :   g_assert_false (is_open);
    1558                 :          1 :   is_open = fcntl (fd2, F_GETFD) != -1;
    1559                 :          1 :   g_assert_true (is_open);
    1560                 :            : 
    1561                 :            :   /* Now test that actually trying to spawn the child gives %G_IO_ERROR_CLOSED,
    1562                 :            :    * as g_subprocess_launcher_close() has been called. */
    1563                 :          1 :   args = get_test_subprocess_args ("cat", NULL);
    1564                 :          1 :   proc = g_subprocess_launcher_spawnv (launcher, (const gchar * const *) args->pdata, error);
    1565                 :          1 :   g_ptr_array_free (args, TRUE);
    1566                 :          1 :   g_assert_null (proc);
    1567                 :          1 :   g_assert_error (local_error, G_IO_ERROR, G_IO_ERROR_CLOSED);
    1568                 :          1 :   g_clear_error (error);
    1569                 :            : 
    1570                 :          1 :   close (fd2);
    1571                 :          1 :   g_object_unref (launcher);
    1572                 :          1 : }
    1573                 :            : 
    1574                 :            : static void
    1575                 :          1 : test_stdout_file (void)
    1576                 :            : {
    1577                 :          1 :   GError *local_error = NULL;
    1578                 :          1 :   GError **error = &local_error;
    1579                 :            :   GSubprocessLauncher *launcher;
    1580                 :            :   GSubprocess *proc;
    1581                 :            :   GPtrArray *args;
    1582                 :            :   GFile *tmpfile;
    1583                 :            :   GFileIOStream *iostream;
    1584                 :            :   GOutputStream *stdin_stream;
    1585                 :          1 :   const char *test_data = "this is some test data\n";
    1586                 :            :   char *tmp_contents;
    1587                 :            :   char *tmp_file_path;
    1588                 :            : 
    1589                 :          1 :   tmpfile = g_file_new_tmp ("gsubprocessXXXXXX", &iostream, error);
    1590                 :          1 :   g_assert_no_error (local_error);
    1591                 :          1 :   g_clear_object (&iostream);
    1592                 :            : 
    1593                 :          1 :   tmp_file_path = g_file_get_path (tmpfile);
    1594                 :            : 
    1595                 :          1 :   args = get_test_subprocess_args ("cat", NULL);
    1596                 :          1 :   launcher = g_subprocess_launcher_new (G_SUBPROCESS_FLAGS_STDIN_PIPE);
    1597                 :          1 :   g_subprocess_launcher_set_stdout_file_path (launcher, tmp_file_path);
    1598                 :          1 :   proc = g_subprocess_launcher_spawnv (launcher, (const gchar * const *) args->pdata, error);
    1599                 :          1 :   g_ptr_array_free (args, TRUE);
    1600                 :          1 :   g_assert_no_error (local_error);
    1601                 :            : 
    1602                 :          1 :   stdin_stream = g_subprocess_get_stdin_pipe (proc);
    1603                 :            : 
    1604                 :          1 :   g_output_stream_write_all (stdin_stream, test_data, strlen (test_data), NULL, NULL, error);
    1605                 :          1 :   g_assert_no_error (local_error);
    1606                 :            : 
    1607                 :          1 :   g_output_stream_close (stdin_stream, NULL, error);
    1608                 :          1 :   g_assert_no_error (local_error);
    1609                 :            : 
    1610                 :          1 :   g_subprocess_wait_check (proc, NULL, error);
    1611                 :            : 
    1612                 :          1 :   g_object_unref (launcher);
    1613                 :          1 :   g_object_unref (proc);
    1614                 :            : 
    1615                 :          1 :   g_file_load_contents (tmpfile, NULL, &tmp_contents, NULL, NULL, error);
    1616                 :          1 :   g_assert_no_error (local_error);
    1617                 :            : 
    1618                 :          1 :   g_assert_cmpstr (test_data, ==, tmp_contents);
    1619                 :          1 :   g_free (tmp_contents);
    1620                 :            : 
    1621                 :          1 :   (void) g_file_delete (tmpfile, NULL, NULL);
    1622                 :          1 :   g_object_unref (tmpfile);
    1623                 :          1 :   g_free (tmp_file_path);
    1624                 :          1 : }
    1625                 :            : 
    1626                 :            : static void
    1627                 :          1 : test_stdout_fd (void)
    1628                 :            : {
    1629                 :          1 :   GError *local_error = NULL;
    1630                 :          1 :   GError **error = &local_error;
    1631                 :            :   GSubprocessLauncher *launcher;
    1632                 :            :   GSubprocess *proc;
    1633                 :            :   GPtrArray *args;
    1634                 :            :   GFile *tmpfile;
    1635                 :            :   GFileIOStream *iostream;
    1636                 :            :   GFileDescriptorBased *descriptor_stream;
    1637                 :            :   GOutputStream *stdin_stream;
    1638                 :          1 :   const char *test_data = "this is some test data\n";
    1639                 :            :   char *tmp_contents;
    1640                 :            : 
    1641                 :          1 :   tmpfile = g_file_new_tmp ("gsubprocessXXXXXX", &iostream, error);
    1642                 :          1 :   g_assert_no_error (local_error);
    1643                 :            : 
    1644                 :          1 :   args = get_test_subprocess_args ("cat", NULL);
    1645                 :          1 :   launcher = g_subprocess_launcher_new (G_SUBPROCESS_FLAGS_STDIN_PIPE);
    1646                 :          1 :   descriptor_stream = G_FILE_DESCRIPTOR_BASED (g_io_stream_get_output_stream (G_IO_STREAM (iostream)));
    1647                 :          1 :   g_subprocess_launcher_take_stdout_fd (launcher, dup (g_file_descriptor_based_get_fd (descriptor_stream)));
    1648                 :          1 :   proc = g_subprocess_launcher_spawnv (launcher, (const gchar * const *) args->pdata, error);
    1649                 :          1 :   g_ptr_array_free (args, TRUE);
    1650                 :          1 :   g_assert_no_error (local_error);
    1651                 :            : 
    1652                 :          1 :   g_clear_object (&iostream);
    1653                 :            : 
    1654                 :          1 :   stdin_stream = g_subprocess_get_stdin_pipe (proc);
    1655                 :            : 
    1656                 :          1 :   g_output_stream_write_all (stdin_stream, test_data, strlen (test_data), NULL, NULL, error);
    1657                 :          1 :   g_assert_no_error (local_error);
    1658                 :            : 
    1659                 :          1 :   g_output_stream_close (stdin_stream, NULL, error);
    1660                 :          1 :   g_assert_no_error (local_error);
    1661                 :            : 
    1662                 :          1 :   g_subprocess_wait_check (proc, NULL, error);
    1663                 :            : 
    1664                 :          1 :   g_object_unref (launcher);
    1665                 :          1 :   g_object_unref (proc);
    1666                 :            : 
    1667                 :          1 :   g_file_load_contents (tmpfile, NULL, &tmp_contents, NULL, NULL, error);
    1668                 :          1 :   g_assert_no_error (local_error);
    1669                 :            : 
    1670                 :          1 :   g_assert_cmpstr (test_data, ==, tmp_contents);
    1671                 :          1 :   g_free (tmp_contents);
    1672                 :            : 
    1673                 :          1 :   (void) g_file_delete (tmpfile, NULL, NULL);
    1674                 :          1 :   g_object_unref (tmpfile);
    1675                 :          1 : }
    1676                 :            : 
    1677                 :            : static void
    1678                 :          1 : child_setup (gpointer user_data)
    1679                 :            : {
    1680                 :          1 :   dup2 (GPOINTER_TO_INT (user_data), 1);
    1681                 :          1 : }
    1682                 :            : 
    1683                 :            : static void
    1684                 :          1 : test_child_setup (void)
    1685                 :            : {
    1686                 :          1 :   GError *local_error = NULL;
    1687                 :          1 :   GError **error = &local_error;
    1688                 :            :   GSubprocessLauncher *launcher;
    1689                 :            :   GSubprocess *proc;
    1690                 :            :   GPtrArray *args;
    1691                 :            :   GFile *tmpfile;
    1692                 :            :   GFileIOStream *iostream;
    1693                 :            :   GOutputStream *stdin_stream;
    1694                 :          1 :   const char *test_data = "this is some test data\n";
    1695                 :            :   char *tmp_contents;
    1696                 :            :   int fd;
    1697                 :            : 
    1698                 :          1 :   tmpfile = g_file_new_tmp ("gsubprocessXXXXXX", &iostream, error);
    1699                 :          1 :   g_assert_no_error (local_error);
    1700                 :            : 
    1701                 :          1 :   fd = g_file_descriptor_based_get_fd (G_FILE_DESCRIPTOR_BASED (g_io_stream_get_output_stream (G_IO_STREAM (iostream))));
    1702                 :            : 
    1703                 :          1 :   args = get_test_subprocess_args ("cat", NULL);
    1704                 :          1 :   launcher = g_subprocess_launcher_new (G_SUBPROCESS_FLAGS_STDIN_PIPE);
    1705                 :          1 :   g_subprocess_launcher_set_child_setup (launcher, child_setup, GINT_TO_POINTER (fd), NULL);
    1706                 :          1 :   proc = g_subprocess_launcher_spawnv (launcher, (const gchar * const *) args->pdata, error);
    1707                 :          1 :   g_ptr_array_free (args, TRUE);
    1708                 :          1 :   g_assert_no_error (local_error);
    1709                 :            : 
    1710                 :          1 :   g_clear_object (&iostream);
    1711                 :            : 
    1712                 :          1 :   stdin_stream = g_subprocess_get_stdin_pipe (proc);
    1713                 :            : 
    1714                 :          1 :   g_output_stream_write_all (stdin_stream, test_data, strlen (test_data), NULL, NULL, error);
    1715                 :          1 :   g_assert_no_error (local_error);
    1716                 :            : 
    1717                 :          1 :   g_output_stream_close (stdin_stream, NULL, error);
    1718                 :          1 :   g_assert_no_error (local_error);
    1719                 :            : 
    1720                 :          1 :   g_subprocess_wait_check (proc, NULL, error);
    1721                 :            : 
    1722                 :          1 :   g_object_unref (launcher);
    1723                 :          1 :   g_object_unref (proc);
    1724                 :            : 
    1725                 :          1 :   g_file_load_contents (tmpfile, NULL, &tmp_contents, NULL, NULL, error);
    1726                 :          1 :   g_assert_no_error (local_error);
    1727                 :            : 
    1728                 :          1 :   g_assert_cmpstr (test_data, ==, tmp_contents);
    1729                 :          1 :   g_free (tmp_contents);
    1730                 :            : 
    1731                 :          1 :   (void) g_file_delete (tmpfile, NULL, NULL);
    1732                 :          1 :   g_object_unref (tmpfile);
    1733                 :          1 : }
    1734                 :            : 
    1735                 :            : static void
    1736                 :          3 : do_test_pass_fd (GSubprocessFlags     flags,
    1737                 :            :                  GSpawnChildSetupFunc child_setup)
    1738                 :            : {
    1739                 :          3 :   GError *local_error = NULL;
    1740                 :          3 :   GError **error = &local_error;
    1741                 :            :   GInputStream *child_input;
    1742                 :            :   GDataInputStream *child_datainput;
    1743                 :            :   GSubprocessLauncher *launcher;
    1744                 :            :   GSubprocess *proc;
    1745                 :            :   GPtrArray *args;
    1746                 :            :   int basic_pipefds[2];
    1747                 :            :   int needdup_pipefds[2];
    1748                 :            :   char *buf;
    1749                 :            :   gsize len;
    1750                 :            :   char *basic_fd_str;
    1751                 :            :   char *needdup_fd_str;
    1752                 :            : 
    1753                 :          3 :   g_unix_open_pipe (basic_pipefds, O_CLOEXEC, error);
    1754                 :          3 :   g_assert_no_error (local_error);
    1755                 :          3 :   g_unix_open_pipe (needdup_pipefds, O_CLOEXEC, error);
    1756                 :          3 :   g_assert_no_error (local_error);
    1757                 :            : 
    1758                 :          3 :   basic_fd_str = g_strdup_printf ("%d", basic_pipefds[1]);
    1759                 :          3 :   needdup_fd_str = g_strdup_printf ("%d", needdup_pipefds[1] + 1);
    1760                 :            : 
    1761                 :          3 :   args = get_test_subprocess_args ("write-to-fds", basic_fd_str, needdup_fd_str, NULL);
    1762                 :          3 :   launcher = g_subprocess_launcher_new (flags);
    1763                 :          3 :   g_subprocess_launcher_take_fd (launcher, basic_pipefds[1], basic_pipefds[1]);
    1764                 :          3 :   g_subprocess_launcher_take_fd (launcher, needdup_pipefds[1], needdup_pipefds[1] + 1);
    1765         [ +  + ]:          3 :   if (child_setup != NULL)
    1766                 :          1 :     g_subprocess_launcher_set_child_setup (launcher, child_setup, NULL, NULL);
    1767                 :          3 :   proc = g_subprocess_launcher_spawnv (launcher, (const gchar * const *) args->pdata, error);
    1768                 :          3 :   g_ptr_array_free (args, TRUE);
    1769                 :          3 :   g_assert_no_error (local_error);
    1770                 :            : 
    1771                 :          3 :   g_free (basic_fd_str);
    1772                 :          3 :   g_free (needdup_fd_str);
    1773                 :            : 
    1774                 :          3 :   child_input = g_unix_input_stream_new (basic_pipefds[0], TRUE);
    1775                 :          3 :   child_datainput = g_data_input_stream_new (child_input);
    1776                 :          3 :   buf = g_data_input_stream_read_line_utf8 (child_datainput, &len, NULL, error);
    1777                 :          3 :   g_assert_no_error (local_error);
    1778                 :          3 :   g_assert_cmpstr (buf, ==, "hello world");
    1779                 :          3 :   g_object_unref (child_datainput);
    1780                 :          3 :   g_object_unref (child_input);
    1781                 :          3 :   g_free (buf);
    1782                 :            : 
    1783                 :          3 :   child_input = g_unix_input_stream_new (needdup_pipefds[0], TRUE);
    1784                 :          3 :   child_datainput = g_data_input_stream_new (child_input);
    1785                 :          3 :   buf = g_data_input_stream_read_line_utf8 (child_datainput, &len, NULL, error);
    1786                 :          3 :   g_assert_no_error (local_error);
    1787                 :          3 :   g_assert_cmpstr (buf, ==, "hello world");
    1788                 :          3 :   g_free (buf);
    1789                 :          3 :   g_object_unref (child_datainput);
    1790                 :          3 :   g_object_unref (child_input);
    1791                 :            : 
    1792                 :          3 :   g_object_unref (launcher);
    1793                 :          3 :   g_object_unref (proc);
    1794                 :          3 : }
    1795                 :            : 
    1796                 :            : static void
    1797                 :          1 : test_pass_fd (void)
    1798                 :            : {
    1799                 :          1 :   do_test_pass_fd (G_SUBPROCESS_FLAGS_NONE, NULL);
    1800                 :          1 : }
    1801                 :            : 
    1802                 :            : static void
    1803                 :          3 : empty_child_setup (gpointer user_data)
    1804                 :            : {
    1805                 :          3 : }
    1806                 :            : 
    1807                 :            : static void
    1808                 :          1 : test_pass_fd_empty_child_setup (void)
    1809                 :            : {
    1810                 :            :   /* Using a child setup function forces gspawn to use fork/exec
    1811                 :            :    * rather than posix_spawn.
    1812                 :            :    */
    1813                 :          1 :   do_test_pass_fd (G_SUBPROCESS_FLAGS_NONE, empty_child_setup);
    1814                 :          1 : }
    1815                 :            : 
    1816                 :            : static void
    1817                 :          1 : test_pass_fd_inherit_fds (void)
    1818                 :            : {
    1819                 :            :   /* Try to test the optimized posix_spawn codepath instead of
    1820                 :            :    * fork/exec. Currently this requires using INHERIT_FDS since gspawn's
    1821                 :            :    * posix_spawn codepath does not currently handle closing
    1822                 :            :    * non-inherited fds. Note that using INHERIT_FDS means our testing of
    1823                 :            :    * g_subprocess_launcher_take_fd() is less-comprehensive than when
    1824                 :            :    * using G_SUBPROCESS_FLAGS_NONE.
    1825                 :            :    */
    1826                 :          1 :   do_test_pass_fd (G_SUBPROCESS_FLAGS_INHERIT_FDS, NULL);
    1827                 :          1 : }
    1828                 :            : 
    1829                 :            : static void
    1830                 :          8 : do_test_fd_conflation (GSubprocessFlags     flags,
    1831                 :            :                        GSpawnChildSetupFunc child_setup,
    1832                 :            :                        gboolean             test_child_err_report_fd)
    1833                 :            : {
    1834                 :          8 :   char success_message[] = "Yay success!";
    1835                 :          8 :   GError *error = NULL;
    1836                 :            :   GOutputStream *output_stream;
    1837                 :            :   GSubprocessLauncher *launcher;
    1838                 :            :   GSubprocess *proc;
    1839                 :            :   GPtrArray *args;
    1840                 :            :   int unused_pipefds[2];
    1841                 :            :   int pipefds[2];
    1842                 :            :   int fd_to_pass_to_child;
    1843                 :            :   gsize bytes_written;
    1844                 :            :   gboolean success;
    1845                 :            :   char *fd_str;
    1846                 :            : 
    1847                 :            :   /* This test must run in a new process because it is extremely sensitive to
    1848                 :            :    * order of opened fds.
    1849                 :            :    */
    1850         [ +  + ]:          8 :   if (!g_test_subprocess ())
    1851                 :            :     {
    1852                 :          4 :       g_test_trap_subprocess (NULL, 0, G_TEST_SUBPROCESS_INHERIT_STDOUT | G_TEST_SUBPROCESS_INHERIT_STDERR);
    1853                 :          4 :       g_test_trap_assert_passed ();
    1854                 :          4 :       return;
    1855                 :            :     }
    1856                 :            : 
    1857                 :          4 :   g_unix_open_pipe (unused_pipefds, O_CLOEXEC, &error);
    1858                 :          4 :   g_assert_no_error (error);
    1859                 :            : 
    1860                 :          4 :   g_unix_open_pipe (pipefds, O_CLOEXEC, &error);
    1861                 :          4 :   g_assert_no_error (error);
    1862                 :            : 
    1863                 :            :   /* The fds should be sequential since we are in a new process. */
    1864                 :          4 :   g_assert_cmpint (unused_pipefds[0] /* 3 */, ==, unused_pipefds[1] - 1);
    1865                 :          4 :   g_assert_cmpint (unused_pipefds[1] /* 4 */, ==, pipefds[0] - 1);
    1866                 :          4 :   g_assert_cmpint (pipefds[0] /* 5 */, ==, pipefds[1] /* 6 */ - 1);
    1867                 :            : 
    1868                 :            :   /* Because GSubprocess allows arbitrary remapping of fds, it has to be careful
    1869                 :            :    * to avoid fd conflation issues, e.g. it should properly handle 5 -> 4 and
    1870                 :            :    * 4 -> 5 at the same time. GIO previously attempted to handle this by naively
    1871                 :            :    * dup'ing the source fds, but this was not good enough because it was
    1872                 :            :    * possible that the dup'ed result could still conflict with one of the target
    1873                 :            :    * fds. For example:
    1874                 :            :    *
    1875                 :            :    * source_fd 5 -> target_fd 9, source_fd 3 -> target_fd 7
    1876                 :            :    *
    1877                 :            :    * dup(5) -> dup returns 8
    1878                 :            :    * dup(3) -> dup returns 9
    1879                 :            :    *
    1880                 :            :    * After dup'ing, we wind up with: 8 -> 9, 9 -> 7. That means that after we
    1881                 :            :    * dup2(8, 9), we have clobbered fd 9 before we dup2(9, 7). The end result is
    1882                 :            :    * we have remapped 5 -> 9 as expected, but then remapped 5 -> 7 instead of
    1883                 :            :    * 3 -> 7 as the application intended.
    1884                 :            :    *
    1885                 :            :    * This issue has been fixed in the simplest way possible, by passing a
    1886                 :            :    * minimum fd value when using F_DUPFD_CLOEXEC that is higher than any of the
    1887                 :            :    * target fds, to guarantee all source fds are different than all target fds,
    1888                 :            :    * eliminating any possibility of conflation.
    1889                 :            :    *
    1890                 :            :    * Anyway, that is why we have the unused_pipefds here. We need to open fds in
    1891                 :            :    * a certain order in order to trick older GSubprocess into conflating the
    1892                 :            :    * fds. The primary goal of this test is to ensure this particular conflation
    1893                 :            :    * issue is not reintroduced. See glib#2503.
    1894                 :            :    *
    1895                 :            :    * This test also has an alternate mode of operation where it instead tests
    1896                 :            :    * for conflation with gspawn's child_err_report_fd, glib#2506.
    1897                 :            :    *
    1898                 :            :    * Be aware this test is necessarily extremely fragile. To reproduce these
    1899                 :            :    * bugs, it relies on internals of gspawn and gmain that will likely change
    1900                 :            :    * in the future, eventually causing this test to no longer test the bugs
    1901                 :            :    * it was originally designed to test. That is OK! If the test fails, at
    1902                 :            :    * least you know *something* is wrong.
    1903                 :            :    */
    1904         [ +  + ]:          4 :   if (test_child_err_report_fd)
    1905                 :          1 :     fd_to_pass_to_child = pipefds[1] + 2 /* 8 */;
    1906                 :            :   else
    1907                 :          3 :     fd_to_pass_to_child = pipefds[1] + 3 /* 9 */;
    1908                 :            : 
    1909                 :          4 :   launcher = g_subprocess_launcher_new (flags);
    1910                 :          4 :   g_subprocess_launcher_take_fd (launcher, pipefds[0] /* 5 */, fd_to_pass_to_child);
    1911                 :          4 :   g_subprocess_launcher_take_fd (launcher, unused_pipefds[0] /* 3 */, pipefds[1] + 1 /* 7 */);
    1912         [ +  + ]:          4 :   if (child_setup != NULL)
    1913                 :          2 :     g_subprocess_launcher_set_child_setup (launcher, child_setup, NULL, NULL);
    1914                 :          4 :   fd_str = g_strdup_printf ("%d", fd_to_pass_to_child);
    1915                 :          4 :   args = get_test_subprocess_args ("read-from-fd", fd_str, NULL);
    1916                 :          4 :   proc = g_subprocess_launcher_spawnv (launcher, (const gchar * const *) args->pdata, &error);
    1917                 :          4 :   g_assert_no_error (error);
    1918                 :          4 :   g_assert_nonnull (proc);
    1919                 :          4 :   g_ptr_array_free (args, TRUE);
    1920                 :          4 :   g_object_unref (launcher);
    1921                 :          4 :   g_free (fd_str);
    1922                 :            : 
    1923                 :            :   /* Close the read ends of the pipes. */
    1924                 :          4 :   close (unused_pipefds[0]);
    1925                 :          4 :   close (pipefds[0]);
    1926                 :            : 
    1927                 :            :   /* Also close the write end of the unused pipe. */
    1928                 :          4 :   close (unused_pipefds[1]);
    1929                 :            : 
    1930                 :            :   /* If doing our normal test:
    1931                 :            :    *
    1932                 :            :    * So now pipefds[0] should be inherited into the subprocess as
    1933                 :            :    * pipefds[1] + 2, and unused_pipefds[0] should be inherited as
    1934                 :            :    * pipefds[1] + 1. We will write to pipefds[1] and the subprocess will verify
    1935                 :            :    * that it reads the expected data. But older broken GIO will accidentally
    1936                 :            :    * clobber pipefds[1] + 2 with pipefds[1] + 1! This will cause the subprocess
    1937                 :            :    * to hang trying to read from the wrong pipe.
    1938                 :            :    *
    1939                 :            :    * If testing conflation with child_err_report_fd:
    1940                 :            :    *
    1941                 :            :    * We are actually already done. The real test succeeded if we made it this
    1942                 :            :    * far without hanging while spawning the child. But let's continue with our
    1943                 :            :    * write and read anyway, to ensure things are good.
    1944                 :            :    */
    1945                 :          4 :   output_stream = g_unix_output_stream_new (pipefds[1], TRUE);
    1946                 :          4 :   success = g_output_stream_write_all (output_stream,
    1947                 :            :                                        success_message, sizeof (success_message),
    1948                 :            :                                        &bytes_written,
    1949                 :            :                                        NULL,
    1950                 :            :                                        &error);
    1951                 :          4 :   g_assert_no_error (error);
    1952                 :          4 :   g_assert_cmpint (bytes_written, ==, sizeof (success_message));
    1953                 :          4 :   g_assert_true (success);
    1954                 :          4 :   g_object_unref (output_stream);
    1955                 :            : 
    1956                 :          4 :   success = g_subprocess_wait_check (proc, NULL, &error);
    1957                 :          4 :   g_assert_no_error (error);
    1958                 :          4 :   g_object_unref (proc);
    1959                 :            : }
    1960                 :            : 
    1961                 :            : static void
    1962                 :          2 : test_fd_conflation (void)
    1963                 :            : {
    1964                 :          2 :   do_test_fd_conflation (G_SUBPROCESS_FLAGS_NONE, NULL, FALSE);
    1965                 :          2 : }
    1966                 :            : 
    1967                 :            : static void
    1968                 :          2 : test_fd_conflation_empty_child_setup (void)
    1969                 :            : {
    1970                 :            :   /* Using a child setup function forces gspawn to use fork/exec
    1971                 :            :    * rather than posix_spawn.
    1972                 :            :    */
    1973                 :          2 :   do_test_fd_conflation (G_SUBPROCESS_FLAGS_NONE, empty_child_setup, FALSE);
    1974                 :          2 : }
    1975                 :            : 
    1976                 :            : static void
    1977                 :          2 : test_fd_conflation_inherit_fds (void)
    1978                 :            : {
    1979                 :            :   /* Try to test the optimized posix_spawn codepath instead of
    1980                 :            :    * fork/exec. Currently this requires using INHERIT_FDS since gspawn's
    1981                 :            :    * posix_spawn codepath does not currently handle closing
    1982                 :            :    * non-inherited fds.
    1983                 :            :    */
    1984                 :          2 :   do_test_fd_conflation (G_SUBPROCESS_FLAGS_INHERIT_FDS, NULL, FALSE);
    1985                 :          2 : }
    1986                 :            : 
    1987                 :            : static void
    1988                 :          2 : test_fd_conflation_child_err_report_fd (void)
    1989                 :            : {
    1990                 :            :   /* Using a child setup function forces gspawn to use fork/exec
    1991                 :            :    * rather than posix_spawn.
    1992                 :            :    */
    1993                 :          2 :   do_test_fd_conflation (G_SUBPROCESS_FLAGS_NONE, empty_child_setup, TRUE);
    1994                 :          2 : }
    1995                 :            : 
    1996                 :            : #ifdef __linux__
    1997                 :            : 
    1998                 :            : /* Handle ptrace events on @main_child, and assert that when it exits, it does
    1999                 :            :  * so with status %EXIT_SUCCESS, rather than signalling. Other than that, this
    2000                 :            :  * just calls %PTRACE_CONT for all trace events. */
    2001                 :            : static void
    2002                 :          1 : trace_children (pid_t main_child)
    2003                 :            : {
    2004                 :            :   int wstatus;
    2005                 :            : 
    2006                 :          1 :   g_assert_no_errno (waitpid (main_child, &wstatus, 0));
    2007                 :          1 :   g_assert_no_errno (ptrace (PTRACE_SETOPTIONS, main_child, NULL,
    2008                 :            :                              (PTRACE_O_TRACEFORK |
    2009                 :            : #ifdef HAVE_PTRACE_O_EXITKILL
    2010                 :            :                               PTRACE_O_EXITKILL |
    2011                 :            : #endif
    2012                 :            :                               PTRACE_O_TRACEVFORK |
    2013                 :            :                               PTRACE_O_TRACECLONE |
    2014                 :            :                               PTRACE_O_TRACEEXEC)));
    2015                 :          1 :   g_assert_no_errno (ptrace (PTRACE_CONT, main_child, NULL, 0));
    2016                 :            : 
    2017                 :            :   while (TRUE)
    2018                 :         11 :     {
    2019                 :            :       pid_t pid;
    2020                 :            :       int wstatus;
    2021                 :            :       int stop_signum;
    2022                 :            :       int ptrace_event;
    2023                 :            : 
    2024                 :         12 :       pid = waitpid (-1, &wstatus, 0);
    2025   [ -  +  -  - ]:         12 :       if (pid == -1 && errno == ECHILD)
    2026                 :          0 :         break;
    2027                 :            : 
    2028                 :         12 :       g_assert_cmpint (errno, ==, 0);
    2029                 :         12 :       g_assert_cmpint (pid, >=, 0);
    2030                 :            : 
    2031         [ +  + ]:         12 :       if (WIFSTOPPED (wstatus))
    2032                 :          8 :         stop_signum = WSTOPSIG (wstatus);
    2033                 :            :       else
    2034                 :          4 :         stop_signum = 0;
    2035                 :            : 
    2036      [ +  +  + ]:         12 :       switch (stop_signum)
    2037                 :            :         {
    2038                 :          4 :         case SIGTRAP:
    2039         [ -  + ]:          4 :           ptrace_event = (wstatus >> 16) & 0xffff;
    2040                 :            :           switch (ptrace_event)
    2041                 :            :             {
    2042                 :          0 :             case 0:
    2043                 :          0 :               g_assert_no_errno (ptrace (PTRACE_CONT, pid, NULL, stop_signum));
    2044                 :          0 :               break;
    2045                 :          4 :             default:
    2046                 :          4 :               g_assert_no_errno (ptrace (PTRACE_CONT, pid, NULL, 0));
    2047                 :          4 :               break;
    2048                 :            :             }
    2049                 :          4 :           break;
    2050                 :          3 :         case SIGSTOP:
    2051                 :          3 :           g_assert_no_errno (ptrace (PTRACE_CONT, pid, NULL, 0));
    2052                 :          3 :           break;
    2053                 :          5 :         default:
    2054   [ +  +  +  + ]:          5 :           if (!WIFEXITED (wstatus) && !WIFSIGNALED (wstatus))
    2055                 :          1 :             g_assert_no_errno (ptrace (PTRACE_CONT, pid, NULL, stop_signum));
    2056                 :          5 :           break;
    2057                 :            :         }
    2058                 :            : 
    2059         [ +  + ]:         12 :       if (pid == main_child)
    2060                 :            :         {
    2061                 :          5 :           g_assert_false (WIFSIGNALED (wstatus));
    2062         [ +  + ]:          5 :           if (WIFEXITED (wstatus))
    2063                 :            :             {
    2064                 :          1 :               g_assert_cmpint (WEXITSTATUS (wstatus), ==, EXIT_SUCCESS);
    2065                 :          1 :               break;
    2066                 :            :             }
    2067                 :            :         }
    2068                 :            :     }
    2069                 :          1 : }
    2070                 :            : 
    2071                 :            : #endif  /* __linux__ */
    2072                 :            : 
    2073                 :            : static void
    2074                 :          1 : test_exit_status_trapped (void)
    2075                 :            : {
    2076                 :            : #ifdef __linux__
    2077                 :          1 :   GPtrArray *args = NULL;
    2078                 :            :   pid_t test_child;
    2079                 :            : #endif
    2080                 :            : 
    2081                 :          1 :   g_test_summary ("Test that exit status is reported correctly for ptrace()d child processes");
    2082                 :          1 :   g_test_bug ("https://gitlab.gnome.org/GNOME/glib/-/merge_requests/3433");
    2083                 :            : 
    2084                 :            : #ifdef __linux__
    2085                 :            :   /* Call fork() directly here, rather than using #GSubprocess, so that we can
    2086                 :            :    * safely call waitpid() on it ourselves without interfering with the internals
    2087                 :            :    * of #GSubprocess.
    2088                 :            :    * See https://gitlab.gnome.org/GNOME/glib/-/merge_requests/3433#note_1749055 */
    2089                 :          1 :   args = get_test_subprocess_args ("sleep-and-kill", NULL);
    2090                 :          1 :   test_child = fork ();
    2091         [ +  + ]:          2 :   if (test_child == 0)
    2092                 :            :     {
    2093                 :            :       /* Between fork() and exec() we can only call async-signal-safe functions. */
    2094         [ -  + ]:          1 :       if (ptrace (PTRACE_TRACEME, 0, NULL, NULL) < 0)
    2095                 :          0 :         abort ();
    2096                 :            : 
    2097                 :          1 :       g_assert_no_errno (execvp (args->pdata[0], (char * const *) args->pdata));
    2098                 :            :     }
    2099                 :            : 
    2100                 :          2 :   trace_children (test_child);
    2101                 :            : 
    2102                 :          1 :   g_clear_pointer (&args, g_ptr_array_unref);
    2103                 :            : #else
    2104                 :            :   g_test_skip ("ptrace() support for this test is only tested on Linux");
    2105                 :            : #endif
    2106                 :          1 : }
    2107                 :            : 
    2108                 :            : #endif  /* G_OS_UNIX */
    2109                 :            : 
    2110                 :            : static void
    2111                 :          1 : test_launcher_environment (void)
    2112                 :            : {
    2113                 :            :   GSubprocessLauncher *launcher;
    2114                 :          1 :   GError *error = NULL;
    2115                 :            :   GSubprocess *proc;
    2116                 :            :   GPtrArray *args;
    2117                 :            :   gchar *out;
    2118                 :            : 
    2119                 :          1 :   g_setenv ("A", "B", TRUE);
    2120                 :          1 :   g_setenv ("C", "D", TRUE);
    2121                 :            : 
    2122                 :          1 :   launcher = g_subprocess_launcher_new (G_SUBPROCESS_FLAGS_STDOUT_PIPE);
    2123                 :            : 
    2124                 :            :   /* unset a variable */
    2125                 :          1 :   g_subprocess_launcher_unsetenv (launcher, "A");
    2126                 :            : 
    2127                 :            :   /* and set a different one */
    2128                 :          1 :   g_subprocess_launcher_setenv (launcher, "E", "F", TRUE);
    2129                 :            : 
    2130                 :          1 :   args = get_test_subprocess_args ("printenv", "A", "C", "E", NULL);
    2131                 :          1 :   proc = g_subprocess_launcher_spawnv (launcher, (const gchar **) args->pdata, &error);
    2132                 :          1 :   g_assert_no_error (error);
    2133                 :          1 :   g_assert_nonnull (proc);
    2134                 :            : 
    2135                 :          1 :   g_subprocess_communicate_utf8 (proc, NULL, NULL, &out, NULL, &error);
    2136                 :          1 :   g_assert_no_error (error);
    2137                 :            : 
    2138                 :          1 :   g_assert_cmpstr (out, ==, "C=D" LINEEND "E=F" LINEEND);
    2139                 :          1 :   g_free (out);
    2140                 :            : 
    2141                 :          1 :   g_object_unref (proc);
    2142                 :          1 :   g_object_unref (launcher);
    2143                 :          1 :   g_ptr_array_unref (args);
    2144                 :          1 : }
    2145                 :            : 
    2146                 :            : int
    2147                 :          5 : main (int argc, char **argv)
    2148                 :            : {
    2149                 :            :   const struct
    2150                 :            :     {
    2151                 :            :       const gchar *subtest;
    2152                 :            :       GSubprocessFlags flags;
    2153                 :            :     }
    2154                 :          5 :   flags_vectors[] =
    2155                 :            :     {
    2156                 :            :       { "", G_SUBPROCESS_FLAGS_STDOUT_PIPE | G_SUBPROCESS_FLAGS_STDERR_MERGE },
    2157                 :            :       { "/no-pipes", G_SUBPROCESS_FLAGS_NONE },
    2158                 :            :       { "/separate-stderr", G_SUBPROCESS_FLAGS_STDOUT_PIPE | G_SUBPROCESS_FLAGS_STDERR_PIPE },
    2159                 :            :       { "/stdout-only", G_SUBPROCESS_FLAGS_STDOUT_PIPE },
    2160                 :            :       { "/stderr-only", G_SUBPROCESS_FLAGS_STDERR_PIPE },
    2161                 :            :       { "/stdout-silence", G_SUBPROCESS_FLAGS_STDOUT_SILENCE },
    2162                 :            :     };
    2163                 :            :   gsize i;
    2164                 :            : 
    2165                 :          5 :   g_test_init (&argc, &argv, NULL);
    2166                 :            : 
    2167                 :          5 :   g_test_add_func ("/gsubprocess/noop", test_noop);
    2168                 :          5 :   g_test_add_func ("/gsubprocess/noop-all-to-null", test_noop_all_to_null);
    2169                 :          5 :   g_test_add_func ("/gsubprocess/noop-no-wait", test_noop_no_wait);
    2170                 :          5 :   g_test_add_func ("/gsubprocess/noop-stdin-inherit", test_noop_stdin_inherit);
    2171                 :            : #ifdef G_OS_UNIX
    2172                 :          5 :   g_test_add_func ("/gsubprocess/search-path", test_search_path);
    2173                 :          5 :   g_test_add_func ("/gsubprocess/search-path-from-envp", test_search_path_from_envp);
    2174                 :          5 :   g_test_add_func ("/gsubprocess/signal", test_signal);
    2175                 :            : #endif
    2176                 :          5 :   g_test_add_func ("/gsubprocess/exit1", test_exit1);
    2177                 :          5 :   g_test_add_func ("/gsubprocess/exit1/cancel", test_exit1_cancel);
    2178                 :          5 :   g_test_add_func ("/gsubprocess/exit1/cancel_in_cb", test_exit1_cancel_in_cb);
    2179                 :          5 :   g_test_add_func ("/gsubprocess/echo1", test_echo1);
    2180                 :            : #ifdef G_OS_UNIX
    2181                 :          5 :   g_test_add_func ("/gsubprocess/echo-merged", test_echo_merged);
    2182                 :            : #endif
    2183                 :          5 :   g_test_add_func ("/gsubprocess/cat-utf8", test_cat_utf8);
    2184                 :          5 :   g_test_add_func ("/gsubprocess/cat-eof", test_cat_eof);
    2185                 :          5 :   g_test_add_func ("/gsubprocess/multi1", test_multi_1);
    2186                 :            : 
    2187                 :            :   /* Add various tests for g_subprocess_communicate() with different flags. */
    2188         [ +  + ]:         35 :   for (i = 0; i < G_N_ELEMENTS (flags_vectors); i++)
    2189                 :            :     {
    2190                 :         30 :       gchar *test_path = NULL;
    2191                 :            : 
    2192                 :         30 :       test_path = g_strdup_printf ("/gsubprocess/communicate%s", flags_vectors[i].subtest);
    2193                 :         30 :       g_test_add_data_func (test_path, GINT_TO_POINTER (flags_vectors[i].flags),
    2194                 :            :                             test_communicate);
    2195                 :         30 :       g_free (test_path);
    2196                 :            : 
    2197                 :         30 :       test_path = g_strdup_printf ("/gsubprocess/communicate/cancelled%s", flags_vectors[i].subtest);
    2198                 :         30 :       g_test_add_data_func (test_path, GINT_TO_POINTER (flags_vectors[i].flags),
    2199                 :            :                             test_communicate_cancelled);
    2200                 :         30 :       g_free (test_path);
    2201                 :            : 
    2202                 :         30 :       test_path = g_strdup_printf ("/gsubprocess/communicate/async%s", flags_vectors[i].subtest);
    2203                 :         30 :       g_test_add_data_func (test_path, GINT_TO_POINTER (flags_vectors[i].flags),
    2204                 :            :                             test_communicate_async);
    2205                 :         30 :       g_free (test_path);
    2206                 :            : 
    2207                 :         30 :       test_path = g_strdup_printf ("/gsubprocess/communicate/async/cancelled%s", flags_vectors[i].subtest);
    2208                 :         30 :       g_test_add_data_func (test_path, GINT_TO_POINTER (flags_vectors[i].flags),
    2209                 :            :                             test_communicate_cancelled_async);
    2210                 :         30 :       g_free (test_path);
    2211                 :            : 
    2212                 :         30 :       test_path = g_strdup_printf ("/gsubprocess/communicate/utf8%s", flags_vectors[i].subtest);
    2213                 :         30 :       g_test_add_data_func (test_path, GINT_TO_POINTER (flags_vectors[i].flags),
    2214                 :            :                             test_communicate_utf8);
    2215                 :         30 :       g_free (test_path);
    2216                 :            : 
    2217                 :         30 :       test_path = g_strdup_printf ("/gsubprocess/communicate/utf8/cancelled%s", flags_vectors[i].subtest);
    2218                 :         30 :       g_test_add_data_func (test_path, GINT_TO_POINTER (flags_vectors[i].flags),
    2219                 :            :                             test_communicate_utf8_cancelled);
    2220                 :         30 :       g_free (test_path);
    2221                 :            : 
    2222                 :         30 :       test_path = g_strdup_printf ("/gsubprocess/communicate/utf8/async%s", flags_vectors[i].subtest);
    2223                 :         30 :       g_test_add_data_func (test_path, GINT_TO_POINTER (flags_vectors[i].flags),
    2224                 :            :                             test_communicate_utf8_async);
    2225                 :         30 :       g_free (test_path);
    2226                 :            : 
    2227                 :         30 :       test_path = g_strdup_printf ("/gsubprocess/communicate/utf8/async/cancelled%s", flags_vectors[i].subtest);
    2228                 :         30 :       g_test_add_data_func (test_path, GINT_TO_POINTER (flags_vectors[i].flags),
    2229                 :            :                             test_communicate_utf8_cancelled_async);
    2230                 :         30 :       g_free (test_path);
    2231                 :            :     }
    2232                 :            : 
    2233                 :          5 :   g_test_add_func ("/gsubprocess/communicate/utf8/async/invalid", test_communicate_utf8_async_invalid);
    2234                 :          5 :   g_test_add_func ("/gsubprocess/communicate/utf8/invalid", test_communicate_utf8_invalid);
    2235                 :          5 :   g_test_add_func ("/gsubprocess/communicate/nothing", test_communicate_nothing);
    2236                 :          5 :   g_test_add_func ("/gsubprocess/terminate", test_terminate);
    2237                 :          5 :   g_test_add_func ("/gsubprocess/env", test_env);
    2238                 :          5 :   g_test_add_func ("/gsubprocess/env/inherit", test_env_inherit);
    2239                 :          5 :   g_test_add_func ("/gsubprocess/cwd", test_cwd);
    2240                 :            : #ifdef G_OS_UNIX
    2241                 :          5 :   g_test_add_func ("/gsubprocess/launcher-close", test_subprocess_launcher_close);
    2242                 :          5 :   g_test_add_func ("/gsubprocess/stdout-file", test_stdout_file);
    2243                 :          5 :   g_test_add_func ("/gsubprocess/stdout-fd", test_stdout_fd);
    2244                 :          5 :   g_test_add_func ("/gsubprocess/child-setup", test_child_setup);
    2245                 :          5 :   g_test_add_func ("/gsubprocess/pass-fd/basic", test_pass_fd);
    2246                 :          5 :   g_test_add_func ("/gsubprocess/pass-fd/empty-child-setup", test_pass_fd_empty_child_setup);
    2247                 :          5 :   g_test_add_func ("/gsubprocess/pass-fd/inherit-fds", test_pass_fd_inherit_fds);
    2248                 :          5 :   g_test_add_func ("/gsubprocess/fd-conflation/basic", test_fd_conflation);
    2249                 :          5 :   g_test_add_func ("/gsubprocess/fd-conflation/empty-child-setup", test_fd_conflation_empty_child_setup);
    2250                 :          5 :   g_test_add_func ("/gsubprocess/fd-conflation/inherit-fds", test_fd_conflation_inherit_fds);
    2251                 :          5 :   g_test_add_func ("/gsubprocess/fd-conflation/child-err-report-fd", test_fd_conflation_child_err_report_fd);
    2252                 :          5 :   g_test_add_func ("/gsubprocess/exit-status/trapped", test_exit_status_trapped);
    2253                 :            : #endif
    2254                 :          5 :   g_test_add_func ("/gsubprocess/launcher-environment", test_launcher_environment);
    2255                 :            : 
    2256                 :          5 :   return g_test_run ();
    2257                 :            : }

Generated by: LCOV version 1.14