Fix typo in variable name in gen-locale.sh.
[glibc.git] / support / tst-support_capture_subprocess.c
blob5672fba0f7f4d94c2eebe05d659dc1f25b6b55c0
1 /* Test capturing output from a subprocess.
2 Copyright (C) 2017 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, see
17 <http://www.gnu.org/licenses/>. */
19 #include <stdbool.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <support/capture_subprocess.h>
24 #include <support/check.h>
25 #include <support/support.h>
26 #include <sys/wait.h>
27 #include <unistd.h>
29 /* Write one byte at *P to FD and advance *P. Do nothing if *P is
30 '\0'. */
31 static void
32 transfer (const unsigned char **p, int fd)
34 if (**p != '\0')
36 TEST_VERIFY (write (fd, *p, 1) == 1);
37 ++*p;
41 /* Determine the order in which stdout and stderr are written. */
42 enum write_mode { out_first, err_first, interleave,
43 write_mode_last = interleave };
45 /* Describe what to write in the subprocess. */
46 struct test
48 char *out;
49 char *err;
50 enum write_mode write_mode;
51 int signal;
52 int status;
55 /* For use with support_capture_subprocess. */
56 static void
57 callback (void *closure)
59 const struct test *test = closure;
60 bool mode_ok = false;
61 switch (test->write_mode)
63 case out_first:
64 TEST_VERIFY (fputs (test->out, stdout) >= 0);
65 TEST_VERIFY (fflush (stdout) == 0);
66 TEST_VERIFY (fputs (test->err, stderr) >= 0);
67 TEST_VERIFY (fflush (stderr) == 0);
68 mode_ok = true;
69 break;
70 case err_first:
71 TEST_VERIFY (fputs (test->err, stderr) >= 0);
72 TEST_VERIFY (fflush (stderr) == 0);
73 TEST_VERIFY (fputs (test->out, stdout) >= 0);
74 TEST_VERIFY (fflush (stdout) == 0);
75 mode_ok = true;
76 break;
77 case interleave:
79 const unsigned char *pout = (const unsigned char *) test->out;
80 const unsigned char *perr = (const unsigned char *) test->err;
83 transfer (&pout, STDOUT_FILENO);
84 transfer (&perr, STDERR_FILENO);
86 while (*pout != '\0' || *perr != '\0');
88 mode_ok = true;
89 break;
91 TEST_VERIFY (mode_ok);
93 if (test->signal != 0)
94 raise (test->signal);
95 exit (test->status);
98 /* Create a heap-allocated random string of letters. */
99 static char *
100 random_string (size_t length)
102 char *result = xmalloc (length + 1);
103 for (size_t i = 0; i < length; ++i)
104 result[i] = 'a' + (rand () % 26);
105 result[length] = '\0';
106 return result;
109 /* Check that the specific stream from the captured subprocess matches
110 expectations. */
111 static void
112 check_stream (const char *what, const struct xmemstream *stream,
113 const char *expected)
115 if (strcmp (stream->buffer, expected) != 0)
117 support_record_failure ();
118 printf ("error: captured %s data incorrect\n"
119 " expected: %s\n"
120 " actual: %s\n",
121 what, expected, stream->buffer);
123 if (stream->length != strlen (expected))
125 support_record_failure ();
126 printf ("error: captured %s data length incorrect\n"
127 " expected: %zu\n"
128 " actual: %zu\n",
129 what, strlen (expected), stream->length);
133 static int
134 do_test (void)
136 const int lengths[] = {0, 1, 17, 512, 20000, -1};
138 /* Test multiple combinations of support_capture_subprocess.
140 length_idx_stdout: Index into the lengths array above,
141 controls how many bytes are written by the subprocess to
142 standard output.
143 length_idx_stderr: Same for standard error.
144 write_mode: How standard output and standard error writes are
145 ordered.
146 signal: Exit with no signal if zero, with SIGTERM if one.
147 status: Process exit status: 0 if zero, 3 if one. */
148 for (int length_idx_stdout = 0; lengths[length_idx_stdout] >= 0;
149 ++length_idx_stdout)
150 for (int length_idx_stderr = 0; lengths[length_idx_stderr] >= 0;
151 ++length_idx_stderr)
152 for (int write_mode = 0; write_mode < write_mode_last; ++write_mode)
153 for (int signal = 0; signal < 2; ++signal)
154 for (int status = 0; status < 2; ++status)
156 struct test test =
158 .out = random_string (lengths[length_idx_stdout]),
159 .err = random_string (lengths[length_idx_stderr]),
160 .write_mode = write_mode,
161 .signal = signal * SIGTERM, /* 0 or SIGTERM. */
162 .status = status * 3, /* 0 or 3. */
164 TEST_VERIFY (strlen (test.out) == lengths[length_idx_stdout]);
165 TEST_VERIFY (strlen (test.err) == lengths[length_idx_stderr]);
167 struct support_capture_subprocess result
168 = support_capture_subprocess (callback, &test);
169 check_stream ("stdout", &result.out, test.out);
170 check_stream ("stderr", &result.err, test.err);
171 if (test.signal != 0)
173 TEST_VERIFY (WIFSIGNALED (result.status));
174 TEST_VERIFY (WTERMSIG (result.status) == test.signal);
176 else
178 TEST_VERIFY (WIFEXITED (result.status));
179 TEST_VERIFY (WEXITSTATUS (result.status) == test.status);
181 support_capture_subprocess_free (&result);
182 free (test.out);
183 free (test.err);
185 return 0;
188 #include <support/test-driver.c>