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