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#include <unistd.h>
10#include <fcntl.h>
11#endif
12
13/* We write 2^1 + 2^2 ... + 2^10 or 2047 copies of "Hello World!\n"
14 * ultimately
15 */
16#define TOTAL_HELLOS 2047
17#define HELLO_WORLD "hello world!\n"
18
19#ifdef G_OS_WIN32
20#define LINEEND "\r\n"
21#define EXEEXT ".exe"
22#define SPLICELEN (TOTAL_HELLOS * (strlen (HELLO_WORLD) + 1)) /* because \r */
23#else
24#define LINEEND "\n"
25#define EXEEXT
26#define SPLICELEN (TOTAL_HELLOS * strlen (HELLO_WORLD))
27#endif
28
29static GPtrArray *
30get_test_subprocess_args (const char *mode,
31 ...) G_GNUC_NULL_TERMINATED;
32
33static GPtrArray *
34get_test_subprocess_args (const char *mode,
35 ...)
36{
37 GPtrArray *ret;
38 char *path;
39 const char *binname;
40 va_list args;
41 gpointer arg;
42
43 ret = g_ptr_array_new_with_free_func (element_free_func: g_free);
44
45#ifdef G_OS_WIN32
46 binname = "gsubprocess-testprog.exe";
47#else
48 binname = "gsubprocess-testprog";
49#endif
50
51 path = g_test_build_filename (file_type: G_TEST_BUILT, first_path: binname, NULL);
52 g_ptr_array_add (array: ret, data: path);
53 g_ptr_array_add (array: ret, data: g_strdup (str: mode));
54
55 va_start (args, mode);
56 while ((arg = va_arg (args, gpointer)) != NULL)
57 g_ptr_array_add (array: ret, data: g_strdup (str: arg));
58 va_end (args);
59
60 g_ptr_array_add (array: ret, NULL);
61 return ret;
62}
63
64static void
65test_noop (void)
66{
67 GError *local_error = NULL;
68 GError **error = &local_error;
69 GPtrArray *args;
70 GSubprocess *proc;
71
72 args = get_test_subprocess_args (mode: "noop", NULL);
73 proc = g_subprocess_newv (argv: (const gchar * const *) args->pdata, flags: G_SUBPROCESS_FLAGS_NONE, error);
74 g_ptr_array_free (array: args, TRUE);
75 g_assert_no_error (local_error);
76
77 g_subprocess_wait_check (subprocess: proc, NULL, error);
78 g_assert_no_error (local_error);
79 g_assert_true (g_subprocess_get_successful (proc));
80
81 g_object_unref (object: proc);
82}
83
84static void
85check_ready (GObject *source,
86 GAsyncResult *res,
87 gpointer user_data)
88{
89 gboolean ret;
90 GError *error = NULL;
91
92 ret = g_subprocess_wait_check_finish (G_SUBPROCESS (source),
93 result: res,
94 error: &error);
95 g_assert_true (ret);
96 g_assert_no_error (error);
97
98 g_object_unref (object: source);
99}
100
101static void
102test_noop_all_to_null (void)
103{
104 GError *local_error = NULL;
105 GError **error = &local_error;
106 GPtrArray *args;
107 GSubprocess *proc;
108
109 args = get_test_subprocess_args (mode: "noop", NULL);
110 proc = g_subprocess_newv (argv: (const gchar * const *) args->pdata,
111 flags: G_SUBPROCESS_FLAGS_STDOUT_SILENCE | G_SUBPROCESS_FLAGS_STDERR_SILENCE,
112 error);
113 g_ptr_array_free (array: args, TRUE);
114 g_assert_no_error (local_error);
115
116 g_subprocess_wait_check_async (subprocess: proc, NULL, callback: check_ready, NULL);
117}
118
119static void
120test_noop_no_wait (void)
121{
122 GError *local_error = NULL;
123 GError **error = &local_error;
124 GPtrArray *args;
125 GSubprocess *proc;
126
127 args = get_test_subprocess_args (mode: "noop", NULL);
128 proc = g_subprocess_newv (argv: (const gchar * const *) args->pdata, flags: G_SUBPROCESS_FLAGS_NONE, error);
129 g_ptr_array_free (array: args, TRUE);
130 g_assert_no_error (local_error);
131
132 g_object_unref (object: proc);
133}
134
135static void
136test_noop_stdin_inherit (void)
137{
138 GError *local_error = NULL;
139 GError **error = &local_error;
140 GPtrArray *args;
141 GSubprocess *proc;
142
143 args = get_test_subprocess_args (mode: "noop", NULL);
144 proc = g_subprocess_newv (argv: (const gchar * const *) args->pdata, flags: G_SUBPROCESS_FLAGS_STDIN_INHERIT, error);
145 g_ptr_array_free (array: args, TRUE);
146 g_assert_no_error (local_error);
147
148 g_subprocess_wait_check (subprocess: proc, NULL, error);
149 g_assert_no_error (local_error);
150
151 g_object_unref (object: proc);
152}
153
154#ifdef G_OS_UNIX
155static void
156test_search_path (void)
157{
158 GError *local_error = NULL;
159 GError **error = &local_error;
160 GSubprocess *proc;
161
162 proc = g_subprocess_new (flags: G_SUBPROCESS_FLAGS_NONE, error, argv0: "true", NULL);
163 g_assert_no_error (local_error);
164
165 g_subprocess_wait_check (subprocess: proc, NULL, error);
166 g_assert_no_error (local_error);
167
168 g_object_unref (object: proc);
169}
170#endif
171
172static void
173test_exit1 (void)
174{
175 GError *local_error = NULL;
176 GError **error = &local_error;
177 GPtrArray *args;
178 GSubprocess *proc;
179
180 args = get_test_subprocess_args (mode: "exit1", NULL);
181 proc = g_subprocess_newv (argv: (const gchar * const *) args->pdata, flags: G_SUBPROCESS_FLAGS_NONE, error);
182 g_ptr_array_free (array: args, TRUE);
183 g_assert_no_error (local_error);
184
185 g_subprocess_wait_check (subprocess: proc, NULL, error);
186 g_assert_error (local_error, G_SPAWN_EXIT_ERROR, 1);
187 g_clear_error (err: error);
188
189 g_object_unref (object: proc);
190}
191
192typedef struct {
193 GMainLoop *loop;
194 GCancellable *cancellable;
195 gboolean cb_called;
196} TestExit1CancelData;
197
198static gboolean
199test_exit1_cancel_idle_quit_cb (gpointer user_data)
200{
201 GMainLoop *loop = user_data;
202 g_main_loop_quit (loop);
203 return G_SOURCE_REMOVE;
204}
205
206static void
207test_exit1_cancel_wait_check_cb (GObject *source,
208 GAsyncResult *result,
209 gpointer user_data)
210{
211 GSubprocess *subprocess = G_SUBPROCESS (source);
212 TestExit1CancelData *data = user_data;
213 gboolean ret;
214 GError *error = NULL;
215
216 g_assert_false (data->cb_called);
217 data->cb_called = TRUE;
218
219 ret = g_subprocess_wait_check_finish (subprocess, result, error: &error);
220 g_assert_false (ret);
221 g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
222 g_clear_error (err: &error);
223
224 g_idle_add (function: test_exit1_cancel_idle_quit_cb, data: data->loop);
225}
226
227static void
228test_exit1_cancel (void)
229{
230 GError *local_error = NULL;
231 GError **error = &local_error;
232 GPtrArray *args;
233 GSubprocess *proc;
234 TestExit1CancelData data = { 0 };
235
236 g_test_bug (bug_uri_snippet: "786456");
237
238 args = get_test_subprocess_args (mode: "exit1", NULL);
239 proc = g_subprocess_newv (argv: (const gchar * const *) args->pdata, flags: G_SUBPROCESS_FLAGS_NONE, error);
240 g_ptr_array_free (array: args, TRUE);
241 g_assert_no_error (local_error);
242
243 data.loop = g_main_loop_new (NULL, FALSE);
244 data.cancellable = g_cancellable_new ();
245 g_subprocess_wait_check_async (subprocess: proc, cancellable: data.cancellable, callback: test_exit1_cancel_wait_check_cb, user_data: &data);
246
247 g_subprocess_wait_check (subprocess: proc, NULL, error);
248 g_assert_error (local_error, G_SPAWN_EXIT_ERROR, 1);
249 g_clear_error (err: error);
250
251 g_cancellable_cancel (cancellable: data.cancellable);
252 g_main_loop_run (loop: data.loop);
253
254 g_object_unref (object: proc);
255 g_main_loop_unref (loop: data.loop);
256 g_clear_object (&data.cancellable);
257}
258
259static void
260test_exit1_cancel_in_cb_wait_check_cb (GObject *source,
261 GAsyncResult *result,
262 gpointer user_data)
263{
264 GSubprocess *subprocess = G_SUBPROCESS (source);
265 TestExit1CancelData *data = user_data;
266 gboolean ret;
267 GError *error = NULL;
268
269 g_assert_false (data->cb_called);
270 data->cb_called = TRUE;
271
272 ret = g_subprocess_wait_check_finish (subprocess, result, error: &error);
273 g_assert_false (ret);
274 g_assert_error (error, G_SPAWN_EXIT_ERROR, 1);
275 g_clear_error (err: &error);
276
277 g_cancellable_cancel (cancellable: data->cancellable);
278
279 g_idle_add (function: test_exit1_cancel_idle_quit_cb, data: data->loop);
280}
281
282static void
283test_exit1_cancel_in_cb (void)
284{
285 GError *local_error = NULL;
286 GError **error = &local_error;
287 GPtrArray *args;
288 GSubprocess *proc;
289 TestExit1CancelData data = { 0 };
290
291 g_test_bug (bug_uri_snippet: "786456");
292
293 args = get_test_subprocess_args (mode: "exit1", NULL);
294 proc = g_subprocess_newv (argv: (const gchar * const *) args->pdata, flags: G_SUBPROCESS_FLAGS_NONE, error);
295 g_ptr_array_free (array: args, TRUE);
296 g_assert_no_error (local_error);
297
298 data.loop = g_main_loop_new (NULL, FALSE);
299 data.cancellable = g_cancellable_new ();
300 g_subprocess_wait_check_async (subprocess: proc, cancellable: data.cancellable, callback: test_exit1_cancel_in_cb_wait_check_cb, user_data: &data);
301
302 g_subprocess_wait_check (subprocess: proc, NULL, error);
303 g_assert_error (local_error, G_SPAWN_EXIT_ERROR, 1);
304 g_clear_error (err: error);
305
306 g_main_loop_run (loop: data.loop);
307
308 g_object_unref (object: proc);
309 g_main_loop_unref (loop: data.loop);
310 g_clear_object (&data.cancellable);
311}
312
313static gchar *
314splice_to_string (GInputStream *stream,
315 GError **error)
316{
317 GMemoryOutputStream *buffer = NULL;
318 char *ret = NULL;
319
320 buffer = (GMemoryOutputStream*)g_memory_output_stream_new (NULL, size: 0, realloc_function: g_realloc, destroy_function: g_free);
321 if (g_output_stream_splice (stream: (GOutputStream*)buffer, source: stream, flags: 0, NULL, error) < 0)
322 goto out;
323
324 if (!g_output_stream_write (stream: (GOutputStream*)buffer, buffer: "\0", count: 1, NULL, error))
325 goto out;
326
327 if (!g_output_stream_close (stream: (GOutputStream*)buffer, NULL, error))
328 goto out;
329
330 ret = g_memory_output_stream_steal_data (ostream: buffer);
331 out:
332 g_clear_object (&buffer);
333 return ret;
334}
335
336static void
337test_echo1 (void)
338{
339 GError *local_error = NULL;
340 GError **error = &local_error;
341 GSubprocess *proc;
342 GPtrArray *args;
343 GInputStream *stdout_stream;
344 gchar *result;
345
346 args = get_test_subprocess_args (mode: "echo", "hello", "world!", NULL);
347 proc = g_subprocess_newv (argv: (const gchar * const *) args->pdata, flags: G_SUBPROCESS_FLAGS_STDOUT_PIPE, error);
348 g_ptr_array_free (array: args, TRUE);
349 g_assert_no_error (local_error);
350
351 stdout_stream = g_subprocess_get_stdout_pipe (subprocess: proc);
352
353 result = splice_to_string (stream: stdout_stream, error);
354 g_assert_no_error (local_error);
355
356 g_assert_cmpstr (result, ==, "hello" LINEEND "world!" LINEEND);
357
358 g_free (mem: result);
359 g_object_unref (object: proc);
360}
361
362#ifdef G_OS_UNIX
363static void
364test_echo_merged (void)
365{
366 GError *local_error = NULL;
367 GError **error = &local_error;
368 GSubprocess *proc;
369 GPtrArray *args;
370 GInputStream *stdout_stream;
371 gchar *result;
372
373 args = get_test_subprocess_args (mode: "echo-stdout-and-stderr", "merge", "this", NULL);
374 proc = g_subprocess_newv (argv: (const gchar * const *) args->pdata,
375 flags: G_SUBPROCESS_FLAGS_STDOUT_PIPE | G_SUBPROCESS_FLAGS_STDERR_MERGE,
376 error);
377 g_ptr_array_free (array: args, TRUE);
378 g_assert_no_error (local_error);
379
380 stdout_stream = g_subprocess_get_stdout_pipe (subprocess: proc);
381 result = splice_to_string (stream: stdout_stream, error);
382 g_assert_no_error (local_error);
383
384 g_assert_cmpstr (result, ==, "merge\nmerge\nthis\nthis\n");
385
386 g_free (mem: result);
387 g_object_unref (object: proc);
388}
389#endif
390
391typedef struct {
392 guint events_pending;
393 GMainLoop *loop;
394} TestCatData;
395
396static void
397test_cat_on_input_splice_complete (GObject *object,
398 GAsyncResult *result,
399 gpointer user_data)
400{
401 TestCatData *data = user_data;
402 GError *error = NULL;
403
404 (void)g_output_stream_splice_finish (stream: (GOutputStream*)object, result, error: &error);
405 g_assert_no_error (error);
406
407 data->events_pending--;
408 if (data->events_pending == 0)
409 g_main_loop_quit (loop: data->loop);
410}
411
412static void
413test_cat_utf8 (void)
414{
415 GError *local_error = NULL;
416 GError **error = &local_error;
417 GSubprocess *proc;
418 GPtrArray *args;
419 GBytes *input_buf;
420 GBytes *output_buf;
421 GInputStream *input_buf_stream = NULL;
422 GOutputStream *output_buf_stream = NULL;
423 GOutputStream *stdin_stream = NULL;
424 GInputStream *stdout_stream = NULL;
425 TestCatData data;
426
427 memset (s: &data, c: 0, n: sizeof (data));
428 data.loop = g_main_loop_new (NULL, TRUE);
429
430 args = get_test_subprocess_args (mode: "cat", NULL);
431 proc = g_subprocess_newv (argv: (const gchar * const *) args->pdata,
432 flags: G_SUBPROCESS_FLAGS_STDIN_PIPE | G_SUBPROCESS_FLAGS_STDOUT_PIPE,
433 error);
434 g_ptr_array_free (array: args, TRUE);
435 g_assert_no_error (local_error);
436
437 stdin_stream = g_subprocess_get_stdin_pipe (subprocess: proc);
438 stdout_stream = g_subprocess_get_stdout_pipe (subprocess: proc);
439
440 input_buf = g_bytes_new_static (data: "hello, world!", size: strlen (s: "hello, world!"));
441 input_buf_stream = g_memory_input_stream_new_from_bytes (bytes: input_buf);
442 g_bytes_unref (bytes: input_buf);
443
444 output_buf_stream = g_memory_output_stream_new (NULL, size: 0, realloc_function: g_realloc, destroy_function: g_free);
445
446 g_output_stream_splice_async (stream: stdin_stream, source: input_buf_stream, flags: G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE | G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET,
447 G_PRIORITY_DEFAULT, NULL, callback: test_cat_on_input_splice_complete,
448 user_data: &data);
449 data.events_pending++;
450 g_output_stream_splice_async (stream: output_buf_stream, source: stdout_stream, flags: G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE | G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET,
451 G_PRIORITY_DEFAULT, NULL, callback: test_cat_on_input_splice_complete,
452 user_data: &data);
453 data.events_pending++;
454
455 g_main_loop_run (loop: data.loop);
456
457 g_subprocess_wait_check (subprocess: proc, NULL, error);
458 g_assert_no_error (local_error);
459
460 output_buf = g_memory_output_stream_steal_as_bytes (ostream: (GMemoryOutputStream*)output_buf_stream);
461
462 g_assert_cmpmem (g_bytes_get_data (output_buf, NULL),
463 g_bytes_get_size (output_buf),
464 "hello, world!", 13);
465
466 g_bytes_unref (bytes: output_buf);
467 g_main_loop_unref (loop: data.loop);
468 g_object_unref (object: input_buf_stream);
469 g_object_unref (object: output_buf_stream);
470 g_object_unref (object: proc);
471}
472
473static gpointer
474cancel_soon (gpointer user_data)
475{
476 GCancellable *cancellable = user_data;
477
478 g_usleep (G_TIME_SPAN_SECOND);
479 g_cancellable_cancel (cancellable);
480 g_object_unref (object: cancellable);
481
482 return NULL;
483}
484
485static void
486test_cat_eof (void)
487{
488 GCancellable *cancellable;
489 GError *error = NULL;
490 GSubprocess *cat;
491 gboolean result;
492 gchar buffer;
493 gssize s;
494
495#ifdef G_OS_WIN32
496 g_test_skip ("This test has not been ported to Win32");
497 return;
498#endif
499
500 /* Spawn 'cat' */
501 cat = g_subprocess_new (flags: G_SUBPROCESS_FLAGS_STDIN_PIPE | G_SUBPROCESS_FLAGS_STDOUT_PIPE, error: &error, argv0: "cat", NULL);
502 g_assert_no_error (error);
503 g_assert_nonnull (cat);
504
505 /* Make sure that reading stdout blocks (until we cancel) */
506 cancellable = g_cancellable_new ();
507 g_thread_unref (thread: g_thread_new (name: "cancel thread", func: cancel_soon, g_object_ref (cancellable)));
508 s = g_input_stream_read (stream: g_subprocess_get_stdout_pipe (subprocess: cat), buffer: &buffer, count: sizeof buffer, cancellable, error: &error);
509 g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
510 g_assert_cmpint (s, ==, -1);
511 g_object_unref (object: cancellable);
512 g_clear_error (err: &error);
513
514 /* Close the stream (EOF on cat's stdin) */
515 result = g_output_stream_close (stream: g_subprocess_get_stdin_pipe (subprocess: cat), NULL, error: &error);
516 g_assert_no_error (error);
517 g_assert_true (result);
518
519 /* Now check that reading cat's stdout gets us an EOF (since it quit) */
520 s = g_input_stream_read (stream: g_subprocess_get_stdout_pipe (subprocess: cat), buffer: &buffer, count: sizeof buffer, NULL, error: &error);
521 g_assert_no_error (error);
522 g_assert_false (s);
523
524 /* Check that the process has exited as a result of the EOF */
525 result = g_subprocess_wait (subprocess: cat, NULL, error: &error);
526 g_assert_no_error (error);
527 g_assert_true (g_subprocess_get_if_exited (cat));
528 g_assert_cmpint (g_subprocess_get_exit_status (cat), ==, 0);
529 g_assert_true (result);
530
531 g_object_unref (object: cat);
532}
533
534typedef struct {
535 guint events_pending;
536 gboolean caught_error;
537 GError *error;
538 GMainLoop *loop;
539
540 gint counter;
541 GOutputStream *first_stdin;
542} TestMultiSpliceData;
543
544static void
545on_one_multi_splice_done (GObject *obj,
546 GAsyncResult *res,
547 gpointer user_data)
548{
549 TestMultiSpliceData *data = user_data;
550
551 if (!data->caught_error)
552 {
553 if (g_output_stream_splice_finish (stream: (GOutputStream*)obj, result: res, error: &data->error) < 0)
554 data->caught_error = TRUE;
555 }
556
557 data->events_pending--;
558 if (data->events_pending == 0)
559 g_main_loop_quit (loop: data->loop);
560}
561
562static gboolean
563on_idle_multisplice (gpointer user_data)
564{
565 TestMultiSpliceData *data = user_data;
566
567 if (data->counter >= TOTAL_HELLOS || data->caught_error)
568 {
569 if (!g_output_stream_close (stream: data->first_stdin, NULL, error: &data->error))
570 data->caught_error = TRUE;
571 data->events_pending--;
572 if (data->events_pending == 0)
573 {
574 g_main_loop_quit (loop: data->loop);
575 }
576 return FALSE;
577 }
578 else
579 {
580 int i;
581 for (i = 0; i < data->counter; i++)
582 {
583 gsize bytes_written;
584 if (!g_output_stream_write_all (stream: data->first_stdin, HELLO_WORLD,
585 count: strlen (HELLO_WORLD), bytes_written: &bytes_written,
586 NULL, error: &data->error))
587 {
588 data->caught_error = TRUE;
589 return FALSE;
590 }
591 }
592 data->counter *= 2;
593 return TRUE;
594 }
595}
596
597static void
598on_subprocess_exited (GObject *object,
599 GAsyncResult *result,
600 gpointer user_data)
601{
602 GSubprocess *subprocess = G_SUBPROCESS (object);
603 TestMultiSpliceData *data = user_data;
604 GError *error = NULL;
605
606 if (!g_subprocess_wait_finish (subprocess, result, error: &error))
607 {
608 if (!data->caught_error)
609 {
610 data->caught_error = TRUE;
611 g_propagate_error (dest: &data->error, src: error);
612 }
613 }
614 g_spawn_check_exit_status (exit_status: g_subprocess_get_exit_status (subprocess), error: &error);
615 g_assert_no_error (error);
616 data->events_pending--;
617 if (data->events_pending == 0)
618 g_main_loop_quit (loop: data->loop);
619}
620
621static void
622test_multi_1 (void)
623{
624 GError *local_error = NULL;
625 GError **error = &local_error;
626 GPtrArray *args;
627 GSubprocessLauncher *launcher;
628 GSubprocess *first;
629 GSubprocess *second;
630 GSubprocess *third;
631 GOutputStream *first_stdin;
632 GInputStream *first_stdout;
633 GOutputStream *second_stdin;
634 GInputStream *second_stdout;
635 GOutputStream *third_stdin;
636 GInputStream *third_stdout;
637 GOutputStream *membuf;
638 TestMultiSpliceData data;
639 int splice_flags = G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE | G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET;
640
641 args = get_test_subprocess_args (mode: "cat", NULL);
642 launcher = g_subprocess_launcher_new (flags: G_SUBPROCESS_FLAGS_STDIN_PIPE | G_SUBPROCESS_FLAGS_STDOUT_PIPE);
643 first = g_subprocess_launcher_spawnv (self: launcher, argv: (const gchar * const *) args->pdata, error);
644 g_assert_no_error (local_error);
645 second = g_subprocess_launcher_spawnv (self: launcher, argv: (const gchar * const *) args->pdata, error);
646 g_assert_no_error (local_error);
647 third = g_subprocess_launcher_spawnv (self: launcher, argv: (const gchar * const *) args->pdata, error);
648 g_assert_no_error (local_error);
649
650 g_ptr_array_free (array: args, TRUE);
651
652 membuf = g_memory_output_stream_new (NULL, size: 0, realloc_function: g_realloc, destroy_function: g_free);
653
654 first_stdin = g_subprocess_get_stdin_pipe (subprocess: first);
655 first_stdout = g_subprocess_get_stdout_pipe (subprocess: first);
656 second_stdin = g_subprocess_get_stdin_pipe (subprocess: second);
657 second_stdout = g_subprocess_get_stdout_pipe (subprocess: second);
658 third_stdin = g_subprocess_get_stdin_pipe (subprocess: third);
659 third_stdout = g_subprocess_get_stdout_pipe (subprocess: third);
660
661 memset (s: &data, c: 0, n: sizeof (data));
662 data.loop = g_main_loop_new (NULL, TRUE);
663 data.counter = 1;
664 data.first_stdin = first_stdin;
665
666 data.events_pending++;
667 g_output_stream_splice_async (stream: second_stdin, source: first_stdout, flags: splice_flags, G_PRIORITY_DEFAULT,
668 NULL, callback: on_one_multi_splice_done, user_data: &data);
669 data.events_pending++;
670 g_output_stream_splice_async (stream: third_stdin, source: second_stdout, flags: splice_flags, G_PRIORITY_DEFAULT,
671 NULL, callback: on_one_multi_splice_done, user_data: &data);
672 data.events_pending++;
673 g_output_stream_splice_async (stream: membuf, source: third_stdout, flags: splice_flags, G_PRIORITY_DEFAULT,
674 NULL, callback: on_one_multi_splice_done, user_data: &data);
675
676 data.events_pending++;
677 g_timeout_add (interval: 250, function: on_idle_multisplice, data: &data);
678
679 data.events_pending++;
680 g_subprocess_wait_async (subprocess: first, NULL, callback: on_subprocess_exited, user_data: &data);
681 data.events_pending++;
682 g_subprocess_wait_async (subprocess: second, NULL, callback: on_subprocess_exited, user_data: &data);
683 data.events_pending++;
684 g_subprocess_wait_async (subprocess: third, NULL, callback: on_subprocess_exited, user_data: &data);
685
686 g_main_loop_run (loop: data.loop);
687
688 g_assert_false (data.caught_error);
689 g_assert_no_error (data.error);
690
691 g_assert_cmpint (g_memory_output_stream_get_data_size ((GMemoryOutputStream*)membuf), ==, SPLICELEN);
692
693 g_main_loop_unref (loop: data.loop);
694 g_object_unref (object: membuf);
695 g_object_unref (object: launcher);
696 g_object_unref (object: first);
697 g_object_unref (object: second);
698 g_object_unref (object: third);
699}
700
701typedef struct {
702 GSubprocessFlags flags;
703 gboolean is_utf8;
704 gboolean running;
705 GError *error;
706} TestAsyncCommunicateData;
707
708static void
709on_communicate_complete (GObject *proc,
710 GAsyncResult *result,
711 gpointer user_data)
712{
713 TestAsyncCommunicateData *data = user_data;
714 GBytes *stdout_bytes = NULL, *stderr_bytes = NULL;
715 char *stdout_str = NULL, *stderr_str = NULL;
716 const guint8 *stdout_data;
717 gsize stdout_len;
718
719 data->running = FALSE;
720 if (data->is_utf8)
721 (void) g_subprocess_communicate_utf8_finish (subprocess: (GSubprocess*)proc, result,
722 stdout_buf: &stdout_str, stderr_buf: &stderr_str, error: &data->error);
723 else
724 (void) g_subprocess_communicate_finish (subprocess: (GSubprocess*)proc, result,
725 stdout_buf: &stdout_bytes, stderr_buf: &stderr_bytes, error: &data->error);
726 if (data->error)
727 return;
728
729 if (data->flags & G_SUBPROCESS_FLAGS_STDOUT_PIPE)
730 {
731 if (data->is_utf8)
732 {
733 stdout_data = (guint8*)stdout_str;
734 stdout_len = strlen (s: stdout_str);
735 }
736 else
737 stdout_data = g_bytes_get_data (bytes: stdout_bytes, size: &stdout_len);
738
739 g_assert_cmpmem (stdout_data, stdout_len, "# hello world" LINEEND, 13 + strlen (LINEEND));
740 }
741 else
742 {
743 g_assert_null (stdout_str);
744 g_assert_null (stdout_bytes);
745 }
746
747 if (data->flags & G_SUBPROCESS_FLAGS_STDERR_PIPE)
748 {
749 if (data->is_utf8)
750 g_assert_nonnull (stderr_str);
751 else
752 g_assert_nonnull (stderr_bytes);
753 }
754 else
755 {
756 g_assert_null (stderr_str);
757 g_assert_null (stderr_bytes);
758 }
759
760 g_clear_pointer (&stdout_bytes, g_bytes_unref);
761 g_clear_pointer (&stderr_bytes, g_bytes_unref);
762 g_free (mem: stdout_str);
763 g_free (mem: stderr_str);
764}
765
766/* Test g_subprocess_communicate_async() works correctly with a variety of flags,
767 * as passed in via @test_data. */
768static void
769test_communicate_async (gconstpointer test_data)
770{
771 GSubprocessFlags flags = GPOINTER_TO_INT (test_data);
772 GError *error = NULL;
773 GPtrArray *args;
774 TestAsyncCommunicateData data = { flags, 0, };
775 GSubprocess *proc;
776 GCancellable *cancellable = NULL;
777 GBytes *input;
778 const char *hellostring;
779
780 args = get_test_subprocess_args (mode: "cat", NULL);
781 proc = g_subprocess_newv (argv: (const gchar* const*)args->pdata,
782 flags: G_SUBPROCESS_FLAGS_STDIN_PIPE | flags,
783 error: &error);
784 g_assert_no_error (error);
785 g_ptr_array_free (array: args, TRUE);
786
787 /* Include a leading hash and trailing newline so that if this gets onto the
788 * test’s stdout, it doesn’t mess up TAP output. */
789 hellostring = "# hello world\n";
790 input = g_bytes_new_static (data: hellostring, size: strlen (s: hellostring));
791
792 g_subprocess_communicate_async (subprocess: proc, stdin_buf: input,
793 cancellable,
794 callback: on_communicate_complete,
795 user_data: &data);
796
797 data.running = TRUE;
798 while (data.running)
799 g_main_context_iteration (NULL, TRUE);
800
801 g_assert_no_error (data.error);
802
803 g_bytes_unref (bytes: input);
804 g_object_unref (object: proc);
805}
806
807/* Test g_subprocess_communicate() works correctly with a variety of flags,
808 * as passed in via @test_data. */
809static void
810test_communicate (gconstpointer test_data)
811{
812 GSubprocessFlags flags = GPOINTER_TO_INT (test_data);
813 GError *error = NULL;
814 GPtrArray *args;
815 GSubprocess *proc;
816 GCancellable *cancellable = NULL;
817 GBytes *input;
818 const gchar *hellostring;
819 GBytes *stdout_bytes, *stderr_bytes;
820 const gchar *stdout_data;
821 gsize stdout_len;
822
823 args = get_test_subprocess_args (mode: "cat", NULL);
824 proc = g_subprocess_newv (argv: (const gchar* const*)args->pdata,
825 flags: G_SUBPROCESS_FLAGS_STDIN_PIPE | flags,
826 error: &error);
827 g_assert_no_error (error);
828 g_ptr_array_free (array: args, TRUE);
829
830 /* Include a leading hash and trailing newline so that if this gets onto the
831 * test’s stdout, it doesn’t mess up TAP output. */
832 hellostring = "# hello world\n";
833 input = g_bytes_new_static (data: hellostring, size: strlen (s: hellostring));
834
835 g_subprocess_communicate (subprocess: proc, stdin_buf: input, cancellable, stdout_buf: &stdout_bytes, stderr_buf: &stderr_bytes, error: &error);
836 g_assert_no_error (error);
837
838 if (flags & G_SUBPROCESS_FLAGS_STDOUT_PIPE)
839 {
840 stdout_data = g_bytes_get_data (bytes: stdout_bytes, size: &stdout_len);
841 g_assert_cmpmem (stdout_data, stdout_len, "# hello world" LINEEND, 13 + strlen (LINEEND));
842 }
843 else
844 g_assert_null (stdout_bytes);
845 if (flags & G_SUBPROCESS_FLAGS_STDERR_PIPE)
846 g_assert_nonnull (stderr_bytes);
847 else
848 g_assert_null (stderr_bytes);
849
850 g_bytes_unref (bytes: input);
851 g_clear_pointer (&stdout_bytes, g_bytes_unref);
852 g_clear_pointer (&stderr_bytes, g_bytes_unref);
853 g_object_unref (object: proc);
854}
855
856typedef struct {
857 GSubprocess *proc;
858 GCancellable *cancellable;
859 gboolean is_utf8;
860 gboolean running;
861 GError *error;
862} TestCancelledCommunicateData;
863
864static gboolean
865on_test_communicate_cancelled_idle (gpointer user_data)
866{
867 TestCancelledCommunicateData *data = user_data;
868 GBytes *input;
869 const gchar *hellostring;
870 GBytes *stdout_bytes = NULL, *stderr_bytes = NULL;
871 gchar *stdout_buf = NULL, *stderr_buf = NULL;
872
873 /* Include a leading hash and trailing newline so that if this gets onto the
874 * test’s stdout, it doesn’t mess up TAP output. */
875 hellostring = "# hello world\n";
876 input = g_bytes_new_static (data: hellostring, size: strlen (s: hellostring));
877
878 if (data->is_utf8)
879 g_subprocess_communicate_utf8 (subprocess: data->proc, stdin_buf: hellostring, cancellable: data->cancellable,
880 stdout_buf: &stdout_buf, stderr_buf: &stderr_buf, error: &data->error);
881 else
882 g_subprocess_communicate (subprocess: data->proc, stdin_buf: input, cancellable: data->cancellable, stdout_buf: &stdout_bytes,
883 stderr_buf: &stderr_bytes, error: &data->error);
884
885 data->running = FALSE;
886
887 if (data->is_utf8)
888 {
889 g_assert_null (stdout_buf);
890 g_assert_null (stderr_buf);
891 }
892 else
893 {
894 g_assert_null (stdout_bytes);
895 g_assert_null (stderr_bytes);
896 }
897
898 g_bytes_unref (bytes: input);
899
900 return G_SOURCE_REMOVE;
901}
902
903/* Test g_subprocess_communicate() can be cancelled correctly */
904static void
905test_communicate_cancelled (gconstpointer test_data)
906{
907 GSubprocessFlags flags = GPOINTER_TO_INT (test_data);
908 GPtrArray *args;
909 GSubprocess *proc;
910 GCancellable *cancellable = NULL;
911 GError *error = NULL;
912 TestCancelledCommunicateData data = { 0 };
913
914 args = get_test_subprocess_args (mode: "cat", NULL);
915 proc = g_subprocess_newv (argv: (const gchar* const*)args->pdata,
916 flags: G_SUBPROCESS_FLAGS_STDIN_PIPE | flags,
917 error: &error);
918 g_assert_no_error (error);
919 g_ptr_array_free (array: args, TRUE);
920
921 cancellable = g_cancellable_new ();
922
923 data.proc = proc;
924 data.cancellable = cancellable;
925 data.error = error;
926
927 g_cancellable_cancel (cancellable);
928 g_idle_add (function: on_test_communicate_cancelled_idle, data: &data);
929
930 data.running = TRUE;
931 while (data.running)
932 g_main_context_iteration (NULL, TRUE);
933
934 g_assert_error (data.error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
935 g_clear_error (err: &data.error);
936
937 g_object_unref (object: cancellable);
938 g_object_unref (object: proc);
939}
940
941static void
942on_communicate_cancelled_complete (GObject *proc,
943 GAsyncResult *result,
944 gpointer user_data)
945{
946 TestAsyncCommunicateData *data = user_data;
947 GBytes *stdout_bytes = NULL, *stderr_bytes = NULL;
948 char *stdout_str = NULL, *stderr_str = NULL;
949
950 data->running = FALSE;
951 if (data->is_utf8)
952 (void) g_subprocess_communicate_utf8_finish (subprocess: (GSubprocess*)proc, result,
953 stdout_buf: &stdout_str, stderr_buf: &stderr_str, error: &data->error);
954 else
955 (void) g_subprocess_communicate_finish (subprocess: (GSubprocess*)proc, result,
956 stdout_buf: &stdout_bytes, stderr_buf: &stderr_bytes, error: &data->error);
957
958 if (data->is_utf8)
959 {
960 g_assert_null (stdout_str);
961 g_assert_null (stderr_str);
962 }
963 else
964 {
965 g_assert_null (stdout_bytes);
966 g_assert_null (stderr_bytes);
967 }
968}
969
970/* Test g_subprocess_communicate_async() can be cancelled correctly,
971 * as passed in via @test_data. */
972static void
973test_communicate_cancelled_async (gconstpointer test_data)
974{
975 GSubprocessFlags flags = GPOINTER_TO_INT (test_data);
976 GError *error = NULL;
977 GPtrArray *args;
978 TestAsyncCommunicateData data = { 0 };
979 GSubprocess *proc;
980 GCancellable *cancellable = NULL;
981 GBytes *input;
982 const char *hellostring;
983
984 args = get_test_subprocess_args (mode: "cat", NULL);
985 proc = g_subprocess_newv (argv: (const gchar* const*)args->pdata,
986 flags: G_SUBPROCESS_FLAGS_STDIN_PIPE | flags,
987 error: &error);
988 g_assert_no_error (error);
989 g_ptr_array_free (array: args, TRUE);
990
991 /* Include a leading hash and trailing newline so that if this gets onto the
992 * test’s stdout, it doesn’t mess up TAP output. */
993 hellostring = "# hello world\n";
994 input = g_bytes_new_static (data: hellostring, size: strlen (s: hellostring));
995
996 cancellable = g_cancellable_new ();
997
998 g_subprocess_communicate_async (subprocess: proc, stdin_buf: input,
999 cancellable,
1000 callback: on_communicate_cancelled_complete,
1001 user_data: &data);
1002
1003 g_cancellable_cancel (cancellable);
1004
1005 data.running = TRUE;
1006 while (data.running)
1007 g_main_context_iteration (NULL, TRUE);
1008
1009 g_assert_error (data.error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
1010 g_clear_error (err: &data.error);
1011
1012 g_bytes_unref (bytes: input);
1013 g_object_unref (object: cancellable);
1014 g_object_unref (object: proc);
1015}
1016
1017/* Test g_subprocess_communicate_utf8_async() works correctly with a variety of
1018 * flags, as passed in via @test_data. */
1019static void
1020test_communicate_utf8_async (gconstpointer test_data)
1021{
1022 GSubprocessFlags flags = GPOINTER_TO_INT (test_data);
1023 GError *error = NULL;
1024 GPtrArray *args;
1025 TestAsyncCommunicateData data = { flags, 0, };
1026 GSubprocess *proc;
1027 GCancellable *cancellable = NULL;
1028
1029 args = get_test_subprocess_args (mode: "cat", NULL);
1030 proc = g_subprocess_newv (argv: (const gchar* const*)args->pdata,
1031 flags: G_SUBPROCESS_FLAGS_STDIN_PIPE | flags,
1032 error: &error);
1033 g_assert_no_error (error);
1034 g_ptr_array_free (array: args, TRUE);
1035
1036 data.is_utf8 = TRUE;
1037 g_subprocess_communicate_utf8_async (subprocess: proc, stdin_buf: "# hello world\n",
1038 cancellable,
1039 callback: on_communicate_complete,
1040 user_data: &data);
1041
1042 data.running = TRUE;
1043 while (data.running)
1044 g_main_context_iteration (NULL, TRUE);
1045
1046 g_assert_no_error (data.error);
1047
1048 g_object_unref (object: proc);
1049}
1050
1051/* Test g_subprocess_communicate_utf8_async() can be cancelled correctly. */
1052static void
1053test_communicate_utf8_cancelled_async (gconstpointer test_data)
1054{
1055 GSubprocessFlags flags = GPOINTER_TO_INT (test_data);
1056 GError *error = NULL;
1057 GPtrArray *args;
1058 TestAsyncCommunicateData data = { flags, 0, };
1059 GSubprocess *proc;
1060 GCancellable *cancellable = NULL;
1061
1062 args = get_test_subprocess_args (mode: "cat", NULL);
1063 proc = g_subprocess_newv (argv: (const gchar* const*)args->pdata,
1064 flags: G_SUBPROCESS_FLAGS_STDIN_PIPE | flags,
1065 error: &error);
1066 g_assert_no_error (error);
1067 g_ptr_array_free (array: args, TRUE);
1068
1069 cancellable = g_cancellable_new ();
1070 data.is_utf8 = TRUE;
1071 g_subprocess_communicate_utf8_async (subprocess: proc, stdin_buf: "# hello world\n",
1072 cancellable,
1073 callback: on_communicate_cancelled_complete,
1074 user_data: &data);
1075
1076 g_cancellable_cancel (cancellable);
1077
1078 data.running = TRUE;
1079 while (data.running)
1080 g_main_context_iteration (NULL, TRUE);
1081
1082 g_assert_error (data.error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
1083 g_clear_error (err: &data.error);
1084
1085 g_object_unref (object: cancellable);
1086 g_object_unref (object: proc);
1087}
1088
1089/* Test g_subprocess_communicate_utf8() works correctly with a variety of flags,
1090 * as passed in via @test_data. */
1091static void
1092test_communicate_utf8 (gconstpointer test_data)
1093{
1094 GSubprocessFlags flags = GPOINTER_TO_INT (test_data);
1095 GError *error = NULL;
1096 GPtrArray *args;
1097 GSubprocess *proc;
1098 GCancellable *cancellable = NULL;
1099 const gchar *stdin_buf;
1100 gchar *stdout_buf, *stderr_buf;
1101
1102 args = get_test_subprocess_args (mode: "cat", NULL);
1103 proc = g_subprocess_newv (argv: (const gchar* const*)args->pdata,
1104 flags: G_SUBPROCESS_FLAGS_STDIN_PIPE | flags,
1105 error: &error);
1106 g_assert_no_error (error);
1107 g_ptr_array_free (array: args, TRUE);
1108
1109 /* Include a leading hash and trailing newline so that if this gets onto the
1110 * test’s stdout, it doesn’t mess up TAP output. */
1111 stdin_buf = "# hello world\n";
1112
1113 g_subprocess_communicate_utf8 (subprocess: proc, stdin_buf, cancellable, stdout_buf: &stdout_buf, stderr_buf: &stderr_buf, error: &error);
1114 g_assert_no_error (error);
1115
1116 if (flags & G_SUBPROCESS_FLAGS_STDOUT_PIPE)
1117 g_assert_cmpstr (stdout_buf, ==, "# hello world" LINEEND);
1118 else
1119 g_assert_null (stdout_buf);
1120 if (flags & G_SUBPROCESS_FLAGS_STDERR_PIPE)
1121 g_assert_nonnull (stderr_buf);
1122 else g_assert_null (stderr_buf);
1123
1124 g_free (mem: stdout_buf);
1125 g_free (mem: stderr_buf);
1126 g_object_unref (object: proc);
1127}
1128
1129/* Test g_subprocess_communicate_utf8() can be cancelled correctly */
1130static void
1131test_communicate_utf8_cancelled (gconstpointer test_data)
1132{
1133 GSubprocessFlags flags = GPOINTER_TO_INT (test_data);
1134 GPtrArray *args;
1135 GSubprocess *proc;
1136 GCancellable *cancellable = NULL;
1137 GError *error = NULL;
1138 TestCancelledCommunicateData data = { 0 };
1139
1140 args = get_test_subprocess_args (mode: "cat", NULL);
1141 proc = g_subprocess_newv (argv: (const gchar* const*)args->pdata,
1142 flags: G_SUBPROCESS_FLAGS_STDIN_PIPE | flags,
1143 error: &error);
1144 g_assert_no_error (error);
1145 g_ptr_array_free (array: args, TRUE);
1146
1147 cancellable = g_cancellable_new ();
1148
1149 data.proc = proc;
1150 data.cancellable = cancellable;
1151 data.error = error;
1152
1153 g_cancellable_cancel (cancellable);
1154 g_idle_add (function: on_test_communicate_cancelled_idle, data: &data);
1155
1156 data.is_utf8 = TRUE;
1157 data.running = TRUE;
1158 while (data.running)
1159 g_main_context_iteration (NULL, TRUE);
1160
1161 g_assert_error (data.error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
1162 g_clear_error (err: &data.error);
1163
1164 g_object_unref (object: cancellable);
1165 g_object_unref (object: proc);
1166}
1167
1168static void
1169test_communicate_nothing (void)
1170{
1171 GError *error = NULL;
1172 GPtrArray *args;
1173 GSubprocess *proc;
1174 GCancellable *cancellable = NULL;
1175 gchar *stdout_buf;
1176
1177 args = get_test_subprocess_args (mode: "cat", NULL);
1178 proc = g_subprocess_newv (argv: (const gchar* const*)args->pdata,
1179 flags: G_SUBPROCESS_FLAGS_STDIN_PIPE
1180 | G_SUBPROCESS_FLAGS_STDOUT_PIPE
1181 | G_SUBPROCESS_FLAGS_STDERR_MERGE,
1182 error: &error);
1183 g_assert_no_error (error);
1184 g_ptr_array_free (array: args, TRUE);
1185
1186 g_subprocess_communicate_utf8 (subprocess: proc, stdin_buf: "", cancellable, stdout_buf: &stdout_buf, NULL, error: &error);
1187 g_assert_no_error (error);
1188
1189 g_assert_cmpstr (stdout_buf, ==, "");
1190
1191 g_free (mem: stdout_buf);
1192
1193 g_object_unref (object: proc);
1194}
1195
1196static void
1197test_communicate_utf8_async_invalid (void)
1198{
1199 GSubprocessFlags flags = G_SUBPROCESS_FLAGS_STDOUT_PIPE;
1200 GError *error = NULL;
1201 GPtrArray *args;
1202 TestAsyncCommunicateData data = { flags, 0, };
1203 GSubprocess *proc;
1204 GCancellable *cancellable = NULL;
1205
1206 args = get_test_subprocess_args (mode: "cat", NULL);
1207 proc = g_subprocess_newv (argv: (const gchar* const*)args->pdata,
1208 flags: G_SUBPROCESS_FLAGS_STDIN_PIPE | flags,
1209 error: &error);
1210 g_assert_no_error (error);
1211 g_ptr_array_free (array: args, TRUE);
1212
1213 data.is_utf8 = TRUE;
1214 g_subprocess_communicate_utf8_async (subprocess: proc, stdin_buf: "\xFF\xFF",
1215 cancellable,
1216 callback: on_communicate_complete,
1217 user_data: &data);
1218
1219 data.running = TRUE;
1220 while (data.running)
1221 g_main_context_iteration (NULL, TRUE);
1222
1223 g_assert_error (data.error, G_IO_ERROR, G_IO_ERROR_FAILED);
1224 g_error_free (error: data.error);
1225
1226 g_object_unref (object: proc);
1227}
1228
1229/* Test that invalid UTF-8 received using g_subprocess_communicate_utf8()
1230 * results in an error. */
1231static void
1232test_communicate_utf8_invalid (void)
1233{
1234 GSubprocessFlags flags = G_SUBPROCESS_FLAGS_STDOUT_PIPE;
1235 GError *local_error = NULL;
1236 gboolean ret;
1237 GPtrArray *args;
1238 gchar *stdout_str = NULL, *stderr_str = NULL;
1239 GSubprocess *proc;
1240
1241 args = get_test_subprocess_args (mode: "cat", NULL);
1242 proc = g_subprocess_newv (argv: (const gchar* const*)args->pdata,
1243 flags: G_SUBPROCESS_FLAGS_STDIN_PIPE | flags,
1244 error: &local_error);
1245 g_assert_no_error (local_error);
1246 g_ptr_array_free (array: args, TRUE);
1247
1248 ret = g_subprocess_communicate_utf8 (subprocess: proc, stdin_buf: "\xFF\xFF", NULL,
1249 stdout_buf: &stdout_str, stderr_buf: &stderr_str, error: &local_error);
1250 g_assert_error (local_error, G_IO_ERROR, G_IO_ERROR_FAILED);
1251 g_error_free (error: local_error);
1252 g_assert_false (ret);
1253
1254 g_assert_null (stdout_str);
1255 g_assert_null (stderr_str);
1256
1257 g_object_unref (object: proc);
1258}
1259
1260static gboolean
1261send_terminate (gpointer user_data)
1262{
1263 GSubprocess *proc = user_data;
1264
1265 g_subprocess_force_exit (subprocess: proc);
1266
1267 return FALSE;
1268}
1269
1270static void
1271on_request_quit_exited (GObject *object,
1272 GAsyncResult *result,
1273 gpointer user_data)
1274{
1275 GSubprocess *subprocess = G_SUBPROCESS (object);
1276 GError *error = NULL;
1277
1278 g_subprocess_wait_finish (subprocess, result, error: &error);
1279 g_assert_no_error (error);
1280#ifdef G_OS_UNIX
1281 g_assert_true (g_subprocess_get_if_signaled (subprocess));
1282 g_assert_cmpint (g_subprocess_get_term_sig (subprocess), ==, 9);
1283#endif
1284 g_spawn_check_exit_status (exit_status: g_subprocess_get_status (subprocess), error: &error);
1285 g_assert_nonnull (error);
1286 g_clear_error (err: &error);
1287
1288 g_main_loop_quit (loop: (GMainLoop*)user_data);
1289}
1290
1291static void
1292test_terminate (void)
1293{
1294 GError *local_error = NULL;
1295 GError **error = &local_error;
1296 GSubprocess *proc;
1297 GPtrArray *args;
1298 GMainLoop *loop;
1299 const gchar *id;
1300
1301 args = get_test_subprocess_args (mode: "sleep-forever", NULL);
1302 proc = g_subprocess_newv (argv: (const gchar * const *) args->pdata, flags: G_SUBPROCESS_FLAGS_NONE, error);
1303 g_ptr_array_free (array: args, TRUE);
1304 g_assert_no_error (local_error);
1305
1306 id = g_subprocess_get_identifier (subprocess: proc);
1307 g_assert_nonnull (id);
1308
1309 loop = g_main_loop_new (NULL, TRUE);
1310
1311 g_subprocess_wait_async (subprocess: proc, NULL, callback: on_request_quit_exited, user_data: loop);
1312
1313 g_timeout_add_seconds (interval: 3, function: send_terminate, data: proc);
1314
1315 g_main_loop_run (loop);
1316
1317 g_main_loop_unref (loop);
1318 g_object_unref (object: proc);
1319}
1320
1321#ifdef G_OS_UNIX
1322static gboolean
1323send_signal (gpointer user_data)
1324{
1325 GSubprocess *proc = user_data;
1326
1327 g_subprocess_send_signal (subprocess: proc, SIGKILL);
1328
1329 return FALSE;
1330}
1331
1332static void
1333test_signal (void)
1334{
1335 GError *local_error = NULL;
1336 GError **error = &local_error;
1337 GSubprocess *proc;
1338 GPtrArray *args;
1339 GMainLoop *loop;
1340
1341 args = get_test_subprocess_args (mode: "sleep-forever", NULL);
1342 proc = g_subprocess_newv (argv: (const gchar * const *) args->pdata, flags: G_SUBPROCESS_FLAGS_NONE, error);
1343 g_ptr_array_free (array: args, TRUE);
1344 g_assert_no_error (local_error);
1345
1346 loop = g_main_loop_new (NULL, TRUE);
1347
1348 g_subprocess_wait_async (subprocess: proc, NULL, callback: on_request_quit_exited, user_data: loop);
1349
1350 g_timeout_add_seconds (interval: 3, function: send_signal, data: proc);
1351
1352 g_main_loop_run (loop);
1353
1354 g_main_loop_unref (loop);
1355 g_object_unref (object: proc);
1356}
1357#endif
1358
1359static void
1360test_env (void)
1361{
1362 GError *local_error = NULL;
1363 GError **error = &local_error;
1364 GSubprocessLauncher *launcher;
1365 GSubprocess *proc;
1366 GPtrArray *args;
1367 GInputStream *stdout_stream;
1368 gchar *result;
1369 gchar *envp[] = { NULL, "ONE=1", "TWO=1", "THREE=3", "FOUR=1", NULL };
1370 gchar **split;
1371
1372 envp[0] = g_strdup_printf (format: "PATH=%s", g_getenv (variable: "PATH"));
1373 args = get_test_subprocess_args (mode: "env", NULL);
1374 launcher = g_subprocess_launcher_new (flags: G_SUBPROCESS_FLAGS_NONE);
1375 g_subprocess_launcher_set_flags (self: launcher, flags: G_SUBPROCESS_FLAGS_STDOUT_PIPE);
1376 g_subprocess_launcher_set_environ (self: launcher, env: envp);
1377 g_subprocess_launcher_setenv (self: launcher, variable: "TWO", value: "2", TRUE);
1378 g_subprocess_launcher_setenv (self: launcher, variable: "THREE", value: "1", FALSE);
1379 g_subprocess_launcher_unsetenv (self: launcher, variable: "FOUR");
1380
1381 g_assert_null (g_subprocess_launcher_getenv (launcher, "FOUR"));
1382
1383 proc = g_subprocess_launcher_spawn (self: launcher, error, argv0: args->pdata[0], "env", NULL);
1384 g_ptr_array_free (array: args, TRUE);
1385 g_assert_no_error (local_error);
1386 g_free (mem: envp[0]);
1387
1388 stdout_stream = g_subprocess_get_stdout_pipe (subprocess: proc);
1389
1390 result = splice_to_string (stream: stdout_stream, error);
1391 split = g_strsplit (string: result, LINEEND, max_tokens: -1);
1392 g_assert_cmpstr (g_environ_getenv (split, "ONE"), ==, "1");
1393 g_assert_cmpstr (g_environ_getenv (split, "TWO"), ==, "2");
1394 g_assert_cmpstr (g_environ_getenv (split, "THREE"), ==, "3");
1395 g_assert_null (g_environ_getenv (split, "FOUR"));
1396
1397 g_strfreev (str_array: split);
1398 g_free (mem: result);
1399 g_object_unref (object: proc);
1400 g_object_unref (object: launcher);
1401}
1402
1403/* Test that explicitly inheriting and modifying the parent process’
1404 * environment works. */
1405static void
1406test_env_inherit (void)
1407{
1408 GError *local_error = NULL;
1409 GError **error = &local_error;
1410 GSubprocessLauncher *launcher;
1411 GSubprocess *proc;
1412 GPtrArray *args;
1413 GInputStream *stdout_stream;
1414 gchar *result;
1415 gchar **split;
1416
1417 g_setenv (variable: "TEST_ENV_INHERIT1", value: "1", TRUE);
1418 g_setenv (variable: "TEST_ENV_INHERIT2", value: "2", TRUE);
1419
1420 args = get_test_subprocess_args (mode: "env", NULL);
1421 launcher = g_subprocess_launcher_new (flags: G_SUBPROCESS_FLAGS_NONE);
1422 g_subprocess_launcher_set_flags (self: launcher, flags: G_SUBPROCESS_FLAGS_STDOUT_PIPE);
1423 g_subprocess_launcher_set_environ (self: launcher, NULL);
1424 g_subprocess_launcher_setenv (self: launcher, variable: "TWO", value: "2", TRUE);
1425 g_subprocess_launcher_unsetenv (self: launcher, variable: "TEST_ENV_INHERIT1");
1426
1427 g_assert_null (g_subprocess_launcher_getenv (launcher, "TEST_ENV_INHERIT1"));
1428 g_assert_cmpstr (g_subprocess_launcher_getenv (launcher, "TEST_ENV_INHERIT2"), ==, "2");
1429 g_assert_cmpstr (g_subprocess_launcher_getenv (launcher, "TWO"), ==, "2");
1430
1431 proc = g_subprocess_launcher_spawn (self: launcher, error, argv0: args->pdata[0], "env", NULL);
1432 g_ptr_array_free (array: args, TRUE);
1433 g_assert_no_error (local_error);
1434
1435 stdout_stream = g_subprocess_get_stdout_pipe (subprocess: proc);
1436
1437 result = splice_to_string (stream: stdout_stream, error);
1438 split = g_strsplit (string: result, LINEEND, max_tokens: -1);
1439 g_assert_null (g_environ_getenv (split, "TEST_ENV_INHERIT1"));
1440 g_assert_cmpstr (g_environ_getenv (split, "TEST_ENV_INHERIT2"), ==, "2");
1441 g_assert_cmpstr (g_environ_getenv (split, "TWO"), ==, "2");
1442
1443 g_strfreev (str_array: split);
1444 g_free (mem: result);
1445 g_object_unref (object: proc);
1446 g_object_unref (object: launcher);
1447}
1448
1449static void
1450test_cwd (void)
1451{
1452 GError *local_error = NULL;
1453 GError **error = &local_error;
1454 GSubprocessLauncher *launcher;
1455 GSubprocess *proc;
1456 GPtrArray *args;
1457 GInputStream *stdout_stream;
1458 gchar *result;
1459 const char *basename;
1460 gchar *tmp_lineend;
1461 const gchar *tmp_lineend_basename;
1462
1463 args = get_test_subprocess_args (mode: "cwd", NULL);
1464 launcher = g_subprocess_launcher_new (flags: G_SUBPROCESS_FLAGS_STDOUT_PIPE);
1465 g_subprocess_launcher_set_flags (self: launcher, flags: G_SUBPROCESS_FLAGS_STDOUT_PIPE);
1466 g_subprocess_launcher_set_cwd (self: launcher, cwd: g_get_tmp_dir ());
1467 tmp_lineend = g_strdup_printf (format: "%s%s", g_get_tmp_dir (), LINEEND);
1468 tmp_lineend_basename = g_strrstr (haystack: tmp_lineend, G_DIR_SEPARATOR_S);
1469
1470 proc = g_subprocess_launcher_spawnv (self: launcher, argv: (const char * const *)args->pdata, error);
1471 g_ptr_array_free (array: args, TRUE);
1472 g_assert_no_error (local_error);
1473
1474 stdout_stream = g_subprocess_get_stdout_pipe (subprocess: proc);
1475
1476 result = splice_to_string (stream: stdout_stream, error);
1477
1478 basename = g_strrstr (haystack: result, G_DIR_SEPARATOR_S);
1479 g_assert_nonnull (basename);
1480 g_assert_cmpstr (basename, ==, tmp_lineend_basename);
1481 g_free (mem: tmp_lineend);
1482
1483 g_free (mem: result);
1484 g_object_unref (object: proc);
1485 g_object_unref (object: launcher);
1486}
1487#ifdef G_OS_UNIX
1488
1489static void
1490test_subprocess_launcher_close (void)
1491{
1492 GError *local_error = NULL;
1493 GError **error = &local_error;
1494 GSubprocessLauncher *launcher;
1495 GSubprocess *proc;
1496 GPtrArray *args;
1497 int fd, fd2;
1498 gboolean is_open;
1499
1500 /* Open two arbitrary FDs. One of them, @fd, will be transferred to the
1501 * launcher, and the other’s FD integer will be used as its target FD, giving
1502 * the mapping `fd → fd2` if a child process were to be spawned.
1503 *
1504 * The launcher will then be closed, which should close @fd but *not* @fd2,
1505 * as the value of @fd2 is only valid as an FD in a child process. (A child
1506 * process is not actually spawned in this test.)
1507 */
1508 fd = dup (fd: 0);
1509 fd2 = dup (fd: 0);
1510 launcher = g_subprocess_launcher_new (flags: G_SUBPROCESS_FLAGS_NONE);
1511 g_subprocess_launcher_take_fd (self: launcher, source_fd: fd, target_fd: fd2);
1512
1513 is_open = fcntl (fd: fd, F_GETFD) != -1;
1514 g_assert_true (is_open);
1515 is_open = fcntl (fd: fd2, F_GETFD) != -1;
1516 g_assert_true (is_open);
1517
1518 g_subprocess_launcher_close (self: launcher);
1519
1520 is_open = fcntl (fd: fd, F_GETFD) != -1;
1521 g_assert_false (is_open);
1522 is_open = fcntl (fd: fd2, F_GETFD) != -1;
1523 g_assert_true (is_open);
1524
1525 /* Now test that actually trying to spawn the child gives %G_IO_ERROR_CLOSED,
1526 * as g_subprocess_launcher_close() has been called. */
1527 args = get_test_subprocess_args (mode: "cat", NULL);
1528 proc = g_subprocess_launcher_spawnv (self: launcher, argv: (const gchar * const *) args->pdata, error);
1529 g_ptr_array_free (array: args, TRUE);
1530 g_assert_null (proc);
1531 g_assert_error (local_error, G_IO_ERROR, G_IO_ERROR_CLOSED);
1532 g_clear_error (err: error);
1533
1534 close (fd: fd2);
1535 g_object_unref (object: launcher);
1536}
1537
1538static void
1539test_stdout_file (void)
1540{
1541 GError *local_error = NULL;
1542 GError **error = &local_error;
1543 GSubprocessLauncher *launcher;
1544 GSubprocess *proc;
1545 GPtrArray *args;
1546 GFile *tmpfile;
1547 GFileIOStream *iostream;
1548 GOutputStream *stdin_stream;
1549 const char *test_data = "this is some test data\n";
1550 char *tmp_contents;
1551 char *tmp_file_path;
1552
1553 tmpfile = g_file_new_tmp (tmpl: "gsubprocessXXXXXX", iostream: &iostream, error);
1554 g_assert_no_error (local_error);
1555 g_clear_object (&iostream);
1556
1557 tmp_file_path = g_file_get_path (file: tmpfile);
1558
1559 args = get_test_subprocess_args (mode: "cat", NULL);
1560 launcher = g_subprocess_launcher_new (flags: G_SUBPROCESS_FLAGS_STDIN_PIPE);
1561 g_subprocess_launcher_set_stdout_file_path (self: launcher, path: tmp_file_path);
1562 proc = g_subprocess_launcher_spawnv (self: launcher, argv: (const gchar * const *) args->pdata, error);
1563 g_ptr_array_free (array: args, TRUE);
1564 g_assert_no_error (local_error);
1565
1566 stdin_stream = g_subprocess_get_stdin_pipe (subprocess: proc);
1567
1568 g_output_stream_write_all (stream: stdin_stream, buffer: test_data, count: strlen (s: test_data), NULL, NULL, error);
1569 g_assert_no_error (local_error);
1570
1571 g_output_stream_close (stream: stdin_stream, NULL, error);
1572 g_assert_no_error (local_error);
1573
1574 g_subprocess_wait_check (subprocess: proc, NULL, error);
1575
1576 g_object_unref (object: launcher);
1577 g_object_unref (object: proc);
1578
1579 g_file_load_contents (file: tmpfile, NULL, contents: &tmp_contents, NULL, NULL, error);
1580 g_assert_no_error (local_error);
1581
1582 g_assert_cmpstr (test_data, ==, tmp_contents);
1583 g_free (mem: tmp_contents);
1584
1585 (void) g_file_delete (file: tmpfile, NULL, NULL);
1586 g_object_unref (object: tmpfile);
1587 g_free (mem: tmp_file_path);
1588}
1589
1590static void
1591test_stdout_fd (void)
1592{
1593 GError *local_error = NULL;
1594 GError **error = &local_error;
1595 GSubprocessLauncher *launcher;
1596 GSubprocess *proc;
1597 GPtrArray *args;
1598 GFile *tmpfile;
1599 GFileIOStream *iostream;
1600 GFileDescriptorBased *descriptor_stream;
1601 GOutputStream *stdin_stream;
1602 const char *test_data = "this is some test data\n";
1603 char *tmp_contents;
1604
1605 tmpfile = g_file_new_tmp (tmpl: "gsubprocessXXXXXX", iostream: &iostream, error);
1606 g_assert_no_error (local_error);
1607
1608 args = get_test_subprocess_args (mode: "cat", NULL);
1609 launcher = g_subprocess_launcher_new (flags: G_SUBPROCESS_FLAGS_STDIN_PIPE);
1610 descriptor_stream = G_FILE_DESCRIPTOR_BASED (g_io_stream_get_output_stream (G_IO_STREAM (iostream)));
1611 g_subprocess_launcher_take_stdout_fd (self: launcher, fd: dup (fd: g_file_descriptor_based_get_fd (fd_based: descriptor_stream)));
1612 proc = g_subprocess_launcher_spawnv (self: launcher, argv: (const gchar * const *) args->pdata, error);
1613 g_ptr_array_free (array: args, TRUE);
1614 g_assert_no_error (local_error);
1615
1616 g_clear_object (&iostream);
1617
1618 stdin_stream = g_subprocess_get_stdin_pipe (subprocess: proc);
1619
1620 g_output_stream_write_all (stream: stdin_stream, buffer: test_data, count: strlen (s: test_data), NULL, NULL, error);
1621 g_assert_no_error (local_error);
1622
1623 g_output_stream_close (stream: stdin_stream, NULL, error);
1624 g_assert_no_error (local_error);
1625
1626 g_subprocess_wait_check (subprocess: proc, NULL, error);
1627
1628 g_object_unref (object: launcher);
1629 g_object_unref (object: proc);
1630
1631 g_file_load_contents (file: tmpfile, NULL, contents: &tmp_contents, NULL, NULL, error);
1632 g_assert_no_error (local_error);
1633
1634 g_assert_cmpstr (test_data, ==, tmp_contents);
1635 g_free (mem: tmp_contents);
1636
1637 (void) g_file_delete (file: tmpfile, NULL, NULL);
1638 g_object_unref (object: tmpfile);
1639}
1640
1641static void
1642child_setup (gpointer user_data)
1643{
1644 dup2 (GPOINTER_TO_INT (user_data), fd2: 1);
1645}
1646
1647static void
1648test_child_setup (void)
1649{
1650 GError *local_error = NULL;
1651 GError **error = &local_error;
1652 GSubprocessLauncher *launcher;
1653 GSubprocess *proc;
1654 GPtrArray *args;
1655 GFile *tmpfile;
1656 GFileIOStream *iostream;
1657 GOutputStream *stdin_stream;
1658 const char *test_data = "this is some test data\n";
1659 char *tmp_contents;
1660 int fd;
1661
1662 tmpfile = g_file_new_tmp (tmpl: "gsubprocessXXXXXX", iostream: &iostream, error);
1663 g_assert_no_error (local_error);
1664
1665 fd = g_file_descriptor_based_get_fd (G_FILE_DESCRIPTOR_BASED (g_io_stream_get_output_stream (G_IO_STREAM (iostream))));
1666
1667 args = get_test_subprocess_args (mode: "cat", NULL);
1668 launcher = g_subprocess_launcher_new (flags: G_SUBPROCESS_FLAGS_STDIN_PIPE);
1669 g_subprocess_launcher_set_child_setup (self: launcher, child_setup, GINT_TO_POINTER (fd), NULL);
1670 proc = g_subprocess_launcher_spawnv (self: launcher, argv: (const gchar * const *) args->pdata, error);
1671 g_ptr_array_free (array: args, TRUE);
1672 g_assert_no_error (local_error);
1673
1674 g_clear_object (&iostream);
1675
1676 stdin_stream = g_subprocess_get_stdin_pipe (subprocess: proc);
1677
1678 g_output_stream_write_all (stream: stdin_stream, buffer: test_data, count: strlen (s: test_data), NULL, NULL, error);
1679 g_assert_no_error (local_error);
1680
1681 g_output_stream_close (stream: stdin_stream, NULL, error);
1682 g_assert_no_error (local_error);
1683
1684 g_subprocess_wait_check (subprocess: proc, NULL, error);
1685
1686 g_object_unref (object: launcher);
1687 g_object_unref (object: proc);
1688
1689 g_file_load_contents (file: tmpfile, NULL, contents: &tmp_contents, NULL, NULL, error);
1690 g_assert_no_error (local_error);
1691
1692 g_assert_cmpstr (test_data, ==, tmp_contents);
1693 g_free (mem: tmp_contents);
1694
1695 (void) g_file_delete (file: tmpfile, NULL, NULL);
1696 g_object_unref (object: tmpfile);
1697}
1698
1699static void
1700test_pass_fd (void)
1701{
1702 GError *local_error = NULL;
1703 GError **error = &local_error;
1704 GInputStream *child_input;
1705 GDataInputStream *child_datainput;
1706 GSubprocessLauncher *launcher;
1707 GSubprocess *proc;
1708 GPtrArray *args;
1709 int basic_pipefds[2];
1710 int needdup_pipefds[2];
1711 char *buf;
1712 gsize len;
1713 char *basic_fd_str;
1714 char *needdup_fd_str;
1715
1716 g_unix_open_pipe (fds: basic_pipefds, FD_CLOEXEC, error);
1717 g_assert_no_error (local_error);
1718 g_unix_open_pipe (fds: needdup_pipefds, FD_CLOEXEC, error);
1719 g_assert_no_error (local_error);
1720
1721 basic_fd_str = g_strdup_printf (format: "%d", basic_pipefds[1]);
1722 needdup_fd_str = g_strdup_printf (format: "%d", needdup_pipefds[1] + 1);
1723
1724 args = get_test_subprocess_args (mode: "write-to-fds", basic_fd_str, needdup_fd_str, NULL);
1725 launcher = g_subprocess_launcher_new (flags: G_SUBPROCESS_FLAGS_NONE);
1726 g_subprocess_launcher_take_fd (self: launcher, source_fd: basic_pipefds[1], target_fd: basic_pipefds[1]);
1727 g_subprocess_launcher_take_fd (self: launcher, source_fd: needdup_pipefds[1], target_fd: needdup_pipefds[1] + 1);
1728 proc = g_subprocess_launcher_spawnv (self: launcher, argv: (const gchar * const *) args->pdata, error);
1729 g_ptr_array_free (array: args, TRUE);
1730 g_assert_no_error (local_error);
1731
1732 g_free (mem: basic_fd_str);
1733 g_free (mem: needdup_fd_str);
1734
1735 child_input = g_unix_input_stream_new (fd: basic_pipefds[0], TRUE);
1736 child_datainput = g_data_input_stream_new (base_stream: child_input);
1737 buf = g_data_input_stream_read_line_utf8 (stream: child_datainput, length: &len, NULL, error);
1738 g_assert_no_error (local_error);
1739 g_assert_cmpstr (buf, ==, "hello world");
1740 g_object_unref (object: child_datainput);
1741 g_object_unref (object: child_input);
1742 g_free (mem: buf);
1743
1744 child_input = g_unix_input_stream_new (fd: needdup_pipefds[0], TRUE);
1745 child_datainput = g_data_input_stream_new (base_stream: child_input);
1746 buf = g_data_input_stream_read_line_utf8 (stream: child_datainput, length: &len, NULL, error);
1747 g_assert_no_error (local_error);
1748 g_assert_cmpstr (buf, ==, "hello world");
1749 g_free (mem: buf);
1750 g_object_unref (object: child_datainput);
1751 g_object_unref (object: child_input);
1752
1753 g_object_unref (object: launcher);
1754 g_object_unref (object: proc);
1755}
1756
1757#endif
1758
1759static void
1760test_launcher_environment (void)
1761{
1762 GSubprocessLauncher *launcher;
1763 GError *error = NULL;
1764 GSubprocess *proc;
1765 GPtrArray *args;
1766 gchar *out;
1767
1768 g_setenv (variable: "A", value: "B", TRUE);
1769 g_setenv (variable: "C", value: "D", TRUE);
1770
1771 launcher = g_subprocess_launcher_new (flags: G_SUBPROCESS_FLAGS_STDOUT_PIPE);
1772
1773 /* unset a variable */
1774 g_subprocess_launcher_unsetenv (self: launcher, variable: "A");
1775
1776 /* and set a different one */
1777 g_subprocess_launcher_setenv (self: launcher, variable: "E", value: "F", TRUE);
1778
1779 args = get_test_subprocess_args (mode: "printenv", "A", "C", "E", NULL);
1780 proc = g_subprocess_launcher_spawnv (self: launcher, argv: (const gchar **) args->pdata, error: &error);
1781 g_assert_no_error (error);
1782 g_assert_nonnull (proc);
1783
1784 g_subprocess_communicate_utf8 (subprocess: proc, NULL, NULL, stdout_buf: &out, NULL, error: &error);
1785 g_assert_no_error (error);
1786
1787 g_assert_cmpstr (out, ==, "C=D" LINEEND "E=F" LINEEND);
1788 g_free (mem: out);
1789
1790 g_object_unref (object: proc);
1791 g_object_unref (object: launcher);
1792 g_ptr_array_unref (array: args);
1793}
1794
1795int
1796main (int argc, char **argv)
1797{
1798 const struct
1799 {
1800 const gchar *subtest;
1801 GSubprocessFlags flags;
1802 }
1803 flags_vectors[] =
1804 {
1805 { "", G_SUBPROCESS_FLAGS_STDOUT_PIPE | G_SUBPROCESS_FLAGS_STDERR_MERGE },
1806 { "/no-pipes", G_SUBPROCESS_FLAGS_NONE },
1807 { "/separate-stderr", G_SUBPROCESS_FLAGS_STDOUT_PIPE | G_SUBPROCESS_FLAGS_STDERR_PIPE },
1808 { "/stdout-only", G_SUBPROCESS_FLAGS_STDOUT_PIPE },
1809 { "/stderr-only", G_SUBPROCESS_FLAGS_STDERR_PIPE },
1810 { "/stdout-silence", G_SUBPROCESS_FLAGS_STDOUT_SILENCE },
1811 };
1812 gsize i;
1813
1814 g_test_init (argc: &argc, argv: &argv, NULL);
1815 g_test_bug_base (uri_pattern: "https://bugzilla.gnome.org/");
1816
1817 g_test_add_func (testpath: "/gsubprocess/noop", test_func: test_noop);
1818 g_test_add_func (testpath: "/gsubprocess/noop-all-to-null", test_func: test_noop_all_to_null);
1819 g_test_add_func (testpath: "/gsubprocess/noop-no-wait", test_func: test_noop_no_wait);
1820 g_test_add_func (testpath: "/gsubprocess/noop-stdin-inherit", test_func: test_noop_stdin_inherit);
1821#ifdef G_OS_UNIX
1822 g_test_add_func (testpath: "/gsubprocess/search-path", test_func: test_search_path);
1823 g_test_add_func (testpath: "/gsubprocess/signal", test_func: test_signal);
1824#endif
1825 g_test_add_func (testpath: "/gsubprocess/exit1", test_func: test_exit1);
1826 g_test_add_func (testpath: "/gsubprocess/exit1/cancel", test_func: test_exit1_cancel);
1827 g_test_add_func (testpath: "/gsubprocess/exit1/cancel_in_cb", test_func: test_exit1_cancel_in_cb);
1828 g_test_add_func (testpath: "/gsubprocess/echo1", test_func: test_echo1);
1829#ifdef G_OS_UNIX
1830 g_test_add_func (testpath: "/gsubprocess/echo-merged", test_func: test_echo_merged);
1831#endif
1832 g_test_add_func (testpath: "/gsubprocess/cat-utf8", test_func: test_cat_utf8);
1833 g_test_add_func (testpath: "/gsubprocess/cat-eof", test_func: test_cat_eof);
1834 g_test_add_func (testpath: "/gsubprocess/multi1", test_func: test_multi_1);
1835
1836 /* Add various tests for g_subprocess_communicate() with different flags. */
1837 for (i = 0; i < G_N_ELEMENTS (flags_vectors); i++)
1838 {
1839 gchar *test_path = NULL;
1840
1841 test_path = g_strdup_printf (format: "/gsubprocess/communicate%s", flags_vectors[i].subtest);
1842 g_test_add_data_func (testpath: test_path, GINT_TO_POINTER (flags_vectors[i].flags),
1843 test_func: test_communicate);
1844 g_free (mem: test_path);
1845
1846 test_path = g_strdup_printf (format: "/gsubprocess/communicate/cancelled%s", flags_vectors[i].subtest);
1847 g_test_add_data_func (testpath: test_path, GINT_TO_POINTER (flags_vectors[i].flags),
1848 test_func: test_communicate_cancelled);
1849 g_free (mem: test_path);
1850
1851 test_path = g_strdup_printf (format: "/gsubprocess/communicate/async%s", flags_vectors[i].subtest);
1852 g_test_add_data_func (testpath: test_path, GINT_TO_POINTER (flags_vectors[i].flags),
1853 test_func: test_communicate_async);
1854 g_free (mem: test_path);
1855
1856 test_path = g_strdup_printf (format: "/gsubprocess/communicate/async/cancelled%s", flags_vectors[i].subtest);
1857 g_test_add_data_func (testpath: test_path, GINT_TO_POINTER (flags_vectors[i].flags),
1858 test_func: test_communicate_cancelled_async);
1859 g_free (mem: test_path);
1860
1861 test_path = g_strdup_printf (format: "/gsubprocess/communicate/utf8%s", flags_vectors[i].subtest);
1862 g_test_add_data_func (testpath: test_path, GINT_TO_POINTER (flags_vectors[i].flags),
1863 test_func: test_communicate_utf8);
1864 g_free (mem: test_path);
1865
1866 test_path = g_strdup_printf (format: "/gsubprocess/communicate/utf8/cancelled%s", flags_vectors[i].subtest);
1867 g_test_add_data_func (testpath: test_path, GINT_TO_POINTER (flags_vectors[i].flags),
1868 test_func: test_communicate_utf8_cancelled);
1869 g_free (mem: test_path);
1870
1871 test_path = g_strdup_printf (format: "/gsubprocess/communicate/utf8/async%s", flags_vectors[i].subtest);
1872 g_test_add_data_func (testpath: test_path, GINT_TO_POINTER (flags_vectors[i].flags),
1873 test_func: test_communicate_utf8_async);
1874 g_free (mem: test_path);
1875
1876 test_path = g_strdup_printf (format: "/gsubprocess/communicate/utf8/async/cancelled%s", flags_vectors[i].subtest);
1877 g_test_add_data_func (testpath: test_path, GINT_TO_POINTER (flags_vectors[i].flags),
1878 test_func: test_communicate_utf8_cancelled_async);
1879 g_free (mem: test_path);
1880 }
1881
1882 g_test_add_func (testpath: "/gsubprocess/communicate/utf8/async/invalid", test_func: test_communicate_utf8_async_invalid);
1883 g_test_add_func (testpath: "/gsubprocess/communicate/utf8/invalid", test_func: test_communicate_utf8_invalid);
1884 g_test_add_func (testpath: "/gsubprocess/communicate/nothing", test_func: test_communicate_nothing);
1885 g_test_add_func (testpath: "/gsubprocess/terminate", test_func: test_terminate);
1886 g_test_add_func (testpath: "/gsubprocess/env", test_func: test_env);
1887 g_test_add_func (testpath: "/gsubprocess/env/inherit", test_func: test_env_inherit);
1888 g_test_add_func (testpath: "/gsubprocess/cwd", test_func: test_cwd);
1889#ifdef G_OS_UNIX
1890 g_test_add_func (testpath: "/gsubprocess/launcher-close", test_func: test_subprocess_launcher_close);
1891 g_test_add_func (testpath: "/gsubprocess/stdout-file", test_func: test_stdout_file);
1892 g_test_add_func (testpath: "/gsubprocess/stdout-fd", test_func: test_stdout_fd);
1893 g_test_add_func (testpath: "/gsubprocess/child-setup", test_func: test_child_setup);
1894 g_test_add_func (testpath: "/gsubprocess/pass-fd", test_func: test_pass_fd);
1895#endif
1896 g_test_add_func (testpath: "/gsubprocess/launcher-environment", test_func: test_launcher_environment);
1897
1898 return g_test_run ();
1899}
1900

source code of gtk/subprojects/glib/gio/tests/gsubprocess.c