re PR ada/37139 (DEP prevents using Ada tasking)
[gcc.git] / gcc / selftest.c
1 /* A self-testing framework, for use by -fself-test.
2 Copyright (C) 2015-2016 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 (0 == strcmp (val_expected, val_actual))
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 /* Selftests for the selftest system itself. */
202
203 /* Sanity-check the ASSERT_ macros with various passing cases. */
204
205 static void
206 test_assertions ()
207 {
208 ASSERT_TRUE (true);
209 ASSERT_FALSE (false);
210 ASSERT_EQ (1, 1);
211 ASSERT_EQ_AT (SELFTEST_LOCATION, 1, 1);
212 ASSERT_NE (1, 2);
213 ASSERT_STREQ ("test", "test");
214 ASSERT_STREQ_AT (SELFTEST_LOCATION, "test", "test");
215 ASSERT_STR_CONTAINS ("foo bar baz", "bar");
216 }
217
218 /* Verify named_temp_file. */
219
220 static void
221 test_named_temp_file ()
222 {
223 named_temp_file t (".txt");
224 FILE *f = fopen (t.get_filename (), "w");
225 if (!f)
226 fail_formatted (SELFTEST_LOCATION,
227 "unable to open %s for writing", t.get_filename ());
228 fclose (f);
229 }
230
231 /* Verify read_file (and also temp_source_file). */
232
233 static void
234 test_read_file ()
235 {
236 temp_source_file t (SELFTEST_LOCATION, "test1.s",
237 "\tjmp\t.L2\n");
238 char *buf = read_file (SELFTEST_LOCATION, t.get_filename ());
239 ASSERT_STREQ ("\tjmp\t.L2\n", buf);
240 free (buf);
241 }
242
243 /* Run all of the selftests within this file. */
244
245 void
246 selftest_c_tests ()
247 {
248 test_assertions ();
249 test_named_temp_file ();
250 test_read_file ();
251 }
252
253 } // namespace selftest
254
255 #endif /* #if CHECKING_P */