selftest.cc revision 1.1 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