Home | History | Annotate | Line # | Download | only in gcc
      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