1 /* A self-testing framework, for use by -fself-test.
2 Copyright (C) 2015-2021 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
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
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/>. */
22 #include "coretypes.h"
32 /* Record the successful outcome of some aspect of a test. */
35 pass (const location
&/*loc*/, const char */
*msg*/
)
40 /* Report the failed outcome of some aspect of a test and abort. */
43 fail (const location
&loc
, const char *msg
)
45 fprintf (stderr
,"%s:%i: %s: FAIL: %s\n", loc
.m_file
, loc
.m_line
,
50 /* As "fail", but using printf-style formatted output. */
53 fail_formatted (const location
&loc
, const char *fmt
, ...)
57 fprintf (stderr
, "%s:%i: %s: FAIL: ", loc
.m_file
, loc
.m_line
,
60 vfprintf (stderr
, fmt
, ap
);
62 fprintf (stderr
, "\n");
66 /* Implementation detail of ASSERT_STREQ.
67 Compare val1 and val2 with strcmp. They ought
68 to be non-NULL; fail gracefully if either or both are NULL. */
71 assert_streq (const location
&loc
,
72 const char *desc_val1
, const char *desc_val2
,
73 const char *val1
, const char *val2
)
75 /* If val1 or val2 are NULL, fail with a custom error message. */
78 fail_formatted (loc
, "ASSERT_STREQ (%s, %s) val1=NULL val2=NULL",
79 desc_val1
, desc_val2
);
81 fail_formatted (loc
, "ASSERT_STREQ (%s, %s) val1=NULL val2=\"%s\"",
82 desc_val1
, desc_val2
, val2
);
85 fail_formatted (loc
, "ASSERT_STREQ (%s, %s) val1=\"%s\" val2=NULL",
86 desc_val1
, desc_val2
, val1
);
89 if (strcmp (val1
, val2
) == 0)
90 pass (loc
, "ASSERT_STREQ");
92 fail_formatted (loc
, "ASSERT_STREQ (%s, %s) val1=\"%s\" val2=\"%s\"",
93 desc_val1
, desc_val2
, val1
, val2
);
97 /* Implementation detail of ASSERT_STR_CONTAINS.
98 Use strstr to determine if val_needle is within val_haystack.
99 ::selftest::pass if it is found.
100 ::selftest::fail if it is not found. */
103 assert_str_contains (const location
&loc
,
104 const char *desc_haystack
,
105 const char *desc_needle
,
106 const char *val_haystack
,
107 const char *val_needle
)
109 /* If val_haystack is NULL, fail with a custom error message. */
110 if (val_haystack
== NULL
)
111 fail_formatted (loc
, "ASSERT_STR_CONTAINS (%s, %s) haystack=NULL",
112 desc_haystack
, desc_needle
);
114 /* If val_needle is NULL, fail with a custom error message. */
115 if (val_needle
== NULL
)
117 "ASSERT_STR_CONTAINS (%s, %s) haystack=\"%s\" needle=NULL",
118 desc_haystack
, desc_needle
, val_haystack
);
120 const char *test
= strstr (val_haystack
, val_needle
);
122 pass (loc
, "ASSERT_STR_CONTAINS");
125 (loc
, "ASSERT_STR_CONTAINS (%s, %s) haystack=\"%s\" needle=\"%s\"",
126 desc_haystack
, desc_needle
, val_haystack
, val_needle
);
129 /* Implementation detail of ASSERT_STR_STARTSWITH.
130 Determine if VAL_STR starts with VAL_PREFIX.
131 ::selftest::pass if VAL_STR does start with VAL_PREFIX.
132 ::selftest::fail if it does not, or either is NULL (using
133 DESC_STR and DESC_PREFIX in the error message). */
136 assert_str_startswith (const location
&loc
,
137 const char *desc_str
,
138 const char *desc_prefix
,
140 const char *val_prefix
)
142 /* If val_str is NULL, fail with a custom error message. */
144 fail_formatted (loc
, "ASSERT_STR_STARTSWITH (%s, %s) str=NULL",
145 desc_str
, desc_prefix
);
147 /* If val_prefix is NULL, fail with a custom error message. */
148 if (val_prefix
== NULL
)
150 "ASSERT_STR_STARTSWITH (%s, %s) str=\"%s\" prefix=NULL",
151 desc_str
, desc_prefix
, val_str
);
153 if (startswith (val_str
, val_prefix
))
154 pass (loc
, "ASSERT_STR_STARTSWITH");
157 (loc
, "ASSERT_STR_STARTSWITH (%s, %s) str=\"%s\" prefix=\"%s\"",
158 desc_str
, desc_prefix
, val_str
, val_prefix
);
162 /* Constructor. Generate a name for the file. */
164 named_temp_file::named_temp_file (const char *suffix
)
166 m_filename
= make_temp_file (suffix
);
167 ASSERT_NE (m_filename
, NULL
);
170 /* Destructor. Delete the tempfile. */
172 named_temp_file::~named_temp_file ()
175 diagnostics_file_cache_forcibly_evict_file (m_filename
);
179 /* Constructor. Create a tempfile using SUFFIX, and write CONTENT to
180 it. Abort if anything goes wrong, using LOC as the effective
181 location in the problem report. */
183 temp_source_file::temp_source_file (const location
&loc
,
186 : named_temp_file (suffix
)
188 FILE *out
= fopen (get_filename (), "w");
190 fail_formatted (loc
, "unable to open tempfile: %s", get_filename ());
191 fprintf (out
, "%s", content
);
195 /* Avoid introducing locale-specific differences in the results
196 by hardcoding open_quote and close_quote. */
198 auto_fix_quotes::auto_fix_quotes ()
200 m_saved_open_quote
= open_quote
;
201 m_saved_close_quote
= close_quote
;
206 /* Restore old values of open_quote and close_quote. */
208 auto_fix_quotes::~auto_fix_quotes ()
210 open_quote
= m_saved_open_quote
;
211 close_quote
= m_saved_close_quote
;
214 /* Read the contents of PATH into memory, returning a 0-terminated buffer
215 that must be freed by the caller.
216 Fail (and abort) if there are any problems, with LOC as the reported
217 location of the failure. */
220 read_file (const location
&loc
, const char *path
)
222 FILE *f_in
= fopen (path
, "r");
224 fail_formatted (loc
, "unable to open file: %s", path
);
226 /* Read content, allocating FIXME. */
233 while ( (iter_sz_in
= fread (buf
, 1, sizeof (buf
), f_in
)) )
235 gcc_assert (alloc_sz
>= total_sz
);
236 size_t old_total_sz
= total_sz
;
237 total_sz
+= iter_sz_in
;
238 /* Allow 1 extra byte for 0-termination. */
239 if (alloc_sz
< (total_sz
+ 1))
241 size_t new_alloc_sz
= alloc_sz
? alloc_sz
* 2: total_sz
+ 1;
242 result
= (char *)xrealloc (result
, new_alloc_sz
);
243 alloc_sz
= new_alloc_sz
;
245 memcpy (result
+ old_total_sz
, buf
, iter_sz_in
);
249 fail_formatted (loc
, "error reading from %s: %s", path
,
254 /* 0-terminate the buffer. */
255 gcc_assert (total_sz
< alloc_sz
);
256 result
[total_sz
] = '\0';
261 /* The path of SRCDIR/testsuite/selftests. */
263 const char *path_to_selftest_files
= NULL
;
265 /* Convert a path relative to SRCDIR/testsuite/selftests
266 to a real path (either absolute, or relative to pwd).
267 The result should be freed by the caller. */
270 locate_file (const char *name
)
272 ASSERT_NE (NULL
, path_to_selftest_files
);
273 return concat (path_to_selftest_files
, "/", name
, NULL
);
276 /* selftest::test_runner's ctor. */
278 test_runner::test_runner (const char *name
)
280 m_start_time (get_run_time ())
284 /* selftest::test_runner's dtor. Print a summary line to stderr. */
286 test_runner::~test_runner ()
288 /* Finished running tests. */
289 long finish_time
= get_run_time ();
290 long elapsed_time
= finish_time
- m_start_time
;
293 "%s: %i pass(es) in %ld.%06ld seconds\n",
295 elapsed_time
/ 1000000, elapsed_time
% 1000000);
298 /* Selftests for libiberty. */
300 /* Verify that xstrndup generates EXPECTED when called on SRC and N. */
303 assert_xstrndup_eq (const char *expected
, const char *src
, size_t n
)
305 char *buf
= xstrndup (src
, n
);
306 ASSERT_STREQ (expected
, buf
);
310 /* Verify that xstrndup works as expected. */
315 assert_xstrndup_eq ("", "test", 0);
316 assert_xstrndup_eq ("t", "test", 1);
317 assert_xstrndup_eq ("te", "test", 2);
318 assert_xstrndup_eq ("tes", "test", 3);
319 assert_xstrndup_eq ("test", "test", 4);
320 assert_xstrndup_eq ("test", "test", 5);
322 /* Test on an string without zero termination. */
323 const char src
[4] = {'t', 'e', 's', 't'};
324 assert_xstrndup_eq ("", src
, 0);
325 assert_xstrndup_eq ("t", src
, 1);
326 assert_xstrndup_eq ("te", src
, 2);
327 assert_xstrndup_eq ("tes", src
, 3);
328 assert_xstrndup_eq ("test", src
, 4);
331 /* Run selftests for libiberty. */
339 /* Selftests for the selftest system itself. */
341 /* Sanity-check the ASSERT_ macros with various passing cases. */
347 ASSERT_FALSE (false);
349 ASSERT_EQ_AT (SELFTEST_LOCATION
, 1, 1);
352 ASSERT_GT_AT (SELFTEST_LOCATION
, 2, 1);
354 ASSERT_LT_AT (SELFTEST_LOCATION
, 1, 2);
355 ASSERT_STREQ ("test", "test");
356 ASSERT_STREQ_AT (SELFTEST_LOCATION
, "test", "test");
357 ASSERT_STR_CONTAINS ("foo bar baz", "bar");
360 /* Verify named_temp_file. */
363 test_named_temp_file ()
365 named_temp_file
t (".txt");
366 FILE *f
= fopen (t
.get_filename (), "w");
368 fail_formatted (SELFTEST_LOCATION
,
369 "unable to open %s for writing", t
.get_filename ());
373 /* Verify read_file (and also temp_source_file). */
378 temp_source_file
t (SELFTEST_LOCATION
, "test1.s",
380 char *buf
= read_file (SELFTEST_LOCATION
, t
.get_filename ());
381 ASSERT_STREQ ("\tjmp\t.L2\n", buf
);
385 /* Verify locate_file (and read_file). */
390 char *path
= locate_file ("example.txt");
391 char *buf
= read_file (SELFTEST_LOCATION
, path
);
392 ASSERT_STREQ ("example of a selftest file\n", buf
);
397 /* Run all of the selftests within this file. */
404 test_named_temp_file ();
409 } // namespace selftest
411 #endif /* #if CHECKING_P */