1 1.1 mrg /* A self-testing framework, for use by -fself-test. 2 1.1 mrg Copyright (C) 2015-2022 Free Software Foundation, Inc. 3 1.1 mrg 4 1.1 mrg This file is part of GCC. 5 1.1 mrg 6 1.1 mrg GCC is free software; you can redistribute it and/or modify it under 7 1.1 mrg the terms of the GNU General Public License as published by the Free 8 1.1 mrg Software Foundation; either version 3, or (at your option) any later 9 1.1 mrg version. 10 1.1 mrg 11 1.1 mrg GCC is distributed in the hope that it will be useful, but WITHOUT ANY 12 1.1 mrg WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 1.1 mrg FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 1.1 mrg for more details. 15 1.1 mrg 16 1.1 mrg You should have received a copy of the GNU General Public License 17 1.1 mrg along with GCC; see the file COPYING3. If not see 18 1.1 mrg <http://www.gnu.org/licenses/>. */ 19 1.1 mrg 20 1.1 mrg #include "config.h" 21 1.1 mrg #include "system.h" 22 1.1 mrg #include "coretypes.h" 23 1.1 mrg #include "selftest.h" 24 1.1 mrg #include "intl.h" 25 1.1 mrg 26 1.1 mrg #if CHECKING_P 27 1.1 mrg 28 1.1 mrg namespace selftest { 29 1.1 mrg 30 1.1 mrg int num_passes; 31 1.1 mrg 32 1.1 mrg /* Record the successful outcome of some aspect of a test. */ 33 1.1 mrg 34 1.1 mrg void 35 1.1 mrg pass (const location &/*loc*/, const char */*msg*/) 36 1.1 mrg { 37 1.1 mrg num_passes++; 38 1.1 mrg } 39 1.1 mrg 40 1.1 mrg /* Report the failed outcome of some aspect of a test and abort. */ 41 1.1 mrg 42 1.1 mrg void 43 1.1 mrg fail (const location &loc, const char *msg) 44 1.1 mrg { 45 1.1 mrg fprintf (stderr,"%s:%i: %s: FAIL: %s\n", loc.m_file, loc.m_line, 46 1.1 mrg loc.m_function, msg); 47 1.1 mrg abort (); 48 1.1 mrg } 49 1.1 mrg 50 1.1 mrg /* As "fail", but using printf-style formatted output. */ 51 1.1 mrg 52 1.1 mrg void 53 1.1 mrg fail_formatted (const location &loc, const char *fmt, ...) 54 1.1 mrg { 55 1.1 mrg va_list ap; 56 1.1 mrg 57 1.1 mrg fprintf (stderr, "%s:%i: %s: FAIL: ", loc.m_file, loc.m_line, 58 1.1 mrg loc.m_function); 59 1.1 mrg va_start (ap, fmt); 60 1.1 mrg vfprintf (stderr, fmt, ap); 61 1.1 mrg va_end (ap); 62 1.1 mrg fprintf (stderr, "\n"); 63 1.1 mrg abort (); 64 1.1 mrg } 65 1.1 mrg 66 1.1 mrg /* Implementation detail of ASSERT_STREQ. 67 1.1 mrg Compare val1 and val2 with strcmp. They ought 68 1.1 mrg to be non-NULL; fail gracefully if either or both are NULL. */ 69 1.1 mrg 70 1.1 mrg void 71 1.1 mrg assert_streq (const location &loc, 72 1.1 mrg const char *desc_val1, const char *desc_val2, 73 1.1 mrg const char *val1, const char *val2) 74 1.1 mrg { 75 1.1 mrg /* If val1 or val2 are NULL, fail with a custom error message. */ 76 1.1 mrg if (val1 == NULL) 77 1.1 mrg if (val2 == NULL) 78 1.1 mrg fail_formatted (loc, "ASSERT_STREQ (%s, %s) val1=NULL val2=NULL", 79 1.1 mrg desc_val1, desc_val2); 80 1.1 mrg else 81 1.1 mrg fail_formatted (loc, "ASSERT_STREQ (%s, %s) val1=NULL val2=\"%s\"", 82 1.1 mrg desc_val1, desc_val2, val2); 83 1.1 mrg else 84 1.1 mrg if (val2 == NULL) 85 1.1 mrg fail_formatted (loc, "ASSERT_STREQ (%s, %s) val1=\"%s\" val2=NULL", 86 1.1 mrg desc_val1, desc_val2, val1); 87 1.1 mrg else 88 1.1 mrg { 89 1.1 mrg if (strcmp (val1, val2) == 0) 90 1.1 mrg pass (loc, "ASSERT_STREQ"); 91 1.1 mrg else 92 1.1 mrg fail_formatted (loc, "ASSERT_STREQ (%s, %s)\n val1=\"%s\"\n val2=\"%s\"\n", 93 1.1 mrg desc_val1, desc_val2, val1, val2); 94 1.1 mrg } 95 1.1 mrg } 96 1.1 mrg 97 1.1 mrg /* Implementation detail of ASSERT_STR_CONTAINS. 98 1.1 mrg Use strstr to determine if val_needle is within val_haystack. 99 1.1 mrg ::selftest::pass if it is found. 100 1.1 mrg ::selftest::fail if it is not found. */ 101 1.1 mrg 102 1.1 mrg void 103 1.1 mrg assert_str_contains (const location &loc, 104 1.1 mrg const char *desc_haystack, 105 1.1 mrg const char *desc_needle, 106 1.1 mrg const char *val_haystack, 107 1.1 mrg const char *val_needle) 108 1.1 mrg { 109 1.1 mrg /* If val_haystack is NULL, fail with a custom error message. */ 110 1.1 mrg if (val_haystack == NULL) 111 1.1 mrg fail_formatted (loc, "ASSERT_STR_CONTAINS (%s, %s) haystack=NULL", 112 1.1 mrg desc_haystack, desc_needle); 113 1.1 mrg 114 1.1 mrg /* If val_needle is NULL, fail with a custom error message. */ 115 1.1 mrg if (val_needle == NULL) 116 1.1 mrg fail_formatted (loc, 117 1.1 mrg "ASSERT_STR_CONTAINS (%s, %s) haystack=\"%s\" needle=NULL", 118 1.1 mrg desc_haystack, desc_needle, val_haystack); 119 1.1 mrg 120 1.1 mrg const char *test = strstr (val_haystack, val_needle); 121 1.1 mrg if (test) 122 1.1 mrg pass (loc, "ASSERT_STR_CONTAINS"); 123 1.1 mrg else 124 1.1 mrg fail_formatted 125 1.1 mrg (loc, "ASSERT_STR_CONTAINS (%s, %s) haystack=\"%s\" needle=\"%s\"", 126 1.1 mrg desc_haystack, desc_needle, val_haystack, val_needle); 127 1.1 mrg } 128 1.1 mrg 129 1.1 mrg /* Implementation detail of ASSERT_STR_STARTSWITH. 130 1.1 mrg Determine if VAL_STR starts with VAL_PREFIX. 131 1.1 mrg ::selftest::pass if VAL_STR does start with VAL_PREFIX. 132 1.1 mrg ::selftest::fail if it does not, or either is NULL (using 133 1.1 mrg DESC_STR and DESC_PREFIX in the error message). */ 134 1.1 mrg 135 1.1 mrg void 136 1.1 mrg assert_str_startswith (const location &loc, 137 1.1 mrg const char *desc_str, 138 1.1 mrg const char *desc_prefix, 139 1.1 mrg const char *val_str, 140 1.1 mrg const char *val_prefix) 141 1.1 mrg { 142 1.1 mrg /* If val_str is NULL, fail with a custom error message. */ 143 1.1 mrg if (val_str == NULL) 144 1.1 mrg fail_formatted (loc, "ASSERT_STR_STARTSWITH (%s, %s) str=NULL", 145 1.1 mrg desc_str, desc_prefix); 146 1.1 mrg 147 1.1 mrg /* If val_prefix is NULL, fail with a custom error message. */ 148 1.1 mrg if (val_prefix == NULL) 149 1.1 mrg fail_formatted (loc, 150 1.1 mrg "ASSERT_STR_STARTSWITH (%s, %s) str=\"%s\" prefix=NULL", 151 1.1 mrg desc_str, desc_prefix, val_str); 152 1.1 mrg 153 1.1 mrg if (startswith (val_str, val_prefix)) 154 1.1 mrg pass (loc, "ASSERT_STR_STARTSWITH"); 155 1.1 mrg else 156 1.1 mrg fail_formatted 157 1.1 mrg (loc, "ASSERT_STR_STARTSWITH (%s, %s) str=\"%s\" prefix=\"%s\"", 158 1.1 mrg desc_str, desc_prefix, val_str, val_prefix); 159 1.1 mrg } 160 1.1 mrg 161 1.1 mrg 162 1.1 mrg /* Constructor. Generate a name for the file. */ 163 1.1 mrg 164 1.1 mrg named_temp_file::named_temp_file (const char *suffix) 165 1.1 mrg { 166 1.1 mrg m_filename = make_temp_file (suffix); 167 1.1 mrg ASSERT_NE (m_filename, NULL); 168 1.1 mrg } 169 1.1 mrg 170 1.1 mrg /* Destructor. Delete the tempfile. */ 171 1.1 mrg 172 1.1 mrg named_temp_file::~named_temp_file () 173 1.1 mrg { 174 1.1 mrg unlink (m_filename); 175 1.1 mrg diagnostics_file_cache_forcibly_evict_file (m_filename); 176 1.1 mrg free (m_filename); 177 1.1 mrg } 178 1.1 mrg 179 1.1 mrg /* Constructor. Create a tempfile using SUFFIX, and write CONTENT to 180 1.1 mrg it. Abort if anything goes wrong, using LOC as the effective 181 1.1 mrg location in the problem report. */ 182 1.1 mrg 183 1.1 mrg temp_source_file::temp_source_file (const location &loc, 184 1.1 mrg const char *suffix, 185 1.1 mrg const char *content) 186 1.1 mrg : named_temp_file (suffix) 187 1.1 mrg { 188 1.1 mrg FILE *out = fopen (get_filename (), "w"); 189 1.1 mrg if (!out) 190 1.1 mrg fail_formatted (loc, "unable to open tempfile: %s", get_filename ()); 191 1.1 mrg fprintf (out, "%s", content); 192 1.1 mrg fclose (out); 193 1.1 mrg } 194 1.1 mrg 195 1.1 mrg /* As above, but with a size, to allow for NUL bytes in CONTENT. */ 196 1.1 mrg 197 1.1 mrg temp_source_file::temp_source_file (const location &loc, 198 1.1 mrg const char *suffix, 199 1.1 mrg const char *content, 200 1.1 mrg size_t sz) 201 1.1 mrg : named_temp_file (suffix) 202 1.1 mrg { 203 1.1 mrg FILE *out = fopen (get_filename (), "w"); 204 1.1 mrg if (!out) 205 1.1 mrg fail_formatted (loc, "unable to open tempfile: %s", get_filename ()); 206 1.1 mrg fwrite (content, sz, 1, out); 207 1.1 mrg fclose (out); 208 1.1 mrg } 209 1.1 mrg 210 1.1 mrg /* Avoid introducing locale-specific differences in the results 211 1.1 mrg by hardcoding open_quote and close_quote. */ 212 1.1 mrg 213 1.1 mrg auto_fix_quotes::auto_fix_quotes () 214 1.1 mrg { 215 1.1 mrg m_saved_open_quote = open_quote; 216 1.1 mrg m_saved_close_quote = close_quote; 217 1.1 mrg open_quote = "`"; 218 1.1 mrg close_quote = "'"; 219 1.1 mrg } 220 1.1 mrg 221 1.1 mrg /* Restore old values of open_quote and close_quote. */ 222 1.1 mrg 223 1.1 mrg auto_fix_quotes::~auto_fix_quotes () 224 1.1 mrg { 225 1.1 mrg open_quote = m_saved_open_quote; 226 1.1 mrg close_quote = m_saved_close_quote; 227 1.1 mrg } 228 1.1 mrg 229 1.1 mrg /* Read the contents of PATH into memory, returning a 0-terminated buffer 230 1.1 mrg that must be freed by the caller. 231 1.1 mrg Fail (and abort) if there are any problems, with LOC as the reported 232 1.1 mrg location of the failure. */ 233 1.1 mrg 234 1.1 mrg char * 235 1.1 mrg read_file (const location &loc, const char *path) 236 1.1 mrg { 237 1.1 mrg FILE *f_in = fopen (path, "r"); 238 1.1 mrg if (!f_in) 239 1.1 mrg fail_formatted (loc, "unable to open file: %s", path); 240 1.1 mrg 241 1.1 mrg /* Read content, allocating FIXME. */ 242 1.1 mrg char *result = NULL; 243 1.1 mrg size_t total_sz = 0; 244 1.1 mrg size_t alloc_sz = 0; 245 1.1 mrg char buf[4096]; 246 1.1 mrg size_t iter_sz_in; 247 1.1 mrg 248 1.1 mrg while ( (iter_sz_in = fread (buf, 1, sizeof (buf), f_in)) ) 249 1.1 mrg { 250 1.1 mrg gcc_assert (alloc_sz >= total_sz); 251 1.1 mrg size_t old_total_sz = total_sz; 252 1.1 mrg total_sz += iter_sz_in; 253 1.1 mrg /* Allow 1 extra byte for 0-termination. */ 254 1.1 mrg if (alloc_sz < (total_sz + 1)) 255 1.1 mrg { 256 1.1 mrg size_t new_alloc_sz = alloc_sz ? alloc_sz * 2: total_sz + 1; 257 1.1 mrg result = (char *)xrealloc (result, new_alloc_sz); 258 1.1 mrg alloc_sz = new_alloc_sz; 259 1.1 mrg } 260 1.1 mrg memcpy (result + old_total_sz, buf, iter_sz_in); 261 1.1 mrg } 262 1.1 mrg 263 1.1 mrg if (!feof (f_in)) 264 1.1 mrg fail_formatted (loc, "error reading from %s: %s", path, 265 1.1 mrg xstrerror (errno)); 266 1.1 mrg 267 1.1 mrg fclose (f_in); 268 1.1 mrg 269 1.1 mrg /* 0-terminate the buffer. */ 270 1.1 mrg gcc_assert (total_sz < alloc_sz); 271 1.1 mrg result[total_sz] = '\0'; 272 1.1 mrg 273 1.1 mrg return result; 274 1.1 mrg } 275 1.1 mrg 276 1.1 mrg /* The path of SRCDIR/testsuite/selftests. */ 277 1.1 mrg 278 1.1 mrg const char *path_to_selftest_files = NULL; 279 1.1 mrg 280 1.1 mrg /* Convert a path relative to SRCDIR/testsuite/selftests 281 1.1 mrg to a real path (either absolute, or relative to pwd). 282 1.1 mrg The result should be freed by the caller. */ 283 1.1 mrg 284 1.1 mrg char * 285 1.1 mrg locate_file (const char *name) 286 1.1 mrg { 287 1.1 mrg ASSERT_NE (NULL, path_to_selftest_files); 288 1.1 mrg return concat (path_to_selftest_files, "/", name, NULL); 289 1.1 mrg } 290 1.1 mrg 291 1.1 mrg /* selftest::test_runner's ctor. */ 292 1.1 mrg 293 1.1 mrg test_runner::test_runner (const char *name) 294 1.1 mrg : m_name (name), 295 1.1 mrg m_start_time (get_run_time ()) 296 1.1 mrg { 297 1.1 mrg } 298 1.1 mrg 299 1.1 mrg /* selftest::test_runner's dtor. Print a summary line to stderr. */ 300 1.1 mrg 301 1.1 mrg test_runner::~test_runner () 302 1.1 mrg { 303 1.1 mrg /* Finished running tests. */ 304 1.1 mrg long finish_time = get_run_time (); 305 1.1 mrg long elapsed_time = finish_time - m_start_time; 306 1.1 mrg 307 1.1 mrg fprintf (stderr, 308 1.1 mrg "%s: %i pass(es) in %ld.%06ld seconds\n", 309 1.1 mrg m_name, num_passes, 310 1.1 mrg elapsed_time / 1000000, elapsed_time % 1000000); 311 1.1 mrg } 312 1.1 mrg 313 1.1 mrg /* Selftests for libiberty. */ 314 1.1 mrg 315 1.1 mrg /* Verify that xstrndup generates EXPECTED when called on SRC and N. */ 316 1.1 mrg 317 1.1 mrg static void 318 1.1 mrg assert_xstrndup_eq (const char *expected, const char *src, size_t n) 319 1.1 mrg { 320 1.1 mrg char *buf = xstrndup (src, n); 321 1.1 mrg ASSERT_STREQ (expected, buf); 322 1.1 mrg free (buf); 323 1.1 mrg } 324 1.1 mrg 325 1.1 mrg /* Verify that xstrndup works as expected. */ 326 1.1 mrg 327 1.1 mrg static void 328 1.1 mrg test_xstrndup () 329 1.1 mrg { 330 1.1 mrg assert_xstrndup_eq ("", "test", 0); 331 1.1 mrg assert_xstrndup_eq ("t", "test", 1); 332 1.1 mrg assert_xstrndup_eq ("te", "test", 2); 333 1.1 mrg assert_xstrndup_eq ("tes", "test", 3); 334 1.1 mrg assert_xstrndup_eq ("test", "test", 4); 335 1.1 mrg assert_xstrndup_eq ("test", "test", 5); 336 1.1 mrg 337 1.1 mrg /* Test on an string without zero termination. */ 338 1.1 mrg const char src[4] = {'t', 'e', 's', 't'}; 339 1.1 mrg assert_xstrndup_eq ("", src, 0); 340 1.1 mrg assert_xstrndup_eq ("t", src, 1); 341 1.1 mrg assert_xstrndup_eq ("te", src, 2); 342 1.1 mrg assert_xstrndup_eq ("tes", src, 3); 343 1.1 mrg assert_xstrndup_eq ("test", src, 4); 344 1.1 mrg } 345 1.1 mrg 346 1.1 mrg /* Run selftests for libiberty. */ 347 1.1 mrg 348 1.1 mrg static void 349 1.1 mrg test_libiberty () 350 1.1 mrg { 351 1.1 mrg test_xstrndup (); 352 1.1 mrg } 353 1.1 mrg 354 1.1 mrg /* Selftests for the selftest system itself. */ 355 1.1 mrg 356 1.1 mrg /* Sanity-check the ASSERT_ macros with various passing cases. */ 357 1.1 mrg 358 1.1 mrg static void 359 1.1 mrg test_assertions () 360 1.1 mrg { 361 1.1 mrg ASSERT_TRUE (true); 362 1.1 mrg ASSERT_FALSE (false); 363 1.1 mrg ASSERT_EQ (1, 1); 364 1.1 mrg ASSERT_EQ_AT (SELFTEST_LOCATION, 1, 1); 365 1.1 mrg ASSERT_NE (1, 2); 366 1.1 mrg ASSERT_GT (2, 1); 367 1.1 mrg ASSERT_GT_AT (SELFTEST_LOCATION, 2, 1); 368 1.1 mrg ASSERT_LT (1, 2); 369 1.1 mrg ASSERT_LT_AT (SELFTEST_LOCATION, 1, 2); 370 1.1 mrg ASSERT_STREQ ("test", "test"); 371 1.1 mrg ASSERT_STREQ_AT (SELFTEST_LOCATION, "test", "test"); 372 1.1 mrg ASSERT_STR_CONTAINS ("foo bar baz", "bar"); 373 1.1 mrg } 374 1.1 mrg 375 1.1 mrg /* Verify named_temp_file. */ 376 1.1 mrg 377 1.1 mrg static void 378 1.1 mrg test_named_temp_file () 379 1.1 mrg { 380 1.1 mrg named_temp_file t (".txt"); 381 1.1 mrg FILE *f = fopen (t.get_filename (), "w"); 382 1.1 mrg if (!f) 383 1.1 mrg fail_formatted (SELFTEST_LOCATION, 384 1.1 mrg "unable to open %s for writing", t.get_filename ()); 385 1.1 mrg fclose (f); 386 1.1 mrg } 387 1.1 mrg 388 1.1 mrg /* Verify read_file (and also temp_source_file). */ 389 1.1 mrg 390 1.1 mrg static void 391 1.1 mrg test_read_file () 392 1.1 mrg { 393 1.1 mrg temp_source_file t (SELFTEST_LOCATION, "test1.s", 394 1.1 mrg "\tjmp\t.L2\n"); 395 1.1 mrg char *buf = read_file (SELFTEST_LOCATION, t.get_filename ()); 396 1.1 mrg ASSERT_STREQ ("\tjmp\t.L2\n", buf); 397 1.1 mrg free (buf); 398 1.1 mrg } 399 1.1 mrg 400 1.1 mrg /* Verify locate_file (and read_file). */ 401 1.1 mrg 402 1.1 mrg static void 403 1.1 mrg test_locate_file () 404 1.1 mrg { 405 1.1 mrg char *path = locate_file ("example.txt"); 406 1.1 mrg char *buf = read_file (SELFTEST_LOCATION, path); 407 1.1 mrg ASSERT_STREQ ("example of a selftest file\n", buf); 408 1.1 mrg free (buf); 409 1.1 mrg free (path); 410 1.1 mrg } 411 1.1 mrg 412 1.1 mrg /* Run all of the selftests within this file. */ 413 1.1 mrg 414 1.1 mrg void 415 1.1 mrg selftest_cc_tests () 416 1.1 mrg { 417 1.1 mrg test_libiberty (); 418 1.1 mrg test_assertions (); 419 1.1 mrg test_named_temp_file (); 420 1.1 mrg test_read_file (); 421 1.1 mrg test_locate_file (); 422 1.1 mrg } 423 1.1 mrg 424 1.1 mrg } // namespace selftest 425 1.1 mrg 426 1.1 mrg #endif /* #if CHECKING_P */ 427