Fix warnings in a the actions test
[platform/upstream/glib.git] / gio / tests / gsubprocess.c
1 #include <gio/gio.h>
2 #include <string.h>
3
4 #ifdef G_OS_UNIX
5 #include <sys/wait.h>
6 #include <glib-unix.h>
7 #include <gio/gunixinputstream.h>
8 #include <gio/gfiledescriptorbased.h>
9 #endif
10
11 #ifdef G_OS_WIN32
12 #define LINEEND "\r\n"
13 #define EXEEXT ".exe"
14 #else
15 #define LINEEND "\n"
16 #define EXEEXT
17 #endif
18
19 static GPtrArray *
20 get_test_subprocess_args (const char *mode,
21                           ...) G_GNUC_NULL_TERMINATED;
22
23 static GPtrArray *
24 get_test_subprocess_args (const char *mode,
25                           ...)
26 {
27   GPtrArray *ret;
28   char *path;
29   const char *binname;
30   va_list args;
31   gpointer arg;
32
33   ret = g_ptr_array_new_with_free_func (g_free);
34
35 #ifdef G_OS_WIN32
36   binname = "gsubprocess-testprog.exe";
37 #else
38   binname = "gsubprocess-testprog";
39 #endif
40
41   path = g_test_build_filename (G_TEST_BUILT, binname, NULL);
42   g_ptr_array_add (ret, path);
43   g_ptr_array_add (ret, g_strdup (mode));
44
45   va_start (args, mode);
46   while ((arg = va_arg (args, gpointer)) != NULL)
47     g_ptr_array_add (ret, g_strdup (arg));
48   va_end (args);
49
50   g_ptr_array_add (ret, NULL);
51   return ret;
52 }
53
54 static void
55 test_noop (void)
56 {
57   GError *local_error = NULL;
58   GError **error = &local_error;
59   GPtrArray *args;
60   GSubprocess *proc;
61
62   args = get_test_subprocess_args ("noop", NULL);
63   proc = g_subprocess_newv ((const gchar * const *) args->pdata, G_SUBPROCESS_FLAGS_NONE, error);
64   g_ptr_array_free (args, TRUE);
65   g_assert_no_error (local_error);
66
67   g_subprocess_wait_check (proc, NULL, error);
68   g_assert_no_error (local_error);
69
70   g_object_unref (proc);
71 }
72
73 static void
74 test_noop_all_to_null (void)
75 {
76   GError *local_error = NULL;
77   GError **error = &local_error;
78   GPtrArray *args;
79   GSubprocess *proc;
80
81   args = get_test_subprocess_args ("noop", NULL);
82   proc = g_subprocess_newv ((const gchar * const *) args->pdata,
83                             G_SUBPROCESS_FLAGS_STDOUT_SILENCE | G_SUBPROCESS_FLAGS_STDERR_SILENCE,
84                             error);
85   g_ptr_array_free (args, TRUE);
86   g_assert_no_error (local_error);
87
88   g_subprocess_wait_check (proc, NULL, error);
89   g_assert_no_error (local_error);
90
91   g_object_unref (proc);
92 }
93
94 static void
95 test_noop_no_wait (void)
96 {
97   GError *local_error = NULL;
98   GError **error = &local_error;
99   GPtrArray *args;
100   GSubprocess *proc;
101
102   args = get_test_subprocess_args ("noop", NULL);
103   proc = g_subprocess_newv ((const gchar * const *) args->pdata, G_SUBPROCESS_FLAGS_NONE, error);
104   g_ptr_array_free (args, TRUE);
105   g_assert_no_error (local_error);
106
107   g_object_unref (proc);
108 }
109
110 static void
111 test_noop_stdin_inherit (void)
112 {
113   GError *local_error = NULL;
114   GError **error = &local_error;
115   GPtrArray *args;
116   GSubprocess *proc;
117
118   args = get_test_subprocess_args ("noop", NULL);
119   proc = g_subprocess_newv ((const gchar * const *) args->pdata, G_SUBPROCESS_FLAGS_STDIN_INHERIT, error);
120   g_ptr_array_free (args, TRUE);
121   g_assert_no_error (local_error);
122
123   g_subprocess_wait_check (proc, NULL, error);
124   g_assert_no_error (local_error);
125
126   g_object_unref (proc);
127 }
128
129 #ifdef G_OS_UNIX
130 static void
131 test_search_path (void)
132 {
133   GError *local_error = NULL;
134   GError **error = &local_error;
135   GSubprocess *proc;
136
137   proc = g_subprocess_new (G_SUBPROCESS_FLAGS_NONE, error, "true", NULL);
138   g_assert_no_error (local_error);
139
140   g_subprocess_wait_check (proc, NULL, error);
141   g_assert_no_error (local_error);
142
143   g_object_unref (proc);
144 }
145 #endif
146
147 static void
148 test_exit1 (void)
149 {
150   GError *local_error = NULL;
151   GError **error = &local_error;
152   GPtrArray *args;
153   GSubprocess *proc;
154
155   args = get_test_subprocess_args ("exit1", NULL);
156   proc = g_subprocess_newv ((const gchar * const *) args->pdata, G_SUBPROCESS_FLAGS_NONE, error);
157   g_ptr_array_free (args, TRUE);
158   g_assert_no_error (local_error);
159
160   g_subprocess_wait_check (proc, NULL, error);
161   g_assert_error (local_error, G_SPAWN_EXIT_ERROR, 1);
162   g_clear_error (error);
163
164   g_object_unref (proc);
165 }
166
167 static gchar *
168 splice_to_string (GInputStream   *stream,
169                   GError        **error)
170 {
171   GMemoryOutputStream *buffer = NULL;
172   char *ret = NULL;
173
174   buffer = (GMemoryOutputStream*)g_memory_output_stream_new (NULL, 0, g_realloc, g_free);
175   if (g_output_stream_splice ((GOutputStream*)buffer, stream, 0, NULL, error) < 0)
176     goto out;
177
178   if (!g_output_stream_write ((GOutputStream*)buffer, "\0", 1, NULL, error))
179     goto out;
180
181   if (!g_output_stream_close ((GOutputStream*)buffer, NULL, error))
182     goto out;
183
184   ret = g_memory_output_stream_steal_data (buffer);
185  out:
186   g_clear_object (&buffer);
187   return ret;
188 }
189
190 static void
191 test_echo1 (void)
192 {
193   GError *local_error = NULL;
194   GError **error = &local_error;
195   GSubprocess *proc;
196   GPtrArray *args;
197   GInputStream *stdout;
198   gchar *result;
199
200   args = get_test_subprocess_args ("echo", "hello", "world!", NULL);
201   proc = g_subprocess_newv ((const gchar * const *) args->pdata, G_SUBPROCESS_FLAGS_STDOUT_PIPE, error);
202   g_ptr_array_free (args, TRUE);
203   g_assert_no_error (local_error);
204
205   stdout = g_subprocess_get_stdout_pipe (proc);
206
207   result = splice_to_string (stdout, error);
208   g_assert_no_error (local_error);
209
210   g_assert_cmpstr (result, ==, "hello" LINEEND "world!" LINEEND);
211
212   g_free (result);
213   g_object_unref (proc);
214 }
215
216 #ifdef G_OS_UNIX
217 static void
218 test_echo_merged (void)
219 {
220   GError *local_error = NULL;
221   GError **error = &local_error;
222   GSubprocess *proc;
223   GPtrArray *args;
224   GInputStream *stdout;
225   gchar *result;
226
227   args = get_test_subprocess_args ("echo-stdout-and-stderr", "merge", "this", NULL);
228   proc = g_subprocess_newv ((const gchar * const *) args->pdata,
229                             G_SUBPROCESS_FLAGS_STDOUT_PIPE | G_SUBPROCESS_FLAGS_STDERR_MERGE,
230                             error);
231   g_ptr_array_free (args, TRUE);
232   g_assert_no_error (local_error);
233
234   stdout = g_subprocess_get_stdout_pipe (proc);
235   result = splice_to_string (stdout, error);
236   g_assert_no_error (local_error);
237
238   g_assert_cmpstr (result, ==, "merge\nmerge\nthis\nthis\n");
239
240   g_free (result);
241   g_object_unref (proc);
242 }
243 #endif
244
245 typedef struct {
246   guint events_pending;
247   GMainLoop *loop;
248 } TestCatData;
249
250 static void
251 test_cat_on_input_splice_complete (GObject      *object,
252                                    GAsyncResult *result,
253                                    gpointer      user_data)
254 {
255   TestCatData *data = user_data;
256   GError *error = NULL;
257
258   (void)g_output_stream_splice_finish ((GOutputStream*)object, result, &error);
259   g_assert_no_error (error);
260
261   data->events_pending--;
262   if (data->events_pending == 0)
263     g_main_loop_quit (data->loop);
264 }
265
266 static void
267 test_cat_utf8 (void)
268 {
269   GError *local_error = NULL;
270   GError **error = &local_error;
271   GSubprocess *proc;
272   GPtrArray *args;
273   GBytes *input_buf;
274   GBytes *output_buf;
275   GInputStream *input_buf_stream = NULL;
276   GOutputStream *output_buf_stream = NULL;
277   GOutputStream *stdin_stream = NULL;
278   GInputStream *stdout_stream = NULL;
279   TestCatData data;
280
281   memset (&data, 0, sizeof (data));
282   data.loop = g_main_loop_new (NULL, TRUE);
283
284   args = get_test_subprocess_args ("cat", NULL);
285   proc = g_subprocess_newv ((const gchar * const *) args->pdata,
286                             G_SUBPROCESS_FLAGS_STDIN_PIPE | G_SUBPROCESS_FLAGS_STDOUT_PIPE,
287                             error);
288   g_ptr_array_free (args, TRUE);
289   g_assert_no_error (local_error);
290
291   stdin_stream = g_subprocess_get_stdin_pipe (proc);
292   stdout_stream = g_subprocess_get_stdout_pipe (proc);
293
294   input_buf = g_bytes_new_static ("hello, world!", strlen ("hello, world!"));
295   input_buf_stream = g_memory_input_stream_new_from_bytes (input_buf);
296   g_bytes_unref (input_buf);
297
298   output_buf_stream = g_memory_output_stream_new (NULL, 0, g_realloc, g_free);
299
300   g_output_stream_splice_async (stdin_stream, input_buf_stream, G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE | G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET,
301                                 G_PRIORITY_DEFAULT, NULL, test_cat_on_input_splice_complete,
302                                 &data);
303   data.events_pending++;
304   g_output_stream_splice_async (output_buf_stream, stdout_stream, G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE | G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET,
305                                 G_PRIORITY_DEFAULT, NULL, test_cat_on_input_splice_complete,
306                                 &data);
307   data.events_pending++;
308
309   g_main_loop_run (data.loop);
310
311   g_subprocess_wait_check (proc, NULL, error);
312   g_assert_no_error (local_error);
313
314   output_buf = g_memory_output_stream_steal_as_bytes ((GMemoryOutputStream*)output_buf_stream);
315
316   g_assert_cmpint (g_bytes_get_size (output_buf), ==, 13);
317   g_assert_cmpint (memcmp (g_bytes_get_data (output_buf, NULL), "hello, world!", 13), ==, 0);
318
319   g_bytes_unref (output_buf);
320   g_main_loop_unref (data.loop);
321   g_object_unref (input_buf_stream);
322   g_object_unref (output_buf_stream);
323   g_object_unref (proc);
324 }
325
326 static gpointer
327 cancel_soon (gpointer user_data)
328 {
329   GCancellable *cancellable = user_data;
330
331   g_usleep (G_TIME_SPAN_SECOND);
332   g_cancellable_cancel (cancellable);
333   g_object_unref (cancellable);
334
335   return NULL;
336 }
337
338 static void
339 test_cat_eof (void)
340 {
341   GCancellable *cancellable;
342   GError *error = NULL;
343   GSubprocess *cat;
344   gboolean result;
345   gchar buffer;
346   gssize s;
347
348 #ifdef G_OS_WIN32
349   g_test_skip ("This test has not been ported to Win32");
350   return;
351 #endif
352
353   /* Spawn 'cat' */
354   cat = g_subprocess_new (G_SUBPROCESS_FLAGS_STDIN_PIPE | G_SUBPROCESS_FLAGS_STDOUT_PIPE, &error, "cat", NULL);
355   g_assert_no_error (error);
356   g_assert (cat);
357
358   /* Make sure that reading stdout blocks (until we cancel) */
359   cancellable = g_cancellable_new ();
360   g_thread_unref (g_thread_new ("cancel thread", cancel_soon, g_object_ref (cancellable)));
361   s = g_input_stream_read (g_subprocess_get_stdout_pipe (cat), &buffer, sizeof buffer, cancellable, &error);
362   g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
363   g_assert_cmpint (s, ==, -1);
364   g_object_unref (cancellable);
365   g_clear_error (&error);
366
367   /* Close the stream (EOF on cat's stdin) */
368   result = g_output_stream_close (g_subprocess_get_stdin_pipe (cat), NULL, &error);
369   g_assert_no_error (error);
370   g_assert (result);
371
372   /* Now check that reading cat's stdout gets us an EOF (since it quit) */
373   s = g_input_stream_read (g_subprocess_get_stdout_pipe (cat), &buffer, sizeof buffer, NULL, &error);
374   g_assert_no_error (error);
375   g_assert (!s);
376
377   /* Check that the process has exited as a result of the EOF */
378   result = g_subprocess_wait (cat, NULL, &error);
379   g_assert_no_error (error);
380   g_assert (g_subprocess_get_if_exited (cat));
381   g_assert_cmpint (g_subprocess_get_exit_status (cat), ==, 0);
382   g_assert (result);
383
384   g_object_unref (cat);
385 }
386
387 typedef struct {
388   guint events_pending;
389   gboolean caught_error;
390   GError *error;
391   GMainLoop *loop;
392
393   gint counter;
394   GOutputStream *first_stdin;
395 } TestMultiSpliceData;
396
397 static void
398 on_one_multi_splice_done (GObject       *obj,
399                           GAsyncResult  *res,
400                           gpointer       user_data)
401 {
402   TestMultiSpliceData *data = user_data;
403
404   if (!data->caught_error)
405     {
406       if (g_output_stream_splice_finish ((GOutputStream*)obj, res, &data->error) < 0)
407         data->caught_error = TRUE;
408     }
409
410   data->events_pending--;
411   if (data->events_pending == 0)
412     g_main_loop_quit (data->loop);
413 }
414
415 static gboolean
416 on_idle_multisplice (gpointer     user_data)
417 {
418   TestMultiSpliceData *data = user_data;
419
420   /* We write 2^1 + 2^2 ... + 2^10 or 2047 copies of "Hello World!\n"
421    * ultimately
422    */
423   if (data->counter >= 2047 || data->caught_error)
424     {
425       if (!g_output_stream_close (data->first_stdin, NULL, &data->error))
426         data->caught_error = TRUE;
427       data->events_pending--;
428       if (data->events_pending == 0)
429         {
430           g_main_loop_quit (data->loop);
431         }
432       return FALSE;
433     }
434   else
435     {
436       int i;
437       for (i = 0; i < data->counter; i++)
438         {
439           gsize bytes_written;
440           if (!g_output_stream_write_all (data->first_stdin, "hello world!\n",
441                                           strlen ("hello world!\n"), &bytes_written,
442                                           NULL, &data->error))
443             {
444               data->caught_error = TRUE;
445               return FALSE;
446             }
447         }
448       data->counter *= 2;
449       return TRUE;
450     }
451 }
452
453 static void
454 on_subprocess_exited (GObject         *object,
455                       GAsyncResult    *result,
456                       gpointer         user_data)
457 {
458   GSubprocess *subprocess = G_SUBPROCESS (object);
459   TestMultiSpliceData *data = user_data;
460   GError *error = NULL;
461
462   if (!g_subprocess_wait_finish (subprocess, result, &error))
463     {
464       if (!data->caught_error)
465         {
466           data->caught_error = TRUE;
467           g_propagate_error (&data->error, error);
468         }
469     }
470   g_spawn_check_exit_status (g_subprocess_get_exit_status (subprocess), &error);
471   g_assert_no_error (error);
472   data->events_pending--;
473   if (data->events_pending == 0)
474     g_main_loop_quit (data->loop);
475 }
476
477 static void
478 test_multi_1 (void)
479 {
480   GError *local_error = NULL;
481   GError **error = &local_error;
482   GPtrArray *args;
483   GSubprocessLauncher *launcher;
484   GSubprocess *first;
485   GSubprocess *second;
486   GSubprocess *third;
487   GOutputStream *first_stdin;
488   GInputStream *first_stdout;
489   GOutputStream *second_stdin;
490   GInputStream *second_stdout;
491   GOutputStream *third_stdin;
492   GInputStream *third_stdout;
493   GOutputStream *membuf;
494   TestMultiSpliceData data;
495   int splice_flags = G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE | G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET;
496
497   args = get_test_subprocess_args ("cat", NULL);
498   launcher = g_subprocess_launcher_new (G_SUBPROCESS_FLAGS_STDIN_PIPE | G_SUBPROCESS_FLAGS_STDOUT_PIPE);
499   first = g_subprocess_launcher_spawnv (launcher, (const gchar * const *) args->pdata, error);
500   g_assert_no_error (local_error);
501   second = g_subprocess_launcher_spawnv (launcher, (const gchar * const *) args->pdata, error);
502   g_assert_no_error (local_error);
503   third = g_subprocess_launcher_spawnv (launcher, (const gchar * const *) args->pdata, error);
504   g_assert_no_error (local_error);
505
506   g_ptr_array_free (args, TRUE);
507
508   membuf = g_memory_output_stream_new (NULL, 0, g_realloc, g_free);
509
510   first_stdin = g_subprocess_get_stdin_pipe (first);
511   first_stdout = g_subprocess_get_stdout_pipe (first);
512   second_stdin = g_subprocess_get_stdin_pipe (second);
513   second_stdout = g_subprocess_get_stdout_pipe (second);
514   third_stdin = g_subprocess_get_stdin_pipe (third);
515   third_stdout = g_subprocess_get_stdout_pipe (third);
516
517   memset (&data, 0, sizeof (data));
518   data.loop = g_main_loop_new (NULL, TRUE);
519   data.counter = 1;
520   data.first_stdin = first_stdin;
521
522   data.events_pending++;
523   g_output_stream_splice_async (second_stdin, first_stdout, splice_flags, G_PRIORITY_DEFAULT,
524                                 NULL, on_one_multi_splice_done, &data);
525   data.events_pending++;
526   g_output_stream_splice_async (third_stdin, second_stdout, splice_flags, G_PRIORITY_DEFAULT,
527                                 NULL, on_one_multi_splice_done, &data);
528   data.events_pending++;
529   g_output_stream_splice_async (membuf, third_stdout, splice_flags, G_PRIORITY_DEFAULT,
530                                 NULL, on_one_multi_splice_done, &data);
531
532   data.events_pending++;
533   g_timeout_add (250, on_idle_multisplice, &data);
534
535   data.events_pending++;
536   g_subprocess_wait_async (first, NULL, on_subprocess_exited, &data);
537   data.events_pending++;
538   g_subprocess_wait_async (second, NULL, on_subprocess_exited, &data);
539   data.events_pending++;
540   g_subprocess_wait_async (third, NULL, on_subprocess_exited, &data);
541
542   g_main_loop_run (data.loop);
543
544   g_assert (!data.caught_error);
545   g_assert_no_error (data.error);
546
547   g_assert_cmpint (g_memory_output_stream_get_data_size ((GMemoryOutputStream*)membuf), ==, 26611);
548
549   g_main_loop_unref (data.loop);
550   g_object_unref (membuf);
551   g_object_unref (launcher);
552   g_object_unref (first);
553   g_object_unref (second);
554   g_object_unref (third);
555 }
556
557 typedef struct {
558   gboolean is_utf8;
559   gboolean running;
560   GError *error;
561 } TestAsyncCommunicateData;
562
563 static void
564 on_communicate_complete (GObject               *proc,
565                          GAsyncResult          *result,
566                          gpointer               user_data)
567 {
568   TestAsyncCommunicateData *data = user_data;
569   GBytes *stdout = NULL;
570   char *stdout_str = NULL;
571   const guint8 *stdout_data;
572   gsize stdout_len;
573
574   data->running = FALSE;
575   if (data->is_utf8)
576     (void) g_subprocess_communicate_utf8_finish ((GSubprocess*)proc, result,
577                                                  &stdout_str, NULL, &data->error);
578   else
579     (void) g_subprocess_communicate_finish ((GSubprocess*)proc, result,
580                                             &stdout, NULL, &data->error);
581   if (data->error)
582       return;
583
584   if (!data->is_utf8)
585     {
586       stdout_data = g_bytes_get_data (stdout, &stdout_len);
587     }
588   else
589     {
590       stdout_data = (guint8*)stdout_str;
591       stdout_len = strlen (stdout_str);
592     }
593
594   g_assert_cmpint (stdout_len, ==, 11);
595   g_assert (memcmp (stdout_data, "hello world", 11) == 0);
596   if (stdout)
597     g_bytes_unref (stdout);
598   g_free (stdout_str);
599 }
600
601 static void
602 test_communicate (void)
603 {
604   GError *error = NULL;
605   GPtrArray *args;
606   TestAsyncCommunicateData data = { 0, };
607   GSubprocess *proc;
608   GCancellable *cancellable = NULL;
609   GBytes *input;
610   const char *hellostring;
611
612   args = get_test_subprocess_args ("cat", NULL);
613   proc = g_subprocess_newv ((const gchar* const*)args->pdata,
614                             G_SUBPROCESS_FLAGS_STDIN_PIPE | G_SUBPROCESS_FLAGS_STDOUT_PIPE,
615                             &error);
616   g_assert_no_error (error);
617   g_ptr_array_free (args, TRUE);
618
619   hellostring = "hello world";
620   input = g_bytes_new_static (hellostring, strlen (hellostring));
621
622   g_subprocess_communicate_async (proc, input,
623                                   cancellable,
624                                   on_communicate_complete, 
625                                   &data);
626   
627   data.running = TRUE;
628   while (data.running)
629     g_main_context_iteration (NULL, TRUE);
630
631   g_assert_no_error (data.error);
632
633   g_bytes_unref (input);
634   g_object_unref (proc);
635 }
636
637 static void
638 test_communicate_utf8 (void)
639 {
640   GError *error = NULL;
641   GPtrArray *args;
642   TestAsyncCommunicateData data = { 0, };
643   GSubprocess *proc;
644   GCancellable *cancellable = NULL;
645
646   args = get_test_subprocess_args ("cat", NULL);
647   proc = g_subprocess_newv ((const gchar* const*)args->pdata,
648                             G_SUBPROCESS_FLAGS_STDIN_PIPE | G_SUBPROCESS_FLAGS_STDOUT_PIPE,
649                             &error);
650   g_assert_no_error (error);
651   g_ptr_array_free (args, TRUE);
652
653   data.is_utf8 = TRUE;
654   g_subprocess_communicate_utf8_async (proc, "hello world",
655                                        cancellable,
656                                        on_communicate_complete, 
657                                        &data);
658   
659   data.running = TRUE;
660   while (data.running)
661     g_main_context_iteration (NULL, TRUE);
662
663   g_assert_no_error (data.error);
664
665   g_object_unref (proc);
666 }
667
668 static void
669 test_communicate_utf8_invalid (void)
670 {
671   GError *error = NULL;
672   GPtrArray *args;
673   TestAsyncCommunicateData data = { 0, };
674   GSubprocess *proc;
675   GCancellable *cancellable = NULL;
676
677   args = get_test_subprocess_args ("cat", NULL);
678   proc = g_subprocess_newv ((const gchar* const*)args->pdata,
679                             G_SUBPROCESS_FLAGS_STDIN_PIPE | G_SUBPROCESS_FLAGS_STDOUT_PIPE,
680                             &error);
681   g_assert_no_error (error);
682   g_ptr_array_free (args, TRUE);
683
684   data.is_utf8 = TRUE;
685   g_subprocess_communicate_utf8_async (proc, "\xFF\xFF",
686                                        cancellable,
687                                        on_communicate_complete, 
688                                        &data);
689   
690   data.running = TRUE;
691   while (data.running)
692     g_main_context_iteration (NULL, TRUE);
693
694   g_assert_error (data.error, G_IO_ERROR, G_IO_ERROR_FAILED);
695   g_error_free (data.error);
696
697   g_object_unref (proc);
698 }
699
700 static gboolean
701 send_terminate (gpointer   user_data)
702 {
703   GSubprocess *proc = user_data;
704
705   g_subprocess_force_exit (proc);
706
707   return FALSE;
708 }
709
710 static void
711 on_request_quit_exited (GObject        *object,
712                         GAsyncResult   *result,
713                         gpointer        user_data)
714 {
715   GSubprocess *subprocess = G_SUBPROCESS (object);
716   GError *error = NULL;
717
718   g_subprocess_wait_finish (subprocess, result, &error);
719   g_assert_no_error (error);
720 #ifdef G_OS_UNIX
721   g_assert (g_subprocess_get_if_signaled (subprocess));
722   g_assert (g_subprocess_get_term_sig (subprocess) == 9);
723 #endif
724   g_spawn_check_exit_status (g_subprocess_get_status (subprocess), &error);
725   g_assert (error != NULL);
726   g_clear_error (&error);
727
728   g_main_loop_quit ((GMainLoop*)user_data);
729 }
730
731 static void
732 test_terminate (void)
733 {
734   GError *local_error = NULL;
735   GError **error = &local_error;
736   GSubprocess *proc;
737   GPtrArray *args;
738   GMainLoop *loop;
739
740   args = get_test_subprocess_args ("sleep-forever", NULL);
741   proc = g_subprocess_newv ((const gchar * const *) args->pdata, G_SUBPROCESS_FLAGS_NONE, error);
742   g_ptr_array_free (args, TRUE);
743   g_assert_no_error (local_error);
744
745   loop = g_main_loop_new (NULL, TRUE);
746
747   g_subprocess_wait_async (proc, NULL, on_request_quit_exited, loop);
748
749   g_timeout_add_seconds (3, send_terminate, proc);
750
751   g_main_loop_run (loop);
752
753   g_main_loop_unref (loop);
754   g_object_unref (proc);
755 }
756
757 #ifdef G_OS_UNIX
758 static void
759 test_stdout_file (void)
760 {
761   GError *local_error = NULL;
762   GError **error = &local_error;
763   GSubprocessLauncher *launcher;
764   GSubprocess *proc;
765   GPtrArray *args;
766   GFile *tmpfile;
767   GFileIOStream *iostream;
768   GOutputStream *stdin;
769   const char *test_data = "this is some test data\n";
770   char *tmp_contents;
771   char *tmp_file_path;
772
773   tmpfile = g_file_new_tmp ("gsubprocessXXXXXX", &iostream, error);
774   g_assert_no_error (local_error);
775   g_clear_object (&iostream);
776
777   tmp_file_path = g_file_get_path (tmpfile);
778
779   args = get_test_subprocess_args ("cat", NULL);
780   launcher = g_subprocess_launcher_new (G_SUBPROCESS_FLAGS_STDIN_PIPE);
781   g_subprocess_launcher_set_stdout_file_path (launcher, tmp_file_path);
782   proc = g_subprocess_launcher_spawnv (launcher, (const gchar * const *) args->pdata, error);
783   g_ptr_array_free (args, TRUE);
784   g_assert_no_error (local_error);
785
786   stdin = g_subprocess_get_stdin_pipe (proc);
787
788   g_output_stream_write_all (stdin, test_data, strlen (test_data), NULL, NULL, error);
789   g_assert_no_error (local_error);
790
791   g_output_stream_close (stdin, NULL, error);
792   g_assert_no_error (local_error);
793
794   g_subprocess_wait_check (proc, NULL, error);
795
796   g_object_unref (launcher);
797   g_object_unref (proc);
798
799   g_file_load_contents (tmpfile, NULL, &tmp_contents, NULL, NULL, error);
800   g_assert_no_error (local_error);
801
802   g_assert_cmpstr (test_data, ==, tmp_contents);
803   g_free (tmp_contents);
804
805   (void) g_file_delete (tmpfile, NULL, NULL);
806   g_object_unref (tmpfile);
807   g_free (tmp_file_path);
808 }
809
810 static void
811 test_stdout_fd (void)
812 {
813   GError *local_error = NULL;
814   GError **error = &local_error;
815   GSubprocessLauncher *launcher;
816   GSubprocess *proc;
817   GPtrArray *args;
818   GFile *tmpfile;
819   GFileIOStream *iostream;
820   GFileDescriptorBased *descriptor_stream;
821   GOutputStream *stdin;
822   const char *test_data = "this is some test data\n";
823   char *tmp_contents;
824
825   tmpfile = g_file_new_tmp ("gsubprocessXXXXXX", &iostream, error);
826   g_assert_no_error (local_error);
827
828   args = get_test_subprocess_args ("cat", NULL);
829   launcher = g_subprocess_launcher_new (G_SUBPROCESS_FLAGS_STDIN_PIPE);
830   descriptor_stream = G_FILE_DESCRIPTOR_BASED (g_io_stream_get_output_stream (G_IO_STREAM (iostream)));
831   g_subprocess_launcher_take_stdout_fd (launcher, dup (g_file_descriptor_based_get_fd (descriptor_stream)));
832   proc = g_subprocess_launcher_spawnv (launcher, (const gchar * const *) args->pdata, error);
833   g_ptr_array_free (args, TRUE);
834   g_assert_no_error (local_error);
835
836   g_clear_object (&iostream);
837
838   stdin = g_subprocess_get_stdin_pipe (proc);
839
840   g_output_stream_write_all (stdin, test_data, strlen (test_data), NULL, NULL, error);
841   g_assert_no_error (local_error);
842
843   g_output_stream_close (stdin, NULL, error);
844   g_assert_no_error (local_error);
845
846   g_subprocess_wait_check (proc, NULL, error);
847
848   g_object_unref (launcher);
849   g_object_unref (proc);
850
851   g_file_load_contents (tmpfile, NULL, &tmp_contents, NULL, NULL, error);
852   g_assert_no_error (local_error);
853
854   g_assert_cmpstr (test_data, ==, tmp_contents);
855   g_free (tmp_contents);
856
857   (void) g_file_delete (tmpfile, NULL, NULL);
858   g_object_unref (tmpfile);
859 }
860
861 static void
862 child_setup (gpointer user_data)
863 {
864   dup2 (GPOINTER_TO_INT (user_data), 1);
865 }
866
867 static void
868 test_child_setup (void)
869 {
870   GError *local_error = NULL;
871   GError **error = &local_error;
872   GSubprocessLauncher *launcher;
873   GSubprocess *proc;
874   GPtrArray *args;
875   GFile *tmpfile;
876   GFileIOStream *iostream;
877   GOutputStream *stdin;
878   const char *test_data = "this is some test data\n";
879   char *tmp_contents;
880   int fd;
881
882   tmpfile = g_file_new_tmp ("gsubprocessXXXXXX", &iostream, error);
883   g_assert_no_error (local_error);
884
885   fd = g_file_descriptor_based_get_fd (G_FILE_DESCRIPTOR_BASED (g_io_stream_get_output_stream (G_IO_STREAM (iostream))));
886
887   args = get_test_subprocess_args ("cat", NULL);
888   launcher = g_subprocess_launcher_new (G_SUBPROCESS_FLAGS_STDIN_PIPE);
889   g_subprocess_launcher_set_child_setup (launcher, child_setup, GINT_TO_POINTER (fd), NULL);
890   proc = g_subprocess_launcher_spawnv (launcher, (const gchar * const *) args->pdata, error);
891   g_ptr_array_free (args, TRUE);
892   g_assert_no_error (local_error);
893
894   g_clear_object (&iostream);
895
896   stdin = g_subprocess_get_stdin_pipe (proc);
897
898   g_output_stream_write_all (stdin, test_data, strlen (test_data), NULL, NULL, error);
899   g_assert_no_error (local_error);
900
901   g_output_stream_close (stdin, NULL, error);
902   g_assert_no_error (local_error);
903
904   g_subprocess_wait_check (proc, NULL, error);
905
906   g_object_unref (launcher);
907   g_object_unref (proc);
908
909   g_file_load_contents (tmpfile, NULL, &tmp_contents, NULL, NULL, error);
910   g_assert_no_error (local_error);
911
912   g_assert_cmpstr (test_data, ==, tmp_contents);
913   g_free (tmp_contents);
914
915   (void) g_file_delete (tmpfile, NULL, NULL);
916   g_object_unref (tmpfile);
917 }
918
919 static void
920 test_pass_fd (void)
921 {
922   GError *local_error = NULL;
923   GError **error = &local_error;
924   GInputStream *child_input;
925   GDataInputStream *child_datainput;
926   GSubprocessLauncher *launcher;
927   GSubprocess *proc;
928   GPtrArray *args;
929   int basic_pipefds[2];
930   int needdup_pipefds[2];
931   char *buf;
932   gsize len;
933   char *basic_fd_str;
934   char *needdup_fd_str;
935
936   g_unix_open_pipe (basic_pipefds, FD_CLOEXEC, error);
937   g_assert_no_error (local_error);
938   g_unix_open_pipe (needdup_pipefds, FD_CLOEXEC, error);
939   g_assert_no_error (local_error);
940
941   basic_fd_str = g_strdup_printf ("%d", basic_pipefds[1]);
942   needdup_fd_str = g_strdup_printf ("%d", needdup_pipefds[1] + 1);
943
944   args = get_test_subprocess_args ("write-to-fds", basic_fd_str, needdup_fd_str, NULL);
945   launcher = g_subprocess_launcher_new (G_SUBPROCESS_FLAGS_NONE);
946   g_subprocess_launcher_take_fd (launcher, basic_pipefds[1], basic_pipefds[1]);
947   g_subprocess_launcher_take_fd (launcher, needdup_pipefds[1], needdup_pipefds[1] + 1);
948   proc = g_subprocess_launcher_spawnv (launcher, (const gchar * const *) args->pdata, error);
949   g_ptr_array_free (args, TRUE);
950   g_assert_no_error (local_error);
951
952   g_free (basic_fd_str);
953   g_free (needdup_fd_str);
954
955   child_input = g_unix_input_stream_new (basic_pipefds[0], TRUE);
956   child_datainput = g_data_input_stream_new (child_input);
957   buf = g_data_input_stream_read_line_utf8 (child_datainput, &len, NULL, error);
958   g_assert_no_error (local_error);
959   g_assert_cmpstr (buf, ==, "hello world");
960   g_object_unref (child_datainput);
961   g_object_unref (child_input);
962   g_free (buf);
963
964   child_input = g_unix_input_stream_new (needdup_pipefds[0], TRUE);
965   child_datainput = g_data_input_stream_new (child_input);
966   buf = g_data_input_stream_read_line_utf8 (child_datainput, &len, NULL, error);
967   g_assert_no_error (local_error);
968   g_assert_cmpstr (buf, ==, "hello world");
969   g_free (buf);
970   g_object_unref (child_datainput);
971   g_object_unref (child_input);
972
973   g_object_unref (launcher);
974   g_object_unref (proc);
975 }
976
977 #endif
978
979 int
980 main (int argc, char **argv)
981 {
982   g_test_init (&argc, &argv, NULL);
983
984   g_test_add_func ("/gsubprocess/noop", test_noop);
985   g_test_add_func ("/gsubprocess/noop-all-to-null", test_noop_all_to_null);
986   g_test_add_func ("/gsubprocess/noop-no-wait", test_noop_no_wait);
987   g_test_add_func ("/gsubprocess/noop-stdin-inherit", test_noop_stdin_inherit);
988 #ifdef G_OS_UNIX
989   g_test_add_func ("/gsubprocess/search-path", test_search_path);
990 #endif
991   g_test_add_func ("/gsubprocess/exit1", test_exit1);
992   g_test_add_func ("/gsubprocess/echo1", test_echo1);
993 #ifdef G_OS_UNIX
994   g_test_add_func ("/gsubprocess/echo-merged", test_echo_merged);
995 #endif
996   g_test_add_func ("/gsubprocess/cat-utf8", test_cat_utf8);
997   g_test_add_func ("/gsubprocess/cat-eof", test_cat_eof);
998   g_test_add_func ("/gsubprocess/multi1", test_multi_1);
999   g_test_add_func ("/gsubprocess/communicate", test_communicate);
1000   g_test_add_func ("/gsubprocess/communicate-utf8", test_communicate_utf8);
1001   g_test_add_func ("/gsubprocess/communicate-utf8-invalid", test_communicate_utf8_invalid);
1002   g_test_add_func ("/gsubprocess/terminate", test_terminate);
1003 #ifdef G_OS_UNIX
1004   g_test_add_func ("/gsubprocess/stdout-file", test_stdout_file);
1005   g_test_add_func ("/gsubprocess/stdout-fd", test_stdout_fd);
1006   g_test_add_func ("/gsubprocess/child-setup", test_child_setup);
1007   g_test_add_func ("/gsubprocess/pass-fd", test_pass_fd);
1008 #endif
1009
1010   return g_test_run ();
1011 }