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