Mercurial > hg > CbC > CbC_gcc
comparison gcc/selftest.c @ 111:04ced10e8804
gcc 7
author | kono |
---|---|
date | Fri, 27 Oct 2017 22:46:09 +0900 |
parents | |
children | 84e7813d76e9 |
comparison
equal
deleted
inserted
replaced
68:561a7518be6b | 111:04ced10e8804 |
---|---|
1 /* A self-testing framework, for use by -fself-test. | |
2 Copyright (C) 2015-2017 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 /* The path of SRCDIR/testsuite/selftests. */ | |
202 | |
203 const char *path_to_selftest_files = NULL; | |
204 | |
205 /* Convert a path relative to SRCDIR/testsuite/selftests | |
206 to a real path (either absolute, or relative to pwd). | |
207 The result should be freed by the caller. */ | |
208 | |
209 char * | |
210 locate_file (const char *name) | |
211 { | |
212 ASSERT_NE (NULL, path_to_selftest_files); | |
213 return concat (path_to_selftest_files, "/", name, NULL); | |
214 } | |
215 | |
216 /* Selftests for libiberty. */ | |
217 | |
218 /* Verify that xstrndup generates EXPECTED when called on SRC and N. */ | |
219 | |
220 static void | |
221 assert_xstrndup_eq (const char *expected, const char *src, size_t n) | |
222 { | |
223 char *buf = xstrndup (src, n); | |
224 ASSERT_STREQ (expected, buf); | |
225 free (buf); | |
226 } | |
227 | |
228 /* Verify that xstrndup works as expected. */ | |
229 | |
230 static void | |
231 test_xstrndup () | |
232 { | |
233 assert_xstrndup_eq ("", "test", 0); | |
234 assert_xstrndup_eq ("t", "test", 1); | |
235 assert_xstrndup_eq ("te", "test", 2); | |
236 assert_xstrndup_eq ("tes", "test", 3); | |
237 assert_xstrndup_eq ("test", "test", 4); | |
238 assert_xstrndup_eq ("test", "test", 5); | |
239 | |
240 /* Test on an string without zero termination. */ | |
241 const char src[4] = {'t', 'e', 's', 't'}; | |
242 assert_xstrndup_eq ("", src, 0); | |
243 assert_xstrndup_eq ("t", src, 1); | |
244 assert_xstrndup_eq ("te", src, 2); | |
245 assert_xstrndup_eq ("tes", src, 3); | |
246 assert_xstrndup_eq ("test", src, 4); | |
247 } | |
248 | |
249 /* Run selftests for libiberty. */ | |
250 | |
251 static void | |
252 test_libiberty () | |
253 { | |
254 test_xstrndup (); | |
255 } | |
256 | |
257 /* Selftests for the selftest system itself. */ | |
258 | |
259 /* Sanity-check the ASSERT_ macros with various passing cases. */ | |
260 | |
261 static void | |
262 test_assertions () | |
263 { | |
264 ASSERT_TRUE (true); | |
265 ASSERT_FALSE (false); | |
266 ASSERT_EQ (1, 1); | |
267 ASSERT_EQ_AT (SELFTEST_LOCATION, 1, 1); | |
268 ASSERT_NE (1, 2); | |
269 ASSERT_STREQ ("test", "test"); | |
270 ASSERT_STREQ_AT (SELFTEST_LOCATION, "test", "test"); | |
271 ASSERT_STR_CONTAINS ("foo bar baz", "bar"); | |
272 } | |
273 | |
274 /* Verify named_temp_file. */ | |
275 | |
276 static void | |
277 test_named_temp_file () | |
278 { | |
279 named_temp_file t (".txt"); | |
280 FILE *f = fopen (t.get_filename (), "w"); | |
281 if (!f) | |
282 fail_formatted (SELFTEST_LOCATION, | |
283 "unable to open %s for writing", t.get_filename ()); | |
284 fclose (f); | |
285 } | |
286 | |
287 /* Verify read_file (and also temp_source_file). */ | |
288 | |
289 static void | |
290 test_read_file () | |
291 { | |
292 temp_source_file t (SELFTEST_LOCATION, "test1.s", | |
293 "\tjmp\t.L2\n"); | |
294 char *buf = read_file (SELFTEST_LOCATION, t.get_filename ()); | |
295 ASSERT_STREQ ("\tjmp\t.L2\n", buf); | |
296 free (buf); | |
297 } | |
298 | |
299 /* Verify locate_file (and read_file). */ | |
300 | |
301 static void | |
302 test_locate_file () | |
303 { | |
304 char *path = locate_file ("example.txt"); | |
305 char *buf = read_file (SELFTEST_LOCATION, path); | |
306 ASSERT_STREQ ("example of a selftest file\n", buf); | |
307 free (buf); | |
308 free (path); | |
309 } | |
310 | |
311 /* Run all of the selftests within this file. */ | |
312 | |
313 void | |
314 selftest_c_tests () | |
315 { | |
316 test_libiberty (); | |
317 test_assertions (); | |
318 test_named_temp_file (); | |
319 test_read_file (); | |
320 test_locate_file (); | |
321 } | |
322 | |
323 } // namespace selftest | |
324 | |
325 #endif /* #if CHECKING_P */ |