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