test-expandargv.c revision 1.10 1 1.1 christos /* expandargv test program,
2 1.10 christos Copyright (C) 2006-2024 Free Software Foundation, Inc.
3 1.1 christos Written by Carlos O'Donell <carlos (at) codesourcery.com>
4 1.1 christos
5 1.1 christos This file is part of the libiberty library, which is part of GCC.
6 1.1 christos
7 1.1 christos This file is free software; you can redistribute it and/or modify
8 1.1 christos it under the terms of the GNU General Public License as published by
9 1.1 christos the Free Software Foundation; either version 2 of the License, or
10 1.1 christos (at your option) any later version.
11 1.1 christos
12 1.1 christos In addition to the permissions in the GNU General Public License, the
13 1.1 christos Free Software Foundation gives you unlimited permission to link the
14 1.1 christos compiled version of this file into combinations with other programs,
15 1.1 christos and to distribute those combinations without any restriction coming
16 1.1 christos from the use of this file. (The General Public License restrictions
17 1.1 christos do apply in other respects; for example, they cover modification of
18 1.1 christos the file, and distribution when not linked into a combined
19 1.1 christos executable.)
20 1.1 christos
21 1.1 christos This program is distributed in the hope that it will be useful,
22 1.1 christos but WITHOUT ANY WARRANTY; without even the implied warranty of
23 1.1 christos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 1.1 christos GNU General Public License for more details.
25 1.1 christos
26 1.1 christos You should have received a copy of the GNU General Public License
27 1.1 christos along with this program; if not, write to the Free Software
28 1.1 christos Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
29 1.1 christos */
30 1.1 christos
31 1.1 christos #ifdef HAVE_CONFIG_H
32 1.1 christos #include "config.h"
33 1.1 christos #endif
34 1.1 christos #include "libiberty.h"
35 1.1 christos #include <stdio.h>
36 1.1 christos #include <errno.h>
37 1.1 christos #ifdef HAVE_STDLIB_H
38 1.1 christos #include <stdlib.h>
39 1.1 christos #endif
40 1.1 christos #ifdef HAVE_STRING_H
41 1.1 christos #include <string.h>
42 1.1 christos #endif
43 1.1 christos #ifdef HAVE_UNISTD_H
44 1.1 christos #include <unistd.h>
45 1.1 christos #endif
46 1.1 christos
47 1.1 christos #ifndef EXIT_SUCCESS
48 1.1 christos #define EXIT_SUCCESS 0
49 1.1 christos #endif
50 1.1 christos
51 1.1 christos #ifndef EXIT_FAILURE
52 1.1 christos #define EXIT_FAILURE 1
53 1.1 christos #endif
54 1.1 christos
55 1.1 christos static void fatal_error (int, const char *, int) ATTRIBUTE_NORETURN;
56 1.1 christos void writeout_test (int, const char *);
57 1.1 christos void run_replaces (char *);
58 1.1 christos void hook_char_replace (char *, size_t, char, char);
59 1.1 christos int run_tests (const char **);
60 1.1 christos void erase_test (int);
61 1.1 christos
62 1.1 christos /* Test input data, argv before, and argv after:
63 1.1 christos
64 1.1 christos The \n is an important part of test_data since expandargv
65 1.1 christos may have to work in environments where \n is translated
66 1.1 christos as \r\n. Thus \n is included in the test data for the file.
67 1.1 christos
68 1.1 christos We use \b to indicate that the test data is the null character.
69 1.1 christos This is because we use \0 normally to represent the end of the
70 1.1 christos file data, so we need something else for this. */
71 1.1 christos
72 1.1 christos #define FILENAME_PATTERN "test-expandargv-%d.lst"
73 1.1 christos #define ARGV0 "test-expandargv"
74 1.1 christos
75 1.1 christos const char *test_data[] = {
76 1.1 christos /* Test 0 - Check for expansion with \r\n */
77 1.1 christos "a\r\nb", /* Test 0 data */
78 1.1 christos ARGV0,
79 1.1 christos "@test-expandargv-0.lst",
80 1.1 christos 0, /* End of argv[] before expansion */
81 1.1 christos ARGV0,
82 1.1 christos "a",
83 1.1 christos "b",
84 1.1 christos 0, /* End of argv[] after expansion */
85 1.1 christos
86 1.1 christos /* Test 1 - Check for expansion with \n */
87 1.1 christos "a\nb", /* Test 1 data */
88 1.1 christos ARGV0,
89 1.1 christos "@test-expandargv-1.lst",
90 1.1 christos 0,
91 1.1 christos ARGV0,
92 1.1 christos "a",
93 1.1 christos "b",
94 1.1 christos 0,
95 1.1 christos
96 1.1 christos /* Test 2 - Check for expansion with \0 */
97 1.1 christos "a\bb", /* Test 2 data */
98 1.1 christos ARGV0,
99 1.1 christos "@test-expandargv-2.lst",
100 1.1 christos 0,
101 1.1 christos ARGV0,
102 1.1 christos "a",
103 1.1 christos 0,
104 1.1 christos
105 1.1 christos /* Test 3 - Check for expansion with only \0 */
106 1.1 christos "\b", /* Test 3 data */
107 1.1 christos ARGV0,
108 1.1 christos "@test-expandargv-3.lst",
109 1.1 christos 0,
110 1.1 christos ARGV0,
111 1.1 christos 0,
112 1.1 christos
113 1.1 christos /* Test 4 - Check for options beginning with an empty line. */
114 1.1 christos "\na\nb", /* Test 4 data */
115 1.1 christos ARGV0,
116 1.1 christos "@test-expandargv-4.lst",
117 1.1 christos 0,
118 1.1 christos ARGV0,
119 1.1 christos "a",
120 1.1 christos "b",
121 1.1 christos 0,
122 1.1 christos
123 1.1 christos /* Test 5 - Check for options containing an empty argument. */
124 1.1 christos "a\n''\nb", /* Test 5 data */
125 1.1 christos ARGV0,
126 1.1 christos "@test-expandargv-5.lst",
127 1.1 christos 0,
128 1.1 christos ARGV0,
129 1.1 christos "a",
130 1.1 christos "",
131 1.1 christos "b",
132 1.1 christos 0,
133 1.1 christos
134 1.1 christos /* Test 6 - Check for options containing a quoted newline. */
135 1.1 christos "a\n'a\n\nb'\nb", /* Test 6 data */
136 1.1 christos ARGV0,
137 1.1 christos "@test-expandargv-6.lst",
138 1.1 christos 0,
139 1.1 christos ARGV0,
140 1.1 christos "a",
141 1.1 christos "a\n\nb",
142 1.1 christos "b",
143 1.1 christos 0,
144 1.1 christos
145 1.1 christos 0 /* Test done marker, don't remove. */
146 1.1 christos };
147 1.1 christos
148 1.1 christos /* Print a fatal error and exit. LINE is the line number where we
149 1.1 christos detected the error, ERRMSG is the error message to print, and ERR
150 1.1 christos is 0 or an errno value to print. */
151 1.1 christos
152 1.1 christos static void
153 1.1 christos fatal_error (int line, const char *errmsg, int err)
154 1.1 christos {
155 1.1 christos fprintf (stderr, "test-expandargv:%d: %s", line, errmsg);
156 1.1 christos if (errno != 0)
157 1.1 christos fprintf (stderr, ": %s", xstrerror (err));
158 1.1 christos fprintf (stderr, "\n");
159 1.1 christos exit (EXIT_FAILURE);
160 1.1 christos }
161 1.1 christos
162 1.1 christos /* hook_char_replace:
163 1.1 christos Replace 'replacethis' with 'withthis' */
164 1.1 christos
165 1.1 christos void
166 1.1 christos hook_char_replace (char *string, size_t len, char replacethis, char withthis)
167 1.1 christos {
168 1.1 christos int i = 0;
169 1.1 christos for (i = 0; i < len; i++)
170 1.1 christos if (string[i] == replacethis)
171 1.1 christos string[i] = withthis;
172 1.1 christos }
173 1.1 christos
174 1.1 christos /* run_replaces:
175 1.1 christos Hook here all the character for character replaces.
176 1.1 christos Be warned that expanding the string or contracting the string
177 1.1 christos should be handled with care. */
178 1.1 christos
179 1.1 christos void
180 1.1 christos run_replaces (char * string)
181 1.1 christos {
182 1.1 christos /* Store original string size */
183 1.1 christos size_t len = strlen (string);
184 1.1 christos hook_char_replace (string, len, '\b', '\0');
185 1.1 christos }
186 1.1 christos
187 1.1 christos /* write_test:
188 1.1 christos Write test datafile */
189 1.1 christos
190 1.1 christos void
191 1.1 christos writeout_test (int test, const char * test_data)
192 1.1 christos {
193 1.1 christos char filename[256];
194 1.1 christos FILE *fd;
195 1.1 christos size_t len, sys_fwrite;
196 1.1 christos char * parse;
197 1.1 christos
198 1.1 christos /* Unique filename per test */
199 1.1 christos sprintf (filename, FILENAME_PATTERN, test);
200 1.1 christos fd = fopen (filename, "w");
201 1.1 christos if (fd == NULL)
202 1.1 christos fatal_error (__LINE__, "Failed to create test file.", errno);
203 1.1 christos
204 1.1 christos /* Generate RW copy of data for replaces */
205 1.1 christos len = strlen (test_data);
206 1.1 christos parse = malloc (sizeof (char) * (len + 1));
207 1.1 christos if (parse == NULL)
208 1.1 christos fatal_error (__LINE__, "Failed to malloc parse.", errno);
209 1.1 christos
210 1.1 christos memcpy (parse, test_data, sizeof (char) * (len + 1));
211 1.1 christos /* Run all possible replaces */
212 1.1 christos run_replaces (parse);
213 1.1 christos
214 1.1 christos sys_fwrite = fwrite (parse, sizeof (char), len, fd);
215 1.1 christos if (sys_fwrite != len)
216 1.1 christos fatal_error (__LINE__, "Failed to write to test file.", errno);
217 1.1 christos
218 1.1 christos free (parse);
219 1.1 christos fclose (fd);
220 1.1 christos }
221 1.1 christos
222 1.1 christos /* erase_test:
223 1.1 christos Erase the test file */
224 1.1 christos
225 1.1 christos void
226 1.1 christos erase_test (int test)
227 1.1 christos {
228 1.1 christos char filename[256];
229 1.1 christos sprintf (filename, FILENAME_PATTERN, test);
230 1.1 christos if (unlink (filename) != 0)
231 1.1 christos fatal_error (__LINE__, "Failed to erase test file.", errno);
232 1.1 christos }
233 1.1 christos
234 1.1 christos
235 1.1 christos /* run_tests:
236 1.1 christos Run expandargv
237 1.1 christos Compare argv before and after.
238 1.1 christos Return number of fails */
239 1.1 christos
240 1.1 christos int
241 1.1 christos run_tests (const char **test_data)
242 1.1 christos {
243 1.1 christos int argc_after, argc_before;
244 1.1 christos char ** argv_before, ** argv_after;
245 1.1 christos int i, j, k, fails, failed;
246 1.1 christos
247 1.1 christos i = j = fails = 0;
248 1.1 christos /* Loop over all the tests */
249 1.1 christos while (test_data[j])
250 1.1 christos {
251 1.1 christos /* Write test data */
252 1.1 christos writeout_test (i, test_data[j++]);
253 1.1 christos /* Copy argv before */
254 1.1 christos argv_before = dupargv ((char **) &test_data[j]);
255 1.1 christos
256 1.1 christos /* Count argc before/after */
257 1.1 christos argc_before = 0;
258 1.1 christos argc_after = 0;
259 1.1 christos while (test_data[j + argc_before])
260 1.1 christos argc_before++;
261 1.1 christos j += argc_before + 1; /* Skip null */
262 1.1 christos while (test_data[j + argc_after])
263 1.1 christos argc_after++;
264 1.1 christos
265 1.1 christos /* Copy argv after */
266 1.1 christos argv_after = dupargv ((char **) &test_data[j]);
267 1.1 christos
268 1.1 christos /* Run all possible replaces */
269 1.1 christos for (k = 0; k < argc_before; k++)
270 1.1 christos run_replaces (argv_before[k]);
271 1.1 christos for (k = 0; k < argc_after; k++)
272 1.1 christos run_replaces (argv_after[k]);
273 1.1 christos
274 1.1 christos /* Run test: Expand arguments */
275 1.1 christos expandargv (&argc_before, &argv_before);
276 1.1 christos
277 1.1 christos failed = 0;
278 1.1 christos /* Compare size first */
279 1.1 christos if (argc_before != argc_after)
280 1.1 christos {
281 1.1 christos printf ("FAIL: test-expandargv-%d. Number of arguments don't match.\n", i);
282 1.1 christos failed++;
283 1.1 christos }
284 1.1 christos /* Compare each of the argv's ... */
285 1.1 christos else
286 1.1 christos for (k = 0; k < argc_after; k++)
287 1.1 christos if (strcmp (argv_before[k], argv_after[k]) != 0)
288 1.1 christos {
289 1.1 christos printf ("FAIL: test-expandargv-%d. Arguments don't match.\n", i);
290 1.1 christos failed++;
291 1.1 christos }
292 1.1 christos
293 1.1 christos if (!failed)
294 1.1 christos printf ("PASS: test-expandargv-%d.\n", i);
295 1.1 christos else
296 1.1 christos fails++;
297 1.1 christos
298 1.1 christos freeargv (argv_before);
299 1.1 christos freeargv (argv_after);
300 1.1 christos /* Advance to next test */
301 1.1 christos j += argc_after + 1;
302 1.1 christos /* Erase test file */
303 1.1 christos erase_test (i);
304 1.1 christos i++;
305 1.1 christos }
306 1.1 christos return fails;
307 1.1 christos }
308 1.1 christos
309 1.1 christos /* main:
310 1.1 christos Run tests.
311 1.1 christos Check result and exit with appropriate code. */
312 1.1 christos
313 1.1 christos int
314 1.1 christos main(int argc, char **argv)
315 1.1 christos {
316 1.1 christos int fails;
317 1.1 christos /* Repeat for all the tests:
318 1.1 christos - Parse data array and write into file.
319 1.1 christos - Run replace hooks before writing to file.
320 1.1 christos - Parse data array and build argv before/after.
321 1.1 christos - Run replace hooks on argv before/after
322 1.1 christos - Run expandargv.
323 1.1 christos - Compare output of expandargv argv to after argv.
324 1.1 christos - If they compare the same then test passes
325 1.1 christos else the test fails.
326 1.1 christos - Erase test file. */
327 1.1 christos
328 1.1 christos fails = run_tests (test_data);
329 1.1 christos if (!fails)
330 1.1 christos exit (EXIT_SUCCESS);
331 1.1 christos else
332 1.1 christos exit (EXIT_FAILURE);
333 1.1 christos }
334 1.1 christos
335