LCOV - code coverage report
Current view: top level - gio/tests - gsubprocess.c (source / functions) Coverage Total Hit
Test: unnamed Lines: 98.5 % 1143 1126
Test Date: 2024-11-26 05:23:01 Functions: 100.0 % 66 66
Branches: - 0 0

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

Generated by: LCOV version 2.0-1