Core issue 2310 - conversion to base of incomplete type.
[official-gcc.git] / gcc / selftest.c
blob74adc63e65cd004c4d26757511c4422534643dd1
1 /* A self-testing framework, for use by -fself-test.
2 Copyright (C) 2015-2018 Free Software Foundation, Inc.
4 This file is part of GCC.
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.
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.
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/>. */
20 #include "config.h"
21 #include "system.h"
22 #include "coretypes.h"
23 #include "selftest.h"
25 #if CHECKING_P
27 namespace selftest {
29 int num_passes;
31 /* Record the successful outcome of some aspect of a test. */
33 void
34 pass (const location &/*loc*/, const char */*msg*/)
36 num_passes++;
39 /* Report the failed outcome of some aspect of a test and abort. */
41 void
42 fail (const location &loc, const char *msg)
44 fprintf (stderr,"%s:%i: %s: FAIL: %s\n", loc.m_file, loc.m_line,
45 loc.m_function, msg);
46 abort ();
49 /* As "fail", but using printf-style formatted output. */
51 void
52 fail_formatted (const location &loc, const char *fmt, ...)
54 va_list ap;
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 ();
65 /* Implementation detail of ASSERT_STREQ.
66 Compare val1 and val2 with strcmp. They ought
67 to be non-NULL; fail gracefully if either or both are NULL. */
69 void
70 assert_streq (const location &loc,
71 const char *desc_val1, const char *desc_val2,
72 const char *val1, const char *val2)
74 /* If val1 or val2 are NULL, fail with a custom error message. */
75 if (val1 == NULL)
76 if (val2 == NULL)
77 fail_formatted (loc, "ASSERT_STREQ (%s, %s) val1=NULL val2=NULL",
78 desc_val1, desc_val2);
79 else
80 fail_formatted (loc, "ASSERT_STREQ (%s, %s) val1=NULL val2=\"%s\"",
81 desc_val1, desc_val2, val2);
82 else
83 if (val2 == NULL)
84 fail_formatted (loc, "ASSERT_STREQ (%s, %s) val1=\"%s\" val2=NULL",
85 desc_val1, desc_val2, val1);
86 else
88 if (strcmp (val1, val2) == 0)
89 pass (loc, "ASSERT_STREQ");
90 else
91 fail_formatted (loc, "ASSERT_STREQ (%s, %s) val1=\"%s\" val2=\"%s\"",
92 desc_val1, desc_val2, val1, val2);
96 /* Implementation detail of ASSERT_STR_CONTAINS.
97 Use strstr to determine if val_needle is is within val_haystack.
98 ::selftest::pass if it is found.
99 ::selftest::fail if it is not found. */
101 void
102 assert_str_contains (const location &loc,
103 const char *desc_haystack,
104 const char *desc_needle,
105 const char *val_haystack,
106 const char *val_needle)
108 /* If val_haystack is NULL, fail with a custom error message. */
109 if (val_haystack == NULL)
110 fail_formatted (loc, "ASSERT_STR_CONTAINS (%s, %s) haystack=NULL",
111 desc_haystack, desc_needle);
113 /* If val_needle is NULL, fail with a custom error message. */
114 if (val_needle == NULL)
115 fail_formatted (loc,
116 "ASSERT_STR_CONTAINS (%s, %s) haystack=\"%s\" needle=NULL",
117 desc_haystack, desc_needle, val_haystack);
119 const char *test = strstr (val_haystack, val_needle);
120 if (test)
121 pass (loc, "ASSERT_STR_CONTAINS");
122 else
123 fail_formatted
124 (loc, "ASSERT_STR_CONTAINS (%s, %s) haystack=\"%s\" needle=\"%s\"",
125 desc_haystack, desc_needle, val_haystack, val_needle);
128 /* Constructor. Generate a name for the file. */
130 named_temp_file::named_temp_file (const char *suffix)
132 m_filename = make_temp_file (suffix);
133 ASSERT_NE (m_filename, NULL);
136 /* Destructor. Delete the tempfile. */
138 named_temp_file::~named_temp_file ()
140 unlink (m_filename);
141 diagnostics_file_cache_forcibly_evict_file (m_filename);
142 free (m_filename);
145 /* Constructor. Create a tempfile using SUFFIX, and write CONTENT to
146 it. Abort if anything goes wrong, using LOC as the effective
147 location in the problem report. */
149 temp_source_file::temp_source_file (const location &loc,
150 const char *suffix,
151 const char *content)
152 : named_temp_file (suffix)
154 FILE *out = fopen (get_filename (), "w");
155 if (!out)
156 fail_formatted (loc, "unable to open tempfile: %s", get_filename ());
157 fprintf (out, "%s", content);
158 fclose (out);
161 /* Read the contents of PATH into memory, returning a 0-terminated buffer
162 that must be freed by the caller.
163 Fail (and abort) if there are any problems, with LOC as the reported
164 location of the failure. */
166 char *
167 read_file (const location &loc, const char *path)
169 FILE *f_in = fopen (path, "r");
170 if (!f_in)
171 fail_formatted (loc, "unable to open file: %s", path);
173 /* Read content, allocating FIXME. */
174 char *result = NULL;
175 size_t total_sz = 0;
176 size_t alloc_sz = 0;
177 char buf[4096];
178 size_t iter_sz_in;
180 while ( (iter_sz_in = fread (buf, 1, sizeof (buf), f_in)) )
182 gcc_assert (alloc_sz >= total_sz);
183 size_t old_total_sz = total_sz;
184 total_sz += iter_sz_in;
185 /* Allow 1 extra byte for 0-termination. */
186 if (alloc_sz < (total_sz + 1))
188 size_t new_alloc_sz = alloc_sz ? alloc_sz * 2: total_sz + 1;
189 result = (char *)xrealloc (result, new_alloc_sz);
190 alloc_sz = new_alloc_sz;
192 memcpy (result + old_total_sz, buf, iter_sz_in);
195 if (!feof (f_in))
196 fail_formatted (loc, "error reading from %s: %s", path,
197 xstrerror (errno));
199 fclose (f_in);
201 /* 0-terminate the buffer. */
202 gcc_assert (total_sz < alloc_sz);
203 result[total_sz] = '\0';
205 return result;
208 /* The path of SRCDIR/testsuite/selftests. */
210 const char *path_to_selftest_files = NULL;
212 /* Convert a path relative to SRCDIR/testsuite/selftests
213 to a real path (either absolute, or relative to pwd).
214 The result should be freed by the caller. */
216 char *
217 locate_file (const char *name)
219 ASSERT_NE (NULL, path_to_selftest_files);
220 return concat (path_to_selftest_files, "/", name, NULL);
223 /* selftest::test_runner's ctor. */
225 test_runner::test_runner (const char *name)
226 : m_name (name),
227 m_start_time (get_run_time ())
231 /* selftest::test_runner's dtor. Print a summary line to stderr. */
233 test_runner::~test_runner ()
235 /* Finished running tests. */
236 long finish_time = get_run_time ();
237 long elapsed_time = finish_time - m_start_time;
239 fprintf (stderr,
240 "%s: %i pass(es) in %ld.%06ld seconds\n",
241 m_name, num_passes,
242 elapsed_time / 1000000, elapsed_time % 1000000);
245 /* Selftests for libiberty. */
247 /* Verify that xstrndup generates EXPECTED when called on SRC and N. */
249 static void
250 assert_xstrndup_eq (const char *expected, const char *src, size_t n)
252 char *buf = xstrndup (src, n);
253 ASSERT_STREQ (expected, buf);
254 free (buf);
257 /* Verify that xstrndup works as expected. */
259 static void
260 test_xstrndup ()
262 assert_xstrndup_eq ("", "test", 0);
263 assert_xstrndup_eq ("t", "test", 1);
264 assert_xstrndup_eq ("te", "test", 2);
265 assert_xstrndup_eq ("tes", "test", 3);
266 assert_xstrndup_eq ("test", "test", 4);
267 assert_xstrndup_eq ("test", "test", 5);
269 /* Test on an string without zero termination. */
270 const char src[4] = {'t', 'e', 's', 't'};
271 assert_xstrndup_eq ("", src, 0);
272 assert_xstrndup_eq ("t", src, 1);
273 assert_xstrndup_eq ("te", src, 2);
274 assert_xstrndup_eq ("tes", src, 3);
275 assert_xstrndup_eq ("test", src, 4);
278 /* Run selftests for libiberty. */
280 static void
281 test_libiberty ()
283 test_xstrndup ();
286 /* Selftests for the selftest system itself. */
288 /* Sanity-check the ASSERT_ macros with various passing cases. */
290 static void
291 test_assertions ()
293 ASSERT_TRUE (true);
294 ASSERT_FALSE (false);
295 ASSERT_EQ (1, 1);
296 ASSERT_EQ_AT (SELFTEST_LOCATION, 1, 1);
297 ASSERT_NE (1, 2);
298 ASSERT_GT (2, 1);
299 ASSERT_GT_AT (SELFTEST_LOCATION, 2, 1);
300 ASSERT_LT (1, 2);
301 ASSERT_LT_AT (SELFTEST_LOCATION, 1, 2);
302 ASSERT_STREQ ("test", "test");
303 ASSERT_STREQ_AT (SELFTEST_LOCATION, "test", "test");
304 ASSERT_STR_CONTAINS ("foo bar baz", "bar");
307 /* Verify named_temp_file. */
309 static void
310 test_named_temp_file ()
312 named_temp_file t (".txt");
313 FILE *f = fopen (t.get_filename (), "w");
314 if (!f)
315 fail_formatted (SELFTEST_LOCATION,
316 "unable to open %s for writing", t.get_filename ());
317 fclose (f);
320 /* Verify read_file (and also temp_source_file). */
322 static void
323 test_read_file ()
325 temp_source_file t (SELFTEST_LOCATION, "test1.s",
326 "\tjmp\t.L2\n");
327 char *buf = read_file (SELFTEST_LOCATION, t.get_filename ());
328 ASSERT_STREQ ("\tjmp\t.L2\n", buf);
329 free (buf);
332 /* Verify locate_file (and read_file). */
334 static void
335 test_locate_file ()
337 char *path = locate_file ("example.txt");
338 char *buf = read_file (SELFTEST_LOCATION, path);
339 ASSERT_STREQ ("example of a selftest file\n", buf);
340 free (buf);
341 free (path);
344 /* Run all of the selftests within this file. */
346 void
347 selftest_c_tests ()
349 test_libiberty ();
350 test_assertions ();
351 test_named_temp_file ();
352 test_read_file ();
353 test_locate_file ();
356 } // namespace selftest
358 #endif /* #if CHECKING_P */