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