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