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 #ifdef HAVE_STDLIB_H 38 #include <stdlib.h> 39 #endif 40 #ifdef HAVE_STRING_H 41 #include <string.h> 42 #endif 43 44 #ifndef EXIT_SUCCESS 45 #define EXIT_SUCCESS 0 46 #endif 47 48 #ifndef EXIT_FAILURE 49 #define EXIT_FAILURE 1 50 #endif 51 52 static void fatal_error (int, const char *, int) ATTRIBUTE_NORETURN; 53 void writeout_test (int, const char *); 54 void run_replaces (char *); 55 void hook_char_replace (char *, size_t, char, char); 56 int run_tests (const char **); 57 void erase_test (int); 58 59 /* Test input data, argv before, and argv after: 60 61 The \n is an important part of test_data since expandargv 62 may have to work in environments where \n is translated 63 as \r\n. Thus \n is included in the test data for the file. 64 65 We use \b to indicate that the test data is the null character. 66 This is because we use \0 normally to represent the end of the 67 file data, so we need something else for this. */ 68 69 #define FILENAME_PATTERN "test-expandargv-%d.lst" 70 #define ARGV0 "test-expandargv" 71 72 const char *test_data[] = { 73 /* Test 0 - Check for expansion with \r\n */ 74 "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 0 /* Test done marker, don't remove. */ 111 }; 112 113 /* Print a fatal error and exit. LINE is the line number where we 114 detected the error, ERRMSG is the error message to print, and ERR 115 is 0 or an errno value to print. */ 116 117 static void 118 fatal_error (int line, const char *errmsg, int err) 119 { 120 fprintf (stderr, "test-expandargv:%d: %s", line, errmsg); 121 if (errno != 0) 122 fprintf (stderr, ": %s", xstrerror (err)); 123 fprintf (stderr, "\n"); 124 exit (EXIT_FAILURE); 125 } 126 127 /* hook_char_replace: 128 Replace 'replacethis' with 'withthis' */ 129 130 void 131 hook_char_replace (char *string, size_t len, char replacethis, char withthis) 132 { 133 int i = 0; 134 for (i = 0; i < len; i++) 135 if (string[i] == replacethis) 136 string[i] = withthis; 137 } 138 139 /* run_replaces: 140 Hook here all the character for character replaces. 141 Be warned that expanding the string or contracting the string 142 should be handled with care. */ 143 144 void 145 run_replaces (char * string) 146 { 147 /* Store original string size */ 148 size_t len = strlen (string); 149 hook_char_replace (string, len, '\b', '\0'); 150 } 151 152 /* write_test: 153 Write test datafile */ 154 155 void 156 writeout_test (int test, const char * test_data) 157 { 158 char filename[256]; 159 FILE *fd; 160 size_t len; 161 char * parse; 162 163 /* Unique filename per test */ 164 sprintf (filename, FILENAME_PATTERN, test); 165 fd = fopen (filename, "w"); 166 if (fd == NULL) 167 fatal_error (__LINE__, "Failed to create test file.", errno); 168 169 /* Generate RW copy of data for replaces */ 170 len = strlen (test_data); 171 parse = malloc (sizeof (char) * (len + 1)); 172 if (parse == NULL) 173 fatal_error (__LINE__, "Failed to malloc parse.", errno); 174 175 memcpy (parse, test_data, sizeof (char) * len); 176 /* Run all possible replaces */ 177 run_replaces (parse); 178 179 fwrite (parse, len, sizeof (char), fd); 180 free (parse); 181 fclose (fd); 182 } 183 184 /* erase_test: 185 Erase the test file */ 186 187 void 188 erase_test (int test) 189 { 190 char filename[256]; 191 sprintf (filename, FILENAME_PATTERN, test); 192 if (unlink (filename) != 0) 193 fatal_error (__LINE__, "Failed to erase test file.", errno); 194 } 195 196 197 /* run_tests: 198 Run expandargv 199 Compare argv before and after. 200 Return number of fails */ 201 202 int 203 run_tests (const char **test_data) 204 { 205 int argc_after, argc_before; 206 char ** argv_before, ** argv_after; 207 int i, j, k, fails, failed; 208 209 i = j = fails = 0; 210 /* Loop over all the tests */ 211 while (test_data[j]) 212 { 213 /* Write test data */ 214 writeout_test (i, test_data[j++]); 215 /* Copy argv before */ 216 argv_before = dupargv ((char **) &test_data[j]); 217 218 /* Count argc before/after */ 219 argc_before = 0; 220 argc_after = 0; 221 while (test_data[j + argc_before]) 222 argc_before++; 223 j += argc_before + 1; /* Skip null */ 224 while (test_data[j + argc_after]) 225 argc_after++; 226 227 /* Copy argv after */ 228 argv_after = dupargv ((char **) &test_data[j]); 229 230 /* Run all possible replaces */ 231 for (k = 0; k < argc_before; k++) 232 run_replaces (argv_before[k]); 233 for (k = 0; k < argc_after; k++) 234 run_replaces (argv_after[k]); 235 236 /* Run test: Expand arguments */ 237 expandargv (&argc_before, &argv_before); 238 239 failed = 0; 240 /* Compare size first */ 241 if (argc_before != argc_after) 242 { 243 printf ("FAIL: test-expandargv-%d. Number of arguments don't match.\n", i); 244 failed++; 245 } 246 /* Compare each of the argv's ... */ 247 else 248 for (k = 0; k < argc_after; k++) 249 if (strncmp (argv_before[k], argv_after[k], strlen(argv_after[k])) != 0) 250 { 251 printf ("FAIL: test-expandargv-%d. Arguments don't match.\n", i); 252 failed++; 253 } 254 255 if (!failed) 256 printf ("PASS: test-expandargv-%d.\n", i); 257 else 258 fails++; 259 260 freeargv (argv_before); 261 freeargv (argv_after); 262 /* Advance to next test */ 263 j += argc_after + 1; 264 /* Erase test file */ 265 erase_test (i); 266 i++; 267 } 268 return fails; 269 } 270 271 /* main: 272 Run tests. 273 Check result and exit with appropriate code. */ 274 275 int 276 main(int argc, char **argv) 277 { 278 int fails; 279 /* Repeat for all the tests: 280 - Parse data array and write into file. 281 - Run replace hooks before writing to file. 282 - Parse data array and build argv before/after. 283 - Run replace hooks on argv before/after 284 - Run expandargv. 285 - Compare output of expandargv argv to after argv. 286 - If they compare the same then test passes 287 else the test fails. 288 - Erase test file. */ 289 290 fails = run_tests (test_data); 291 if (!fails) 292 exit (EXIT_SUCCESS); 293 else 294 exit (EXIT_FAILURE); 295 } 296 297