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