Home | History | Annotate | Line # | Download | only in testsuite
      1   1.1  christos /* expandargv test program,
      2  1.10  christos    Copyright (C) 2006-2024 Free Software Foundation, Inc.
      3   1.1  christos    Written by Carlos O'Donell <carlos (at) codesourcery.com>
      4   1.1  christos 
      5   1.1  christos    This file is part of the libiberty library, which is part of GCC.
      6   1.1  christos 
      7   1.1  christos    This file is free software; you can redistribute it and/or modify
      8   1.1  christos    it under the terms of the GNU General Public License as published by
      9   1.1  christos    the Free Software Foundation; either version 2 of the License, or
     10   1.1  christos    (at your option) any later version.
     11   1.1  christos 
     12   1.1  christos    In addition to the permissions in the GNU General Public License, the
     13   1.1  christos    Free Software Foundation gives you unlimited permission to link the
     14   1.1  christos    compiled version of this file into combinations with other programs,
     15   1.1  christos    and to distribute those combinations without any restriction coming
     16   1.1  christos    from the use of this file.  (The General Public License restrictions
     17   1.1  christos    do apply in other respects; for example, they cover modification of
     18   1.1  christos    the file, and distribution when not linked into a combined
     19   1.1  christos    executable.)
     20   1.1  christos 
     21   1.1  christos    This program is distributed in the hope that it will be useful,
     22   1.1  christos    but WITHOUT ANY WARRANTY; without even the implied warranty of
     23   1.1  christos    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     24   1.1  christos    GNU General Public License for more details.
     25   1.1  christos 
     26   1.1  christos    You should have received a copy of the GNU General Public License
     27   1.1  christos    along with this program; if not, write to the Free Software
     28   1.1  christos    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
     29   1.1  christos */
     30   1.1  christos 
     31   1.1  christos #ifdef HAVE_CONFIG_H
     32   1.1  christos #include "config.h"
     33   1.1  christos #endif
     34   1.1  christos #include "libiberty.h"
     35   1.1  christos #include <stdio.h>
     36   1.1  christos #include <errno.h>
     37   1.1  christos #ifdef HAVE_STDLIB_H
     38   1.1  christos #include <stdlib.h>
     39   1.1  christos #endif
     40   1.1  christos #ifdef HAVE_STRING_H
     41   1.1  christos #include <string.h>
     42   1.1  christos #endif
     43   1.1  christos #ifdef HAVE_UNISTD_H
     44   1.1  christos #include <unistd.h>
     45   1.1  christos #endif
     46   1.1  christos 
     47   1.1  christos #ifndef EXIT_SUCCESS
     48   1.1  christos #define EXIT_SUCCESS 0
     49   1.1  christos #endif
     50   1.1  christos 
     51   1.1  christos #ifndef EXIT_FAILURE
     52   1.1  christos #define EXIT_FAILURE 1
     53   1.1  christos #endif
     54   1.1  christos 
     55   1.1  christos static void fatal_error (int, const char *, int) ATTRIBUTE_NORETURN;
     56   1.1  christos void writeout_test (int, const char *);
     57   1.1  christos void run_replaces (char *);
     58   1.1  christos void hook_char_replace (char *, size_t, char, char);
     59   1.1  christos int run_tests (const char **);
     60   1.1  christos void erase_test (int);
     61   1.1  christos 
     62   1.1  christos /* Test input data, argv before, and argv after:
     63   1.1  christos 
     64   1.1  christos    The \n is an important part of test_data since expandargv
     65   1.1  christos    may have to work in environments where \n is translated
     66   1.1  christos    as \r\n. Thus \n is included in the test data for the file.
     67   1.1  christos 
     68   1.1  christos    We use \b to indicate that the test data is the null character.
     69   1.1  christos    This is because we use \0 normally to represent the end of the
     70   1.1  christos    file data, so we need something else for this. */
     71   1.1  christos 
     72   1.1  christos #define FILENAME_PATTERN "test-expandargv-%d.lst"
     73   1.1  christos #define ARGV0 "test-expandargv"
     74   1.1  christos 
     75   1.1  christos const char *test_data[] = {
     76   1.1  christos   /* Test 0 - Check for expansion with \r\n */
     77   1.1  christos   "a\r\nb",	/* Test 0 data */
     78   1.1  christos   ARGV0,
     79   1.1  christos   "@test-expandargv-0.lst",
     80   1.1  christos   0, /* End of argv[] before expansion */
     81   1.1  christos   ARGV0,
     82   1.1  christos   "a",
     83   1.1  christos   "b",
     84   1.1  christos   0, /* End of argv[] after expansion */
     85   1.1  christos 
     86   1.1  christos   /* Test 1 - Check for expansion with \n */
     87   1.1  christos   "a\nb",	/* Test 1 data */
     88   1.1  christos   ARGV0,
     89   1.1  christos   "@test-expandargv-1.lst",
     90   1.1  christos   0,
     91   1.1  christos   ARGV0,
     92   1.1  christos   "a",
     93   1.1  christos   "b",
     94   1.1  christos   0,
     95   1.1  christos 
     96   1.1  christos   /* Test 2 - Check for expansion with \0 */
     97   1.1  christos   "a\bb",	/* Test 2 data */
     98   1.1  christos   ARGV0,
     99   1.1  christos   "@test-expandargv-2.lst",
    100   1.1  christos   0,
    101   1.1  christos   ARGV0,
    102   1.1  christos   "a",
    103   1.1  christos   0,
    104   1.1  christos 
    105   1.1  christos   /* Test 3 - Check for expansion with only \0 */
    106   1.1  christos   "\b",		/* Test 3 data */
    107   1.1  christos   ARGV0,
    108   1.1  christos   "@test-expandargv-3.lst",
    109   1.1  christos   0,
    110   1.1  christos   ARGV0,
    111   1.1  christos   0,
    112   1.1  christos 
    113   1.1  christos   /* Test 4 - Check for options beginning with an empty line.  */
    114   1.1  christos   "\na\nb",	/* Test 4 data */
    115   1.1  christos   ARGV0,
    116   1.1  christos   "@test-expandargv-4.lst",
    117   1.1  christos   0,
    118   1.1  christos   ARGV0,
    119   1.1  christos   "a",
    120   1.1  christos   "b",
    121   1.1  christos   0,
    122   1.1  christos 
    123   1.1  christos   /* Test 5 - Check for options containing an empty argument.  */
    124   1.1  christos   "a\n''\nb",    /* Test 5 data */
    125   1.1  christos   ARGV0,
    126   1.1  christos   "@test-expandargv-5.lst",
    127   1.1  christos   0,
    128   1.1  christos   ARGV0,
    129   1.1  christos   "a",
    130   1.1  christos   "",
    131   1.1  christos   "b",
    132   1.1  christos   0,
    133   1.1  christos 
    134   1.1  christos   /* Test 6 - Check for options containing a quoted newline.  */
    135   1.1  christos   "a\n'a\n\nb'\nb",    /* Test 6 data */
    136   1.1  christos   ARGV0,
    137   1.1  christos   "@test-expandargv-6.lst",
    138   1.1  christos   0,
    139   1.1  christos   ARGV0,
    140   1.1  christos   "a",
    141   1.1  christos   "a\n\nb",
    142   1.1  christos   "b",
    143   1.1  christos   0,
    144   1.1  christos 
    145  1.11  christos   /* Test 7 - No backslash removal within single quotes.  */
    146  1.11  christos   "'a\\$VAR' '\\\"'",    /* Test 7 data */
    147  1.11  christos   ARGV0,
    148  1.11  christos   "@test-expandargv-7.lst",
    149  1.11  christos   0,
    150  1.11  christos   ARGV0,
    151  1.11  christos   "a\\$VAR",
    152  1.11  christos   "\\\"",
    153  1.11  christos   0,
    154  1.11  christos 
    155  1.11  christos   /* Test 8 - Remove backslash / newline pairs.  */
    156  1.11  christos   "\"ab\\\ncd\" ef\\\ngh",    /* Test 8 data */
    157  1.11  christos   ARGV0,
    158  1.11  christos   "@test-expandargv-8.lst",
    159  1.11  christos   0,
    160  1.11  christos   ARGV0,
    161  1.11  christos   "abcd",
    162  1.11  christos   "efgh",
    163  1.11  christos   0,
    164  1.11  christos 
    165  1.11  christos   /* Test 9 - Backslash within double quotes.  */
    166  1.11  christos   "\"\\$VAR\" \"\\`\" \"\\\"\" \"\\\\\" \"\\n\" \"\\t\"",    /* Test 9 data */
    167  1.11  christos   ARGV0,
    168  1.11  christos   "@test-expandargv-9.lst",
    169  1.11  christos   0,
    170  1.11  christos   ARGV0,
    171  1.11  christos   "$VAR",
    172  1.11  christos   "`",
    173  1.11  christos   "\"",
    174  1.11  christos   "\\",
    175  1.11  christos   "\\n",
    176  1.11  christos   "\\t",
    177  1.11  christos   0,
    178  1.11  christos 
    179  1.11  christos   /* Test 10 - Mixed white space characters.  */
    180  1.11  christos   "\t \n \t ",		/* Test 10 data */
    181  1.11  christos   ARGV0,
    182  1.11  christos   "@test-expandargv-10.lst",
    183  1.11  christos   0,
    184  1.11  christos   ARGV0,
    185  1.11  christos   0,
    186  1.11  christos 
    187  1.11  christos   /* Test 11 - Single ' ' character.  */
    188  1.11  christos   " ",		/* Test 11 data */
    189  1.11  christos   ARGV0,
    190  1.11  christos   "@test-expandargv-11.lst",
    191  1.11  christos   0,
    192  1.11  christos   ARGV0,
    193  1.11  christos   0,
    194  1.11  christos 
    195  1.11  christos   /* Test 12 - Multiple ' ' characters.  */
    196  1.11  christos   "   ",		/* Test 12 data */
    197  1.11  christos   ARGV0,
    198  1.11  christos   "@test-expandargv-12.lst",
    199  1.11  christos   0,
    200  1.11  christos   ARGV0,
    201  1.11  christos   0,
    202  1.11  christos 
    203   1.1  christos   0 /* Test done marker, don't remove. */
    204   1.1  christos };
    205   1.1  christos 
    206   1.1  christos /* Print a fatal error and exit.  LINE is the line number where we
    207   1.1  christos    detected the error, ERRMSG is the error message to print, and ERR
    208   1.1  christos    is 0 or an errno value to print.  */
    209   1.1  christos 
    210   1.1  christos static void
    211   1.1  christos fatal_error (int line, const char *errmsg, int err)
    212   1.1  christos {
    213   1.1  christos   fprintf (stderr, "test-expandargv:%d: %s", line, errmsg);
    214   1.1  christos   if (errno != 0)
    215   1.1  christos     fprintf (stderr, ": %s", xstrerror (err));
    216   1.1  christos   fprintf (stderr, "\n");
    217   1.1  christos   exit (EXIT_FAILURE);
    218   1.1  christos }
    219   1.1  christos 
    220   1.1  christos /* hook_char_replace:
    221   1.1  christos      Replace 'replacethis' with 'withthis' */
    222   1.1  christos 
    223   1.1  christos void
    224   1.1  christos hook_char_replace (char *string, size_t len, char replacethis, char withthis)
    225   1.1  christos {
    226   1.1  christos   int i = 0;
    227   1.1  christos   for (i = 0; i < len; i++)
    228   1.1  christos     if (string[i] == replacethis)
    229   1.1  christos       string[i] = withthis;
    230   1.1  christos }
    231   1.1  christos 
    232   1.1  christos /* run_replaces:
    233   1.1  christos      Hook here all the character for character replaces.
    234   1.1  christos      Be warned that expanding the string or contracting the string
    235   1.1  christos      should be handled with care. */
    236   1.1  christos 
    237   1.1  christos void
    238   1.1  christos run_replaces (char * string)
    239   1.1  christos {
    240   1.1  christos   /* Store original string size */
    241   1.1  christos   size_t len = strlen (string);
    242   1.1  christos   hook_char_replace (string, len, '\b', '\0');
    243   1.1  christos }
    244   1.1  christos 
    245   1.1  christos /* write_test:
    246   1.1  christos    Write test datafile */
    247   1.1  christos 
    248   1.1  christos void
    249   1.1  christos writeout_test (int test, const char * test_data)
    250   1.1  christos {
    251   1.1  christos   char filename[256];
    252   1.1  christos   FILE *fd;
    253   1.1  christos   size_t len, sys_fwrite;
    254   1.1  christos   char * parse;
    255   1.1  christos 
    256   1.1  christos   /* Unique filename per test */
    257   1.1  christos   sprintf (filename, FILENAME_PATTERN, test);
    258   1.1  christos   fd = fopen (filename, "w");
    259   1.1  christos   if (fd == NULL)
    260   1.1  christos     fatal_error (__LINE__, "Failed to create test file.", errno);
    261   1.1  christos 
    262   1.1  christos   /* Generate RW copy of data for replaces */
    263   1.1  christos   len = strlen (test_data);
    264   1.1  christos   parse = malloc (sizeof (char) * (len + 1));
    265   1.1  christos   if (parse == NULL)
    266   1.1  christos     fatal_error (__LINE__, "Failed to malloc parse.", errno);
    267   1.1  christos 
    268   1.1  christos   memcpy (parse, test_data, sizeof (char) * (len + 1));
    269   1.1  christos   /* Run all possible replaces */
    270   1.1  christos   run_replaces (parse);
    271   1.1  christos 
    272   1.1  christos   sys_fwrite = fwrite (parse, sizeof (char), len, fd);
    273   1.1  christos   if (sys_fwrite != len)
    274   1.1  christos     fatal_error (__LINE__, "Failed to write to test file.", errno);
    275   1.1  christos 
    276   1.1  christos   free (parse);
    277   1.1  christos   fclose (fd);
    278   1.1  christos }
    279   1.1  christos 
    280   1.1  christos /* erase_test:
    281   1.1  christos      Erase the test file */
    282   1.1  christos 
    283   1.1  christos void
    284   1.1  christos erase_test (int test)
    285   1.1  christos {
    286   1.1  christos   char filename[256];
    287   1.1  christos   sprintf (filename, FILENAME_PATTERN, test);
    288   1.1  christos   if (unlink (filename) != 0)
    289   1.1  christos     fatal_error (__LINE__, "Failed to erase test file.", errno);
    290   1.1  christos }
    291   1.1  christos 
    292  1.11  christos /* compare_argv:
    293  1.11  christos      TEST is the current test number, and NAME is a short string to identify
    294  1.11  christos      which libibery function is being tested.  ARGC_A and ARGV_A describe an
    295  1.11  christos      argument array, and this is compared to ARGC_B and ARGV_B, return 0 if
    296  1.11  christos      the two arrays match, otherwise return 1.  */
    297  1.11  christos 
    298  1.11  christos static int
    299  1.11  christos compare_argv (int test, const char *name, int argc_a, char *argv_a[],
    300  1.11  christos 	      int argc_b, char *argv_b[])
    301  1.11  christos {
    302  1.11  christos   int failed = 0, k;
    303  1.11  christos 
    304  1.11  christos   if (argc_a != argc_b)
    305  1.11  christos     {
    306  1.11  christos       printf ("FAIL: test-%s-%d.  Argument count didn't match\n", name, test);
    307  1.11  christos       failed = 1;
    308  1.11  christos     }
    309  1.11  christos   /* Compare each of the argv's ... */
    310  1.11  christos   else
    311  1.11  christos     for (k = 0; k < argc_a; k++)
    312  1.11  christos       if (strcmp (argv_a[k], argv_b[k]) != 0)
    313  1.11  christos 	{
    314  1.11  christos 	  printf ("FAIL: test-%s-%d. Arguments don't match.\n", name, test);
    315  1.11  christos 	  failed = 1;
    316  1.11  christos 	  break;
    317  1.11  christos 	}
    318  1.11  christos 
    319  1.11  christos   if (!failed)
    320  1.11  christos     printf ("PASS: test-%s-%d.\n", name, test);
    321  1.11  christos 
    322  1.11  christos   return failed;
    323  1.11  christos }
    324  1.11  christos 
    325  1.11  christos /* test_buildargv
    326  1.11  christos      Test the buildargv function from libiberty.  TEST is the current test
    327  1.11  christos      number and TEST_INPUT is the string to pass to buildargv (after calling
    328  1.11  christos      run_replaces on it).  ARGC_AFTER and ARGV_AFTER are the expected
    329  1.11  christos      results.  Return 0 if the test passes, otherwise return 1.  */
    330  1.11  christos 
    331  1.11  christos static int
    332  1.11  christos test_buildargv (int test, const char * test_input, int argc_after,
    333  1.11  christos 		char *argv_after[])
    334  1.11  christos {
    335  1.11  christos   char * input, ** argv;
    336  1.11  christos   size_t len;
    337  1.11  christos   int argc, failed;
    338  1.11  christos 
    339  1.11  christos   /* Generate RW copy of data for replaces */
    340  1.11  christos   len = strlen (test_input);
    341  1.11  christos   input = malloc (sizeof (char) * (len + 1));
    342  1.11  christos   if (input == NULL)
    343  1.11  christos     fatal_error (__LINE__, "Failed to malloc buildargv input buffer.", errno);
    344  1.11  christos 
    345  1.11  christos   memcpy (input, test_input, sizeof (char) * (len + 1));
    346  1.11  christos   /* Run all possible replaces */
    347  1.11  christos   run_replaces (input);
    348  1.11  christos 
    349  1.11  christos   /* Split INPUT into separate arguments.  */
    350  1.11  christos   argv = buildargv (input);
    351  1.11  christos 
    352  1.11  christos   /* Count the arguments we got back.  */
    353  1.11  christos   argc = 0;
    354  1.11  christos   while (argv[argc])
    355  1.11  christos     ++argc;
    356  1.11  christos 
    357  1.11  christos   failed = compare_argv (test, "buildargv", argc_after, argv_after, argc, argv);
    358  1.11  christos 
    359  1.11  christos   free (input);
    360  1.11  christos   freeargv (argv);
    361  1.11  christos 
    362  1.11  christos   return failed;
    363  1.11  christos }
    364   1.1  christos 
    365   1.1  christos /* run_tests:
    366   1.1  christos     Run expandargv
    367   1.1  christos     Compare argv before and after.
    368   1.1  christos     Return number of fails */
    369   1.1  christos 
    370   1.1  christos int
    371   1.1  christos run_tests (const char **test_data)
    372   1.1  christos {
    373   1.1  christos   int argc_after, argc_before;
    374   1.1  christos   char ** argv_before, ** argv_after;
    375  1.11  christos   int i, j, k, fails;
    376  1.11  christos   const char * input_str;
    377   1.1  christos 
    378   1.1  christos   i = j = fails = 0;
    379   1.1  christos   /* Loop over all the tests */
    380   1.1  christos   while (test_data[j])
    381   1.1  christos     {
    382  1.11  christos       /* Save original input in case we run a buildargv test.  */
    383  1.11  christos       input_str = test_data[j];
    384  1.11  christos 
    385   1.1  christos       /* Write test data */
    386   1.1  christos       writeout_test (i, test_data[j++]);
    387   1.1  christos       /* Copy argv before */
    388   1.1  christos       argv_before = dupargv ((char **) &test_data[j]);
    389   1.1  christos 
    390   1.1  christos       /* Count argc before/after */
    391   1.1  christos       argc_before = 0;
    392   1.1  christos       argc_after = 0;
    393   1.1  christos       while (test_data[j + argc_before])
    394   1.1  christos         argc_before++;
    395   1.1  christos       j += argc_before + 1; /* Skip null */
    396   1.1  christos       while (test_data[j + argc_after])
    397   1.1  christos         argc_after++;
    398   1.1  christos 
    399   1.1  christos       /* Copy argv after */
    400   1.1  christos       argv_after = dupargv ((char **) &test_data[j]);
    401   1.1  christos 
    402   1.1  christos       /* Run all possible replaces */
    403   1.1  christos       for (k = 0; k < argc_before; k++)
    404   1.1  christos         run_replaces (argv_before[k]);
    405   1.1  christos       for (k = 0; k < argc_after; k++)
    406   1.1  christos         run_replaces (argv_after[k]);
    407   1.1  christos 
    408  1.11  christos       /* If the test input is just a file to expand then we can also test
    409  1.11  christos 	 calling buildargv directly as the expected output is equivalent to
    410  1.11  christos 	 calling buildargv on the contents of the file.
    411  1.11  christos 
    412  1.11  christos 	 The results of calling buildargv will not include the ARGV0 constant,
    413  1.11  christos 	 which is why we pass 'argc_after - 1' and 'argv_after + 1', this skips
    414  1.11  christos 	 over the ARGV0 in the expected results.  */
    415  1.11  christos       if (argc_before == 2)
    416  1.11  christos 	fails += test_buildargv (i, input_str, argc_after - 1, argv_after + 1);
    417  1.11  christos       else
    418  1.11  christos 	printf ("SKIP: test-buildargv-%d.  This test isn't for buildargv\n", i);
    419  1.11  christos 
    420   1.1  christos       /* Run test: Expand arguments */
    421   1.1  christos       expandargv (&argc_before, &argv_before);
    422   1.1  christos 
    423  1.11  christos       fails += compare_argv (i, "expandargv", argc_before, argv_before,
    424  1.11  christos 			     argc_after, argv_after);
    425   1.1  christos 
    426   1.1  christos       freeargv (argv_before);
    427   1.1  christos       freeargv (argv_after);
    428   1.1  christos       /* Advance to next test */
    429   1.1  christos       j += argc_after + 1;
    430   1.1  christos       /* Erase test file */
    431   1.1  christos       erase_test (i);
    432   1.1  christos       i++;
    433   1.1  christos     }
    434   1.1  christos   return fails;
    435   1.1  christos }
    436   1.1  christos 
    437   1.1  christos /* main:
    438   1.1  christos     Run tests.
    439   1.1  christos     Check result and exit with appropriate code. */
    440   1.1  christos 
    441   1.1  christos int
    442   1.1  christos main(int argc, char **argv)
    443   1.1  christos {
    444   1.1  christos   int fails;
    445   1.1  christos   /* Repeat for all the tests:
    446   1.1  christos      - Parse data array and write into file.
    447   1.1  christos        - Run replace hooks before writing to file.
    448   1.1  christos      - Parse data array and build argv before/after.
    449   1.1  christos        - Run replace hooks on argv before/after
    450   1.1  christos      - Run expandargv.
    451   1.1  christos      - Compare output of expandargv argv to after argv.
    452   1.1  christos        - If they compare the same then test passes
    453   1.1  christos          else the test fails.
    454   1.1  christos      - Erase test file. */
    455   1.1  christos 
    456   1.1  christos   fails = run_tests (test_data);
    457   1.1  christos   if (!fails)
    458   1.1  christos     exit (EXIT_SUCCESS);
    459   1.1  christos   else
    460   1.1  christos     exit (EXIT_FAILURE);
    461   1.1  christos }
    462   1.1  christos 
    463