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#ifdef HAVE_STDLIB_H
38#include <stdlib.h>
39#endif
40#ifdef HAVE_STRING_H
41#include <string.h>
42#endif
43
44#ifndef EXIT_SUCCESS
45#define EXIT_SUCCESS 0
46#endif
47
48#ifndef EXIT_FAILURE
49#define EXIT_FAILURE 1
50#endif
51
52static void fatal_error (int, const char *, int) ATTRIBUTE_NORETURN;
53void writeout_test (int, const char *);
54void run_replaces (char *);
55void hook_char_replace (char *, size_t, char, char);
56int run_tests (const char **);
57void erase_test (int);
58
59/* Test input data, argv before, and argv after:
60
61   The \n is an important part of test_data since expandargv
62   may have to work in environments where \n is translated
63   as \r\n. Thus \n is included in the test data for the file.
64
65   We use \b to indicate that the test data is the null character.
66   This is because we use \0 normally to represent the end of the
67   file data, so we need something else for this. */
68
69#define FILENAME_PATTERN "test-expandargv-%d.lst"
70#define ARGV0 "test-expandargv"
71
72const char *test_data[] = {
73  /* Test 0 - Check for expansion with \r\n */
74  "a\r\nb",	/* Test 0 data */
75  ARGV0,
76  "@test-expandargv-0.lst",
77  0, /* End of argv[] before expansion */
78  ARGV0,
79  "a",
80  "b",
81  0, /* End of argv[] after expansion */
82
83  /* Test 1 - Check for expansion with \n */
84  "a\nb",	/* Test 1 data */
85  ARGV0,
86  "@test-expandargv-1.lst",
87  0,
88  ARGV0,
89  "a",
90  "b",
91  0,
92
93  /* Test 2 - Check for expansion with \0 */
94  "a\bb",	/* Test 2 data */
95  ARGV0,
96  "@test-expandargv-2.lst",
97  0,
98  ARGV0,
99  "a",
100  0,
101
102  /* Test 3 - Check for expansion with only \0 */
103  "\b",		/* Test 3 data */
104  ARGV0,
105  "@test-expandargv-3.lst",
106  0,
107  ARGV0,
108  0,
109
110  0 /* Test done marker, don't remove. */
111};
112
113/* Print a fatal error and exit.  LINE is the line number where we
114   detected the error, ERRMSG is the error message to print, and ERR
115   is 0 or an errno value to print.  */
116
117static void
118fatal_error (int line, const char *errmsg, int err)
119{
120  fprintf (stderr, "test-expandargv:%d: %s", line, errmsg);
121  if (errno != 0)
122    fprintf (stderr, ": %s", xstrerror (err));
123  fprintf (stderr, "\n");
124  exit (EXIT_FAILURE);
125}
126
127/* hook_char_replace:
128     Replace 'replacethis' with 'withthis' */
129
130void
131hook_char_replace (char *string, size_t len, char replacethis, char withthis)
132{
133  int i = 0;
134  for (i = 0; i < len; i++)
135    if (string[i] == replacethis)
136      string[i] = withthis;
137}
138
139/* run_replaces:
140     Hook here all the character for character replaces.
141     Be warned that expanding the string or contracting the string
142     should be handled with care. */
143
144void
145run_replaces (char * string)
146{
147  /* Store original string size */
148  size_t len = strlen (string);
149  hook_char_replace (string, len, '\b', '\0');
150}
151
152/* write_test:
153   Write test datafile */
154
155void
156writeout_test (int test, const char * test_data)
157{
158  char filename[256];
159  FILE *fd;
160  size_t len;
161  char * parse;
162
163  /* Unique filename per test */
164  sprintf (filename, FILENAME_PATTERN, test);
165  fd = fopen (filename, "w");
166  if (fd == NULL)
167    fatal_error (__LINE__, "Failed to create test file.", errno);
168
169  /* Generate RW copy of data for replaces */
170  len = strlen (test_data);
171  parse = malloc (sizeof (char) * (len + 1));
172  if (parse == NULL)
173    fatal_error (__LINE__, "Failed to malloc parse.", errno);
174
175  memcpy (parse, test_data, sizeof (char) * len);
176  /* Run all possible replaces */
177  run_replaces (parse);
178
179  fwrite (parse, len, sizeof (char), fd);
180  free (parse);
181  fclose (fd);
182}
183
184/* erase_test:
185     Erase the test file */
186
187void
188erase_test (int test)
189{
190  char filename[256];
191  sprintf (filename, FILENAME_PATTERN, test);
192  if (unlink (filename) != 0)
193    fatal_error (__LINE__, "Failed to erase test file.", errno);
194}
195
196
197/* run_tests:
198    Run expandargv
199    Compare argv before and after.
200    Return number of fails */
201
202int
203run_tests (const char **test_data)
204{
205  int argc_after, argc_before;
206  char ** argv_before, ** argv_after;
207  int i, j, k, fails, failed;
208
209  i = j = fails = 0;
210  /* Loop over all the tests */
211  while (test_data[j])
212    {
213      /* Write test data */
214      writeout_test (i, test_data[j++]);
215      /* Copy argv before */
216      argv_before = dupargv ((char **) &test_data[j]);
217
218      /* Count argc before/after */
219      argc_before = 0;
220      argc_after = 0;
221      while (test_data[j + argc_before])
222        argc_before++;
223      j += argc_before + 1; /* Skip null */
224      while (test_data[j + argc_after])
225        argc_after++;
226
227      /* Copy argv after */
228      argv_after = dupargv ((char **) &test_data[j]);
229
230      /* Run all possible replaces */
231      for (k = 0; k < argc_before; k++)
232        run_replaces (argv_before[k]);
233      for (k = 0; k < argc_after; k++)
234        run_replaces (argv_after[k]);
235
236      /* Run test: Expand arguments */
237      expandargv (&argc_before, &argv_before);
238
239      failed = 0;
240      /* Compare size first */
241      if (argc_before != argc_after)
242        {
243          printf ("FAIL: test-expandargv-%d. Number of arguments don't match.\n", i);
244	  failed++;
245        }
246      /* Compare each of the argv's ... */
247      else
248        for (k = 0; k < argc_after; k++)
249          if (strncmp (argv_before[k], argv_after[k], strlen(argv_after[k])) != 0)
250            {
251              printf ("FAIL: test-expandargv-%d. Arguments don't match.\n", i);
252              failed++;
253            }
254
255      if (!failed)
256        printf ("PASS: test-expandargv-%d.\n", i);
257      else
258        fails++;
259
260      freeargv (argv_before);
261      freeargv (argv_after);
262      /* Advance to next test */
263      j += argc_after + 1;
264      /* Erase test file */
265      erase_test (i);
266      i++;
267    }
268  return fails;
269}
270
271/* main:
272    Run tests.
273    Check result and exit with appropriate code. */
274
275int
276main(int argc, char **argv)
277{
278  int fails;
279  /* Repeat for all the tests:
280     - Parse data array and write into file.
281       - Run replace hooks before writing to file.
282     - Parse data array and build argv before/after.
283       - Run replace hooks on argv before/after
284     - Run expandargv.
285     - Compare output of expandargv argv to after argv.
286       - If they compare the same then test passes
287         else the test fails.
288     - Erase test file. */
289
290  fails = run_tests (test_data);
291  if (!fails)
292    exit (EXIT_SUCCESS);
293  else
294    exit (EXIT_FAILURE);
295}
296
297