1169695Skan/* expandargv test program,
2169695Skan   Copyright (C) 2006 Free Software Foundation, Inc.
3169695Skan   Written by Carlos O'Donell <carlos@codesourcery.com>
4169695Skan
5169695Skan   This file is part of the libiberty library, which is part of GCC.
6169695Skan
7169695Skan   This file is free software; you can redistribute it and/or modify
8169695Skan   it under the terms of the GNU General Public License as published by
9169695Skan   the Free Software Foundation; either version 2 of the License, or
10169695Skan   (at your option) any later version.
11169695Skan
12169695Skan   In addition to the permissions in the GNU General Public License, the
13169695Skan   Free Software Foundation gives you unlimited permission to link the
14169695Skan   compiled version of this file into combinations with other programs,
15169695Skan   and to distribute those combinations without any restriction coming
16169695Skan   from the use of this file.  (The General Public License restrictions
17169695Skan   do apply in other respects; for example, they cover modification of
18169695Skan   the file, and distribution when not linked into a combined
19169695Skan   executable.)
20169695Skan
21169695Skan   This program is distributed in the hope that it will be useful,
22169695Skan   but WITHOUT ANY WARRANTY; without even the implied warranty of
23169695Skan   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24169695Skan   GNU General Public License for more details.
25169695Skan
26169695Skan   You should have received a copy of the GNU General Public License
27169695Skan   along with this program; if not, write to the Free Software
28169695Skan   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
29169695Skan*/
30169695Skan
31169695Skan#ifdef HAVE_CONFIG_H
32169695Skan#include "config.h"
33169695Skan#endif
34169695Skan#include "libiberty.h"
35169695Skan#include <stdio.h>
36169695Skan#include <errno.h>
37169695Skan#ifdef HAVE_STDLIB_H
38169695Skan#include <stdlib.h>
39169695Skan#endif
40169695Skan#ifdef HAVE_STRING_H
41169695Skan#include <string.h>
42169695Skan#endif
43169695Skan
44169695Skan#ifndef EXIT_SUCCESS
45169695Skan#define EXIT_SUCCESS 0
46169695Skan#endif
47169695Skan
48169695Skan#ifndef EXIT_FAILURE
49169695Skan#define EXIT_FAILURE 1
50169695Skan#endif
51169695Skan
52169695Skanstatic void fatal_error (int, const char *, int) ATTRIBUTE_NORETURN;
53169695Skanvoid writeout_test (int, const char *);
54169695Skanvoid run_replaces (char *);
55169695Skanvoid hook_char_replace (char *, size_t, char, char);
56169695Skanint run_tests (const char **);
57169695Skanvoid erase_test (int);
58169695Skan
59169695Skan/* Test input data, argv before, and argv after:
60169695Skan
61169695Skan   The \n is an important part of test_data since expandargv
62169695Skan   may have to work in environments where \n is translated
63169695Skan   as \r\n. Thus \n is included in the test data for the file.
64169695Skan
65169695Skan   We use \b to indicate that the test data is the null character.
66169695Skan   This is because we use \0 normally to represent the end of the
67169695Skan   file data, so we need something else for this. */
68169695Skan
69169695Skan#define FILENAME_PATTERN "test-expandargv-%d.lst"
70169695Skan#define ARGV0 "test-expandargv"
71169695Skan
72169695Skanconst char *test_data[] = {
73169695Skan  /* Test 0 - Check for expansion with \r\n */
74169695Skan  "a\r\nb",	/* Test 0 data */
75169695Skan  ARGV0,
76169695Skan  "@test-expandargv-0.lst",
77169695Skan  0, /* End of argv[] before expansion */
78169695Skan  ARGV0,
79169695Skan  "a",
80169695Skan  "b",
81169695Skan  0, /* End of argv[] after expansion */
82169695Skan
83169695Skan  /* Test 1 - Check for expansion with \n */
84169695Skan  "a\nb",	/* Test 1 data */
85169695Skan  ARGV0,
86169695Skan  "@test-expandargv-1.lst",
87169695Skan  0,
88169695Skan  ARGV0,
89169695Skan  "a",
90169695Skan  "b",
91169695Skan  0,
92169695Skan
93169695Skan  /* Test 2 - Check for expansion with \0 */
94169695Skan  "a\bb",	/* Test 2 data */
95169695Skan  ARGV0,
96169695Skan  "@test-expandargv-2.lst",
97169695Skan  0,
98169695Skan  ARGV0,
99169695Skan  "a",
100169695Skan  0,
101169695Skan
102169695Skan  /* Test 3 - Check for expansion with only \0 */
103169695Skan  "\b",		/* Test 3 data */
104169695Skan  ARGV0,
105169695Skan  "@test-expandargv-3.lst",
106169695Skan  0,
107169695Skan  ARGV0,
108169695Skan  0,
109169695Skan
110169695Skan  0 /* Test done marker, don't remove. */
111169695Skan};
112169695Skan
113169695Skan/* Print a fatal error and exit.  LINE is the line number where we
114169695Skan   detected the error, ERRMSG is the error message to print, and ERR
115169695Skan   is 0 or an errno value to print.  */
116169695Skan
117169695Skanstatic void
118169695Skanfatal_error (int line, const char *errmsg, int err)
119169695Skan{
120169695Skan  fprintf (stderr, "test-expandargv:%d: %s", line, errmsg);
121169695Skan  if (errno != 0)
122169695Skan    fprintf (stderr, ": %s", xstrerror (err));
123169695Skan  fprintf (stderr, "\n");
124169695Skan  exit (EXIT_FAILURE);
125169695Skan}
126169695Skan
127169695Skan/* hook_char_replace:
128169695Skan     Replace 'replacethis' with 'withthis' */
129169695Skan
130169695Skanvoid
131169695Skanhook_char_replace (char *string, size_t len, char replacethis, char withthis)
132169695Skan{
133169695Skan  int i = 0;
134169695Skan  for (i = 0; i < len; i++)
135169695Skan    if (string[i] == replacethis)
136169695Skan      string[i] = withthis;
137169695Skan}
138169695Skan
139169695Skan/* run_replaces:
140169695Skan     Hook here all the character for character replaces.
141169695Skan     Be warned that expanding the string or contracting the string
142169695Skan     should be handled with care. */
143169695Skan
144169695Skanvoid
145169695Skanrun_replaces (char * string)
146169695Skan{
147169695Skan  /* Store original string size */
148169695Skan  size_t len = strlen (string);
149169695Skan  hook_char_replace (string, len, '\b', '\0');
150169695Skan}
151169695Skan
152169695Skan/* write_test:
153169695Skan   Write test datafile */
154169695Skan
155169695Skanvoid
156169695Skanwriteout_test (int test, const char * test_data)
157169695Skan{
158169695Skan  char filename[256];
159169695Skan  FILE *fd;
160169695Skan  size_t len;
161169695Skan  char * parse;
162169695Skan
163169695Skan  /* Unique filename per test */
164169695Skan  sprintf (filename, FILENAME_PATTERN, test);
165169695Skan  fd = fopen (filename, "w");
166169695Skan  if (fd == NULL)
167169695Skan    fatal_error (__LINE__, "Failed to create test file.", errno);
168169695Skan
169169695Skan  /* Generate RW copy of data for replaces */
170169695Skan  len = strlen (test_data);
171169695Skan  parse = malloc (sizeof (char) * (len + 1));
172169695Skan  if (parse == NULL)
173169695Skan    fatal_error (__LINE__, "Failed to malloc parse.", errno);
174169695Skan
175169695Skan  memcpy (parse, test_data, sizeof (char) * len);
176169695Skan  /* Run all possible replaces */
177169695Skan  run_replaces (parse);
178169695Skan
179169695Skan  fwrite (parse, len, sizeof (char), fd);
180169695Skan  free (parse);
181169695Skan  fclose (fd);
182169695Skan}
183169695Skan
184169695Skan/* erase_test:
185169695Skan     Erase the test file */
186169695Skan
187169695Skanvoid
188169695Skanerase_test (int test)
189169695Skan{
190169695Skan  char filename[256];
191169695Skan  sprintf (filename, FILENAME_PATTERN, test);
192169695Skan  if (unlink (filename) != 0)
193169695Skan    fatal_error (__LINE__, "Failed to erase test file.", errno);
194169695Skan}
195169695Skan
196169695Skan
197169695Skan/* run_tests:
198169695Skan    Run expandargv
199169695Skan    Compare argv before and after.
200169695Skan    Return number of fails */
201169695Skan
202169695Skanint
203169695Skanrun_tests (const char **test_data)
204169695Skan{
205169695Skan  int argc_after, argc_before;
206169695Skan  char ** argv_before, ** argv_after;
207169695Skan  int i, j, k, fails, failed;
208169695Skan
209169695Skan  i = j = fails = 0;
210169695Skan  /* Loop over all the tests */
211169695Skan  while (test_data[j])
212169695Skan    {
213169695Skan      /* Write test data */
214169695Skan      writeout_test (i, test_data[j++]);
215169695Skan      /* Copy argv before */
216169695Skan      argv_before = dupargv ((char **) &test_data[j]);
217169695Skan
218169695Skan      /* Count argc before/after */
219169695Skan      argc_before = 0;
220169695Skan      argc_after = 0;
221169695Skan      while (test_data[j + argc_before])
222169695Skan        argc_before++;
223169695Skan      j += argc_before + 1; /* Skip null */
224169695Skan      while (test_data[j + argc_after])
225169695Skan        argc_after++;
226169695Skan
227169695Skan      /* Copy argv after */
228169695Skan      argv_after = dupargv ((char **) &test_data[j]);
229169695Skan
230169695Skan      /* Run all possible replaces */
231169695Skan      for (k = 0; k < argc_before; k++)
232169695Skan        run_replaces (argv_before[k]);
233169695Skan      for (k = 0; k < argc_after; k++)
234169695Skan        run_replaces (argv_after[k]);
235169695Skan
236169695Skan      /* Run test: Expand arguments */
237169695Skan      expandargv (&argc_before, &argv_before);
238169695Skan
239169695Skan      failed = 0;
240169695Skan      /* Compare size first */
241169695Skan      if (argc_before != argc_after)
242169695Skan        {
243169695Skan          printf ("FAIL: test-expandargv-%d. Number of arguments don't match.\n", i);
244169695Skan	  failed++;
245169695Skan        }
246169695Skan      /* Compare each of the argv's ... */
247169695Skan      else
248169695Skan        for (k = 0; k < argc_after; k++)
249169695Skan          if (strncmp (argv_before[k], argv_after[k], strlen(argv_after[k])) != 0)
250169695Skan            {
251169695Skan              printf ("FAIL: test-expandargv-%d. Arguments don't match.\n", i);
252169695Skan              failed++;
253169695Skan            }
254169695Skan
255169695Skan      if (!failed)
256169695Skan        printf ("PASS: test-expandargv-%d.\n", i);
257169695Skan      else
258169695Skan        fails++;
259169695Skan
260169695Skan      freeargv (argv_before);
261169695Skan      freeargv (argv_after);
262169695Skan      /* Advance to next test */
263169695Skan      j += argc_after + 1;
264169695Skan      /* Erase test file */
265169695Skan      erase_test (i);
266169695Skan      i++;
267169695Skan    }
268169695Skan  return fails;
269169695Skan}
270169695Skan
271169695Skan/* main:
272169695Skan    Run tests.
273169695Skan    Check result and exit with appropriate code. */
274169695Skan
275169695Skanint
276169695Skanmain(int argc, char **argv)
277169695Skan{
278169695Skan  int fails;
279169695Skan  /* Repeat for all the tests:
280169695Skan     - Parse data array and write into file.
281169695Skan       - Run replace hooks before writing to file.
282169695Skan     - Parse data array and build argv before/after.
283169695Skan       - Run replace hooks on argv before/after
284169695Skan     - Run expandargv.
285169695Skan     - Compare output of expandargv argv to after argv.
286169695Skan       - If they compare the same then test passes
287169695Skan         else the test fails.
288169695Skan     - Erase test file. */
289169695Skan
290169695Skan  fails = run_tests (test_data);
291169695Skan  if (!fails)
292169695Skan    exit (EXIT_SUCCESS);
293169695Skan  else
294169695Skan    exit (EXIT_FAILURE);
295169695Skan}
296169695Skan
297