1178476Sjb/* expandargv test program,
2178476Sjb   Copyright (C) 2006 Free Software Foundation, Inc.
3178476Sjb   Written by Carlos O'Donell <carlos@codesourcery.com>
4178476Sjb
5178476Sjb   This file is part of the libiberty library, which is part of GCC.
6178476Sjb
7178476Sjb   This file is free software; you can redistribute it and/or modify
8178476Sjb   it under the terms of the GNU General Public License as published by
9178476Sjb   the Free Software Foundation; either version 2 of the License, or
10178476Sjb   (at your option) any later version.
11178476Sjb
12178476Sjb   In addition to the permissions in the GNU General Public License, the
13178476Sjb   Free Software Foundation gives you unlimited permission to link the
14178476Sjb   compiled version of this file into combinations with other programs,
15178476Sjb   and to distribute those combinations without any restriction coming
16178476Sjb   from the use of this file.  (The General Public License restrictions
17178476Sjb   do apply in other respects; for example, they cover modification of
18178476Sjb   the file, and distribution when not linked into a combined
19178476Sjb   executable.)
20178476Sjb
21178476Sjb   This program is distributed in the hope that it will be useful,
22178476Sjb   but WITHOUT ANY WARRANTY; without even the implied warranty of
23178476Sjb   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24178476Sjb   GNU General Public License for more details.
25178476Sjb
26178476Sjb   You should have received a copy of the GNU General Public License
27178476Sjb   along with this program; if not, write to the Free Software
28178476Sjb   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
29178476Sjb*/
30178476Sjb
31178476Sjb#ifdef HAVE_CONFIG_H
32178476Sjb#include "config.h"
33178476Sjb#endif
34178476Sjb#include "libiberty.h"
35178476Sjb#include <stdio.h>
36178476Sjb#include <errno.h>
37178476Sjb#ifdef HAVE_STDLIB_H
38178476Sjb#include <stdlib.h>
39178476Sjb#endif
40178476Sjb#ifdef HAVE_STRING_H
41178476Sjb#include <string.h>
42178476Sjb#endif
43178476Sjb
44178476Sjb#ifndef EXIT_SUCCESS
45178476Sjb#define EXIT_SUCCESS 0
46178476Sjb#endif
47178476Sjb
48178476Sjb#ifndef EXIT_FAILURE
49178476Sjb#define EXIT_FAILURE 1
50178476Sjb#endif
51178476Sjb
52178476Sjbstatic void fatal_error (int, const char *, int) ATTRIBUTE_NORETURN;
53178476Sjbvoid writeout_test (int, const char *);
54178476Sjbvoid run_replaces (char *);
55178476Sjbvoid hook_char_replace (char *, size_t, char, char);
56178476Sjbint run_tests (const char **);
57178476Sjbvoid erase_test (int);
58178476Sjb
59178476Sjb/* Test input data, argv before, and argv after:
60178476Sjb
61178476Sjb   The \n is an important part of test_data since expandargv
62178476Sjb   may have to work in environments where \n is translated
63178476Sjb   as \r\n. Thus \n is included in the test data for the file.
64178476Sjb
65178476Sjb   We use \b to indicate that the test data is the null character.
66178476Sjb   This is because we use \0 normally to represent the end of the
67178476Sjb   file data, so we need something else for this. */
68178476Sjb
69178476Sjb#define FILENAME_PATTERN "test-expandargv-%d.lst"
70178476Sjb#define ARGV0 "test-expandargv"
71178476Sjb
72178476Sjbconst char *test_data[] = {
73178476Sjb  /* Test 0 - Check for expansion with \r\n */
74178476Sjb  "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  /* Test 4 - Check for options beginning with an empty line.  */
111  "\na\nb",	/* Test 4 data */
112  ARGV0,
113  "@test-expandargv-4.lst",
114  0,
115  ARGV0,
116  "a",
117  "b",
118  0,
119
120  /* Test 5 - Check for options containing an empty argument.  */
121  "a\n''\nb",    /* Test 5 data */
122  ARGV0,
123  "@test-expandargv-5.lst",
124  0,
125  ARGV0,
126  "a",
127  "",
128  "b",
129  0,
130
131  /* Test 6 - Check for options containing a quoted newline.  */
132  "a\n'a\n\nb'\nb",    /* Test 6 data */
133  ARGV0,
134  "@test-expandargv-6.lst",
135  0,
136  ARGV0,
137  "a",
138  "a\n\nb",
139  "b",
140  0,
141
142  0 /* Test done marker, don't remove. */
143};
144
145/* Print a fatal error and exit.  LINE is the line number where we
146   detected the error, ERRMSG is the error message to print, and ERR
147   is 0 or an errno value to print.  */
148
149static void
150fatal_error (int line, const char *errmsg, int err)
151{
152  fprintf (stderr, "test-expandargv:%d: %s", line, errmsg);
153  if (errno != 0)
154    fprintf (stderr, ": %s", xstrerror (err));
155  fprintf (stderr, "\n");
156  exit (EXIT_FAILURE);
157}
158
159/* hook_char_replace:
160     Replace 'replacethis' with 'withthis' */
161
162void
163hook_char_replace (char *string, size_t len, char replacethis, char withthis)
164{
165  int i = 0;
166  for (i = 0; i < len; i++)
167    if (string[i] == replacethis)
168      string[i] = withthis;
169}
170
171/* run_replaces:
172     Hook here all the character for character replaces.
173     Be warned that expanding the string or contracting the string
174     should be handled with care. */
175
176void
177run_replaces (char * string)
178{
179  /* Store original string size */
180  size_t len = strlen (string);
181  hook_char_replace (string, len, '\b', '\0');
182}
183
184/* write_test:
185   Write test datafile */
186
187void
188writeout_test (int test, const char * test_data)
189{
190  char filename[256];
191  FILE *fd;
192  size_t len;
193  char * parse;
194
195  /* Unique filename per test */
196  sprintf (filename, FILENAME_PATTERN, test);
197  fd = fopen (filename, "w");
198  if (fd == NULL)
199    fatal_error (__LINE__, "Failed to create test file.", errno);
200
201  /* Generate RW copy of data for replaces */
202  len = strlen (test_data);
203  parse = malloc (sizeof (char) * (len + 1));
204  if (parse == NULL)
205    fatal_error (__LINE__, "Failed to malloc parse.", errno);
206
207  memcpy (parse, test_data, sizeof (char) * len);
208  /* Run all possible replaces */
209  run_replaces (parse);
210
211  fwrite (parse, len, sizeof (char), fd);
212  free (parse);
213  fclose (fd);
214}
215
216/* erase_test:
217     Erase the test file */
218
219void
220erase_test (int test)
221{
222  char filename[256];
223  sprintf (filename, FILENAME_PATTERN, test);
224  if (unlink (filename) != 0)
225    fatal_error (__LINE__, "Failed to erase test file.", errno);
226}
227
228
229/* run_tests:
230    Run expandargv
231    Compare argv before and after.
232    Return number of fails */
233
234int
235run_tests (const char **test_data)
236{
237  int argc_after, argc_before;
238  char ** argv_before, ** argv_after;
239  int i, j, k, fails, failed;
240
241  i = j = fails = 0;
242  /* Loop over all the tests */
243  while (test_data[j])
244    {
245      /* Write test data */
246      writeout_test (i, test_data[j++]);
247      /* Copy argv before */
248      argv_before = dupargv ((char **) &test_data[j]);
249
250      /* Count argc before/after */
251      argc_before = 0;
252      argc_after = 0;
253      while (test_data[j + argc_before])
254        argc_before++;
255      j += argc_before + 1; /* Skip null */
256      while (test_data[j + argc_after])
257        argc_after++;
258
259      /* Copy argv after */
260      argv_after = dupargv ((char **) &test_data[j]);
261
262      /* Run all possible replaces */
263      for (k = 0; k < argc_before; k++)
264        run_replaces (argv_before[k]);
265      for (k = 0; k < argc_after; k++)
266        run_replaces (argv_after[k]);
267
268      /* Run test: Expand arguments */
269      expandargv (&argc_before, &argv_before);
270
271      failed = 0;
272      /* Compare size first */
273      if (argc_before != argc_after)
274        {
275          printf ("FAIL: test-expandargv-%d. Number of arguments don't match.\n", i);
276	  failed++;
277        }
278      /* Compare each of the argv's ... */
279      else
280        for (k = 0; k < argc_after; k++)
281          if (strcmp (argv_before[k], argv_after[k]) != 0)
282            {
283              printf ("FAIL: test-expandargv-%d. Arguments don't match.\n", i);
284              failed++;
285            }
286
287      if (!failed)
288        printf ("PASS: test-expandargv-%d.\n", i);
289      else
290        fails++;
291
292      freeargv (argv_before);
293      freeargv (argv_after);
294      /* Advance to next test */
295      j += argc_after + 1;
296      /* Erase test file */
297      erase_test (i);
298      i++;
299    }
300  return fails;
301}
302
303/* main:
304    Run tests.
305    Check result and exit with appropriate code. */
306
307int
308main(int argc, char **argv)
309{
310  int fails;
311  /* Repeat for all the tests:
312     - Parse data array and write into file.
313       - Run replace hooks before writing to file.
314     - Parse data array and build argv before/after.
315       - Run replace hooks on argv before/after
316     - Run expandargv.
317     - Compare output of expandargv argv to after argv.
318       - If they compare the same then test passes
319         else the test fails.
320     - Erase test file. */
321
322  fails = run_tests (test_data);
323  if (!fails)
324    exit (EXIT_SUCCESS);
325  else
326    exit (EXIT_FAILURE);
327}
328
329