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
49static void fatal_error (int, const char *, int) ATTRIBUTE_NORETURN;
50void writeout_test (int, const char *);
51void run_replaces (char *);
52void hook_char_replace (char *, size_t, char, char);
53int run_tests (const char **);
54void 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
69const 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
114static void
115fatal_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
127void
128hook_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
141void
142run_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
152void
153writeout_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
184void
185erase_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
199int
200run_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
272int
273main(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